暫無描述
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.

AccelStructAdapterTests.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. using NUnit.Framework;
  2. using System;
  3. using UnityEditor;
  4. using System.Runtime.InteropServices;
  5. using Unity.Mathematics;
  6. using Unity.Collections.LowLevel.Unsafe;
  7. namespace UnityEngine.Rendering.UnifiedRayTracing.Tests
  8. {
  9. [TestFixture("Compute")]
  10. [TestFixture("Hardware")]
  11. public class AccelStructAdapterTests
  12. {
  13. RayTracingBackend m_Backend;
  14. RayTracingContext m_Context;
  15. AccelStructAdapter m_AccelStruct;
  16. IRayTracingShader m_Shader;
  17. public AccelStructAdapterTests(string backendAsString)
  18. {
  19. m_Backend = Enum.Parse<RayTracingBackend>(backendAsString);
  20. }
  21. [SetUp]
  22. public void SetUp()
  23. {
  24. if (!SystemInfo.supportsRayTracing && m_Backend == RayTracingBackend.Hardware)
  25. {
  26. Assert.Ignore("Cannot run test on this Graphics API. Hardware RayTracing is not supported");
  27. }
  28. if (!SystemInfo.supportsComputeShaders && m_Backend == RayTracingBackend.Compute)
  29. {
  30. Assert.Ignore("Cannot run test on this Graphics API. Compute shaders are not supported");
  31. }
  32. if (SystemInfo.graphicsDeviceName.Contains("llvmpipe"))
  33. {
  34. Assert.Ignore("Cannot run test on this device (Renderer: llvmpipe (LLVM 10.0.0, 128 bits)). Tests are disabled because they fail on some platforms (that do not support 11 SSBOs). Once we do not run Ubuntu 18.04 try removing this");
  35. }
  36. CreateRayTracingResources();
  37. }
  38. [TearDown]
  39. public void TearDown()
  40. {
  41. DisposeRayTracingResources();
  42. }
  43. enum UVDimension
  44. {
  45. Dim2,
  46. Dim3,
  47. Dim4
  48. }
  49. void RayTraceAndCheckUVs(Mesh mesh, Vector4 expected, int uvChannel, float tolerance = 0.0001f)
  50. {
  51. int uvDimension = mesh.GetVertexAttributeDimension(uvChannel == 1 ? VertexAttribute.TexCoord1 : VertexAttribute.TexCoord0);
  52. UVDimension dim = UVDimension.Dim2;
  53. switch (uvDimension)
  54. {
  55. case 2:
  56. dim = UVDimension.Dim2;
  57. break;
  58. case 3:
  59. dim = UVDimension.Dim3;
  60. break;
  61. case 4:
  62. dim = UVDimension.Dim4;
  63. break;
  64. default:
  65. Assert.Fail("Unexpected UV dimension.");
  66. break;
  67. };
  68. const int instanceCount = 4;
  69. CreateMatchingRaysAndInstanceDescs(instanceCount, mesh, out RayWithFlags[] rays, out MeshInstanceDesc[] instanceDescs);
  70. for (int i = 0; i < instanceCount; ++i)
  71. {
  72. m_AccelStruct.AddInstance(i, instanceDescs[i].mesh, instanceDescs[i].localToWorldMatrix, new uint[]{ 0xFFFFFFFF }, new uint[]{ 0xFFFFFFFF });
  73. }
  74. HitGeomAttributes[] hitAttributes = null;
  75. var hits = TraceRays(rays, out hitAttributes);
  76. for (int i = 0; i < rays.Length; ++i)
  77. {
  78. Assert.IsTrue(hits[i].Valid(), "Expected ray to hit the mesh.");
  79. float4 uv = uvChannel == 1 ? hitAttributes[i].uv1 : hitAttributes[i].uv0;
  80. Assert.AreEqual(expected.x, uv.x, tolerance, $"Expected x (from uv{uvChannel}) to be fetched correctly in the ray tracing shader.");
  81. Assert.AreEqual(expected.y, uv.y, tolerance, $"Expected y (from uv{uvChannel}) to be fetched correctly in the ray tracing shader.");
  82. if (dim == UVDimension.Dim3 || dim == UVDimension.Dim4)
  83. Assert.AreEqual(expected.z, uv.z, tolerance, $"Expected z (from uv{uvChannel}) to be fetched correctly in the ray tracing shader.");
  84. if (dim == UVDimension.Dim4)
  85. Assert.AreEqual(expected.w, uv.w, tolerance, $"Expected w (from uv{uvChannel}) to be fetched correctly in the ray tracing shader.");
  86. }
  87. }
  88. [Test]
  89. [TestCase(0)]
  90. [TestCase(1)]
  91. public void GeometryPool_MeshWithTwoWideUVs_UVsAreFetchedCorrectly(int uvChannel)
  92. {
  93. Mesh mesh = MeshUtil.CreateSingleTriangleMesh(new float2(1.5f, 1.5f), new float3(-0.5f, -0.5f, 0.0f));
  94. float x = 100.2f;
  95. float y = -9.3f;
  96. var uvs = new Vector2[] { new Vector2(x, y), new Vector2(x, y), new Vector2(x, y) };
  97. // Here we use the Vector2 version for setting the UVs on the mesh
  98. mesh.SetUVs(uvChannel, uvs);
  99. RayTraceAndCheckUVs(mesh, new Vector4(x, y, 0.0f, 0.0f), uvChannel);
  100. }
  101. [Test]
  102. [TestCase(0)]
  103. [TestCase(1)]
  104. public void GeometryPool_MeshWithThreeWideUVs_UVsAreFetchedCorrectly(int uvChannel)
  105. {
  106. Mesh mesh = MeshUtil.CreateSingleTriangleMesh(new float2(1.5f, 1.5f), new float3(-0.5f, -0.5f, 0.0f));
  107. float x = 100.2f;
  108. float y = -9.3f;
  109. float z = 32.4f;
  110. var uvs = new Vector3[] { new Vector3(x, y, z), new Vector3(x, y, z), new Vector3(x, y, z) };
  111. // Here we use the Vector3 version for setting the UVs on the mesh
  112. mesh.SetUVs(uvChannel, uvs);
  113. RayTraceAndCheckUVs(mesh, new Vector4(x, y, z, 0.0f), uvChannel);
  114. }
  115. [Test]
  116. [TestCase(0)]
  117. [TestCase(1)]
  118. public void GeometryPool_MeshWithFourWideUVs_UVsAreFetchedCorrectly(int uvChannel)
  119. {
  120. Mesh mesh = MeshUtil.CreateSingleTriangleMesh(new float2(1.5f, 1.5f), new float3(-0.5f, -0.5f, 0.0f));
  121. float x = 100.2f;
  122. float y = -9.3f;
  123. float z = 32.4f;
  124. float w = -12.5f;
  125. var uvs = new Vector4[] { new Vector4(x, y, z, w), new Vector4(x, y, z, w), new Vector4(x, y, z, w) };
  126. // Here we use the Vector4 version for setting the UVs on the mesh
  127. mesh.SetUVs(uvChannel, uvs);
  128. RayTraceAndCheckUVs(mesh, new Vector4(x, y, z, w), uvChannel);
  129. }
  130. [Test]
  131. [TestCase(0)]
  132. [TestCase(1)]
  133. public void GeometryPool_MeshWithLargeUVValues_UVsAreFetchedCorrectly(int uvChannel)
  134. {
  135. Mesh mesh = MeshUtil.CreateSingleTriangleMesh(new float2(1.5f, 1.5f), new float3(-0.5f, -0.5f, 0.0f));
  136. float x = 100000.2f;
  137. float y = -900000.3f;
  138. float z = 32000.4f;
  139. float w = -1200000.5f;
  140. var uvs = new Vector4[] { new Vector4(x, y, z, w), new Vector4(x, y, z, w), new Vector4(x, y, z, w) };
  141. // Here we use the Vector4 version for setting the UVs on the mesh
  142. mesh.SetUVs(uvChannel, uvs);
  143. RayTraceAndCheckUVs(mesh, new Vector4(x, y, z, w), uvChannel, 0.2f);
  144. }
  145. [Test]
  146. [TestCase(0)]
  147. [TestCase(1)]
  148. public void GeometryPool_MeshWithDifferentVertexUVs_UVsAreInterpolatedCorrectly(int uvChannel)
  149. {
  150. Mesh mesh = MeshUtil.CreateSingleTriangleMesh(new float2(1.5f, 1.5f), new float3(-0.5f, -0.5f, 0.0f));
  151. float x = 1.0f;
  152. float y = 5.0f;
  153. float z = 7.0f;
  154. var uvs = new Vector4[] { new Vector4(x, x, x, x), new Vector4(y, y, y, y), new Vector4(z, z, z, z) };
  155. // Here we use the Vector4 version for setting the UVs on the mesh
  156. mesh.SetUVs(uvChannel, uvs);
  157. RayTraceAndCheckUVs(mesh, new Vector4(4.333f, 4.333f, 4.333f, 4.333f), uvChannel, 0.001f);
  158. }
  159. void CreateMatchingRaysAndInstanceDescs(uint instanceCount, Mesh mesh, out RayWithFlags[] rays, out MeshInstanceDesc[] instanceDescs)
  160. {
  161. instanceDescs = new MeshInstanceDesc[instanceCount];
  162. rays = new RayWithFlags[instanceCount];
  163. var ray = new RayWithFlags(new float3(0.0f, 0.0f, 1.0f), new float3(0.0f, 0.0f, -1.0f));
  164. float3 step = new float3(2.0f, 0.0f, 0.0f);
  165. for (int i = 0; i < instanceCount; ++i)
  166. {
  167. instanceDescs[i] = new MeshInstanceDesc(mesh);
  168. instanceDescs[i].localToWorldMatrix = float4x4.Translate(step * i);
  169. rays[i] = ray;
  170. rays[i].origin += step * i;
  171. }
  172. }
  173. Hit[] TraceRays(RayWithFlags[] rays, out HitGeomAttributes[] hitAttributes)
  174. {
  175. var bufferTarget = GraphicsBuffer.Target.Structured;
  176. var rayCount = rays.Length;
  177. using var raysBuffer = new GraphicsBuffer(bufferTarget, rayCount, Marshal.SizeOf<RayWithFlags>());
  178. raysBuffer.SetData(rays);
  179. using var hitsBuffer = new GraphicsBuffer(bufferTarget, rayCount, Marshal.SizeOf<Hit>());
  180. using var attributesBuffer = new GraphicsBuffer(bufferTarget, rayCount, Marshal.SizeOf<HitGeomAttributes>());
  181. var scratchBuffer = RayTracingHelper.CreateScratchBufferForBuildAndDispatch(m_AccelStruct.GetAccelerationStructure(), m_Shader, (uint)rayCount, 1, 1);
  182. var cmd = new CommandBuffer();
  183. m_AccelStruct.Build(cmd, ref scratchBuffer);
  184. m_AccelStruct.Bind(cmd, "_AccelStruct", m_Shader);
  185. m_Shader.SetBufferParam(cmd, Shader.PropertyToID("_Rays"), raysBuffer);
  186. m_Shader.SetBufferParam(cmd, Shader.PropertyToID("_Hits"), hitsBuffer);
  187. m_Shader.SetBufferParam(cmd, Shader.PropertyToID("_HitAttributes"), attributesBuffer);
  188. m_Shader.Dispatch(cmd, scratchBuffer, (uint)rayCount, 1, 1);
  189. Graphics.ExecuteCommandBuffer(cmd);
  190. var hits = new Hit[rayCount];
  191. hitsBuffer.GetData(hits);
  192. hitAttributes = new HitGeomAttributes[rayCount];
  193. attributesBuffer.GetData(hitAttributes);
  194. scratchBuffer?.Dispose();
  195. return hits;
  196. }
  197. void CreateRayTracingResources()
  198. {
  199. var resources = new RayTracingResources();
  200. resources.Load();
  201. m_Context = new RayTracingContext(m_Backend, resources);
  202. m_AccelStruct = new AccelStructAdapter(m_Context.CreateAccelerationStructure(new AccelerationStructureOptions()), resources);
  203. Type type = BackendHelpers.GetTypeOfShader(m_Backend);
  204. string filename = BackendHelpers.GetFileNameOfShader(m_Backend, $"Tests/Editor/UnifiedRayTracing/TraceRaysAndFetchAttributes");
  205. Object shader = AssetDatabase.LoadAssetAtPath($"Packages/com.unity.rendering.light-transport/{filename}", type);
  206. m_Shader = m_Context.CreateRayTracingShader(shader);
  207. }
  208. void DisposeRayTracingResources()
  209. {
  210. m_AccelStruct?.Dispose();
  211. m_Context?.Dispose();
  212. }
  213. [StructLayout(LayoutKind.Sequential)]
  214. public struct RayWithFlags
  215. {
  216. public float3 origin;
  217. public float minT;
  218. public float3 direction;
  219. public float maxT;
  220. public uint culling;
  221. public uint instanceMask;
  222. uint padding;
  223. uint padding2;
  224. public RayWithFlags(float3 origin, float3 direction)
  225. {
  226. this.origin = origin;
  227. this.direction = direction;
  228. minT = 0.0f;
  229. maxT = float.MaxValue;
  230. instanceMask = 0xFFFFFFFF;
  231. culling = 0;
  232. padding = 0;
  233. padding2 = 0;
  234. }
  235. }
  236. [System.Flags]
  237. enum RayCulling { None = 0, CullFrontFace = 0x10, CullBackFace = 0x20 }
  238. [StructLayout(LayoutKind.Sequential)]
  239. public struct Hit
  240. {
  241. public uint instanceID;
  242. public uint primitiveIndex;
  243. public float2 uvBarycentrics;
  244. public float hitDistance;
  245. public uint isFrontFace;
  246. public bool Valid() { return instanceID != 0xFFFFFFFF; }
  247. }
  248. [StructLayout(LayoutKind.Sequential)]
  249. public struct HitGeomAttributes
  250. {
  251. public float3 position;
  252. public float3 normal;
  253. public float3 faceNormal;
  254. public float4 uv0;
  255. public float4 uv1;
  256. }
  257. }
  258. }