XRSystem.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. // XRSystem is where information about XR views and passes are read from 2 exclusive sources:
  2. // - XRDisplaySubsystem from the XR SDK
  3. // - the test automated test framework
  4. #if ENABLE_VR && ENABLE_XR_MODULE
  5. using System;
  6. using System.Collections.Generic;
  7. using UnityEngine.XR;
  8. namespace UnityEngine.Rendering.Universal
  9. {
  10. internal partial class XRSystem
  11. {
  12. // Valid empty pass when a camera is not using XR
  13. internal readonly XRPass emptyPass = new XRPass();
  14. // Store active passes and avoid allocating memory every frames
  15. List<XRPass> framePasses = new List<XRPass>();
  16. // XR SDK display interface
  17. static List<XRDisplaySubsystem> displayList = new List<XRDisplaySubsystem>();
  18. XRDisplaySubsystem display = null;
  19. // XRSDK does not support msaa per XR display. All displays share the same msaa level.
  20. static int msaaLevel = 1;
  21. // Internal resources used by XR rendering
  22. Material occlusionMeshMaterial = null;
  23. Material mirrorViewMaterial = null;
  24. MaterialPropertyBlock mirrorViewMaterialProperty = new MaterialPropertyBlock();
  25. RenderTexture testRenderTexture = null;
  26. const string k_XRMirrorTag = "XR Mirror View";
  27. static ProfilingSampler _XRMirrorProfilingSampler = new ProfilingSampler(k_XRMirrorTag);
  28. internal XRSystem()
  29. {
  30. RefreshXrSdk();
  31. TextureXR.maxViews = Math.Max(TextureXR.slices, GetMaxViews());
  32. }
  33. internal void InitializeXRSystemData(XRSystemData data)
  34. {
  35. if (data)
  36. {
  37. if (occlusionMeshMaterial != null)
  38. CoreUtils.Destroy(occlusionMeshMaterial);
  39. if (mirrorViewMaterial != null)
  40. CoreUtils.Destroy(mirrorViewMaterial);
  41. occlusionMeshMaterial = CoreUtils.CreateEngineMaterial(data.shaders.xrOcclusionMeshPS);
  42. mirrorViewMaterial = CoreUtils.CreateEngineMaterial(data.shaders.xrMirrorViewPS);
  43. }
  44. }
  45. static void GetDisplaySubsystem()
  46. {
  47. #if UNITY_2020_2_OR_NEWER
  48. //SubsystemManager.GetSubsystems(displayList);
  49. SubsystemManager.GetInstances(displayList);
  50. #else
  51. SubsystemManager.GetInstances(displayList);
  52. #endif
  53. }
  54. // With XR SDK: disable legacy VR system before rendering first frame
  55. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
  56. internal static void XRSystemInit()
  57. {
  58. if (GraphicsSettings.currentRenderPipeline == null)
  59. return;
  60. GetDisplaySubsystem();
  61. // XRTODO: refactor with RefreshXrSdk()
  62. for (int i = 0; i < displayList.Count; i++)
  63. {
  64. displayList[i].disableLegacyRenderer = true;
  65. displayList[i].textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray;
  66. displayList[i].sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
  67. }
  68. }
  69. internal static void UpdateMSAALevel(int level)
  70. {
  71. if (msaaLevel == level)
  72. return;
  73. level = Mathf.NextPowerOfTwo(level);
  74. level = Mathf.Clamp(level, (int)MsaaQuality.Disabled, (int)MsaaQuality._8x);
  75. GetDisplaySubsystem();
  76. #if UNITY_2020_2_OR_NEWER
  77. for (int i = 0; i < displayList.Count; i++)
  78. displayList[i].SetMSAALevel(level);
  79. #endif
  80. msaaLevel = level;
  81. }
  82. internal static int GetMSAALevel()
  83. {
  84. return msaaLevel;
  85. }
  86. internal static void UpdateRenderScale(float renderScale)
  87. {
  88. GetDisplaySubsystem();
  89. for (int i = 0; i < displayList.Count; i++)
  90. displayList[i].scaleOfAllRenderTargets = renderScale;
  91. }
  92. // Compute the maximum number of views (slices) to allocate for texture arrays
  93. internal int GetMaxViews()
  94. {
  95. int maxViews = 1;
  96. if (display != null)
  97. {
  98. // XRTODO : replace by API from XR SDK, assume we have 2 slices until then
  99. maxViews = 2;
  100. }
  101. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  102. else if (XRGraphicsAutomatedTests.enabled)
  103. {
  104. maxViews = Math.Max(maxViews, 2);
  105. }
  106. #endif
  107. return maxViews;
  108. }
  109. internal void BeginLateLatching(Camera camera, XRPass xrPass)
  110. {
  111. //Only support late latching for multiview use case
  112. if (display != null && xrPass.singlePassEnabled && xrPass.viewCount == 2)
  113. {
  114. display.BeginRecordingIfLateLatched(camera);
  115. xrPass.isLateLatchEnabled = true;
  116. }
  117. }
  118. internal void EndLateLatching(Camera camera, XRPass xrPass)
  119. {
  120. if (display != null && xrPass.isLateLatchEnabled)
  121. {
  122. display.EndRecordingIfLateLatched(camera);
  123. xrPass.isLateLatchEnabled = false;
  124. }
  125. }
  126. internal List<XRPass> SetupFrame(CameraData cameraData)
  127. {
  128. Camera camera = cameraData.camera;
  129. bool xrEnabled = RefreshXrSdk();
  130. if (display != null)
  131. {
  132. // XRTODO: Handle stereo mode selection in URP pipeline asset UI
  133. display.textureLayout = XRDisplaySubsystem.TextureLayout.Texture2DArray;
  134. display.zNear = camera.nearClipPlane;
  135. display.zFar = camera.farClipPlane;
  136. display.sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear;
  137. }
  138. if (framePasses.Count > 0)
  139. {
  140. Debug.LogWarning("XRSystem.ReleaseFrame() was not called!");
  141. ReleaseFrame();
  142. }
  143. if (camera == null)
  144. return framePasses;
  145. // Enable XR layout only for game camera
  146. bool isGameCamera = (camera.cameraType == CameraType.Game || camera.cameraType == CameraType.VR);
  147. bool xrSupported = isGameCamera && camera.targetTexture == null && cameraData.xrRendering;
  148. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  149. if (XRGraphicsAutomatedTests.enabled && XRGraphicsAutomatedTests.running && isGameCamera && LayoutSinglePassTestMode(cameraData, new XRLayout() { camera = camera, xrSystem = this }))
  150. {
  151. // test layout in used
  152. }
  153. else
  154. #endif
  155. if (xrEnabled && xrSupported)
  156. {
  157. // Disable vsync on the main display when rendering to a XR device
  158. // XRTODO: Quest provider has a bug where vSyncCount must be 1, otherwise app is locked to 30fps
  159. if (Application.platform == RuntimePlatform.Android)
  160. QualitySettings.vSyncCount = 1;
  161. else
  162. QualitySettings.vSyncCount = 0;
  163. CreateLayoutFromXrSdk(camera, singlePassAllowed: true);
  164. }
  165. else
  166. {
  167. AddPassToFrame(emptyPass);
  168. }
  169. return framePasses;
  170. }
  171. internal void ReleaseFrame()
  172. {
  173. for (int i = 0; i < framePasses.Count; i++)
  174. {
  175. // Pop from the back to keep initial ordering (see implementation of ObjectPool)
  176. var xrPass = framePasses[framePasses.Count - i - 1];
  177. if (xrPass != emptyPass)
  178. XRPass.Release(xrPass);
  179. }
  180. framePasses.Clear();
  181. if (testRenderTexture)
  182. RenderTexture.ReleaseTemporary(testRenderTexture);
  183. }
  184. internal bool RefreshXrSdk()
  185. {
  186. GetDisplaySubsystem();
  187. if (displayList.Count > 0)
  188. {
  189. if (displayList.Count > 1)
  190. throw new NotImplementedException("Only 1 XR display is supported.");
  191. display = displayList[0];
  192. display.disableLegacyRenderer = true;
  193. // Refresh max views
  194. TextureXR.maxViews = Math.Max(TextureXR.slices, GetMaxViews());
  195. return display.running;
  196. }
  197. else
  198. {
  199. display = null;
  200. }
  201. return false;
  202. }
  203. // Used for updating URP cameraData data struct with XRPass data.
  204. internal void UpdateCameraData(ref CameraData baseCameraData, in XRPass xr)
  205. {
  206. // Update cameraData viewport for XR
  207. Rect cameraRect = baseCameraData.camera.rect;
  208. Rect xrViewport = xr.GetViewport();
  209. baseCameraData.pixelRect = new Rect(cameraRect.x * xrViewport.width + xrViewport.x,
  210. cameraRect.y * xrViewport.height + xrViewport.y,
  211. cameraRect.width * xrViewport.width,
  212. cameraRect.height * xrViewport.height);
  213. Rect camPixelRect = baseCameraData.pixelRect;
  214. baseCameraData.pixelWidth = (int)System.Math.Round(camPixelRect.width + camPixelRect.x) - (int)System.Math.Round(camPixelRect.x);
  215. baseCameraData.pixelHeight = (int)System.Math.Round(camPixelRect.height + camPixelRect.y) - (int)System.Math.Round(camPixelRect.y);
  216. baseCameraData.aspectRatio = (float)baseCameraData.pixelWidth / (float)baseCameraData.pixelHeight;
  217. bool isDefaultXRViewport = (!(Math.Abs(xrViewport.x) > 0.0f || Math.Abs(xrViewport.y) > 0.0f ||
  218. Math.Abs(xrViewport.width) < xr.renderTargetDesc.width ||
  219. Math.Abs(xrViewport.height) < xr.renderTargetDesc.height));
  220. baseCameraData.isDefaultViewport = baseCameraData.isDefaultViewport && isDefaultXRViewport;
  221. // Update cameraData cameraTargetDescriptor for XR. This descriptor is mainly used for configuring intermediate screen space textures
  222. var originalTargetDesc = baseCameraData.cameraTargetDescriptor;
  223. baseCameraData.cameraTargetDescriptor = xr.renderTargetDesc;
  224. if (baseCameraData.isHdrEnabled)
  225. {
  226. baseCameraData.cameraTargetDescriptor.graphicsFormat = originalTargetDesc.graphicsFormat;
  227. }
  228. baseCameraData.cameraTargetDescriptor.msaaSamples = originalTargetDesc.msaaSamples;
  229. baseCameraData.cameraTargetDescriptor.width = baseCameraData.pixelWidth;
  230. baseCameraData.cameraTargetDescriptor.height = baseCameraData.pixelHeight;
  231. }
  232. // Used for camera stacking where we need to update the parameters per camera
  233. internal void UpdateFromCamera(ref XRPass xrPass, CameraData cameraData)
  234. {
  235. bool isGameCamera = (cameraData.camera.cameraType == CameraType.Game || cameraData.camera.cameraType == CameraType.VR);
  236. if (XRGraphicsAutomatedTests.enabled && XRGraphicsAutomatedTests.running && isGameCamera)
  237. {
  238. // XR test framework code path. Update 2nd view with camera's view projection data
  239. Matrix4x4 projMatrix = cameraData.camera.projectionMatrix;
  240. Matrix4x4 viewMatrix = cameraData.camera.worldToCameraMatrix;
  241. Rect viewport = new Rect(0, 0, testRenderTexture.width, testRenderTexture.height);
  242. int textureArraySlice = -1;
  243. xrPass.UpdateView(1, projMatrix, viewMatrix, viewport, textureArraySlice);
  244. // Update culling params for this xr pass using camera's culling params
  245. cameraData.camera.TryGetCullingParameters(false, out var cullingParams);
  246. cullingParams.stereoProjectionMatrix = cameraData.camera.projectionMatrix;
  247. cullingParams.stereoViewMatrix = cameraData.camera.worldToCameraMatrix;
  248. //// Disable legacy stereo culling path
  249. cullingParams.cullingOptions &= ~CullingOptions.Stereo;
  250. xrPass.UpdateCullingParams(0, cullingParams);
  251. }
  252. else if (xrPass.enabled && display != null)
  253. {
  254. display.GetRenderPass(xrPass.multipassId, out var renderPass);
  255. display.GetCullingParameters(cameraData.camera, renderPass.cullingPassIndex, out var cullingParams);
  256. // Disable legacy stereo culling path
  257. cullingParams.cullingOptions &= ~CullingOptions.Stereo;
  258. xrPass.UpdateCullingParams(cullingPassId: renderPass.cullingPassIndex, cullingParams);
  259. if (xrPass.singlePassEnabled)
  260. {
  261. for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
  262. {
  263. renderPass.GetRenderParameter(cameraData.camera, renderParamIndex, out var renderParam);
  264. xrPass.UpdateView(renderParamIndex, renderPass, renderParam);
  265. }
  266. }
  267. else
  268. {
  269. renderPass.GetRenderParameter(cameraData.camera, 0, out var renderParam);
  270. xrPass.UpdateView(0, renderPass, renderParam);
  271. }
  272. }
  273. }
  274. void CreateLayoutFromXrSdk(Camera camera, bool singlePassAllowed)
  275. {
  276. bool CanUseSinglePass(XRDisplaySubsystem.XRRenderPass renderPass)
  277. {
  278. if (renderPass.renderTargetDesc.dimension != TextureDimension.Tex2DArray)
  279. return false;
  280. if (renderPass.GetRenderParameterCount() != 2 || renderPass.renderTargetDesc.volumeDepth != 2)
  281. return false;
  282. renderPass.GetRenderParameter(camera, 0, out var renderParam0);
  283. renderPass.GetRenderParameter(camera, 1, out var renderParam1);
  284. if (renderParam0.textureArraySlice != 0 || renderParam1.textureArraySlice != 1)
  285. return false;
  286. if (renderParam0.viewport != renderParam1.viewport)
  287. return false;
  288. return true;
  289. }
  290. for (int renderPassIndex = 0; renderPassIndex < display.GetRenderPassCount(); ++renderPassIndex)
  291. {
  292. display.GetRenderPass(renderPassIndex, out var renderPass);
  293. display.GetCullingParameters(camera, renderPass.cullingPassIndex, out var cullingParams);
  294. // Disable legacy stereo culling path
  295. cullingParams.cullingOptions &= ~CullingOptions.Stereo;
  296. if (singlePassAllowed && CanUseSinglePass(renderPass))
  297. {
  298. var xrPass = XRPass.Create(renderPass, multipassId: framePasses.Count, cullingParams, occlusionMeshMaterial);
  299. for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
  300. {
  301. renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
  302. xrPass.AddView(renderPass, renderParam);
  303. }
  304. AddPassToFrame(xrPass);
  305. }
  306. else
  307. {
  308. for (int renderParamIndex = 0; renderParamIndex < renderPass.GetRenderParameterCount(); ++renderParamIndex)
  309. {
  310. renderPass.GetRenderParameter(camera, renderParamIndex, out var renderParam);
  311. var xrPass = XRPass.Create(renderPass, multipassId: framePasses.Count, cullingParams, occlusionMeshMaterial);
  312. xrPass.AddView(renderPass, renderParam);
  313. AddPassToFrame(xrPass);
  314. }
  315. }
  316. }
  317. }
  318. internal void Dispose()
  319. {
  320. CoreUtils.Destroy(occlusionMeshMaterial);
  321. CoreUtils.Destroy(mirrorViewMaterial);
  322. }
  323. internal void AddPassToFrame(XRPass xrPass)
  324. {
  325. xrPass.UpdateOcclusionMesh();
  326. framePasses.Add(xrPass);
  327. }
  328. internal static class XRShaderIDs
  329. {
  330. public static readonly int _SourceTexArraySlice = Shader.PropertyToID("_SourceTexArraySlice");
  331. public static readonly int _SRGBRead = Shader.PropertyToID("_SRGBRead");
  332. public static readonly int _SRGBWrite = Shader.PropertyToID("_SRGBWrite");
  333. }
  334. internal void RenderMirrorView(CommandBuffer cmd, Camera camera)
  335. {
  336. // XRTODO : remove this check when the Quest plugin is fixed
  337. if (Application.platform == RuntimePlatform.Android)
  338. return;
  339. if (display == null || !display.running || !mirrorViewMaterial)
  340. return;
  341. using (new ProfilingScope(cmd, _XRMirrorProfilingSampler))
  342. {
  343. cmd.SetRenderTarget(camera.targetTexture != null ? camera.targetTexture : new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget));
  344. bool yflip = camera.targetTexture != null || camera.cameraType == CameraType.SceneView || camera.cameraType == CameraType.Preview;
  345. int mirrorBlitMode = display.GetPreferredMirrorBlitMode();
  346. if (display.GetMirrorViewBlitDesc(null, out var blitDesc, mirrorBlitMode))
  347. {
  348. if (blitDesc.nativeBlitAvailable)
  349. {
  350. display.AddGraphicsThreadMirrorViewBlit(cmd, blitDesc.nativeBlitInvalidStates, mirrorBlitMode);
  351. }
  352. else
  353. {
  354. for (int i = 0; i < blitDesc.blitParamsCount; ++i)
  355. {
  356. blitDesc.GetBlitParameter(i, out var blitParam);
  357. Vector4 scaleBias = yflip ? new Vector4(blitParam.srcRect.width, -blitParam.srcRect.height, blitParam.srcRect.x, blitParam.srcRect.height + blitParam.srcRect.y) :
  358. new Vector4(blitParam.srcRect.width, blitParam.srcRect.height, blitParam.srcRect.x, blitParam.srcRect.y);
  359. Vector4 scaleBiasRt = new Vector4(blitParam.destRect.width, blitParam.destRect.height, blitParam.destRect.x, blitParam.destRect.y);
  360. // 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.
  361. mirrorViewMaterialProperty.SetInt(XRShaderIDs._SRGBRead, (blitParam.srcTex.sRGB) ? 0 : 1);
  362. // Perform explicit sRGB write in shader if color space is gamma
  363. mirrorViewMaterialProperty.SetInt(XRShaderIDs._SRGBWrite, (QualitySettings.activeColorSpace == ColorSpace.Linear) ? 0 : 1);
  364. mirrorViewMaterialProperty.SetTexture(ShaderPropertyId.sourceTex, blitParam.srcTex);
  365. mirrorViewMaterialProperty.SetVector(ShaderPropertyId.scaleBias, scaleBias);
  366. mirrorViewMaterialProperty.SetVector(ShaderPropertyId.scaleBiasRt, scaleBiasRt);
  367. mirrorViewMaterialProperty.SetInt(XRShaderIDs._SourceTexArraySlice, blitParam.srcTexArraySlice);
  368. int shaderPass = (blitParam.srcTex.dimension == TextureDimension.Tex2DArray) ? 1 : 0;
  369. cmd.DrawProcedural(Matrix4x4.identity, mirrorViewMaterial, shaderPass, MeshTopology.Quads, 4, 1, mirrorViewMaterialProperty);
  370. }
  371. }
  372. }
  373. else
  374. {
  375. cmd.ClearRenderTarget(true, true, Color.black);
  376. }
  377. }
  378. }
  379. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  380. static MaterialPropertyBlock testMirrorViewMaterialProperty = new MaterialPropertyBlock();
  381. static Material testMirrorViewMaterial = null;
  382. static void copyToTestRenderTexture(XRPass pass, CommandBuffer cmd, RenderTexture rt, Rect viewport)
  383. {
  384. cmd.SetViewport(viewport);
  385. cmd.SetRenderTarget(rt == null ? new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget) : rt);
  386. Vector4 scaleBias = new Vector4(1.0f, 1.0f, 0.0f, 0.0f);
  387. Vector4 scaleBiasRT = new Vector4(1.0f, 1.0f, 0.0f, 0.0f);
  388. if (rt == null)
  389. {
  390. scaleBias.y = -1.0f;
  391. scaleBias.w = 1.0f;
  392. }
  393. testMirrorViewMaterialProperty.SetVector(ShaderPropertyId.scaleBias, scaleBias);
  394. testMirrorViewMaterialProperty.SetVector(ShaderPropertyId.scaleBiasRt, scaleBiasRT);
  395. // Copy result from the second slice
  396. testMirrorViewMaterialProperty.SetInt(XRShaderIDs._SourceTexArraySlice, 1);
  397. cmd.DrawProcedural(Matrix4x4.identity, testMirrorViewMaterial, 1, MeshTopology.Quads, 4, 1, testMirrorViewMaterialProperty);
  398. }
  399. static XRPass.CustomMirrorView testMirrorView = copyToTestRenderTexture;
  400. bool LayoutSinglePassTestMode(CameraData cameraData, XRLayout frameLayout)
  401. {
  402. Camera camera = frameLayout.camera;
  403. if (camera == null)
  404. return false;
  405. if (camera.TryGetCullingParameters(false, out var cullingParams))
  406. {
  407. cullingParams.stereoProjectionMatrix = camera.projectionMatrix;
  408. cullingParams.stereoViewMatrix = camera.worldToCameraMatrix;
  409. // Allocate temp target to render test scene with single-pass
  410. // And copy the last view to the actual render texture used to compare image in test framework
  411. {
  412. RenderTextureDescriptor rtDesc = cameraData.cameraTargetDescriptor;
  413. rtDesc.dimension = TextureDimension.Tex2DArray;
  414. rtDesc.volumeDepth = 2;
  415. // If camera renders to subrect, we adjust size to match back buffer/target texture
  416. if (!cameraData.isDefaultViewport)
  417. {
  418. if (cameraData.targetTexture == null)
  419. {
  420. rtDesc.width = (int)(rtDesc.width / cameraData.camera.rect.width);
  421. rtDesc.height = (int)(rtDesc.height / cameraData.camera.rect.height);
  422. }
  423. else
  424. {
  425. rtDesc.width = (int)(cameraData.targetTexture.width);
  426. rtDesc.height = (int)(cameraData.targetTexture.height);
  427. }
  428. }
  429. testRenderTexture = RenderTexture.GetTemporary(rtDesc);
  430. testMirrorViewMaterial = mirrorViewMaterial;
  431. testMirrorViewMaterialProperty.SetInt(XRShaderIDs._SRGBRead, (testRenderTexture.sRGB) ? 0 : 1);
  432. testMirrorViewMaterialProperty.SetInt(XRShaderIDs._SRGBWrite, (QualitySettings.activeColorSpace == ColorSpace.Linear) ? 0 : 1);
  433. testMirrorViewMaterialProperty.SetTexture(ShaderPropertyId.sourceTex, testRenderTexture);
  434. }
  435. var passInfo = new XRPassCreateInfo
  436. {
  437. multipassId = 0,
  438. cullingPassId = 0,
  439. cullingParameters = cullingParams,
  440. renderTarget = testRenderTexture,
  441. renderTargetIsRenderTexture = true,
  442. customMirrorView = testMirrorView
  443. };
  444. var viewInfo2 = new XRViewCreateInfo
  445. {
  446. projMatrix = camera.projectionMatrix,
  447. viewMatrix = camera.worldToCameraMatrix,
  448. viewport = new Rect(0, 0, testRenderTexture.width, testRenderTexture.height),
  449. textureArraySlice = -1
  450. };
  451. // Change the first view so that it's a different viewpoint and projection to detect more issues
  452. var viewInfo1 = viewInfo2;
  453. var planes = viewInfo1.projMatrix.decomposeProjection;
  454. planes.left *= 0.44f;
  455. planes.right *= 0.88f;
  456. planes.top *= 0.11f;
  457. planes.bottom *= 0.33f;
  458. viewInfo1.projMatrix = Matrix4x4.Frustum(planes);
  459. viewInfo1.viewMatrix *= Matrix4x4.Translate(new Vector3(.34f, 0.25f, -0.08f));
  460. // single-pass 2x rendering
  461. {
  462. XRPass pass = frameLayout.CreatePass(passInfo);
  463. frameLayout.AddViewToPass(viewInfo1, pass);
  464. frameLayout.AddViewToPass(viewInfo2, pass);
  465. }
  466. // valid layout
  467. return true;
  468. }
  469. return false;
  470. }
  471. #endif
  472. }
  473. }
  474. #endif