initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
|
@ -0,0 +1,26 @@
|
|||
// Helper API to create custom XR layout
|
||||
|
||||
#if ENABLE_VR && ENABLE_XR_MODULE
|
||||
|
||||
namespace UnityEngine.Rendering.Universal
|
||||
{
|
||||
internal struct XRLayout
|
||||
{
|
||||
internal Camera camera;
|
||||
internal XRSystem xrSystem;
|
||||
|
||||
internal XRPass CreatePass(XRPassCreateInfo passCreateInfo)
|
||||
{
|
||||
XRPass pass = XRPass.Create(passCreateInfo);
|
||||
xrSystem.AddPassToFrame(pass);
|
||||
return pass;
|
||||
}
|
||||
|
||||
internal void AddViewToPass(XRViewCreateInfo viewCreateInfo, XRPass pass)
|
||||
{
|
||||
pass.AddView(viewCreateInfo.projMatrix, viewCreateInfo.viewMatrix, viewCreateInfo.viewport, viewCreateInfo.textureArraySlice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e6cbb2e8811b28243a09e7068d408f4b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,535 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
public class XRPass
|
||||
{
|
||||
internal List<XRView> views = new List<XRView>(2);
|
||||
|
||||
public 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
|
||||
public RenderTargetIdentifier renderTarget { get; private set; }
|
||||
public 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; }
|
||||
public 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);
|
||||
}
|
||||
|
||||
internal void StartSinglePass(CommandBuffer cmd)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
if (singlePassEnabled)
|
||||
{
|
||||
if (viewCount <= TextureXR.slices)
|
||||
{
|
||||
if (SystemInfo.supportsMultiview)
|
||||
{
|
||||
cmd.EnableShaderKeyword("STEREO_MULTIVIEW_ON");
|
||||
}
|
||||
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 DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (XRGraphicsAutomatedTests.enabled && XRGraphicsAutomatedTests.running)
|
||||
return;
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderOcclusionMeshExternal(CommandBuffer cmd, Material occlusionMat)
|
||||
{
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (XRGraphicsAutomatedTests.enabled && XRGraphicsAutomatedTests.running)
|
||||
return;
|
||||
#endif
|
||||
|
||||
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, occlusionMat);
|
||||
cmd.DisableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
|
||||
|
||||
StartSinglePass(cmd);
|
||||
}
|
||||
}
|
||||
else if (views[0].occlusionMesh != null)
|
||||
{
|
||||
cmd.DrawMesh(views[0].occlusionMesh, Matrix4x4.identity, occlusionMat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2ebff140b14fa5141bc559fe07a95a5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,483 @@
|
|||
// XRSystem is where information about XR views and passes are read from 2 exclusive sources:
|
||||
// - XRDisplaySubsystem from the XR SDK
|
||||
// - the test automated test framework
|
||||
|
||||
#if ENABLE_VR && ENABLE_XR_MODULE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace UnityEngine.Rendering.Universal
|
||||
{
|
||||
internal partial class XRSystem
|
||||
{
|
||||
// Valid empty pass when a camera is not using XR
|
||||
internal readonly XRPass emptyPass = new XRPass();
|
||||
|
||||
// Store active passes and avoid allocating memory every frames
|
||||
List<XRPass> framePasses = new List<XRPass>();
|
||||
|
||||
// XR SDK display interface
|
||||
static List<XRDisplaySubsystem> displayList = new List<XRDisplaySubsystem>();
|
||||
XRDisplaySubsystem display = null;
|
||||
// XRSDK does not support msaa per XR display. All displays share the same msaa level.
|
||||
static int msaaLevel = 1;
|
||||
|
||||
// Internal resources used by XR rendering
|
||||
Material occlusionMeshMaterial = null;
|
||||
Material mirrorViewMaterial = null;
|
||||
MaterialPropertyBlock mirrorViewMaterialProperty = new MaterialPropertyBlock();
|
||||
|
||||
RenderTexture testRenderTexture = null;
|
||||
|
||||
const string k_XRMirrorTag = "XR Mirror View";
|
||||
static ProfilingSampler _XRMirrorProfilingSampler = new ProfilingSampler(k_XRMirrorTag);
|
||||
|
||||
internal XRSystem()
|
||||
{
|
||||
RefreshXrSdk();
|
||||
|
||||
TextureXR.maxViews = Math.Max(TextureXR.slices, GetMaxViews());
|
||||
}
|
||||
|
||||
internal void InitializeXRSystemData(XRSystemData data)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
if (occlusionMeshMaterial != null)
|
||||
CoreUtils.Destroy(occlusionMeshMaterial);
|
||||
|
||||
if (mirrorViewMaterial != null)
|
||||
CoreUtils.Destroy(mirrorViewMaterial);
|
||||
|
||||
occlusionMeshMaterial = CoreUtils.CreateEngineMaterial(data.shaders.xrOcclusionMeshPS);
|
||||
mirrorViewMaterial = CoreUtils.CreateEngineMaterial(data.shaders.xrMirrorViewPS);
|
||||
}
|
||||
}
|
||||
|
||||
static void GetDisplaySubsystem()
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
//SubsystemManager.GetSubsystems(displayList);
|
||||
SubsystemManager.GetInstances(displayList);
|
||||
#else
|
||||
SubsystemManager.GetInstances(displayList);
|
||||
#endif
|
||||
}
|
||||
|
||||
// With XR SDK: disable legacy VR system before rendering first frame
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
|
||||
internal static void XRSystemInit()
|
||||
{
|
||||
if (GraphicsSettings.currentRenderPipeline == null)
|
||||
return;
|
||||
|
||||
GetDisplaySubsystem();
|
||||
|
||||
// XRTODO: refactor with RefreshXrSdk()
|
||||
for (int i = 0; i < displayList.Count; i++)
|
||||
{
|
||||
displayList[i].disableLegacyRenderer = true;
|
||||
displayList[i].textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray;
|
||||
displayList[i].sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateMSAALevel(int level)
|
||||
{
|
||||
if (msaaLevel == level)
|
||||
return;
|
||||
|
||||
level = Mathf.NextPowerOfTwo(level);
|
||||
level = Mathf.Clamp(level, (int)MsaaQuality.Disabled, (int)MsaaQuality._8x);
|
||||
|
||||
GetDisplaySubsystem();
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
for (int i = 0; i < displayList.Count; i++)
|
||||
displayList[i].SetMSAALevel(level);
|
||||
#endif
|
||||
msaaLevel = level;
|
||||
}
|
||||
|
||||
internal static int GetMSAALevel()
|
||||
{
|
||||
return msaaLevel;
|
||||
}
|
||||
|
||||
internal static void UpdateRenderScale(float renderScale)
|
||||
{
|
||||
GetDisplaySubsystem();
|
||||
|
||||
for (int i = 0; i < displayList.Count; i++)
|
||||
displayList[i].scaleOfAllRenderTargets = renderScale;
|
||||
}
|
||||
|
||||
// Compute the maximum number of views (slices) to allocate for texture arrays
|
||||
internal int GetMaxViews()
|
||||
{
|
||||
int maxViews = 1;
|
||||
|
||||
if (display != null)
|
||||
{
|
||||
// XRTODO : replace by API from XR SDK, assume we have 2 slices until then
|
||||
maxViews = 2;
|
||||
}
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
else if (XRGraphicsAutomatedTests.enabled)
|
||||
{
|
||||
maxViews = Math.Max(maxViews, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return maxViews;
|
||||
}
|
||||
|
||||
internal void BeginLateLatching(Camera camera, XRPass xrPass)
|
||||
{
|
||||
//Only support late latching for multiview use case
|
||||
if (display != null && xrPass.singlePassEnabled && xrPass.viewCount == 2)
|
||||
{
|
||||
display.BeginRecordingIfLateLatched(camera);
|
||||
xrPass.isLateLatchEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void EndLateLatching(Camera camera, XRPass xrPass)
|
||||
{
|
||||
if (display != null && xrPass.isLateLatchEnabled)
|
||||
{
|
||||
display.EndRecordingIfLateLatched(camera);
|
||||
xrPass.isLateLatchEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal List<XRPass> SetupFrame(Camera camera, bool enableXRRendering)
|
||||
{
|
||||
bool xrEnabled = RefreshXrSdk();
|
||||
|
||||
if (display != null)
|
||||
{
|
||||
// XRTODO: Handle stereo mode selection in URP pipeline asset UI
|
||||
display.textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray;
|
||||
display.zNear = camera.nearClipPlane;
|
||||
display.zFar = camera.farClipPlane;
|
||||
display.sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
|
||||
}
|
||||
|
||||
if (framePasses.Count > 0)
|
||||
{
|
||||
Debug.LogWarning("XRSystem.ReleaseFrame() was not called!");
|
||||
ReleaseFrame();
|
||||
}
|
||||
|
||||
if (camera == null)
|
||||
return framePasses;
|
||||
|
||||
// Enable XR layout only for game camera
|
||||
bool isGameCamera = (camera.cameraType == CameraType.Game || camera.cameraType == CameraType.VR);
|
||||
bool xrSupported = isGameCamera && camera.targetTexture == null && enableXRRendering;
|
||||
|
||||
if (xrEnabled && xrSupported)
|
||||
{
|
||||
// Disable vsync on the main display when rendering to a XR device.
|
||||
QualitySettings.vSyncCount = 0;
|
||||
// On Android and iOS, vSyncCount is ignored and all frame rate control is done using Application.targetFrameRate.
|
||||
float frameRate = 300.0f;
|
||||
Application.targetFrameRate = Mathf.CeilToInt(frameRate);
|
||||
|
||||
CreateLayoutFromXrSdk(camera, singlePassAllowed: true);
|
||||
|
||||
OverrideForAutomatedTests(camera);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddPassToFrame(emptyPass);
|
||||
}
|
||||
|
||||
return framePasses;
|
||||
}
|
||||
|
||||
internal void ReleaseFrame()
|
||||
{
|
||||
for (int i = 0; i < framePasses.Count; i++)
|
||||
{
|
||||
// Pop from the back to keep initial ordering (see implementation of ObjectPool)
|
||||
var xrPass = framePasses[framePasses.Count - i - 1];
|
||||
|
||||
if (xrPass != emptyPass)
|
||||
XRPass.Release(xrPass);
|
||||
}
|
||||
|
||||
framePasses.Clear();
|
||||
|
||||
if (testRenderTexture)
|
||||
RenderTexture.ReleaseTemporary(testRenderTexture);
|
||||
}
|
||||
|
||||
internal bool RefreshXrSdk()
|
||||
{
|
||||
GetDisplaySubsystem();
|
||||
|
||||
if (displayList.Count > 0)
|
||||
{
|
||||
if (displayList.Count > 1)
|
||||
throw new NotImplementedException("Only 1 XR display is supported.");
|
||||
|
||||
display = displayList[0];
|
||||
display.disableLegacyRenderer = true;
|
||||
|
||||
// Refresh max views
|
||||
TextureXR.maxViews = Math.Max(TextureXR.slices, GetMaxViews());
|
||||
|
||||
return display.running;
|
||||
}
|
||||
else
|
||||
{
|
||||
display = null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used for updating URP cameraData data struct with XRPass data.
|
||||
internal void UpdateCameraData(ref CameraData baseCameraData, in XRPass xr)
|
||||
{
|
||||
// Update cameraData viewport for XR
|
||||
Rect cameraRect = baseCameraData.camera.rect;
|
||||
Rect xrViewport = xr.GetViewport();
|
||||
baseCameraData.pixelRect = new Rect(cameraRect.x * xrViewport.width + xrViewport.x,
|
||||
cameraRect.y * xrViewport.height + xrViewport.y,
|
||||
cameraRect.width * xrViewport.width,
|
||||
cameraRect.height * xrViewport.height);
|
||||
Rect camPixelRect = baseCameraData.pixelRect;
|
||||
baseCameraData.pixelWidth = (int)System.Math.Round(camPixelRect.width + camPixelRect.x) - (int)System.Math.Round(camPixelRect.x);
|
||||
baseCameraData.pixelHeight = (int)System.Math.Round(camPixelRect.height + camPixelRect.y) - (int)System.Math.Round(camPixelRect.y);
|
||||
baseCameraData.aspectRatio = (float)baseCameraData.pixelWidth / (float)baseCameraData.pixelHeight;
|
||||
|
||||
bool isDefaultXRViewport = (!(Math.Abs(xrViewport.x) > 0.0f || Math.Abs(xrViewport.y) > 0.0f ||
|
||||
Math.Abs(xrViewport.width) < xr.renderTargetDesc.width ||
|
||||
Math.Abs(xrViewport.height) < xr.renderTargetDesc.height));
|
||||
baseCameraData.isDefaultViewport = baseCameraData.isDefaultViewport && isDefaultXRViewport;
|
||||
|
||||
// Update cameraData cameraTargetDescriptor for XR. This descriptor is mainly used for configuring intermediate screen space textures
|
||||
var originalTargetDesc = baseCameraData.cameraTargetDescriptor;
|
||||
baseCameraData.cameraTargetDescriptor = xr.renderTargetDesc;
|
||||
if (baseCameraData.isHdrEnabled)
|
||||
{
|
||||
baseCameraData.cameraTargetDescriptor.graphicsFormat = originalTargetDesc.graphicsFormat;
|
||||
}
|
||||
baseCameraData.cameraTargetDescriptor.msaaSamples = originalTargetDesc.msaaSamples;
|
||||
baseCameraData.cameraTargetDescriptor.width = baseCameraData.pixelWidth;
|
||||
baseCameraData.cameraTargetDescriptor.height = baseCameraData.pixelHeight;
|
||||
}
|
||||
|
||||
// Used for camera stacking where we need to update the parameters per camera
|
||||
internal void UpdateFromCamera(ref XRPass xrPass, CameraData cameraData)
|
||||
{
|
||||
if (xrPass.enabled && display != null)
|
||||
{
|
||||
display.GetRenderPass(xrPass.multipassId, out var renderPass);
|
||||
display.GetCullingParameters(cameraData.camera, renderPass.cullingPassIndex, out var cullingParams);
|
||||
|
||||
// Disable legacy stereo culling path
|
||||
cullingParams.cullingOptions &= ~CullingOptions.Stereo;
|
||||
|
||||
xrPass.UpdateCullingParams(cullingPassId: renderPass.cullingPassIndex, cullingParams);
|
||||
|
||||
if (xrPass.singlePassEnabled)
|
||||
{
|
||||
for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
|
||||
{
|
||||
renderPass.GetRenderParameter(cameraData.camera, renderParamIndex, out var renderParam);
|
||||
xrPass.UpdateView(renderParamIndex, renderPass, renderParam);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
renderPass.GetRenderParameter(cameraData.camera, 0, out var renderParam);
|
||||
xrPass.UpdateView(0, renderPass, renderParam);
|
||||
}
|
||||
|
||||
OverrideForAutomatedTests(cameraData.camera);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateLayoutFromXrSdk(Camera camera, bool singlePassAllowed)
|
||||
{
|
||||
bool CanUseSinglePass(XRDisplaySubsystem.XRRenderPass renderPass)
|
||||
{
|
||||
if (renderPass.renderTargetDesc.dimension != TextureDimension.Tex2DArray)
|
||||
return false;
|
||||
|
||||
if (renderPass.GetRenderParameterCount() != 2 || renderPass.renderTargetDesc.volumeDepth != 2)
|
||||
return false;
|
||||
|
||||
renderPass.GetRenderParameter(camera, 0, out var renderParam0);
|
||||
renderPass.GetRenderParameter(camera, 1, out var renderParam1);
|
||||
|
||||
if (renderParam0.textureArraySlice != 0 || renderParam1.textureArraySlice != 1)
|
||||
return false;
|
||||
|
||||
if (renderParam0.viewport != renderParam1.viewport)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int renderPassIndex = 0; renderPassIndex < display.GetRenderPassCount(); ++renderPassIndex)
|
||||
{
|
||||
display.GetRenderPass(renderPassIndex, out var renderPass);
|
||||
display.GetCullingParameters(camera, renderPass.cullingPassIndex, out var cullingParams);
|
||||
|
||||
// Disable legacy stereo culling path
|
||||
cullingParams.cullingOptions &= ~CullingOptions.Stereo;
|
||||
|
||||
if (singlePassAllowed && CanUseSinglePass(renderPass))
|
||||
{
|
||||
var xrPass = XRPass.Create(renderPass, multipassId: framePasses.Count, cullingParams, occlusionMeshMaterial);
|
||||
|
||||
for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
|
||||
{
|
||||
renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
|
||||
xrPass.AddView(renderPass, renderParam);
|
||||
}
|
||||
|
||||
AddPassToFrame(xrPass);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
|
||||
{
|
||||
renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
|
||||
|
||||
var xrPass = XRPass.Create(renderPass, multipassId: framePasses.Count, cullingParams, occlusionMeshMaterial);
|
||||
xrPass.AddView(renderPass, renderParam);
|
||||
|
||||
AddPassToFrame(xrPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
CoreUtils.Destroy(occlusionMeshMaterial);
|
||||
CoreUtils.Destroy(mirrorViewMaterial);
|
||||
}
|
||||
|
||||
internal void AddPassToFrame(XRPass xrPass)
|
||||
{
|
||||
xrPass.UpdateOcclusionMesh();
|
||||
framePasses.Add(xrPass);
|
||||
}
|
||||
|
||||
internal static class XRShaderIDs
|
||||
{
|
||||
public static readonly int _SourceTexArraySlice = Shader.PropertyToID("_SourceTexArraySlice");
|
||||
public static readonly int _SRGBRead = Shader.PropertyToID("_SRGBRead");
|
||||
public static readonly int _SRGBWrite = Shader.PropertyToID("_SRGBWrite");
|
||||
}
|
||||
|
||||
internal void RenderMirrorView(CommandBuffer cmd, Camera camera)
|
||||
{
|
||||
// XRTODO : remove this check when the Quest plugin is fixed
|
||||
if (Application.platform == RuntimePlatform.Android && !XRGraphicsAutomatedTests.running)
|
||||
return;
|
||||
|
||||
if (display == null || !display.running || !mirrorViewMaterial)
|
||||
return;
|
||||
|
||||
using (new ProfilingScope(cmd, _XRMirrorProfilingSampler))
|
||||
{
|
||||
cmd.SetRenderTarget(camera.targetTexture != null ? camera.targetTexture : new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget));
|
||||
bool yflip = camera.targetTexture != null || camera.cameraType == CameraType.SceneView || camera.cameraType == CameraType.Preview;
|
||||
int mirrorBlitMode = display.GetPreferredMirrorBlitMode();
|
||||
if (display.GetMirrorViewBlitDesc(null, out var blitDesc, mirrorBlitMode))
|
||||
{
|
||||
if (blitDesc.nativeBlitAvailable)
|
||||
{
|
||||
display.AddGraphicsThreadMirrorViewBlit(cmd, blitDesc.nativeBlitInvalidStates, mirrorBlitMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < blitDesc.blitParamsCount; ++i)
|
||||
{
|
||||
blitDesc.GetBlitParameter(i, out var blitParam);
|
||||
|
||||
Vector4 scaleBias = yflip ? new Vector4(blitParam.srcRect.width, -blitParam.srcRect.height, blitParam.srcRect.x, blitParam.srcRect.height + blitParam.srcRect.y) :
|
||||
new Vector4(blitParam.srcRect.width, blitParam.srcRect.height, blitParam.srcRect.x, blitParam.srcRect.y);
|
||||
Vector4 scaleBiasRt = new Vector4(blitParam.destRect.width, blitParam.destRect.height, blitParam.destRect.x, blitParam.destRect.y);
|
||||
|
||||
// Eye texture is always gamma corrected, use explicit sRGB read in shader if srcTex formats is not sRGB format. sRGB format will have implicit sRGB read so it is already handled.
|
||||
mirrorViewMaterialProperty.SetFloat(XRShaderIDs._SRGBRead, (blitParam.srcTex.sRGB) ? 0.0f : 1.0f);
|
||||
// Perform explicit sRGB write in shader if color space is gamma
|
||||
mirrorViewMaterialProperty.SetFloat(XRShaderIDs._SRGBWrite, (QualitySettings.activeColorSpace == ColorSpace.Linear) ? 0.0f : 1.0f);
|
||||
mirrorViewMaterialProperty.SetTexture(ShaderPropertyId.sourceTex, blitParam.srcTex);
|
||||
mirrorViewMaterialProperty.SetVector(ShaderPropertyId.scaleBias, scaleBias);
|
||||
mirrorViewMaterialProperty.SetVector(ShaderPropertyId.scaleBiasRt, scaleBiasRt);
|
||||
mirrorViewMaterialProperty.SetFloat(XRShaderIDs._SourceTexArraySlice, (float)blitParam.srcTexArraySlice);
|
||||
|
||||
int shaderPass = (blitParam.srcTex.dimension == TextureDimension.Tex2DArray) ? 1 : 0;
|
||||
cmd.DrawProcedural(Matrix4x4.identity, mirrorViewMaterial, shaderPass, MeshTopology.Quads, 4, 1, mirrorViewMaterialProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.ClearRenderTarget(true, true, Color.black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OverrideForAutomatedTests(Camera camera)
|
||||
{
|
||||
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||
if (XRGraphicsAutomatedTests.enabled && XRGraphicsAutomatedTests.running)
|
||||
{
|
||||
var camProjMatrix = camera.projectionMatrix;
|
||||
var camViewMatrix = camera.worldToCameraMatrix;
|
||||
|
||||
if (camera.TryGetCullingParameters(false, out var cullingParams))
|
||||
{
|
||||
cullingParams.stereoProjectionMatrix = camProjMatrix;
|
||||
cullingParams.stereoViewMatrix = camViewMatrix;
|
||||
cullingParams.stereoSeparationDistance = 0.0f;
|
||||
cullingParams.cullingOptions &= ~CullingOptions.Stereo;
|
||||
|
||||
for (int passId = 0; passId < framePasses.Count; passId++)
|
||||
{
|
||||
framePasses[passId].UpdateCullingParams(framePasses[passId].cullingPassId, cullingParams);
|
||||
|
||||
for (int viewId = 0; viewId < framePasses[passId].viewCount; viewId++)
|
||||
{
|
||||
var projMatrix = camProjMatrix;
|
||||
var viewMatrix = camViewMatrix;
|
||||
|
||||
// Alter the first view in order to detect more issues
|
||||
bool isFirstViewMultiPass = framePasses.Count == 2 && passId == 0;
|
||||
bool isFirstViewSinglePass = framePasses.Count == 1 && viewId == 0;
|
||||
|
||||
if (isFirstViewMultiPass || isFirstViewSinglePass)
|
||||
{
|
||||
var planes = projMatrix.decomposeProjection;
|
||||
planes.left *= 0.44f;
|
||||
planes.right *= 0.88f;
|
||||
planes.top *= 0.11f;
|
||||
planes.bottom *= 0.33f;
|
||||
projMatrix = Matrix4x4.Frustum(planes);
|
||||
viewMatrix *= Matrix4x4.Translate(new Vector3(.34f, 0.25f, -0.08f));
|
||||
}
|
||||
|
||||
framePasses[passId].UpdateView(viewId, projMatrix, viewMatrix, framePasses[passId].GetViewport(viewId), viewId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8b7250c52bb585e42aada46bd1f36b5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Add table
Add a link
Reference in a new issue