Skip to content

Commit

Permalink
Vulkan ray tracing (#33)
Browse files Browse the repository at this point in the history
* Started work on Vulkan ray tracing integration

* Integrated new classes into GraphicsDevice

* More changes

* Expanded both TLAS and BLAS graphics implementations

* More work has been done, still a bit buggy

* Fixed all obvious issues

* Submit command list instead of flush for TLAS

* Only activate newer SpirV when necessary

* Made several improvements

* Further improvements

* Made opacity check in all RT effects optional

* Working on AS compaction

* More BLAS compaction work

* Working BLAS compaction

* Fix minor code issues

* Fixed some more issues
  • Loading branch information
tippesi authored Jul 29, 2023
1 parent 234adb2 commit efefdb8
Show file tree
Hide file tree
Showing 48 changed files with 1,763 additions and 289 deletions.
8 changes: 5 additions & 3 deletions data/shader/ao/rtao.csh
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,13 @@ void main() {
ray.hitID = -1;
ray.hitDistance = 0.0;

//float hit = 1.0 - HitAnyShadow(ray, 0.0, uniforms.radius);
//ao += hit;

#ifdef OPACITY_CHECK
float hit = 1.0 - HitAnyTransparency(ray, 0.0, uniforms.radius);
ao += hit;
#else
bool hit = HitAny(ray, 0.0, uniforms.radius);
ao += hit ? 1.0 : 0.0;
#endif

}

Expand Down
2 changes: 1 addition & 1 deletion data/shader/pathtracer/rayHit.csh
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ float CheckVisibility(Surface surface, float lightDistance) {
ray.direction = surface.L;
ray.origin = surface.P + surface.N * EPSILON;
ray.inverseDirection = 1.0 / ray.direction;
return HitAnyShadow(ray, 0.0, lightDistance - 2.0 * EPSILON);
return HitAnyTransparency(ray, 0.0, lightDistance - 2.0 * EPSILON);
}
else {
return 0.0;
Expand Down
4 changes: 2 additions & 2 deletions data/shader/raytracer/buffers.hsh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ layout(std430, set = 2, binding = 18) buffer RayBinOffsets {
uint rayBinOffsets[];
};

layout(std430, set = 2, binding = 21) buffer BvhInstances {
BVHInstance bvhInstances[];
layout(std430, set = 2, binding = 21) buffer Instances {
Instance bvhInstances[];
};
275 changes: 270 additions & 5 deletions data/shader/raytracer/bvh.hsh
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
#extension GL_ARB_shader_ballot : require
#ifdef AE_HARDWARE_RAYTRACING
#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_ray_query : enable

layout(set = 2, binding = 23) uniform accelerationStructureEXT topLevelAS;

layout(std430, set = 2, binding = 22) buffer GeometryTriangleOffsets {
uint geometryTriangleOffsets[];
};
#endif

#include <common.hsh>
#include <intersections.hsh>
Expand All @@ -7,7 +16,7 @@
#include <buffers.hsh>

#define STACK_SIZE 32
#define TLAS_INVALID 1000000
#define TLAS_INVALID (STACK_SIZE + 2)

struct PackedBVHNode {
vec4 data0;
Expand Down Expand Up @@ -37,6 +46,8 @@ layout (std430, set = 2, binding = 9) buffer BVHTriangles {
PackedBVHTriangle bvhTriangles[];
};

#ifndef AE_HARDWARE_RAYTRACING

layout(std430, set = 2, binding = 10) buffer BlasNodes {
PackedBVHNode blasNodes[];
};
Expand Down Expand Up @@ -127,6 +138,38 @@ bool CheckLeaf(inout Ray ray, int nodePtr, float tmin, float tmax) {

}

void CheckLeafClosestTransparency(inout Ray ray, int nodePtr, float tmin, float tmax) {

int triPtr = ~nodePtr;
bool endOfNode = false;

vec3 sol, v0, v1, v2, n;

while (!endOfNode) {
Triangle tri = UnpackTriangle(triangles[triPtr]);
v0 = tri.v0.xyz;
v1 = tri.v1.xyz;
v2 = tri.v2.xyz;
endOfNode = tri.endOfNode;
float d = 0.0;
#ifdef BACKFACE_CULLING
n = cross(v0 - v1, v0 - v2);
d = dot(n, ray.direction);
#endif
bool intersect = IntersectTriangle(ray, v0, v1, v2, sol);
if (intersect && sol.x > tmin && sol.x < tmax && d <= 0.0 && sol.x < ray.hitDistance) {
float opacity = GetOpacity(tri, sol.yz, 0);
if (opacity > 0.0) {
ray.hitDistance = sol.x;
ray.hitID = triPtr;
ray.hitInstanceID = ray.currentInstanceID;
}
}
triPtr++;
}

}

float CheckLeafTransparency(inout Ray ray, int nodePtr, float tmin, float tmax, float transparency) {

int triPtr = ~nodePtr;
Expand Down Expand Up @@ -163,7 +206,7 @@ void CheckInstance(inout Ray ray, inout int nodePtr) {

int instancePtr = ~nodePtr;

BVHInstance instance = bvhInstances[instancePtr];
Instance instance = bvhInstances[instancePtr];

// We don't normalize the direction in case there is a scale in the
// matrix. In that case the normalization leads to wrong scales in closest hit distance
Expand Down Expand Up @@ -257,6 +300,87 @@ void HitClosest(inout Ray ray, float tMin, float tMax) {

}

void HitClosestTransparency(inout Ray ray, float tMin, float tMax) {

uint stackPtr = 1u;
int nodePtr = 0;
uint threadID = gl_LocalInvocationIndex;
stack[0][threadID] = nodePtr;

vec3 originalRayOrigin = ray.origin;
vec3 originalRayDirection = ray.direction;

ray.hitDistance = tMax;

if (isnan3(ray.direction))
return;

uint tlasIndex = TLAS_INVALID;

while (stackPtr != 0u) {
if (tlasIndex == TLAS_INVALID || stackPtr < tlasIndex) {
if (tlasIndex != TLAS_INVALID) {
ray.origin = originalRayOrigin;
ray.direction = originalRayDirection;
ray.inverseDirection = 1.0 / ray.direction;
}
tlasIndex = TLAS_INVALID;
if (nodePtr < 0) {
tlasIndex = stackPtr;

CheckInstance(ray, nodePtr);
}
else {
BVHNode node = UnpackNode(tlasNodes[nodePtr]);

float hitL = 0.0, hitR = 0.0;
bool intersectL = IntersectAABB(ray,
node.leftAABB, tMin, ray.hitDistance, hitL);
bool intersectR = IntersectAABB(ray,
node.rightAABB, tMin, ray.hitDistance, hitR);

bool noIntersection = !intersectL && !intersectR;
nodePtr = hitL <= hitR ? node.leftPtr : node.rightPtr;
nodePtr = noIntersection ? stack[--stackPtr][threadID] : nodePtr;
int stackIdx = hitL <= hitR ? node.rightPtr : node.leftPtr;

if (intersectR && intersectL) {
stack[stackPtr++][threadID] = stackIdx;
}
}
}
else {
if(nodePtr < 0) {
CheckLeafClosestTransparency(ray, nodePtr, tMin, ray.hitDistance);
nodePtr = stack[--stackPtr][threadID];
}
else {
BVHNode node = UnpackNode(blasNodes[nodePtr]);

float hitL = 0.0, hitR = 0.0;
bool intersectL = IntersectAABB(ray,
node.leftAABB, tMin, ray.hitDistance, hitL);
bool intersectR = IntersectAABB(ray,
node.rightAABB, tMin, ray.hitDistance, hitR);

bool noIntersection = !intersectL && !intersectR;
nodePtr = hitL <= hitR ? node.leftPtr : node.rightPtr;
nodePtr = noIntersection ? stack[--stackPtr][threadID] : nodePtr;
int stackIdx = hitL <= hitR ? node.rightPtr : node.leftPtr;

if (intersectR && intersectL) {
stack[stackPtr++][threadID] = stackIdx;
}
}
}
}

ray.origin = originalRayOrigin;
ray.direction = originalRayDirection;
ray.inverseDirection = 1.0 / ray.direction;

}

bool HitAny(inout Ray ray, float tMin, float tMax) {

if (isnan3(ray.direction))
Expand Down Expand Up @@ -339,7 +463,7 @@ bool HitAny(inout Ray ray, float tMin, float tMax) {

}

float HitAnyShadow(inout Ray ray, float tMin, float tMax) {
float HitAnyTransparency(inout Ray ray, float tMin, float tMax) {

if (isnan3(ray.direction))
return 1.0;
Expand Down Expand Up @@ -420,4 +544,145 @@ float HitAnyShadow(inout Ray ray, float tMin, float tMax) {

return transparency;

}
}

#else

void HitClosest(inout Ray ray, float tMin, float tMax) {

ray.hitDistance = tMax;

rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, topLevelAS, gl_RayFlagsNoneEXT, 0xFF,
ray.origin, tMin, ray.direction, tMax);

// Start traversal: return false if traversal is complete
while(rayQueryProceedEXT(rayQuery)) {
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCandidateIntersectionTriangleEXT) {
rayQueryConfirmIntersectionEXT(rayQuery);
}
}

// Returns type of committed (true) intersection
if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) {
ray.hitDistance = rayQueryGetIntersectionTEXT(rayQuery, true);
ray.hitInstanceID = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);

int geometryOffset = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, true);
int idx = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true) + geometryOffset;

int triangleOffset = int(geometryTriangleOffsets[idx]);
ray.hitID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true) + triangleOffset;
}
}

bool HitAny(inout Ray ray, float tMin, float tMax) {

ray.hitDistance = tMax;

rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF,
ray.origin, tMin, ray.direction, tMax);

// Start traversal: return false if traversal is complete
while(rayQueryProceedEXT(rayQuery)) {
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCandidateIntersectionTriangleEXT) {
rayQueryConfirmIntersectionEXT(rayQuery);
}
}

