123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- // This file contain the two main data structures controlled by the XRSystem.
- // XRView contains the parameters required to render (proj and view matrices, viewport, etc)
- // XRPass holds the render target information and a list of XRView.
- // When a pass has 2+ views, single-pass will be active.
- // To avoid allocating every frame, XRView is a struct and XRPass is pooled.
- #if ENABLE_VR && ENABLE_XR_MODULE
- using System;
- using System.Collections.Generic;
- using UnityEngine.XR;
- namespace UnityEngine.Rendering.Universal
- {
- internal struct XRPassCreateInfo
- {
- public int multipassId;
- public int cullingPassId;
- public RenderTexture renderTarget;
- public RenderTextureDescriptor renderTargetDesc;
- public bool renderTargetIsRenderTexture;
- public ScriptableCullingParameters cullingParameters;
- public XRPass.CustomMirrorView customMirrorView;
- }
- internal struct XRViewCreateInfo
- {
- public Matrix4x4 projMatrix;
- public Matrix4x4 viewMatrix;
- public Rect viewport;
- public int textureArraySlice;
- }
- internal struct XRView
- {
- internal readonly Matrix4x4 projMatrix;
- internal readonly Matrix4x4 viewMatrix;
- internal readonly Rect viewport;
- internal readonly Mesh occlusionMesh;
- internal readonly int textureArraySlice;
- internal XRView(Matrix4x4 proj, Matrix4x4 view, Rect vp, int dstSlice)
- {
- projMatrix = proj;
- viewMatrix = view;
- viewport = vp;
- occlusionMesh = null;
- textureArraySlice = dstSlice;
- }
- internal XRView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySubsystem.XRRenderParameter renderParameter)
- {
- projMatrix = renderParameter.projection;
- viewMatrix = renderParameter.view;
- viewport = renderParameter.viewport;
- occlusionMesh = renderParameter.occlusionMesh;
- textureArraySlice = renderParameter.textureArraySlice;
- // Convert viewport from normalized to screen space
- viewport.x *= renderPass.renderTargetDesc.width;
- viewport.width *= renderPass.renderTargetDesc.width;
- viewport.y *= renderPass.renderTargetDesc.height;
- viewport.height *= renderPass.renderTargetDesc.height;
- }
- }
- class XRPass
- {
- internal List<XRView> views = new List<XRView>(2);
- internal bool enabled { get => views.Count > 0; }
- internal bool xrSdkEnabled { get; private set; }
- internal bool copyDepth { get; private set; }
- internal int multipassId { get; private set; }
- internal int cullingPassId { get; private set; }
- // Ability to specify where to render the pass
- internal RenderTargetIdentifier renderTarget { get; private set; }
- internal RenderTextureDescriptor renderTargetDesc { get; private set; }
- static RenderTargetIdentifier invalidRT = -1;
- internal bool renderTargetValid { get => renderTarget != invalidRT; }
- internal bool renderTargetIsRenderTexture { get; private set; }
- internal bool isLateLatchEnabled { get; set; }
- internal bool canMarkLateLatch { get; set; }
- internal bool hasMarkedLateLatch { get; set; }
- // Access to view information
- internal Matrix4x4 GetProjMatrix(int viewIndex = 0) { return views[viewIndex].projMatrix; }
- internal Matrix4x4 GetViewMatrix(int viewIndex = 0) { return views[viewIndex].viewMatrix; }
- internal int GetTextureArraySlice(int viewIndex = 0) { return views[viewIndex].textureArraySlice; }
- internal Rect GetViewport(int viewIndex = 0) { return views[viewIndex].viewport; }
- // Combined projection and view matrices for culling
- internal ScriptableCullingParameters cullingParams { get; private set; }
- // Single-pass rendering support (instanced draw calls or multiview extension)
- internal int viewCount { get => views.Count; }
- internal bool singlePassEnabled { get => viewCount > 1; }
- // Occlusion mesh rendering
- Material occlusionMeshMaterial = null;
- Mesh occlusionMeshCombined = null;
- int occlusionMeshCombinedHashCode = 0;
- internal bool isOcclusionMeshSupported { get => enabled && xrSdkEnabled && occlusionMeshMaterial != null; }
- internal bool hasValidOcclusionMesh
- {
- get
- {
- if (isOcclusionMeshSupported)
- {
- if (singlePassEnabled)
- return occlusionMeshCombined != null;
- else
- return views[0].occlusionMesh != null;
- }
- return false;
- }
- }
- // Ability to override mirror view behavior for each pass
- internal delegate void CustomMirrorView(XRPass pass, CommandBuffer cmd, RenderTexture rt, Rect viewport);
- CustomMirrorView customMirrorView = null;
- internal void SetCustomMirrorView(CustomMirrorView callback) => customMirrorView = callback;
- const string k_XRCustomMirrorTag = "XR Custom Mirror View";
- static ProfilingSampler _XRCustomMirrorProfilingSampler = new ProfilingSampler(k_XRCustomMirrorTag);
- const string k_XROcclusionTag = "XR Occlusion Mesh";
- static ProfilingSampler _XROcclusionProfilingSampler = new ProfilingSampler(k_XROcclusionTag);
- internal static XRPass Create(XRPassCreateInfo createInfo)
- {
- XRPass passInfo = GenericPool<XRPass>.Get();
- passInfo.multipassId = createInfo.multipassId;
- passInfo.cullingPassId = createInfo.cullingPassId;
- passInfo.cullingParams = createInfo.cullingParameters;
- passInfo.customMirrorView = createInfo.customMirrorView;
- passInfo.views.Clear();
- if (createInfo.renderTarget != null)
- {
- passInfo.renderTarget = new RenderTargetIdentifier(createInfo.renderTarget, 0, CubemapFace.Unknown, -1);
- passInfo.renderTargetDesc = createInfo.renderTarget.descriptor;
- passInfo.renderTargetIsRenderTexture = createInfo.renderTargetIsRenderTexture;
- }
- else
- {
- passInfo.renderTarget = invalidRT;
- passInfo.renderTargetDesc = createInfo.renderTargetDesc;
- passInfo.renderTargetIsRenderTexture = createInfo.renderTargetIsRenderTexture;
- }
- passInfo.occlusionMeshMaterial = null;
- passInfo.xrSdkEnabled = false;
- passInfo.copyDepth = false;
- return passInfo;
- }
- internal void UpdateView(int viewId, XRDisplaySubsystem.XRRenderPass xrSdkRenderPass, XRDisplaySubsystem.XRRenderParameter xrSdkRenderParameter)
- {
- if (viewId >= views.Count)
- throw new NotImplementedException($"Invalid XR setup to update, trying to update non-existing xr view.");
- views[viewId] = new XRView(xrSdkRenderPass, xrSdkRenderParameter);
- }
- internal void UpdateView(int viewId, Matrix4x4 proj, Matrix4x4 view, Rect vp, int textureArraySlice = -1)
- {
- if (viewId >= views.Count)
- throw new NotImplementedException($"Invalid XR setup to update, trying to update non-existing xr view.");
- views[viewId] = new XRView(proj, view, vp, textureArraySlice);
- }
- internal void UpdateCullingParams(int cullingPassId, ScriptableCullingParameters cullingParams)
- {
- this.cullingPassId = cullingPassId;
- this.cullingParams = cullingParams;
- }
- internal void AddView(Matrix4x4 proj, Matrix4x4 view, Rect vp, int textureArraySlice = -1)
- {
- AddViewInternal(new XRView(proj, view, vp, textureArraySlice));
- }
- internal static XRPass Create(XRDisplaySubsystem.XRRenderPass xrRenderPass, int multipassId, ScriptableCullingParameters cullingParameters, Material occlusionMeshMaterial)
- {
- XRPass passInfo = GenericPool<XRPass>.Get();
- passInfo.multipassId = multipassId;
- passInfo.cullingPassId = xrRenderPass.cullingPassIndex;
- passInfo.cullingParams = cullingParameters;
- passInfo.views.Clear();
- // URP ScriptableRenderer does not track current active depth slice state. We make sure to set all texture slices(-1) across the pipeline to ensure consistency.
- passInfo.renderTarget = new RenderTargetIdentifier(xrRenderPass.renderTarget, 0, CubemapFace.Unknown, -1);
- RenderTextureDescriptor xrDesc = xrRenderPass.renderTargetDesc;
- RenderTextureDescriptor rtDesc = new RenderTextureDescriptor(xrDesc.width, xrDesc.height, xrDesc.colorFormat, xrDesc.depthBufferBits, xrDesc.mipCount);
- rtDesc.dimension = xrRenderPass.renderTargetDesc.dimension;
- rtDesc.volumeDepth = xrRenderPass.renderTargetDesc.volumeDepth;
- rtDesc.vrUsage = xrRenderPass.renderTargetDesc.vrUsage;
- rtDesc.sRGB = xrRenderPass.renderTargetDesc.sRGB;
- // Can't use xr descriptor directly as its descriptor force off y-flip cap
- //passInfo.renderTargetDesc = xrDesc;
- passInfo.renderTargetDesc = rtDesc;
- // Eye textures are back buffer type internally (See c++ core XRTextureManager)
- passInfo.renderTargetIsRenderTexture = false;
- passInfo.occlusionMeshMaterial = occlusionMeshMaterial;
- passInfo.xrSdkEnabled = true;
- passInfo.copyDepth = xrRenderPass.shouldFillOutDepth;
- passInfo.customMirrorView = null;
- Debug.Assert(passInfo.renderTargetValid, "Invalid render target from XRDisplaySubsystem!");
- return passInfo;
- }
- internal void AddView(XRDisplaySubsystem.XRRenderPass xrSdkRenderPass, XRDisplaySubsystem.XRRenderParameter xrSdkRenderParameter)
- {
- AddViewInternal(new XRView(xrSdkRenderPass, xrSdkRenderParameter));
- }
- internal static void Release(XRPass xrPass)
- {
- GenericPool<XRPass>.Release(xrPass);
- }
- internal void AddViewInternal(XRView xrView)
- {
- // XRTODO: Fix hard coded max views
- int maxSupportedViews = Math.Min(TextureXR.slices, 2/*ShaderConfig.s_XrMaxViews*/);
- if (views.Count < maxSupportedViews)
- {
- views.Add(xrView);
- }
- else
- {
- throw new NotImplementedException($"Invalid XR setup for single-pass, trying to add too many views! Max supported: {maxSupportedViews}");
- }
- }
- // Must be called after all views have been added to the pass
- internal void UpdateOcclusionMesh()
- {
- if (isOcclusionMeshSupported && singlePassEnabled && TryGetOcclusionMeshCombinedHashCode(out var hashCode))
- {
- if (occlusionMeshCombined == null || hashCode != occlusionMeshCombinedHashCode)
- {
- CreateOcclusionMeshCombined();
- occlusionMeshCombinedHashCode = hashCode;
- }
- }
- else
- {
- occlusionMeshCombined = null;
- occlusionMeshCombinedHashCode = 0;
- }
- }
- private bool TryGetOcclusionMeshCombinedHashCode(out int hashCode)
- {
- hashCode = 17;
- for (int viewId = 0; viewId < viewCount; ++viewId)
- {
- if (views[viewId].occlusionMesh != null)
- {
- hashCode = hashCode * 23 + views[viewId].occlusionMesh.GetHashCode();
- }
- else
- {
- hashCode = 0;
- return false;
- }
- }
- return true;
- }
- // Create a new mesh that contains the occlusion data from all views
- private void CreateOcclusionMeshCombined()
- {
- occlusionMeshCombined = new Mesh();
- occlusionMeshCombined.indexFormat = IndexFormat.UInt16;
- int combinedVertexCount = 0;
- uint combinedIndexCount = 0;
- for (int viewId = 0; viewId < viewCount; ++viewId)
- {
- Mesh mesh = views[viewId].occlusionMesh;
- Debug.Assert(mesh != null);
- Debug.Assert(mesh.subMeshCount == 1);
- Debug.Assert(mesh.indexFormat == IndexFormat.UInt16);
- combinedVertexCount += mesh.vertexCount;
- combinedIndexCount += mesh.GetIndexCount(0);
- }
- Vector3[] vertices = new Vector3[combinedVertexCount];
- ushort[] indices = new ushort[combinedIndexCount];
- int vertexStart = 0;
- int indexStart = 0;
- for (int viewId = 0; viewId < viewCount; ++viewId)
- {
- Mesh mesh = views[viewId].occlusionMesh;
- var meshIndices = mesh.GetIndices(0);
- // Encore the viewId into the z channel
- {
- mesh.vertices.CopyTo(vertices, vertexStart);
- for (int i = 0; i < mesh.vertices.Length; i++)
- vertices[vertexStart + i].z = viewId;
- }
- // Combine indices into one buffer
- for (int i = 0; i < meshIndices.Length; i++)
- {
- int newIndex = vertexStart + meshIndices[i];
- Debug.Assert(meshIndices[i] < ushort.MaxValue);
- indices[indexStart + i] = (ushort)newIndex;
- }
-
- vertexStart += mesh.vertexCount;
- indexStart += meshIndices.Length;
- }
- occlusionMeshCombined.vertices = vertices;
- occlusionMeshCombined.SetIndices(indices, MeshTopology.Triangles, 0);
- }
- Vector4[] stereoEyeIndices = new Vector4[2] { Vector4.zero , Vector4.one };
- internal void StartSinglePass(CommandBuffer cmd)
- {
- if (enabled)
- {
- if (singlePassEnabled)
- {
- if (viewCount <= TextureXR.slices)
- {
- if (SystemInfo.supportsMultiview)
- {
- cmd.EnableShaderKeyword("STEREO_MULTIVIEW_ON");
- cmd.SetGlobalVectorArray("unity_StereoEyeIndices", stereoEyeIndices);
- }
- else
- {
- cmd.EnableShaderKeyword("STEREO_INSTANCING_ON");
- cmd.SetInstanceMultiplier((uint)viewCount);
- }
- }
- else
- {
- throw new NotImplementedException($"Invalid XR setup for single-pass, trying to render too many views! Max supported: {TextureXR.slices}");
- }
- }
- }
- }
- internal void StopSinglePass(CommandBuffer cmd)
- {
- if (enabled)
- {
- if (singlePassEnabled)
- {
- if (SystemInfo.supportsMultiview)
- {
- cmd.DisableShaderKeyword("STEREO_MULTIVIEW_ON");
- }
- else
- {
- cmd.DisableShaderKeyword("STEREO_INSTANCING_ON");
- cmd.SetInstanceMultiplier(1);
- }
- }
- }
- }
- internal void EndCamera(CommandBuffer cmd, CameraData cameraData)
- {
- if (!enabled)
- return;
- StopSinglePass(cmd);
- // Callback for custom mirror view
- if (customMirrorView != null)
- {
- using (new ProfilingScope(cmd, _XRCustomMirrorProfilingSampler))
- {
- customMirrorView(this, cmd, cameraData.targetTexture, cameraData.pixelRect);
- }
- }
- }
- internal void RenderOcclusionMesh(CommandBuffer cmd)
- {
- if (isOcclusionMeshSupported)
- {
- using (new ProfilingScope(cmd, _XROcclusionProfilingSampler))
- {
- if (singlePassEnabled)
- {
- if (occlusionMeshCombined != null && SystemInfo.supportsRenderTargetArrayIndexFromVertexShader)
- {
- StopSinglePass(cmd);
- cmd.EnableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
- cmd.DrawMesh(occlusionMeshCombined, Matrix4x4.identity, occlusionMeshMaterial);
- cmd.DisableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
- StartSinglePass(cmd);
- }
- }
- else if (views[0].occlusionMesh != null)
- {
- cmd.DrawMesh(views[0].occlusionMesh, Matrix4x4.identity, occlusionMeshMaterial);
- }
- }
- }
- }
- // Store array to avoid allocating every frame
- private Matrix4x4[] stereoProjectionMatrix = new Matrix4x4[2];
- private Matrix4x4[] stereoViewMatrix = new Matrix4x4[2];
- private Matrix4x4[] stereoCameraProjectionMatrix = new Matrix4x4[2];
- internal void UpdateGPUViewAndProjectionMatrices(CommandBuffer cmd, ref CameraData cameraData, bool isRenderToTexture)
- {
- Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(cameraData.xr.GetProjMatrix(0), isRenderToTexture);
- RenderingUtils.SetViewAndProjectionMatrices(cmd, cameraData.xr.GetViewMatrix(0), projectionMatrix, true);
- if (cameraData.xr.singlePassEnabled)
- {
- for (int i = 0; i < 2; i++)
- {
- stereoCameraProjectionMatrix[i] = cameraData.xr.GetProjMatrix(i);
- stereoViewMatrix[i] = cameraData.xr.GetViewMatrix(i);
- stereoProjectionMatrix[i] = GL.GetGPUProjectionMatrix(stereoCameraProjectionMatrix[i], isRenderToTexture);
- }
- RenderingUtils.SetStereoViewAndProjectionMatrices(cmd, stereoViewMatrix, stereoProjectionMatrix, stereoCameraProjectionMatrix, true);
- if (cameraData.xr.canMarkLateLatch)
- MarkLateLatchShaderProperties(cmd, ref cameraData);
- }
- }
- internal static readonly int UNITY_STEREO_MATRIX_V = Shader.PropertyToID("unity_StereoMatrixV");
- internal static readonly int UNITY_STEREO_MATRIX_IV = Shader.PropertyToID("unity_StereoMatrixInvV");
- internal static readonly int UNITY_STEREO_MATRIX_VP = Shader.PropertyToID("unity_StereoMatrixVP");
- internal static readonly int UNITY_STEREO_MATRIX_IVP = Shader.PropertyToID("unity_StereoMatrixIVP");
- internal void MarkLateLatchShaderProperties(CommandBuffer cmd, ref CameraData cameraData)
- {
- cmd.MarkLateLatchMatrixShaderPropertyID(CameraLateLatchMatrixType.View, UNITY_STEREO_MATRIX_V);
- cmd.MarkLateLatchMatrixShaderPropertyID(CameraLateLatchMatrixType.InverseView, UNITY_STEREO_MATRIX_IV);
- cmd.MarkLateLatchMatrixShaderPropertyID(CameraLateLatchMatrixType.ViewProjection, UNITY_STEREO_MATRIX_VP);
- cmd.MarkLateLatchMatrixShaderPropertyID(CameraLateLatchMatrixType.InverseViewProjection, UNITY_STEREO_MATRIX_IVP);
- cmd.SetLateLatchProjectionMatrices(stereoProjectionMatrix);
- cameraData.xr.hasMarkedLateLatch = true;
- }
- internal void UnmarkLateLatchShaderProperties(CommandBuffer cmd, ref CameraData cameraData)
- {
- cmd.UnmarkLateLatchMatrix(CameraLateLatchMatrixType.View);
- cmd.UnmarkLateLatchMatrix(CameraLateLatchMatrixType.InverseView);
- cmd.UnmarkLateLatchMatrix(CameraLateLatchMatrixType.ViewProjection);
- cmd.UnmarkLateLatchMatrix(CameraLateLatchMatrixType.InverseViewProjection);
- cameraData.xr.hasMarkedLateLatch = false;
- }
- }
- }
- #else
- namespace UnityEngine.Rendering.Universal
- {
- internal class XRPass
- {
- internal static readonly XRPass emptyPass = new XRPass();
- internal bool enabled { get => false; }
- internal void StartSinglePass(CommandBuffer cmd) { }
- internal void StopSinglePass(CommandBuffer cmd) { }
- internal void EndCamera(CommandBuffer cmd, CameraData camera) { }
- internal void RenderOcclusionMesh(CommandBuffer cmd) { }
- }
- }
- #endif
|