Implement TraceAnyHit for the non-rayquery variant

This commit is contained in:
Magnus Norddahl 2022-08-31 23:07:31 +02:00
parent 83153c9e45
commit d347464597
4 changed files with 200 additions and 21 deletions

View file

@ -114,6 +114,7 @@ public:
};
const std::vector<Node>& get_nodes() const { return nodes; }
int get_root() const { return root; }
private:
const vec3 *vertices = nullptr;

View file

@ -14,9 +14,16 @@ struct CollisionNode
int element_index;
int padding3;
};
layout(set = 1, binding = 0) buffer NodeBuffer { CollisionNode nodes[]; };
layout(set = 1, binding = 1) buffer VertexBuffer { vec3 vertices[]; };
layout(set = 1, binding = 2) buffer ElementBuffer { vec3 elements[]; };
layout(std430, set = 1, binding = 0) buffer NodeBuffer
{
int nodesRoot;
int nodebufferPadding1;
int nodebufferPadding2;
int nodebufferPadding3;
CollisionNode nodes[];
};
layout(std430, set = 1, binding = 1) buffer VertexBuffer { vec4 vertices[]; };
layout(std430, set = 1, binding = 2) buffer ElementBuffer { int elements[]; };
#endif
layout(set = 0, binding = 0) uniform Uniforms
@ -123,7 +130,7 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light)
float attenuation = distAttenuation * angleAttenuation * spotAttenuation;
if (attenuation > 0.0)
{
if (TraceAnyHit(origin, minDistance, dir, dist))
if (!TraceAnyHit(origin, minDistance, dir, dist))
{
incoming.rgb += light.Color * (attenuation * light.Intensity);
}
@ -205,7 +212,7 @@ bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
while(rayQueryProceedEXT(rayQuery)) { }
return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT;
return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
}
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
@ -257,9 +264,148 @@ int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out fl
#else
struct RayBBox
{
vec3 start, end;
vec3 c, w, v;
};
RayBBox create_ray(vec3 ray_start, vec3 ray_end)
{
RayBBox ray;
ray.start = ray_start;
ray.end = ray_end;
ray.c = (ray_start + ray_end) * 0.5;
ray.w = ray_end - ray.c;
ray.v = abs(ray.w);
return ray;
}
bool overlap_bv_ray(RayBBox ray, int a)
{
vec3 v = ray.v;
vec3 w = ray.w;
vec3 h = nodes[a].extents;
vec3 c = ray.c - nodes[a].center;
if (abs(c.x) > v.x + h.x ||
abs(c.y) > v.y + h.y ||
abs(c.z) > v.z + h.z)
{
return false;
}
if (abs(c.y * w.z - c.z * w.y) > h.y * v.z + h.z * v.y ||
abs(c.x * w.z - c.z * w.x) > h.x * v.z + h.z * v.x ||
abs(c.x * w.y - c.y * w.x) > h.x * v.y + h.y * v.x)
{
return false;
}
return true;
}
#define FLT_EPSILON 1.192092896e-07F // smallest such that 1.0+FLT_EPSILON != 1.0
float intersect_triangle_ray(RayBBox ray, int a, out float barycentricB, out float barycentricC)
{
int start_element = nodes[a].element_index;
vec3 p[3];
p[0] = vertices[elements[start_element]].xyz;
p[1] = vertices[elements[start_element + 1]].xyz;
p[2] = vertices[elements[start_element + 2]].xyz;
// MoellerTrumbore ray-triangle intersection algorithm:
vec3 D = ray.end - ray.start;
// Find vectors for two edges sharing p[0]
vec3 e1 = p[1] - p[0];
vec3 e2 = p[2] - p[0];
// Begin calculating determinant - also used to calculate u parameter
vec3 P = cross(D, e2);
float det = dot(e1, P);
// Backface check
//if (det < 0.0f)
// return 1.0f;
// If determinant is near zero, ray lies in plane of triangle
if (det > -FLT_EPSILON && det < FLT_EPSILON)
return 1.0f;
float inv_det = 1.0f / det;
// Calculate distance from p[0] to ray origin
vec3 T = ray.start - p[0];
// Calculate u parameter and test bound
float u = dot(T, P) * inv_det;
// Check if the intersection lies outside of the triangle
if (u < 0.f || u > 1.f)
return 1.0f;
// Prepare to test v parameter
vec3 Q = cross(T, e1);
// Calculate V parameter and test bound
float v = dot(D, Q) * inv_det;
// The intersection lies outside of the triangle
if (v < 0.f || u + v > 1.f)
return 1.0f;
float t = dot(e2, Q) * inv_det;
if (t <= FLT_EPSILON)
return 1.0f;
// Return hit location on triangle in barycentric coordinates
barycentricB = u;
barycentricC = v;
return t;
}
bool is_leaf(int node_index)
{
return nodes[node_index].element_index != -1;
}
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
{
// To do: port TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end) to glsl
if (tmax <= 0.0f)
return false;
RayBBox ray = create_ray(origin, origin + dir * tmax);
tmin /= tmax;
int stack[64];
int stackIndex = 0;
stack[stackIndex++] = nodesRoot;
do
{
int a = stack[--stackIndex];
if (overlap_bv_ray(ray, a))
{
if (is_leaf(a))
{
float baryB, baryC;
float t = intersect_triangle_ray(ray, a, baryB, baryC);
if (t >= tmin && t < 1.0)
{
return true;
}
}
else
{
stack[stackIndex++] = nodes[a].right;
stack[stackIndex++] = nodes[a].left;
}
}
} while (stackIndex > 0);
return false;
}