// Returns type of committed (true) intersection
if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT)
{
return true;
}

return false;

}

void HitClosestTransparency(inout Ray ray, float tMin, float tMax) {

ray.hitDistance = tMax;

rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, topLevelAS, gl_RayFlagsNoneEXT, 0xFF,
ray.origin, tMin, ray.direction, tMax);

// Start traversal: return false if traversal is complete
bool proceed = true;
while(rayQueryProceedEXT(rayQuery)) {

if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCandidateIntersectionTriangleEXT) {
int geometryOffset = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, false);
int idx = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, false) + geometryOffset;

int triangleOffset = int(geometryTriangleOffsets[idx]);
int hitID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, false) + triangleOffset;

vec2 barrycentric = rayQueryGetIntersectionBarycentricsEXT(rayQuery, false);

Triangle tri = UnpackTriangle(triangles[hitID]);

if (GetOpacity(tri, barrycentric, 0) > 0.0) {
rayQueryConfirmIntersectionEXT(rayQuery);
}

}

}

if (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) {
ray.hitDistance = rayQueryGetIntersectionTEXT(rayQuery, true);
ray.hitInstanceID = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);

int geometryOffset = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, true);
int idx = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true) + geometryOffset;

int triangleOffset = int(geometryTriangleOffsets[idx]);
ray.hitID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true) + triangleOffset;
}

}

