From 447932025fb9376d3d51e351a94e0c279b0f5119 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 12 Apr 2023 02:09:28 +0200 Subject: [PATCH] Add support for gl_light_raytrace for cards that do not support rayquery --- .../vulkan/renderer/vk_descriptorset.cpp | 22 +++ .../rendering/vulkan/renderer/vk_raytrace.cpp | 152 +++++++++++++---- .../rendering/vulkan/renderer/vk_raytrace.h | 47 ++++++ .../static/shaders/scene/layout_shared.glsl | 26 ++- wadsrc/static/shaders/scene/light_shadow.glsl | 158 +++++++++++++++++- 5 files changed, 369 insertions(+), 36 deletions(-) diff --git a/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp b/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp index ea7c9717bf..18f7ac29a5 100644 --- a/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp @@ -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()); diff --git a/src/common/rendering/vulkan/renderer/vk_raytrace.cpp b/src/common/rendering/vulkan/renderer/vk_raytrace.cpp index 8efdb10d1a..c2436678d0 100644 --- a/src/common/rendering/vulkan/renderer/vk_raytrace.cpp +++ b/src/common/rendering/vulkan/renderer/vk_raytrace.cpp @@ -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(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 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 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 VkRaytrace::CreateCollisionNodes() +{ + std::vector 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 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; +} diff --git a/src/common/rendering/vulkan/renderer/vk_raytrace.h b/src/common/rendering/vulkan/renderer/vk_raytrace.h index e54a9c623d..d914f6efeb 100644 --- a/src/common/rendering/vulkan/renderer/vk_raytrace.h +++ b/src/common/rendering/vulkan/renderer/vk_raytrace.h @@ -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 CreateCollisionNodes(); + VulkanRenderDevice* fb = nullptr; + bool useRayQuery = true; + hwrenderer::LevelMesh NullMesh; hwrenderer::LevelMesh* Mesh = nullptr; std::unique_ptr vertexBuffer; std::unique_ptr indexBuffer; std::unique_ptr transferBuffer; + std::unique_ptr nodesBuffer; std::unique_ptr blScratchBuffer; std::unique_ptr blAccelStructBuffer; @@ -41,3 +69,22 @@ private: std::unique_ptr tlAccelStructBuffer; std::unique_ptr 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 Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer); + +private: + struct BufferCopy + { + VulkanBuffer* buffer; + const void* data0; + size_t size0; + const void* data1; + size_t size1; + }; + std::vector bufferCopies; +}; diff --git a/wadsrc/static/shaders/scene/layout_shared.glsl b/wadsrc/static/shaders/scene/layout_shared.glsl index 15ddbfc899..0a29c3d506 100644 --- a/wadsrc/static/shaders/scene/layout_shared.glsl +++ b/wadsrc/static/shaders/scene/layout_shared.glsl @@ -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 diff --git a/wadsrc/static/shaders/scene/light_shadow.glsl b/wadsrc/static/shaders/scene/light_shadow.glsl index 8d42330cd1..009fcd4175 100644 --- a/wadsrc/static/shaders/scene/light_shadow.glsl +++ b/wadsrc/static/shaders/scene/light_shadow.glsl @@ -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),