View file

@ -416,6 +416,15 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
std::vector<SurfaceInfo> surfaces = CreateSurfaceInfo();
std::vector<CollisionNode> nodes = CreateCollisionNodes();
// std430 alignment rules forces us to convert the vec3 to a vec4
std::vector<vec4> vertices;
vertices.reserve(mesh->MeshVertices.Size());
for (const vec3& v : mesh->MeshVertices)
vertices.push_back({ v, 1.0f });
CollisionNodeBufferHeader nodesHeader;
nodesHeader.root = mesh->Collision->get_root();
vertexBuffer = BufferBuilder()
.Usage(
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
@ -424,7 +433,7 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Size((size_t)mesh->MeshVertices.Size() * sizeof(vec3))
.Size(vertices.size() * sizeof(vec4))
.DebugName("vertexBuffer")
.Create(device.get());
@ -454,16 +463,16 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
nodesBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.Size(nodes.size() * sizeof(CollisionNode))
.Size(sizeof(CollisionNodeBufferHeader) + nodes.size() * sizeof(CollisionNode))
.DebugName("nodesBuffer")
.Create(device.get());
transferBuffer = BufferTransfer()
.AddBuffer(vertexBuffer.get(), mesh->MeshVertices.Data(), (size_t)mesh->MeshVertices.Size() * sizeof(vec3))
.AddBuffer(vertexBuffer.get(), vertices.data(), vertices.size() * sizeof(vec4))
.AddBuffer(indexBuffer.get(), mesh->MeshElements.Data(), (size_t)mesh->MeshElements.Size() * sizeof(uint32_t))
.AddBuffer(surfaceIndexBuffer.get(), mesh->MeshSurfaces.Data(), (size_t)mesh->MeshSurfaces.Size() * sizeof(uint32_t))
.AddBuffer(surfaceBuffer.get(), surfaces.data(), surfaces.size() * sizeof(SurfaceInfo))
.AddBuffer(nodesBuffer.get(), nodes.data(), nodes.size() * sizeof(CollisionNode))
.AddBuffer(nodesBuffer.get(), &nodesHeader, sizeof(CollisionNodeBufferHeader), nodes.data(), nodes.size() * sizeof(CollisionNode))
.Execute(device.get(), cmdbuffer.get());
PipelineBarrier()
@ -482,9 +491,9 @@ void GPURaytracer::CreateBottomLevelAccelerationStructure()
accelStructBLDesc.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
accelStructBLDesc.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
accelStructBLDesc.geometry.triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR };
accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
accelStructBLDesc.geometry.triangles.vertexData.deviceAddress = vertexBuffer->GetDeviceAddress();
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(vec3);
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(vec4);
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress();
accelStructBLDesc.geometry.triangles.maxVertex = mesh->MeshVertices.Size() - 1;
@ -946,7 +955,13 @@ void GPURaytracer::PrintVulkanInfo()
BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data, size_t size)
{
bufferCopies.push_back({ data, size, buffer });
bufferCopies.push_back({ buffer, data, size, nullptr, 0 });
return *this;
}
BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1)
{
bufferCopies.push_back({ buffer, data0, size0, data1, size1 });
return *this;
}
@ -954,7 +969,7 @@ std::unique_ptr<VulkanBuffer> BufferTransfer::Execute(VulkanDevice* device, Vulk
{
size_t transferbuffersize = 0;
for (const auto& copy : bufferCopies)
transferbuffersize += copy.size;
transferbuffersize += copy.size0 + copy.size1;
if (transferbuffersize == 0)
return nullptr;
@ -969,17 +984,23 @@ std::unique_ptr<VulkanBuffer> BufferTransfer::Execute(VulkanDevice* device, Vulk
size_t pos = 0;
for (const auto& copy : bufferCopies)
{
memcpy(data + pos, copy.data, copy.size);
pos += copy.size;
memcpy(data + pos, copy.data0, copy.size0);
pos += copy.size0;
memcpy(data + pos, copy.data1, copy.size1);
pos += copy.size1;
}
transferBuffer->Unmap();
pos = 0;
for (const auto& copy : bufferCopies)
{
if (copy.size > 0)
cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, 0, copy.size);
pos += copy.size;
if (copy.size0 > 0)
cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, 0, copy.size0);
pos += copy.size0;
if (copy.size1 > 0)
cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, copy.size0, copy.size1);
pos += copy.size1;
}
return transferBuffer;

View file

@ -50,6 +50,14 @@ struct LightInfo
float Padding2;
};
struct CollisionNodeBufferHeader
{
int root;
int padding1;
int padding2;
int padding3;
};
struct CollisionNode
{
vec3 center;
@ -205,14 +213,17 @@ class BufferTransfer
{
public:
BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data, size_t size);
BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1);
std::unique_ptr<VulkanBuffer> Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer);
private:
struct BufferCopy
{
const void* data;
size_t size;
VulkanBuffer* buffer;
const void* data0;
size_t size0;
const void* data1;
size_t size1;
};
std::vector<BufferCopy> bufferCopies;
};