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.

AccelStructAdapter.cs 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Assertions;
  4. using UnityEngine.Rendering;
  5. using Unity.Mathematics;
  6. #if UNITY_EDITOR
  7. using UnityEditor;
  8. #endif
  9. namespace UnityEngine.Rendering.UnifiedRayTracing
  10. {
  11. internal class AccelStructAdapter : IDisposable
  12. {
  13. private IRayTracingAccelStruct _accelStruct;
  14. AccelStructInstances _instances;
  15. internal AccelStructInstances Instances { get => _instances; }
  16. struct InstanceIDs
  17. {
  18. public int InstanceID;
  19. public int AccelStructID;
  20. }
  21. private readonly Dictionary<int, InstanceIDs[]> _objectHandleToInstances = new();
  22. public AccelStructAdapter(IRayTracingAccelStruct accelStruct, GeometryPool geometryPool)
  23. {
  24. _accelStruct = accelStruct;
  25. _instances = new AccelStructInstances(geometryPool);
  26. }
  27. public AccelStructAdapter(IRayTracingAccelStruct accelStruct, RayTracingResources resources)
  28. : this(accelStruct, new GeometryPool(GeometryPoolDesc.NewDefault(), resources.geometryPoolKernels, resources.copyBuffer))
  29. { }
  30. public IRayTracingAccelStruct GetAccelerationStructure()
  31. {
  32. return _accelStruct;
  33. }
  34. public GeometryPool GeometryPool => _instances.geometryPool;
  35. public void Bind(CommandBuffer cmd, string propertyName, IRayTracingShader shader)
  36. {
  37. shader.SetAccelerationStructure(cmd, propertyName, _accelStruct);
  38. _instances.Bind(cmd, shader);
  39. }
  40. public void Dispose()
  41. {
  42. _instances?.Dispose();
  43. _instances = null;
  44. _accelStruct?.Dispose();
  45. _accelStruct = null;
  46. _objectHandleToInstances.Clear();
  47. }
  48. public void AddInstance(int objectHandle, Component meshRendererOrTerrain, uint[] perSubMeshMask, uint[] perSubMeshMaterialIDs)
  49. {
  50. if (meshRendererOrTerrain is Terrain terrain)
  51. {
  52. Debug.Assert(terrain.enabled, "Terrains are expected to be enabled.");
  53. var terrainDesc = new TerrainDesc();
  54. terrainDesc.terrain = terrain;
  55. terrainDesc.mask = perSubMeshMask[0];
  56. terrainDesc.materialID = perSubMeshMaterialIDs[0];
  57. AddInstance(objectHandle, terrainDesc);
  58. }
  59. else
  60. {
  61. var meshRenderer = (MeshRenderer)meshRendererOrTerrain;
  62. Debug.Assert(meshRenderer.enabled, "Mesh renderers are expected to be enabled.");
  63. Debug.Assert(!meshRenderer.isPartOfStaticBatch, "Mesh renderers are expected to not be part of static batch.");
  64. var mesh = meshRenderer.GetComponent<MeshFilter>().sharedMesh;
  65. AddInstance(objectHandle, mesh, meshRenderer.transform.localToWorldMatrix, perSubMeshMask, perSubMeshMaterialIDs);
  66. }
  67. }
  68. public void AddInstance(int objectHandle, Mesh mesh, Matrix4x4 localToWorldMatrix, uint[] perSubMeshMask, uint[] perSubMeshMaterialIDs)
  69. {
  70. int subMeshCount = mesh.subMeshCount;
  71. var instances = new InstanceIDs[subMeshCount];
  72. for (int i = 0; i < subMeshCount; ++i)
  73. {
  74. var instanceDesc = new MeshInstanceDesc(mesh, i)
  75. {
  76. localToWorldMatrix = localToWorldMatrix,
  77. mask = perSubMeshMask[i],
  78. };
  79. instances[i].InstanceID = _instances.AddInstance(instanceDesc, perSubMeshMaterialIDs[i]);
  80. instanceDesc.instanceID = (uint)instances[i].InstanceID;
  81. instances[i].AccelStructID = _accelStruct.AddInstance(instanceDesc);
  82. }
  83. _objectHandleToInstances.Add(objectHandle, instances);
  84. }
  85. private void AddInstance(int objectHandle, TerrainDesc terrainDesc)
  86. {
  87. List<InstanceIDs> instanceHandles = new List<InstanceIDs>();
  88. AddHeightmap(terrainDesc, ref instanceHandles);
  89. AddTrees(terrainDesc, ref instanceHandles);
  90. _objectHandleToInstances.Add(objectHandle, instanceHandles.ToArray());
  91. }
  92. void AddHeightmap(TerrainDesc terrainDesc, ref List<InstanceIDs> instanceHandles)
  93. {
  94. var terrainMesh = TerrainToMesh.Convert(terrainDesc.terrain);
  95. var instanceDesc = new MeshInstanceDesc(terrainMesh);
  96. instanceDesc.localToWorldMatrix = terrainDesc.localToWorldMatrix;
  97. instanceDesc.mask = terrainDesc.mask;
  98. instanceDesc.enableTriangleCulling = terrainDesc.enableTriangleCulling;
  99. instanceDesc.frontTriangleCounterClockwise = terrainDesc.frontTriangleCounterClockwise;
  100. instanceHandles.Add(AddInstance(instanceDesc, terrainDesc.materialID));
  101. }
  102. void AddTrees(TerrainDesc terrainDesc, ref List<InstanceIDs> instanceHandles)
  103. {
  104. TerrainData terrainData = terrainDesc.terrain.terrainData;
  105. float4x4 terrainLocalToWorld = terrainDesc.localToWorldMatrix;
  106. float3 positionScale = new float3((float)terrainData.heightmapResolution, 1.0f, (float)terrainData.heightmapResolution) * terrainData.heightmapScale;
  107. float3 positionOffset = new float3(terrainLocalToWorld[3].x, terrainLocalToWorld[3].y, terrainLocalToWorld[3].z);
  108. foreach (var treeInstance in terrainData.treeInstances)
  109. {
  110. var localToWorld = Matrix4x4.TRS(
  111. positionOffset + new float3(treeInstance.position) * positionScale,
  112. Quaternion.AngleAxis(treeInstance.rotation, Vector3.up),
  113. new Vector3(treeInstance.widthScale, treeInstance.heightScale, treeInstance.widthScale));
  114. var prefab = terrainData.treePrototypes[treeInstance.prototypeIndex].prefab;
  115. var mesh = prefab.gameObject.GetComponent<MeshFilter>().sharedMesh;
  116. if (!mesh)
  117. continue;
  118. for (int i = 0; i < mesh.subMeshCount; ++i)
  119. {
  120. var instanceDesc = new MeshInstanceDesc(mesh, i);
  121. instanceDesc.localToWorldMatrix = localToWorld;
  122. instanceDesc.mask = terrainDesc.mask;
  123. instanceDesc.enableTriangleCulling = terrainDesc.enableTriangleCulling;
  124. instanceDesc.frontTriangleCounterClockwise = terrainDesc.frontTriangleCounterClockwise;
  125. instanceHandles.Add(AddInstance(instanceDesc, terrainDesc.materialID));
  126. }
  127. }
  128. }
  129. InstanceIDs AddInstance(MeshInstanceDesc instanceDesc, uint materialID)
  130. {
  131. InstanceIDs res = new InstanceIDs();
  132. res.InstanceID = _instances.AddInstance(instanceDesc, materialID);
  133. instanceDesc.instanceID = (uint)res.InstanceID;
  134. res.AccelStructID = _accelStruct.AddInstance(instanceDesc);
  135. return res;
  136. }
  137. public void RemoveInstance(int objectHandle)
  138. {
  139. bool success = _objectHandleToInstances.TryGetValue(objectHandle, out var instances);
  140. Assert.IsTrue(success);
  141. foreach (var instance in instances)
  142. {
  143. _instances.RemoveInstance(instance.InstanceID);
  144. _accelStruct.RemoveInstance(instance.AccelStructID);
  145. }
  146. _objectHandleToInstances.Remove(objectHandle);
  147. }
  148. public void UpdateInstanceTransform(int objectHandle, Matrix4x4 localToWorldMatrix)
  149. {
  150. bool success = _objectHandleToInstances.TryGetValue(objectHandle, out var instances);
  151. Assert.IsTrue(success);
  152. foreach(var instance in instances)
  153. {
  154. _instances.UpdateInstanceTransform(instance.InstanceID, localToWorldMatrix);
  155. _accelStruct.UpdateInstanceTransform(instance.AccelStructID, localToWorldMatrix);
  156. }
  157. }
  158. public void UpdateInstanceMaterialIDs(int objectHandle, uint[] perSubMeshMaterialIDs)
  159. {
  160. bool success = _objectHandleToInstances.TryGetValue(objectHandle, out var instances);
  161. Assert.IsTrue(success);
  162. Assert.IsTrue(perSubMeshMaterialIDs.Length >= instances.Length);
  163. int i = 0;
  164. foreach (var instance in instances)
  165. {
  166. _instances.UpdateInstanceMaterialID(instance.InstanceID, perSubMeshMaterialIDs[i++]);
  167. }
  168. }
  169. public void UpdateInstanceMask(int objectHandle, uint[] perSubMeshMask)
  170. {
  171. bool success = _objectHandleToInstances.TryGetValue(objectHandle, out var instances);
  172. Assert.IsTrue(success);
  173. Assert.IsTrue(perSubMeshMask.Length >= instances.Length);
  174. int i = 0;
  175. foreach (var instance in instances)
  176. {
  177. _instances.UpdateInstanceMask(instance.InstanceID, perSubMeshMask[i]);
  178. _accelStruct.UpdateInstanceMask(instance.AccelStructID, perSubMeshMask[i]);
  179. i++;
  180. }
  181. }
  182. public void Build(CommandBuffer cmd, ref GraphicsBuffer scratchBuffer)
  183. {
  184. RayTracingHelper.ResizeScratchBufferForBuild(_accelStruct, ref scratchBuffer);
  185. _accelStruct.Build(cmd, scratchBuffer);
  186. }
  187. public void NextFrame()
  188. {
  189. _instances.NextFrame();
  190. }
  191. public bool GetInstanceIDs(int rendererID, out int[] instanceIDs)
  192. {
  193. if (!_objectHandleToInstances.TryGetValue(rendererID, out InstanceIDs[] instIDs))
  194. {
  195. // This should never happen as long as the renderer was already added to the acceleration structure
  196. instanceIDs = null;
  197. return false;
  198. }
  199. instanceIDs = Array.ConvertAll(instIDs, item => item.InstanceID);
  200. return true;
  201. }
  202. }
  203. internal struct TerrainDesc
  204. {
  205. public Terrain terrain;
  206. public Matrix4x4 localToWorldMatrix;
  207. public uint mask;
  208. public uint materialID;
  209. public bool enableTriangleCulling;
  210. public bool frontTriangleCounterClockwise;
  211. public TerrainDesc(Terrain terrain)
  212. {
  213. this.terrain = terrain;
  214. localToWorldMatrix = Matrix4x4.identity;
  215. mask = 0xFFFFFFFF;
  216. materialID = 0;
  217. enableTriangleCulling = true;
  218. frontTriangleCounterClockwise = false;
  219. }
  220. }
  221. }