NeroReflex

TLAS

Nov 1st, 2019
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.29 KB | None | 0 0
  1. struct Geometry {
  2.             glm::vec4 signature;
  3.             glm::vec4 vertex1_or_sphere_center;
  4.             glm::vec4 vertex2_or_sphere_radius;
  5.             glm::vec4 vertex3_or_nothing;
  6.         };
  7.  
  8.         struct GeometryCollection {
  9.             Geometry geometry[1 << expOfTwoOfMaxGeometryElementsInCollection]; // geometry slots
  10.         };
  11.  
  12.         struct AABB {
  13.             glm::vec4 position; // this is the point of the aabb with min x, y and z components
  14.             glm::vec4 dimensions; // this is the amount to be added to aabbVertex to obtain the point with max x, y and z in the aabb
  15.         };
  16.  
  17.         struct alignas(16) NodeData {
  18.             AABB aabb;
  19.             alignas(sizeof(glm::uint32)) glm::uint32 left; // this can also be the content if right is zero
  20.             alignas(sizeof(glm::uint32))glm::uint32 right; // this is zero if the node is a leaf
  21.         };
  22.  
  23.         struct BLAS {
  24.             glm::mat4 ModelMatrix;
  25.  
  26.             GeometryCollection collection[1 << expOfTwoOfMaxCollectionElementsInBLAS];
  27.  
  28.             NodeData tree[((1 << expOfTwoOfMaxCollectionElementsInBLAS) * 2) - 1];
  29.         };
  30.  
  31.         struct TLAS {
  32.             glm::mat4 ViewMatrix;
  33.             NodeData tree[((1 << expOfTwoOfMaxBLASElementsInTLAS) * 2) - 1];
  34.             BLAS blas[1 << expOfTwoOfMaxBLASElementsInTLAS];
  35.         };
  36.  
  37.  
  38. /******************************************************************************************/
  39.  
  40. #version 450
  41.  
  42. #define COMP_SIZE 32
  43.  
  44. #define expOfTwoOfMaxGeometryElementsInCollection 3
  45. #define expOfTwoOfMaxCollectionElementsInBLAS 5
  46. #define expOfTwoOfMaxBLASElementsInTLAS 5
  47.  
  48. const float PI = 3.14159265359;
  49. const float infinity = 1. / 0.;
  50. const mat4 identityTransform = mat4(1);
  51.  
  52. // This gets adjusted on each call by the OpenGL core
  53. layout(local_size_x = COMP_SIZE, local_size_y = COMP_SIZE, local_size_z = 1) in;
  54.  
  55. layout(rgba32f, binding = 0) uniform image2D img_output;
  56.  
  57. uniform uint width; // Render target surface width
  58. uniform uint height; // Render target surface height
  59.  
  60. struct Geometry {
  61.     vec4 signature;
  62.     vec4 vertex1_or_sphere_center;
  63.     vec4 vertex2_or_sphere_radius;
  64.     vec4 vertex3_or_nothing;
  65. };
  66.  
  67. struct GeometryCollection {
  68.     Geometry geometry[1 << expOfTwoOfMaxGeometryElementsInCollection]; // geometry slots
  69. };
  70.  
  71. struct AABB {
  72.     vec4 position; // this is the point of the aabb with min x, y and z components
  73.     vec4 dimensions; // this is the amount to be added to aabbVertex to obtain the point with max x, y and z in the aabb
  74. };
  75.  
  76. struct NodeData {
  77.     AABB aabb;
  78.     uint left; // this can also be the content if right is zero
  79.     uint right; // this is zero if the node is a leaf
  80. };
  81.  
  82. struct BLAS {
  83.     mat4 ModelMatrix;
  84.  
  85.     GeometryCollection collection[1 << expOfTwoOfMaxCollectionElementsInBLAS];
  86.    
  87.     NodeData tree[((1 << expOfTwoOfMaxCollectionElementsInBLAS) * 2) - 1];
  88. };
  89.  
  90. struct TLAS {
  91.     mat4 ViewMatrix;
  92.     NodeData tree[((1 << expOfTwoOfMaxBLASElementsInTLAS) * 2) - 1];
  93.     BLAS blas[1 << expOfTwoOfMaxBLASElementsInTLAS];
  94. };
  95.  
  96. // Output buffer object to be written
  97. layout(std430, binding = 3) buffer scene {
  98.     TLAS tlas[];
  99. };
  100.  
  101. uniform uint shadingAlgorithm;
  102.  
  103. uniform vec3 mOrigin;
  104. uniform vec3 mLowerLeftCorner;
  105. uniform vec3 mHorizontal;
  106. uniform vec3 mVertical;
  107.  
  108. /*************************************************************************************************************************
  109.  *                                                  Algorithms                                                           *
  110.  *************************************************************************************************************************/
  111.  
  112. struct RayGeometryIntersection {
  113.     float dist;
  114.     vec4 point;
  115.     vec4 normal;
  116. };
  117.  
  118. struct Ray {
  119.     vec4 origin;
  120.     vec4 direction;
  121. };
  122.  
  123. // Empty geometry is a sphere with radius equals to 0.0 such geometry CANNOT be intersected
  124. const Geometry emptyGeometry = Geometry(
  125.     vec4(0, 0, 0, 0),
  126.     vec4(0, 0, 0, 0),
  127.     vec4(0, 0, 0, 0),
  128.     vec4(0, 0, 0, 0)
  129. );
  130.  
  131. const RayGeometryIntersection miss = RayGeometryIntersection(infinity, vec4(0, 0, 0, 1), vec4(0, 0, 0, 0));
  132.  
  133. bool isLeaf(NodeData node) {
  134.     return node.right == 0;
  135. }
  136.  
  137. bool hasMissed(RayGeometryIntersection test) {
  138.     return isinf(test.dist) || isnan(test.dist);
  139. }
  140.  
  141. vec3 rayPointAt(Ray ray, float coeff) {
  142.     return vec3(ray.origin) + coeff * vec3(ray.direction);
  143. }
  144.  
  145. vec3 applyShading(RayGeometryIntersection isect, uint algorithm) {
  146.     if (algorithm == 0) { // hit or miss
  147.         return hasMissed(isect) ? vec3(0,0,0) : vec3(1,1,1);
  148.     } else if (algorithm == 1) {
  149.         // Here the camera position is vec3(0, 0, 0) because all of this is in camera space
  150.         return vec3(max(0, dot(isect.normal, normalize(/*mPosition*/ -isect.point))));
  151.     }
  152.  
  153.     return vec3(0.5, 0.5, 0.5); // this is to get attention as this should never verify
  154. }
  155.  
  156. vec4 getInvDirection(Ray ray) {
  157.     return vec4(1.0/ray.direction.x, 1.0/ray.direction.y, 1.0/ray.direction.z, 0);
  158. }
  159.  
  160. AABB transformAABB(AABB starting, mat4 transformMatrix) {
  161.     vec4 v[8] = {
  162.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  163.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  164.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  165.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  166.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  167.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  168.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  169.         vec4(starting.position.x, starting.position.y, starting.position.z, 1),
  170.     };
  171.  
  172.     float maxX = 1.0/0.0, maxY = 1.0/0.0, maxZ=1.0/0.0, minX=-1.0/0.0, minY=-1.0/0.0, minZ=-1.0/0.0;
  173.  
  174.     for (uint i = 0; i < 8; ++i) {
  175.         maxX = (v[i].x > maxX) ? v[i].x : maxX;
  176.         maxY = (v[i].y > maxY) ? v[i].y : maxY;
  177.         maxZ = (v[i].z > maxZ) ? v[i].z : maxZ;
  178.         minX = (v[i].x < minX) ? v[i].x : minX;
  179.         minY = (v[i].y < minY) ? v[i].y : minY;
  180.         minZ = (v[i].z < minZ) ? v[i].z : minZ;
  181.     }
  182.  
  183.     return AABB(vec4(minX, minY, minZ, 1), vec4(maxX-minX, maxY-minY, maxZ-minZ, 0));
  184. }
  185.  
  186. struct raySigns {
  187.     bool[3] signs;
  188. };
  189.  
  190. bool intersectAABB(Ray ray, AABB aabb, mat4 transformMatrix) {
  191.     AABB transformedAABB = /*(transformMatrix != identityTransform) ? */transformAABB(aabb, transformMatrix) /*: *this*/;
  192.  
  193.     float tmin, tmax, tymin, tymax, tzmin, tzmax;
  194.  
  195.     vec3 orig = ray.origin.xyz;
  196.     vec3 invdir = getInvDirection(ray).xyz;
  197.  
  198.     vec3 bounds[2] = {
  199.         transformedAABB.position.xyz,
  200.         (transformedAABB.position.xyz) + (transformedAABB.dimensions.xyz)
  201.     };
  202.  
  203.     const int[3] raySigns = int[3](
  204.         (invdir.x < 0) ? 1 : 0,
  205.         (invdir.y < 0) ? 1 : 0,
  206.         (invdir.z < 0) ? 1 : 0
  207.     );
  208.  
  209.     tmin = (bounds[raySigns[0]].x - orig.x) * invdir.x;
  210.     tmax = (bounds[1 - raySigns[0]].x - orig.x) * invdir.x;
  211.     tymin = (bounds[raySigns[1]].y - orig.y) * invdir.y;
  212.     tymax = (bounds[1 - raySigns[1]].y - orig.y) * invdir.y;
  213.  
  214.     if ((tmin > tymax) || (tymin > tmax))
  215.         return false;
  216.     if (tymin > tmin)
  217.         tmin = tymin;
  218.     if (tymax < tmax)
  219.         tmax = tymax;
  220.  
  221.     tzmin = (bounds[raySigns[2]].z - orig.z) * invdir.z;
  222.     tzmax = (bounds[1 - raySigns[2]].z - orig.z) * invdir.z;
  223.  
  224.     if ((tmin > tzmax) || (tzmin > tmax))
  225.         return false;
  226.     if (tzmin > tmin)
  227.         tmin = tzmin;
  228.     if (tzmax < tmax)
  229.         tmax = tzmax;
  230.  
  231.     return true;
  232. }
  233.  
  234. RayGeometryIntersection intersect(Ray ray, Geometry geometry, mat4 transformMatrix, float minDistance, float maxDistance) {
  235.     if (geometry.signature.w == 0.0) { // test ray-sphere intersection
  236.         const vec3 center = vec3(transformMatrix * geometry.vertex1_or_sphere_center);
  237.         const float radius = geometry.vertex2_or_sphere_radius.x;
  238.  
  239.         if (radius == 0) return miss;
  240.  
  241.         const vec3 origin = vec3(ray.origin);
  242.         const vec3 direction = vec3(ray.direction);
  243.  
  244.         vec3 oc = origin - center;
  245.    
  246.         const float a = dot(direction, direction);
  247.         const float b = dot(oc, direction);
  248.         const float c = dot(oc, oc) - radius * radius;
  249.         const float discriminant = b * b - a * c;
  250.  
  251.         if (discriminant > 0.0) { // if delta > 0 then we have two intersections (one for each side of the sphere)
  252.             const float squareRoot = sqrt(discriminant);
  253.  
  254.             // x0 and x1 are the distances to the origin of the ray
  255.             float x0 = (-b - squareRoot) / a, x1 = (-b + squareRoot) / a;
  256.  
  257.             // Use x0 and x1 to calculate intersection points
  258.             vec3 point_x0 = rayPointAt(ray, x0), point_x1 = rayPointAt(ray, x1); // so if I use that distance as a coefficient I obtain the intersection point
  259.        
  260.             // Use intersecting points to calculate the surface normal at that point
  261.             vec3 normal_x0 = (point_x0 - center) / radius, normal_x1 = (point_x1 - center) / radius; // and the normal for a point p is (point - center)/radius
  262.  
  263.             // No valid intersection? return a miss.
  264.             if (((x0 <= minDistance) || (x0 >= maxDistance)) && ((x1 <= minDistance) || (x1 >= maxDistance))) {
  265.                 return miss;
  266.             }
  267.  
  268.             // Choose the closest intersection point
  269.             return (((x0 > minDistance) && (x0 < maxDistance)) && (x0 <= x1)) || ((x1 <= minDistance) || (x1 >= maxDistance)) ?
  270.                 RayGeometryIntersection(x0, vec4(point_x0, 1), vec4(normal_x0, 0)) : RayGeometryIntersection(x1, vec4(point_x1, 1), vec4(normal_x1, 0));
  271.         }
  272.     } else if (geometry.signature.w == 1.0) { // test ray-triangle intersection
  273.  
  274.     }
  275.  
  276.     return miss;
  277. }
  278.  
  279. RayGeometryIntersection intersect(Ray ray, GeometryCollection collection, mat4 transformMatrix, float minDistance, float maxDistance) {
  280.     RayGeometryIntersection bestHit = miss;
  281.  
  282.     for (uint i = 0; i < collection.geometry.length(); ++i) {
  283.         // Execute the ray-geometry intersection algorithm
  284.         const RayGeometryIntersection currentIntersectionInfo = intersect(ray, collection.geometry[i], transformMatrix, minDistance, maxDistance);
  285.  
  286.         // Check if this is a better hit than the former one
  287.         if (currentIntersectionInfo.dist < bestHit.dist) {
  288.             bestHit = currentIntersectionInfo;
  289.         }
  290.     }
  291.  
  292.     return bestHit;
  293. }
  294.  
  295. RayGeometryIntersection intersect(Ray ray, BLAS blas, mat4 transformMatrix, float minDistance, float maxDistance) {
  296.     // Adjust transformation matrix to consider the BLAS model matrix
  297.     transformMatrix = transformMatrix * blas.ModelMatrix;
  298.  
  299.     RayGeometryIntersection bestHit = miss;
  300.  
  301.     int currentDepth = 0;
  302.     uint currentPath = 0;
  303.  
  304.     while ((currentDepth < 32) && (currentDepth >= 0)) {
  305.         uint currentNodeIndex = 0;
  306.  
  307.         // This for cycles is used to reach the interesting node
  308.         for (uint i = 0; i < currentDepth; ++i) {
  309.             currentNodeIndex = ((currentPath & (1 << currentDepth)) == 0) ? blas.tree[currentNodeIndex].left : blas.tree[currentNodeIndex].left;
  310.         }
  311.  
  312.         if ((!isLeaf(blas.tree[currentNodeIndex])) && (intersectAABB(ray, blas.tree[currentNodeIndex].aabb, transformMatrix))) {
  313.             // Go one level deeper
  314.             currentDepth += 1;
  315.         } else {
  316.             // This is a leaf that should be tested...
  317.             if ((isLeaf(blas.tree[currentNodeIndex])) && (intersectAABB(ray, blas.tree[currentNodeIndex].aabb, transformMatrix))) {
  318.                 RayGeometryIntersection currentHit = intersect(ray, blas.collection[blas.tree[currentNodeIndex].left], transformMatrix, minDistance, maxDistance);
  319.  
  320.                 if (currentHit.dist < bestHit.dist) bestHit = currentHit;
  321.             }
  322.  
  323.             // in either case: subtree discarded or visited leaf the algorithm should reduce the depth and change the path
  324.             currentDepth -= 1;
  325.  
  326.             while (((currentPath & (1 << currentDepth)) == 1) && (currentDepth >= 0)) {
  327.                 //set the bit at currentDepth position to 0
  328.                 currentPath &= ~(1 << currentDepth);
  329.  
  330.                 // and decrease currentDepth
  331.                 currentDepth -= 1;
  332.             }
  333.  
  334.             if (currentDepth >= 0) {
  335.                 // set the bit at currentDepth position to 1 (the next visit will choose another path)
  336.                 currentPath |= (1 << currentDepth);
  337.             } else {
  338.                 // the visited node was the very last one (the right-most) and the iteration should come to an end
  339.                 break;
  340.             }
  341.         }
  342.     }
  343.  
  344.     return bestHit;
  345. }
  346.  
  347. RayGeometryIntersection intersect(Ray ray, TLAS tlas, mat4 transformMatrix, float minDistance, float maxDistance) {
  348.     // Adjust transformation matrix to consider the BLAS model matrix
  349.     transformMatrix = transformMatrix * tlas.ViewMatrix;
  350.  
  351.     RayGeometryIntersection bestHit = miss;
  352.  
  353.     int currentDepth = 0;
  354.     uint currentPath = 0;
  355.  
  356.     while ((currentDepth < 32) && (currentDepth >= 0)) {
  357.         uint currentNodeIndex = 0;
  358.  
  359.         // This for cycles is used to reach the interesting node
  360.         for (uint i = 0; i < currentDepth; ++i) {
  361.             currentNodeIndex = ((currentPath & (1 << currentDepth)) == 0) ? tlas.tree[currentNodeIndex].left : tlas.tree[currentNodeIndex].left;
  362.         }
  363.  
  364.         if ((!isLeaf(tlas.tree[currentNodeIndex])) && (intersectAABB(ray, tlas.tree[currentNodeIndex].aabb, transformMatrix))) {
  365.             // Go one level deeper
  366.             currentDepth += 1;
  367.         } else {
  368.             // This is a leaf that should be tested...
  369.             if ((isLeaf(tlas.tree[currentNodeIndex])) && (intersectAABB(ray, tlas.tree[currentNodeIndex].aabb, transformMatrix))) {
  370.                 RayGeometryIntersection currentHit = intersect(ray, tlas.blas[tlas.tree[currentNodeIndex].left], transformMatrix, minDistance, maxDistance);
  371.  
  372.                 if (currentHit.dist < bestHit.dist) bestHit = currentHit;
  373.             }
  374.  
  375.             // in either case: subtree discarded or visited leaf the algorithm should reduce the depth and change the path
  376.             currentDepth -= 1;
  377.  
  378.             while (((currentPath & (1 << currentDepth)) == 1) && (currentDepth >= 0)) {
  379.                 //set the bit at currentDepth position to 0
  380.                 currentPath &= ~(1 << currentDepth);
  381.  
  382.                 // and decrease currentDepth
  383.                 currentDepth -= 1;
  384.             }
  385.  
  386.             if (currentDepth >= 0) {
  387.                 // set the bit at currentDepth position to 1 (the next visit will choose another path)
  388.                 currentPath |= (1 << currentDepth);
  389.             } else {
  390.                 // the visited node was the very last one (the right-most) and the iteration should come to an end
  391.                 break;
  392.             }
  393.         }
  394.     }
  395.  
  396.     return bestHit;
  397. }
  398.  
  399. Ray generateCameraRay(float s, float t) {
  400.     return Ray(vec4(mOrigin, 1), vec4(mLowerLeftCorner + s * mHorizontal + t * mVertical - mOrigin, 0));
  401. }
  402.  
  403. void main() {
  404.     // base pixel colour for image
  405.     vec4 pixel = vec4(0, 0, 0, 0);
  406.     // get index in global work group i.e x,y position
  407.     ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
  408.  
  409.     // Avoid calculating useless pixels
  410.     if ((gl_GlobalInvocationID.x >= width) || (gl_GlobalInvocationID.y >= height)) {
  411.         return;
  412.     }
  413.    
  414.     const float u = float(gl_GlobalInvocationID.x) / float(width);
  415.     const float v = float(gl_GlobalInvocationID.y) / float(height);
  416.  
  417.     // Generate camera ray
  418.     Ray cameraRay = generateCameraRay(u, v);
  419.  
  420.     pixel = vec4(applyShading(intersect(cameraRay, tlas[0], identityTransform, 0.001, 1000.0), shadingAlgorithm), 1.0);
  421.  
  422.     // output to a specific pixel in the image
  423.     imageStore(img_output, pixel_coords, pixel);
  424. }
Advertisement
Add Comment
Please, Sign In to add comment