No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XROcclusionMesh.cs 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using UnityEngine.Rendering;
  2. namespace UnityEngine.Experimental.Rendering
  3. {
  4. // Helper class to render occlusion meshes.
  5. // If possible, the mesh for each view will be combined into one mesh to reduce draw calls.
  6. internal class XROcclusionMesh
  7. {
  8. XRPass m_Pass;
  9. Mesh m_CombinedMesh;
  10. Material m_Material;
  11. int m_CombinedMeshHashCode;
  12. static readonly ProfilingSampler k_OcclusionMeshProfilingSampler = new ProfilingSampler("XR Occlusion Mesh");
  13. internal XROcclusionMesh(XRPass xrPass)
  14. {
  15. m_Pass = xrPass;
  16. }
  17. internal void SetMaterial(Material mat)
  18. {
  19. m_Material = mat;
  20. }
  21. internal bool hasValidOcclusionMesh
  22. {
  23. get
  24. {
  25. if (IsOcclusionMeshSupported())
  26. {
  27. if (m_Pass.singlePassEnabled)
  28. return m_CombinedMesh != null;
  29. else
  30. return m_Pass.GetOcclusionMesh() != null;
  31. }
  32. return false;
  33. }
  34. }
  35. internal void RenderOcclusionMesh(CommandBuffer cmd, float occlusionMeshScale, bool yFlip = false)
  36. {
  37. if (IsOcclusionMeshSupported())
  38. {
  39. using (new ProfilingScope(cmd, k_OcclusionMeshProfilingSampler))
  40. {
  41. if (m_Pass.singlePassEnabled)
  42. {
  43. // Prefer multiview draw
  44. if (m_CombinedMesh != null && SystemInfo.supportsMultiview)
  45. {
  46. // For the multiview code path, keep the multiview state on to propagate geometries to all eye texture slices
  47. cmd.EnableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
  48. Vector3 scale = new Vector3(occlusionMeshScale, yFlip? occlusionMeshScale : -occlusionMeshScale, 1.0f);
  49. cmd.DrawMesh(m_CombinedMesh, Matrix4x4.Scale(scale), m_Material);
  50. cmd.DisableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
  51. }
  52. else if (m_CombinedMesh != null && SystemInfo.supportsRenderTargetArrayIndexFromVertexShader)
  53. {
  54. m_Pass.StopSinglePass(cmd);
  55. cmd.EnableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
  56. Vector3 scale = new Vector3(occlusionMeshScale, yFlip ? occlusionMeshScale : -occlusionMeshScale, 1.0f);
  57. cmd.DrawMesh(m_CombinedMesh, Matrix4x4.Scale(scale), m_Material);
  58. cmd.DisableShaderKeyword("XR_OCCLUSION_MESH_COMBINED");
  59. m_Pass.StartSinglePass(cmd);
  60. }
  61. }
  62. else
  63. {
  64. Mesh mesh = m_Pass.GetOcclusionMesh(0);
  65. if (mesh != null)
  66. {
  67. cmd.DrawMesh(mesh, Matrix4x4.identity, m_Material);
  68. }
  69. }
  70. }
  71. }
  72. }
  73. internal void UpdateCombinedMesh()
  74. {
  75. if (IsOcclusionMeshSupported() && m_Pass.singlePassEnabled && TryGetOcclusionMeshCombinedHashCode(out var hashCode))
  76. {
  77. if (m_CombinedMesh == null || hashCode != m_CombinedMeshHashCode)
  78. {
  79. CreateOcclusionMeshCombined();
  80. m_CombinedMeshHashCode = hashCode;
  81. }
  82. }
  83. else
  84. {
  85. m_CombinedMesh = null;
  86. m_CombinedMeshHashCode = 0;
  87. }
  88. }
  89. bool IsOcclusionMeshSupported()
  90. {
  91. return m_Pass.enabled && m_Material != null;
  92. }
  93. bool TryGetOcclusionMeshCombinedHashCode(out int hashCode)
  94. {
  95. hashCode = 17;
  96. for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId)
  97. {
  98. Mesh mesh = m_Pass.GetOcclusionMesh(viewId);
  99. if (mesh != null)
  100. {
  101. hashCode = hashCode * 23 + mesh.GetHashCode();
  102. }
  103. else
  104. {
  105. hashCode = 0;
  106. return false;
  107. }
  108. }
  109. return true;
  110. }
  111. // Create a new mesh that contains the occlusion data from all views
  112. void CreateOcclusionMeshCombined()
  113. {
  114. CoreUtils.Destroy(m_CombinedMesh);
  115. m_CombinedMesh = new Mesh();
  116. m_CombinedMesh.indexFormat = IndexFormat.UInt16;
  117. int combinedVertexCount = 0;
  118. uint combinedIndexCount = 0;
  119. for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId)
  120. {
  121. Mesh mesh = m_Pass.GetOcclusionMesh(viewId);
  122. Debug.Assert(mesh != null);
  123. Debug.Assert(mesh.subMeshCount == 1);
  124. Debug.Assert(mesh.indexFormat == IndexFormat.UInt16);
  125. combinedVertexCount += mesh.vertexCount;
  126. combinedIndexCount += mesh.GetIndexCount(0);
  127. }
  128. Vector3[] vertices = new Vector3[combinedVertexCount];
  129. ushort[] indices = new ushort[combinedIndexCount];
  130. int vertexStart = 0;
  131. int indexStart = 0;
  132. for (int viewId = 0; viewId < m_Pass.viewCount; ++viewId)
  133. {
  134. Mesh mesh = m_Pass.GetOcclusionMesh(viewId);
  135. var meshIndices = mesh.GetIndices(0);
  136. // Encore the viewId into the z channel
  137. {
  138. mesh.vertices.CopyTo(vertices, vertexStart);
  139. for (int i = 0; i < mesh.vertices.Length; i++)
  140. vertices[vertexStart + i].z = viewId;
  141. }
  142. // Combine indices into one buffer
  143. for (int i = 0; i < meshIndices.Length; i++)
  144. {
  145. int newIndex = vertexStart + meshIndices[i];
  146. Debug.Assert(meshIndices[i] < ushort.MaxValue);
  147. indices[indexStart + i] = (ushort)newIndex;
  148. }
  149. vertexStart += mesh.vertexCount;
  150. indexStart += meshIndices.Length;
  151. }
  152. m_CombinedMesh.vertices = vertices;
  153. m_CombinedMesh.SetIndices(indices, MeshTopology.Triangles, 0);
  154. }
  155. }
  156. }