Açıklama Yok
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.

BvhCheck.cs 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using System.Collections.Generic;
  2. using Unity.Mathematics;
  3. using UnityEngine.Assertions;
  4. namespace UnityEngine.Rendering.RadeonRays
  5. {
  6. internal class AABB
  7. {
  8. public float3 Min;
  9. public float3 Max;
  10. public AABB()
  11. {
  12. Min = new float3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
  13. Max = new float3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
  14. }
  15. public AABB(float3 min, float3 max)
  16. {
  17. Min = min;
  18. Max = max;
  19. }
  20. public void Encapsulate(AABB aabb)
  21. {
  22. Min = math.min(Min, aabb.Min);
  23. Max = math.max(Max, aabb.Max);
  24. }
  25. public void Encapsulate(float3 point)
  26. {
  27. Min = math.min(Min, point);
  28. Max = math.max(Max, point);
  29. }
  30. public bool Contains(AABB rhs)
  31. {
  32. return rhs.Min.x >= Min.x && rhs.Min.y >= Min.y && rhs.Min.z >= Min.z &&
  33. rhs.Max.x <= Max.x && rhs.Max.y <= Max.y && rhs.Max.z <= Max.z;
  34. }
  35. public bool IsValid()
  36. {
  37. return Min.x <= Max.x && Min.y <= Max.y && Min.z <= Max.z;
  38. }
  39. }
  40. internal class BvhCheck
  41. {
  42. const uint kInvalidID = ~0u;
  43. public class VertexBuffers
  44. {
  45. public GraphicsBuffer vertices;
  46. public GraphicsBuffer indices;
  47. public uint vertexBufferOffset = 0;
  48. public uint vertexCount;
  49. public uint vertexStride = 3;
  50. public uint indexBufferOffset = 0;
  51. public uint indexCount;
  52. };
  53. public static double SurfaceArea(AABB aabb)
  54. {
  55. float3 edges = aabb.Max - aabb.Min;
  56. return 2.0f * (edges.x * edges.y + edges.x * edges.z + edges.z * edges.y);
  57. }
  58. public static double NodeSahCost(BvhNode node, AABB nodeAabb, AABB parentAabb)
  59. {
  60. double cost = node.child0 == kInvalidID ? node.child1 : 1.2f;
  61. return cost * SurfaceArea(nodeAabb) / SurfaceArea(parentAabb);
  62. }
  63. public static double CheckConsistency(VertexBuffers bvhVertexBuffers, GraphicsBuffer bvhBuffer, uint bvhBufferOffset, uint primitiveCount)
  64. {
  65. var header = new BvhHeader[1];
  66. bvhBuffer.GetData(header, 0, (int)bvhBufferOffset, 1);
  67. return CheckConsistency(bvhVertexBuffers, bvhBuffer, bvhBufferOffset + 1, header[0].leafNodeCount, header[0].root, primitiveCount);
  68. }
  69. public static double CheckConsistency(
  70. VertexBuffers bvhVertexBuffers, GraphicsBuffer bvhBuffer,
  71. uint bvhBufferOffset, uint leafCount, uint rootAddr, uint primitiveCount)
  72. {
  73. var nodeCount = HlbvhBuilder.GetBvhNodeCount(leafCount);
  74. var bvhNodes = new BvhNode[nodeCount];
  75. bvhBuffer.GetData(bvhNodes, 0, (int)bvhBufferOffset, (int)nodeCount);
  76. bool isTopLevel = bvhVertexBuffers == null;
  77. VertexBuffersCPU vertexBuffers = null;
  78. if (!isTopLevel)
  79. vertexBuffers = DownloadVertexData(bvhVertexBuffers);
  80. uint countedPrimitives = 0;
  81. var rootAabb = GetAabb(vertexBuffers, bvhNodes[rootAddr], isTopLevel);
  82. double sahCost = 0.0f;
  83. var q = new Queue<(uint Addr, uint Parent)>();
  84. q.Enqueue((Addr: rootAddr, Parent: kInvalidID));
  85. while (q.Count != 0)
  86. {
  87. var current = q.Dequeue();
  88. uint addr = current.Addr;
  89. uint parent = current.Parent;
  90. var node = bvhNodes[addr];
  91. AABB aabb = GetAabb(vertexBuffers, node, isTopLevel);
  92. sahCost += NodeSahCost(node, aabb, rootAabb);
  93. Assert.AreEqual(parent, node.parent);
  94. Assert.IsTrue(aabb.IsValid());
  95. if (node.child0 != kInvalidID)
  96. {
  97. var leftAabb = GetAabb(vertexBuffers, bvhNodes[node.child0], isTopLevel);
  98. var rightAabb = GetAabb(vertexBuffers, bvhNodes[node.child1], isTopLevel);
  99. bool leftOk = (aabb.Contains(leftAabb));
  100. bool rightOk = (aabb.Contains(rightAabb));
  101. Assert.IsTrue(leftOk);
  102. Assert.IsTrue(rightOk);
  103. q.Enqueue((Addr: node.child0, Parent: addr));
  104. q.Enqueue((Addr: node.child1, Parent: addr));
  105. }
  106. else // leaf
  107. {
  108. countedPrimitives += isTopLevel ? 1 : node.aabb0_min[0];
  109. }
  110. }
  111. Assert.AreEqual(countedPrimitives, primitiveCount);
  112. return sahCost;
  113. }
  114. private class VertexBuffersCPU
  115. {
  116. public float[] vertices;
  117. public uint[] indices;
  118. public uint vertexStride;
  119. };
  120. static uint3 GetFaceIndices(uint[] indices, uint triangleIdx)
  121. {
  122. return new uint3(
  123. indices[3 * triangleIdx],
  124. indices[3 * triangleIdx + 1],
  125. indices[3 * triangleIdx + 2]);
  126. }
  127. static float3 GetVertex(float[] vertices, uint stride, uint idx)
  128. {
  129. uint indexInFloats = idx * stride;
  130. return new float3(
  131. vertices[indexInFloats],
  132. vertices[indexInFloats + 1],
  133. vertices[indexInFloats + 2]);
  134. }
  135. struct Triangle
  136. {
  137. public float3 v0;
  138. public float3 v1;
  139. public float3 v2;
  140. };
  141. static Triangle GetTriangle(float[] vertices, uint stride, uint3 idx)
  142. {
  143. Triangle tri;
  144. tri.v0 = GetVertex(vertices, stride, idx.x);
  145. tri.v1 = GetVertex(vertices, stride, idx.y);
  146. tri.v2 = GetVertex(vertices, stride, idx.z);
  147. return tri;
  148. }
  149. static VertexBuffersCPU DownloadVertexData(VertexBuffers vertexBuffers)
  150. {
  151. var result = new VertexBuffersCPU();
  152. result.vertices = new float[vertexBuffers.vertexCount * vertexBuffers.vertexStride];
  153. result.indices = new uint[vertexBuffers.indexCount];
  154. result.vertexStride = vertexBuffers.vertexStride;
  155. vertexBuffers.indices.GetData(result.indices, 0, (int)vertexBuffers.indexBufferOffset, (int)vertexBuffers.indexCount);
  156. vertexBuffers.vertices.GetData(result.vertices, 0, (int)vertexBuffers.vertexBufferOffset, (int)(vertexBuffers.vertexCount * vertexBuffers.vertexStride));
  157. return result;
  158. }
  159. static AABB GetAabb(VertexBuffersCPU bvhVertexBuffers, BvhNode node, bool isTopLevel)
  160. {
  161. var aabb = new AABB();
  162. if (node.child0 != kInvalidID || isTopLevel)
  163. {
  164. AABB left = new AABB(math.asfloat(node.aabb0_min), math.asfloat(node.aabb0_max));
  165. aabb.Encapsulate(left);
  166. AABB right = new AABB(math.asfloat(node.aabb1_min), math.asfloat(node.aabb1_max));
  167. aabb.Encapsulate(right);
  168. }
  169. else
  170. {
  171. int fisrtIndex = (int)node.child1;
  172. int triangleCount = (int)node.aabb0_min[0];
  173. for (int i = 0; i < triangleCount; ++i)
  174. {
  175. uint index = (uint)(i + fisrtIndex);
  176. var triangleIndices = GetFaceIndices(bvhVertexBuffers.indices, index);
  177. var triangle = GetTriangle(bvhVertexBuffers.vertices, bvhVertexBuffers.vertexStride, triangleIndices);
  178. aabb.Encapsulate(triangle.v0);
  179. aabb.Encapsulate(triangle.v1);
  180. aabb.Encapsulate(triangle.v2);
  181. }
  182. }
  183. return aabb;
  184. }
  185. }
  186. }