Advertisement
Zgragselus

Traversal bvh2

Jan 10th, 2025
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.77 KB | None | 0 0
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // TraversalBvh2.hlsli
  4. //
  5. // Implements ray traversal through multi-level BVH-2 acceleration structure.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////////////////////////
  8.  
  9. #ifndef __TRAVERSAL_BVH2__HLSLI__
  10. #define __TRAVERSAL_BVH2__HLSLI__
  11.  
  12. #include "../Raytracer.hlsli"
  13.  
  14. // Definition to compact funciton parameters into TraceRayCompute funciton (BVH-2 variant)
  15. #define TRACE_RAY_PARAMS RWStructuredBuffer<GeometryNode> Geometries,\
  16.                          RWStructuredBuffer<InstanceNode> Instances,\
  17.                          RWStructuredBuffer<MemoryNode> ASTreeNodes,\
  18.                          RWStructuredBuffer<BVH2Node> ASTreeData,\
  19.                          RWStructuredBuffer<MemoryNode> ASIndexNodes,\
  20.                          RWStructuredBuffer<uint> ASIndexData,\
  21.                          RWStructuredBuffer<MemoryNode> WoopNodes,\
  22.                          RWStructuredBuffer<float4> WoopData
  23.    
  24. // Definition to compact argument passing into TraceRayCompute function (BVH-2 variant)
  25. #define TRACE_RAY_ARGS  Geometries,\
  26.                         Instances,\
  27.                         ASTreeNodes,\
  28.                         ASTreeData,\
  29.                         ASIndexNodes,\
  30.                         ASIndexData,\
  31.                         WoopNodes,\
  32.                         WoopData
  33.    
  34. /// <summary>
  35. /// Performs ray traversal through acceleration structure for single ray.
  36. ///
  37. /// This function performs traversal through binary Bounding Volume Hierarchy (BVH-2). Result of
  38. /// this funciton is represented by barycentric coordinates, primitive ID, geometry ID and distance
  39. /// along the ray to hitpoint.
  40. /// </summary>
  41. /// <param name="r">Ray to trace.</param>
  42. /// <param name="Geometries">Buffer of GeometryNode - holds all definition for geometries in the scene</param>
  43. /// <param name="Instances">Buffer of InstanceNode - holds all geometry instances definitions in the scene</param>
  44. /// <param name="ASTreeNodes">Buffer of memory nodes - each representing single BVH node data definition/offsets</param>
  45. /// <param name="ASTreeData">Buffer of BVH nodes - BVH node data</param>
  46. /// <param name="ASIndexNodes">Buffer of memory nodes - each representing single BVH index data definition/offsets</param>
  47. /// <param name="ASIndexData">Buffer of BVH indices - BVH index data</param>
  48. /// <param name="WoopNodes">Buffer of memory nodes - each representing definition/offsets into data buffer holding woop triangle data</param>
  49. /// <param name="WoopData">Buffer of woop triangle data - Woop triangle geometry data</param>
  50. /// <returns>
  51. /// 4-component vector, where:
  52. ///   1st component has packed U/V barycentric coordinates (see PackFloat2/UnpackFloat2)
  53. ///   2nd component distance along the ray to hit
  54. ///   3rd component primitive ID (unsigned int)
  55. ///   4th component geometry ID (unsigned int)
  56. /// </returns>
  57. float4 TraceRayCompute(Ray r, TRACE_RAY_PARAMS)
  58. {
  59.     float4 o = r.Origin;
  60.     float4 d = r.Direction;
  61.     float4 inv = r.Inverse;
  62.     float4 oinv = o * inv;
  63.  
  64.     uint node_id = 0;
  65.     uint stack[BVH_STACK_SIZE];
  66.     uint stack_ptr = 0;
  67.     stack[stack_ptr] = 0xFFFFFFFF;
  68.     int meshbvh_stack_ptr = -1;
  69.  
  70.     float tmin = 0.0f;
  71.     float tmax = 10000.0f;
  72.     float bU = 0.0f;
  73.     float bV = 0.0f;
  74.     float dist = tmax;
  75.     uint prim_id = 0;
  76.     uint geometryID = 0;
  77.     bool hit = false;
  78.    
  79.     InstanceNode instance = Instances[0];
  80.  
  81.     int i;
  82.  
  83.     // Traversal (use for for testing)
  84.     [loop]
  85.     for (i = 0; i < 1024; i++)
  86.     //while (node_id != 0xFFFFFFFF) // This is significantly slower on RDNA 2, not sure about others
  87.     {
  88.         // When interior node was intersected
  89.         [branch]
  90.         if (ASTreeData[node_id].PrimitiveCount == 0)
  91.         {
  92.             // Fetch children bounding boxes
  93.             float4 n0xy = ASTreeData[node_id].LXY;
  94.             float4 n1xy = ASTreeData[node_id].RXY;
  95.             float4 nz = ASTreeData[node_id].LRZ;
  96.  
  97.             // Test against child AABBs
  98.             float c0lox = n0xy.x * inv.x - oinv.x;
  99.             float c0hix = n0xy.y * inv.x - oinv.x;
  100.             float c0loy = n0xy.z * inv.y - oinv.y;
  101.             float c0hiy = n0xy.w * inv.y - oinv.y;
  102.             float c0loz = nz.x * inv.z - oinv.z;
  103.             float c0hiz = nz.y * inv.z - oinv.z;
  104.             float c1loz = nz.z * inv.z - oinv.z;
  105.             float c1hiz = nz.w * inv.z - oinv.z;
  106.             float c0min = max(max(min(c0lox, c0hix), min(c0loy, c0hiy)), max(min(c0loz, c0hiz), tmin));
  107.             float c0max = min(min(max(c0lox, c0hix), max(c0loy, c0hiy)), min(max(c0loz, c0hiz), tmax));
  108.             float c1lox = n1xy.x * inv.x - oinv.x;
  109.             float c1hix = n1xy.y * inv.x - oinv.x;
  110.             float c1loy = n1xy.z * inv.y - oinv.y;
  111.             float c1hiy = n1xy.w * inv.y - oinv.y;
  112.             float c1min = max(max(min(c1lox, c1hix), min(c1loy, c1hiy)), max(min(c1loz, c1hiz), tmin));
  113.             float c1max = min(min(max(c1lox, c1hix), max(c1loy, c1hiy)), min(max(c1loz, c1hiz), tmax));
  114.  
  115.             bool traverseChild0 = (c0max >= c0min);
  116.             bool traverseChild1 = (c1max >= c1min);
  117.  
  118.             // If no children was hit, get node from stack
  119.             if (!traverseChild0 && !traverseChild1)
  120.             {
  121.                 // If we're in BLAS and we're on entrypoint, then reset the ray as the traversal will
  122.                 // continue in TLAS
  123.                 if (stack_ptr == meshbvh_stack_ptr)
  124.                 {
  125.                     meshbvh_stack_ptr = -1;
  126.                     o = r.Origin;
  127.                     d = r.Direction;
  128.                     inv = r.Inverse;
  129.                     oinv = o * inv;
  130.                 }
  131.                
  132.                 // Pop from stack
  133.                 node_id = stack[stack_ptr];
  134.                 stack_ptr--;
  135.             }
  136.             // If either (or both children) were it - traverse next on (along the ray direction),
  137.             // and if both were hit, push the other one to stack
  138.             else if (traverseChild0 || traverseChild1)
  139.             {
  140.                 uint first_child = node_id + 1;
  141.                 uint second_child = ASTreeData[node_id].PrimitiveOffset;
  142.                 node_id = (traverseChild0) ? first_child : second_child;
  143.  
  144.                 if (traverseChild0 && traverseChild1)
  145.                 {
  146.                     if (c1min < c0min)
  147.                     {
  148.                         node_id = second_child;
  149.                         stack_ptr++;
  150.                         stack[stack_ptr] = first_child;
  151.                     }
  152.                     else
  153.                     {
  154.                         stack_ptr++;
  155.                         stack[stack_ptr] = second_child;
  156.                     }
  157.                 }
  158.             }
  159.         }
  160.         // When leaf node was intersected - and we're in TLAS
  161.         //
  162.         // Setup the new ray origin/direction for traversing BLAS and enter the BLAS, record
  163.         // entry-point to BLAS into stack so we know when we will finish BLAS traversal
  164.         else if (ASTreeData[node_id].PrimitiveCount == -1)
  165.         {
  166.             meshbvh_stack_ptr = stack_ptr;
  167.  
  168.             uint blas_offset = ASTreeData[node_id].PrimitiveOffset;
  169.             uint instance_index = ASIndexData[blas_offset];
  170.             instance = Instances[instance_index];
  171.  
  172.             node_id = ASTreeNodes[Geometries[instance.GeometryNode].BVHNode + 1].Offset / 64;
  173.  
  174.             o = mul(r.Origin, instance.TransformInverse);
  175.             d = mul(r.Direction, instance.TransformInverse);
  176.             inv = rcp(d);
  177.             oinv = o * inv;
  178.         }
  179.         // When leaf node was intersected - and we're in BLAS
  180.         //
  181.         // Perform ray-triangle intersection test for all triangles in leaf node
  182.         else
  183.         {
  184.             if (ASTreeData[node_id].PrimitiveCount > 0)
  185.             {
  186.                 GeometryNode geom = Geometries[instance.GeometryNode];
  187.                 //MemoryNode vbo = VertexNodes[geom.VertexBufferNode];
  188.                 //MemoryNode ibo = IndexNodes[geom.IndexBufferNode];
  189.                 MemoryNode wbo = WoopNodes[geom.WoopBufferNode];
  190.  
  191.                 uint index_offset = ASIndexNodes[ASTreeData[node_id].PrimitiveOffset].Offset / 4;
  192.  
  193.                 for (uint j = 0; j < ASTreeData[node_id].PrimitiveCount; j++)
  194.                 {
  195.                     // Don't trash cache by reading index through it
  196.                     uint tri_idx = ASIndexData[ASTreeData[node_id].PrimitiveOffset + j] * 3;
  197.                    
  198.                     // Fetch data for Woop's triangle
  199.                     float4 r = WoopData[wbo.Offset / 16 + tri_idx + 0];
  200.                     float4 p = WoopData[wbo.Offset / 16 + tri_idx + 1];
  201.                     float4 q = WoopData[wbo.Offset / 16 + tri_idx + 2];
  202.  
  203.                     // Perform intersection
  204.                     float o_z = r.w - o.x * r.x - o.y * r.y - o.z * r.z;
  205.                     float i_z = 1.0f / (d.x * r.x + d.y * r.y + d.z * r.z);
  206.                     float t = o_z * i_z;
  207.  
  208.                     if (t > tmin && t < tmax)
  209.                     {
  210.                         float o_x = p.w + o.x * p.x + o.y * p.y + o.z * p.z;
  211.                         float d_x = d.x * p.x + d.y * p.y + d.z * p.z;
  212.                         float u = o_x + t * d_x;
  213.  
  214.                         if (u >= 0.0f && u <= 1.0f)
  215.                         {
  216.                             float o_y = q.w + o.x * q.x + o.y * q.y + o.z * q.z;
  217.                             float d_y = d.x * q.x + d.y * q.y + d.z * q.z;
  218.                             float v = o_y + t * d_y;
  219.                            
  220.                             if (v >= 0.0f && u + v <= 1.0f)
  221.                             {
  222.                                 tmax = t;
  223.                                 bU = u;
  224.                                 bV = v;
  225.                                 hit = true;
  226.  
  227.                                 geometryID = instance.GeometryNode;
  228.                                 prim_id = tri_idx;
  229.                             }
  230.                         }
  231.                     }
  232.                 }
  233.             }
  234.  
  235.             // If we're in BLAS and we're on entrypoint, then reset the ray as the traversal will
  236.             // continue in TLAS
  237.             if (stack_ptr == meshbvh_stack_ptr)
  238.             {
  239.                 meshbvh_stack_ptr = -1;
  240.                 o = r.Origin;
  241.                 d = r.Direction;
  242.                 inv = r.Inverse;
  243.                 oinv = o * inv;
  244.             }
  245.  
  246.             // Pop from stack
  247.             node_id = stack[stack_ptr];
  248.             stack_ptr--;
  249.         }
  250.  
  251.         // If we hit entrypoint into the traversal, terminate the traversal as we are finished
  252.         if (node_id == 0xFFFFFFFF)
  253.         {
  254.             break;
  255.         }
  256.     }
  257.    
  258.     return float4(PackFloat2(bU, bV), tmax, asfloat(prim_id), asfloat(geometryID));
  259. }
  260.  
  261. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement