mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-21 19:50:54 +00:00
Implement TraceAnyHit for the non-rayquery variant
This commit is contained in:
parent
83153c9e45
commit
d347464597
4 changed files with 200 additions and 21 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
// Moeller–Trumbore 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue