diff --git a/application/vulkan_ray_tracing/src/hello_vulkan.cpp b/application/vulkan_ray_tracing/src/hello_vulkan.cpp index 2bb7860..15a6624 100644 --- a/application/vulkan_ray_tracing/src/hello_vulkan.cpp +++ b/application/vulkan_ray_tracing/src/hello_vulkan.cpp @@ -706,7 +706,7 @@ void HelloVulkan::createTopLevelAS() { void HelloVulkan::createRtDescriptorSet() { m_rtDescSetLayoutBind.addBinding( RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ); // TLAS m_rtDescSetLayoutBind.addBinding( @@ -767,7 +767,7 @@ void HelloVulkan::createRtPipeline() { enum StageIndices { eRaygen, eMiss, - //eMiss2, + eMiss2, eClosestHit, eShaderGroupCount }; @@ -796,11 +796,11 @@ void HelloVulkan::createRtPipeline() { // // El segundo miss shader se invoca cuando un shadow ray no ha colisionado con la geometría. // // Simplemente, indica que no ha habido oclusión. - // stage.module = nvvk::createShaderModule(m_device, - // nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true - // )); - // stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - // stages[eMiss2] = stage; + stage.module = nvvk::createShaderModule(m_device, + nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true + )); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; // Hit group - closest hit stage.module = nvvk::createShaderModule(m_device, @@ -832,6 +832,11 @@ void HelloVulkan::createRtPipeline() { group.generalShader = eMiss; m_rtShaderGroups.push_back(group); + // Shadow miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); + // closest hit shader // Note that if the geometry were not triangles, we would have set the type @@ -886,13 +891,18 @@ void HelloVulkan::createRtPipeline() { To allow the underlying RTX layer to optimize the pipeline we indicate the maximum recursion depth used by our shaders - For the simplistic shaders we currently have, we set this depth to 1, + For the simplistic shaders we currently have, we can set this depth to 1, meaning that we must not trigger recursion at all (i.e. a hit shader calling TraceRayEXT()). Note that it is preferable to keep the recursion level as low as possible, replacing it by a loop formulation instead. + + When shadow rays are added, we must increase the recursion depth to 2, since we + can shoot rays from the hit points of the camera rays. + + Realisticly, it should be flatten to a loop. */ - rayPipelineInfo.maxPipelineRayRecursionDepth = 1; // Ray depth + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth rayPipelineInfo.layout = m_rtPipelineLayout; vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); @@ -908,8 +918,9 @@ void HelloVulkan::createRtPipeline() { // - Besides exception, this could always be done like this void HelloVulkan::createRtShaderBindingTable() { - // Siempre hay un único raygen, así que podemos ponerlo constantemente 1. - uint32_t missCount{1}; + // Miss count: miss y shadows + // Hit count: solo hit. + uint32_t missCount{2}; uint32_t hitCount{1}; auto handleCount = 1 + missCount + hitCount; uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; diff --git a/application/vulkan_ray_tracing/src/shaders/raytrace.rchit b/application/vulkan_ray_tracing/src/shaders/raytrace.rchit index 465b684..186ea64 100644 --- a/application/vulkan_ray_tracing/src/shaders/raytrace.rchit +++ b/application/vulkan_ray_tracing/src/shaders/raytrace.rchit @@ -12,6 +12,7 @@ hitAttributeEXT vec3 attribs; layout(location = 0) rayPayloadInEXT hitPayload prd; +layout(location = 1) rayPayloadEXT bool isShadowed; layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; // Posición del objeto layout(buffer_reference, scalar) buffer Indices { ivec3 i[]; }; // Indices del triángulo @@ -20,6 +21,7 @@ layout(buffer_reference, scalar) buffer MatIndices { int i[]; }; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; +layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; // Para los shadow rays layout (push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; @@ -79,7 +81,40 @@ void main() } // Specular - vec3 specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); + vec3 specular = vec3(0); + float attenuation = 1; + + // Trazar shadow rays solo si la luz es visible desde la superficie + if (dot(normal, L) > 0) { + float tMin = 0.001; + float tMax = lightDistance; + + vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; + vec3 rayDir = L; + + uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; + isShadowed = true; + + traceRayEXT(topLevelAS, + flags, // rayFlags + 0xFF, // cullMask + 0, // sbtRecordOffset + 0, // sbtRecordStride + 1, // missIndex + origin, // ray origin + tMin, // ray min range + rayDir, // ray direction + tMax, // ray max range + 1 // payload (location = 1) + ); + + if (isShadowed) { + attenuation = 1.0 / (1.0 + lightDistance); + } + else { + specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); + } + } - prd.hitValue = vec3(lightIntensity * (diffuse + specular)); + prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); } diff --git a/application/vulkan_ray_tracing/src/shaders/raytraceShadow.rmiss b/application/vulkan_ray_tracing/src/shaders/raytraceShadow.rmiss new file mode 100644 index 0000000..57be266 --- /dev/null +++ b/application/vulkan_ray_tracing/src/shaders/raytraceShadow.rmiss @@ -0,0 +1,9 @@ +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(location = 1) rayPayloadInEXT bool isShadowed; + +void main() +{ + isShadowed = false; +}