float HitAnyTransparency(inout Ray ray, float tMin, float tMax) {

float transparency = 1.0;

ray.hitDistance = tMax;

rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF,
ray.origin, tMin, ray.direction, tMax);

while(rayQueryProceedEXT(rayQuery)) {

if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCandidateIntersectionTriangleEXT) {
int geometryOffset = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, false);
int idx = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, false) + geometryOffset;

int triangleOffset = int(geometryTriangleOffsets[idx]);
int hitID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, false) + triangleOffset;

vec2 barrycentric = rayQueryGetIntersectionBarycentricsEXT(rayQuery, false);

Triangle tri = UnpackTriangle(triangles[hitID]);
transparency *= (1.0 - GetOpacity(tri, barrycentric, 0));

if (transparency < 0.001) {
rayQueryTerminateEXT(rayQuery);
return 0.0;
}

}

}

if (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) {
return 0.0;
}

return transparency;

}
#endif
17 changes: 9 additions & 8 deletions data/shader/raytracer/common.hsh
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,19 @@ Light UnpackLight(PackedLight compressed) {

Light light;

light.P = compressed.data0.xyz;
light.N = vec3(compressed.N);
light.P = compressed.P.xyz;
light.N = compressed.N.xyz;

light.radiance = vec3(compressed.data0.w,
compressed.data1.w, compressed.N.w);
light.radiance = compressed.color.rgb;

uint data = floatBitsToUint(compressed.data1.x);
uint data = floatBitsToUint(compressed.data.x);
light.type = ((data & 0xF0000000u) >> 28u);
light.idx = (data & 0x0FFFFFFFu);

light.pdf = compressed.data1.y;
light.area = compressed.data1.z;
light.triangleIdx = int(data & 0x0FFFFFFFu);
light.instanceIdx = floatBitsToInt(compressed.data.w);

light.pdf = compressed.data.y;
light.area = compressed.data.z;
light.brightness = dot(light.radiance, vec3(0.33333));

return light;
Expand Down
Loading

0 comments on commit efefdb8

Please sign in to comment.