mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
Add support for gl_light_raytrace for cards that do not support rayquery
This commit is contained in:
parent
16ad25b382
commit
447932025f
5 changed files with 369 additions and 36 deletions
|
@ -104,7 +104,15 @@ void VkDescriptorSetManager::UpdateFixedSet()
|
|||
update.AddCombinedImageSampler(FixedSet.get(), 0, fb->GetTextureManager()->Shadowmap.View.get(), fb->GetSamplerManager()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
update.AddCombinedImageSampler(FixedSet.get(), 1, fb->GetTextureManager()->Lightmap.View.get(), fb->GetSamplerManager()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
if (fb->device->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME))
|
||||
{
|
||||
update.AddAccelerationStructure(FixedSet.get(), 2, fb->GetRaytrace()->GetAccelStruct());
|
||||
}
|
||||
else
|
||||
{
|
||||
update.AddBuffer(FixedSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetRaytrace()->GetNodeBuffer());
|
||||
update.AddBuffer(FixedSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetRaytrace()->GetVertexBuffer());
|
||||
update.AddBuffer(FixedSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetRaytrace()->GetIndexBuffer());
|
||||
}
|
||||
update.Execute(fb->device.get());
|
||||
}
|
||||
|
||||
|
@ -264,7 +272,15 @@ void VkDescriptorSetManager::CreateFixedSetLayout()
|
|||
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
if (fb->device->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME))
|
||||
{
|
||||
builder.AddBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
}
|
||||
builder.DebugName("VkDescriptorSetManager.FixedSetLayout");
|
||||
FixedSetLayout = builder.Create(fb->device.get());
|
||||
}
|
||||
|
@ -284,7 +300,13 @@ void VkDescriptorSetManager::CreateFixedSetPool()
|
|||
DescriptorPoolBuilder poolbuilder;
|
||||
poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 * maxSets);
|
||||
if (fb->device->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME))
|
||||
{
|
||||
poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 * maxSets);
|
||||
}
|
||||
else
|
||||
{
|
||||
poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3 * maxSets);
|
||||
}
|
||||
poolbuilder.MaxSets(maxSets);
|
||||
poolbuilder.DebugName("VkDescriptorSetManager.FixedDescriptorPool");
|
||||
FixedDescriptorPool = poolbuilder.Create(fb->device.get());
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb)
|
||||
{
|
||||
useRayQuery = fb->device->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME);
|
||||
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f });
|
||||
|
@ -43,6 +45,8 @@ VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb)
|
|||
for (int i = 0; i < 3 * 4; i++)
|
||||
NullMesh.MeshElements.Push(i);
|
||||
|
||||
NullMesh.Collision = std::make_unique<TriangleMeshShape>(NullMesh.MeshVertices.Data(), NullMesh.MeshVertices.Size(), NullMesh.MeshElements.Data(), NullMesh.MeshElements.Size());
|
||||
|
||||
SetLevelMesh(nullptr);
|
||||
}
|
||||
|
||||
|
@ -55,10 +59,7 @@ void VkRaytrace::SetLevelMesh(hwrenderer::LevelMesh* mesh)
|
|||
{
|
||||
Reset();
|
||||
Mesh = mesh;
|
||||
if (fb->device->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME))
|
||||
{
|
||||
CreateVulkanObjects();
|
||||
}
|
||||
CreateVulkanObjects();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +69,7 @@ void VkRaytrace::Reset()
|
|||
deletelist->Add(std::move(vertexBuffer));
|
||||
deletelist->Add(std::move(indexBuffer));
|
||||
deletelist->Add(std::move(transferBuffer));
|
||||
deletelist->Add(std::move(nodesBuffer));
|
||||
deletelist->Add(std::move(blScratchBuffer));
|
||||
deletelist->Add(std::move(blAccelStructBuffer));
|
||||
deletelist->Add(std::move(blAccelStruct));
|
||||
|
@ -81,38 +83,35 @@ void VkRaytrace::Reset()
|
|||
void VkRaytrace::CreateVulkanObjects()
|
||||
{
|
||||
CreateVertexAndIndexBuffers();
|
||||
CreateBottomLevelAccelerationStructure();
|
||||
CreateTopLevelAccelerationStructure();
|
||||
if (useRayQuery)
|
||||
{
|
||||
CreateBottomLevelAccelerationStructure();
|
||||
CreateTopLevelAccelerationStructure();
|
||||
}
|
||||
}
|
||||
|
||||
void VkRaytrace::CreateVertexAndIndexBuffers()
|
||||
{
|
||||
static_assert(sizeof(FVector3) == 3 * 4, "sizeof(FVector3) is not 12 bytes!");
|
||||
std::vector<CollisionNode> nodes = CreateCollisionNodes();
|
||||
|
||||
size_t vertexbuffersize = (size_t)Mesh->MeshVertices.Size() * sizeof(FVector3);
|
||||
size_t indexbuffersize = (size_t)Mesh->MeshElements.Size() * sizeof(uint32_t);
|
||||
size_t transferbuffersize = vertexbuffersize + indexbuffersize;
|
||||
size_t vertexoffset = 0;
|
||||
size_t indexoffset = vertexoffset + vertexbuffersize;
|
||||
// std430 alignment rules forces us to convert the vec3 to a vec4
|
||||
std::vector<FVector4> vertices;
|
||||
vertices.reserve(Mesh->MeshVertices.Size());
|
||||
for (const FVector3& v : Mesh->MeshVertices)
|
||||
vertices.push_back({ v, 1.0f });
|
||||
|
||||
transferBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
||||
.Size(transferbuffersize)
|
||||
.DebugName("transferBuffer")
|
||||
.Create(fb->device.get());
|
||||
|
||||
uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize);
|
||||
memcpy(data + vertexoffset, Mesh->MeshVertices.Data(), vertexbuffersize);
|
||||
memcpy(data + indexoffset, Mesh->MeshElements.Data(), indexbuffersize);
|
||||
transferBuffer->Unmap();
|
||||
CollisionNodeBufferHeader nodesHeader;
|
||||
nodesHeader.root = Mesh->Collision->get_root();
|
||||
|
||||
vertexBuffer = BufferBuilder()
|
||||
.Usage(
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR)
|
||||
.Size(vertexbuffersize)
|
||||
(useRayQuery ?
|
||||
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(vertices.size() * sizeof(FVector4))
|
||||
.DebugName("vertexBuffer")
|
||||
.Create(fb->device.get());
|
||||
|
||||
|
@ -120,19 +119,29 @@ void VkRaytrace::CreateVertexAndIndexBuffers()
|
|||
.Usage(
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR)
|
||||
.Size(indexbuffersize)
|
||||
(useRayQuery ?
|
||||
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->MeshElements.Size() * sizeof(uint32_t))
|
||||
.DebugName("indexBuffer")
|
||||
.Create(fb->device.get());
|
||||
|
||||
fb->GetCommands()->GetTransferCommands()->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset);
|
||||
fb->GetCommands()->GetTransferCommands()->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset);
|
||||
nodesBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||
.Size(sizeof(CollisionNodeBufferHeader) + nodes.size() * sizeof(CollisionNode))
|
||||
.DebugName("nodesBuffer")
|
||||
.Create(fb->device.get());
|
||||
|
||||
transferBuffer = BufferTransfer()
|
||||
.AddBuffer(vertexBuffer.get(), vertices.data(), vertices.size() * sizeof(FVector4))
|
||||
.AddBuffer(indexBuffer.get(), Mesh->MeshElements.Data(), (size_t)Mesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(nodesBuffer.get(), &nodesHeader, sizeof(CollisionNodeBufferHeader), nodes.data(), nodes.size() * sizeof(CollisionNode))
|
||||
.Execute(fb->device.get(), fb->GetCommands()->GetTransferCommands());
|
||||
|
||||
// Finish transfer before using it for building
|
||||
PipelineBarrier()
|
||||
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, useRayQuery ? VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
}
|
||||
|
||||
void VkRaytrace::CreateBottomLevelAccelerationStructure()
|
||||
|
@ -146,9 +155,9 @@ void VkRaytrace::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(FVector3);
|
||||
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(FVector4);
|
||||
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress();
|
||||
accelStructBLDesc.geometry.triangles.maxVertex = Mesh->MeshVertices.Size() - 1;
|
||||
|
@ -277,3 +286,78 @@ void VkRaytrace::CreateTopLevelAccelerationStructure()
|
|||
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_SHADER_READ_BIT)
|
||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
}
|
||||
|
||||
std::vector<CollisionNode> VkRaytrace::CreateCollisionNodes()
|
||||
{
|
||||
std::vector<CollisionNode> nodes;
|
||||
nodes.reserve(Mesh->Collision->get_nodes().size());
|
||||
for (const auto& node : Mesh->Collision->get_nodes())
|
||||
{
|
||||
CollisionNode info;
|
||||
info.center = node.aabb.Center;
|
||||
info.extents = node.aabb.Extents;
|
||||
info.left = node.left;
|
||||
info.right = node.right;
|
||||
info.element_index = node.element_index;
|
||||
nodes.push_back(info);
|
||||
}
|
||||
if (nodes.empty()) // vulkan doesn't support zero byte buffers
|
||||
nodes.push_back(CollisionNode());
|
||||
return nodes;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data, size_t size)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanBuffer> BufferTransfer::Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer)
|
||||
{
|
||||
size_t transferbuffersize = 0;
|
||||
for (const auto& copy : bufferCopies)
|
||||
transferbuffersize += copy.size0 + copy.size1;
|
||||
|
||||
if (transferbuffersize == 0)
|
||||
return nullptr;
|
||||
|
||||
auto transferBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
||||
.Size(transferbuffersize)
|
||||
.DebugName("BufferTransfer.transferBuffer")
|
||||
.Create(device);
|
||||
|
||||
uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize);
|
||||
size_t pos = 0;
|
||||
for (const auto& copy : bufferCopies)
|
||||
{
|
||||
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.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;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,26 @@
|
|||
|
||||
class VulkanRenderDevice;
|
||||
|
||||
struct CollisionNodeBufferHeader
|
||||
{
|
||||
int root;
|
||||
int padding1;
|
||||
int padding2;
|
||||
int padding3;
|
||||
};
|
||||
|
||||
struct CollisionNode
|
||||
{
|
||||
FVector3 center;
|
||||
float padding1;
|
||||
FVector3 extents;
|
||||
float padding2;
|
||||
int left;
|
||||
int right;
|
||||
int element_index;
|
||||
int padding3;
|
||||
};
|
||||
|
||||
class VkRaytrace
|
||||
{
|
||||
public:
|
||||
|
@ -14,6 +34,9 @@ public:
|
|||
void SetLevelMesh(hwrenderer::LevelMesh* mesh);
|
||||
|
||||
VulkanAccelerationStructure* GetAccelStruct() { return tlAccelStruct.get(); }
|
||||
VulkanBuffer* GetVertexBuffer() { return vertexBuffer.get(); }
|
||||
VulkanBuffer* GetIndexBuffer() { return indexBuffer.get(); }
|
||||
VulkanBuffer* GetNodeBuffer() { return nodesBuffer.get(); }
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
|
@ -22,14 +45,19 @@ private:
|
|||
void CreateBottomLevelAccelerationStructure();
|
||||
void CreateTopLevelAccelerationStructure();
|
||||
|
||||
std::vector<CollisionNode> CreateCollisionNodes();
|
||||
|
||||
VulkanRenderDevice* fb = nullptr;
|
||||
|
||||
bool useRayQuery = true;
|
||||
|
||||
hwrenderer::LevelMesh NullMesh;
|
||||
hwrenderer::LevelMesh* Mesh = nullptr;
|
||||
|
||||
std::unique_ptr<VulkanBuffer> vertexBuffer;
|
||||
std::unique_ptr<VulkanBuffer> indexBuffer;
|
||||
std::unique_ptr<VulkanBuffer> transferBuffer;
|
||||
std::unique_ptr<VulkanBuffer> nodesBuffer;
|
||||
|
||||
std::unique_ptr<VulkanBuffer> blScratchBuffer;
|
||||
std::unique_ptr<VulkanBuffer> blAccelStructBuffer;
|
||||
|
@ -41,3 +69,22 @@ private:
|
|||
std::unique_ptr<VulkanBuffer> tlAccelStructBuffer;
|
||||
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
VulkanBuffer* buffer;
|
||||
const void* data0;
|
||||
size_t size0;
|
||||
const void* data1;
|
||||
size_t size1;
|
||||
};
|
||||
std::vector<BufferCopy> bufferCopies;
|
||||
};
|
||||
|
|
|
@ -1,8 +1,32 @@
|
|||
|
||||
layout(set = 0, binding = 0) uniform sampler2D ShadowMap;
|
||||
layout(set = 0, binding = 1) uniform sampler2DArray LightMap;
|
||||
#if defined(USE_RAYTRACE) && defined(SUPPORTS_RAYQUERY)
|
||||
#if defined(USE_RAYTRACE)
|
||||
#if defined(SUPPORTS_RAYQUERY)
|
||||
layout(set = 0, binding = 2) uniform accelerationStructureEXT TopLevelAS;
|
||||
#else
|
||||
struct CollisionNode
|
||||
{
|
||||
vec3 center;
|
||||
float padding1;
|
||||
vec3 extents;
|
||||
float padding2;
|
||||
int left;
|
||||
int right;
|
||||
int element_index;
|
||||
int padding3;
|
||||
};
|
||||
layout(std430, set = 0, binding = 2) buffer NodeBuffer
|
||||
{
|
||||
int nodesRoot;
|
||||
int nodebufferPadding1;
|
||||
int nodebufferPadding2;
|
||||
int nodebufferPadding3;
|
||||
CollisionNode nodes[];
|
||||
};
|
||||
layout(std430, set = 0, binding = 3) buffer VertexBuffer { vec4 vertices[]; };
|
||||
layout(std430, set = 0, binding = 4) buffer ElementBuffer { int elements[]; };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This must match the HWViewpointUniforms struct
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
// Check if light is in shadow
|
||||
|
||||
#if defined(USE_RAYTRACE) && defined(SUPPORTS_RAYQUERY)
|
||||
#if defined(USE_RAYTRACE)
|
||||
|
||||
#if defined(SUPPORTS_RAYQUERY)
|
||||
|
||||
bool traceHit(vec3 origin, vec3 direction, float dist)
|
||||
{
|
||||
|
@ -11,6 +13,160 @@ bool traceHit(vec3 origin, vec3 direction, float dist)
|
|||
return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool traceHit(vec3 origin, vec3 direction, float dist)
|
||||
{
|
||||
return TraceAnyHit(origin, 0.01f, direction, dist);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
vec2 softshadow[9 * 3] = vec2[](
|
||||
vec2( 0.0, 0.0),
|
||||
vec2(-2.0,-2.0),
|
||||
|
|
Loading…
Reference in a new issue