Started working on ray tracing intersection shader example
This commit is contained in:
parent
a048bc2635
commit
ebc4127472
8 changed files with 685 additions and 0 deletions
|
|
@ -345,6 +345,10 @@ Renders a texture mapped quad with transparency using the new ray tracing extens
|
||||||
|
|
||||||
Callable shaders can be dynamically invoked from within other ray tracing shaders to execute different shaders based on dynamic conditions. The example ray traces multiple geometries, with each calling a different callable shader from the closest hit shader.
|
Callable shaders can be dynamically invoked from within other ray tracing shaders to execute different shaders based on dynamic conditions. The example ray traces multiple geometries, with each calling a different callable shader from the closest hit shader.
|
||||||
|
|
||||||
|
#### [Ray tracing intersection shaders](examples/raytracingintersection)
|
||||||
|
|
||||||
|
Uses an intersection shader for procedural geometry. Instead of using actual geometry, this sample on passes bounding boxes and object definitions. An intersection shader is then used to trace against the procedural objects.
|
||||||
|
|
||||||
#### [Ray query](examples/rayquery)
|
#### [Ray query](examples/rayquery)
|
||||||
|
|
||||||
Ray queries add acceleration structure intersection functionality to non ray tracing shader stages. This allows for combining ray tracing with rasterization. This example makes uses ray queries to add ray casted shadows to a rasterized sample in the fragment shader.
|
Ray queries add acceleration structure intersection functionality to non ray tracing shader stages. This allows for combining ray tracing with rasterization. This example makes uses ray queries to add ray casted shadows to a rasterized sample in the fragment shader.
|
||||||
|
|
|
||||||
604
examples/raytracingintersection/raytracingintersection.cpp
Normal file
604
examples/raytracingintersection/raytracingintersection.cpp
Normal file
|
|
@ -0,0 +1,604 @@
|
||||||
|
/*
|
||||||
|
* Vulkan Example - Hardware accelerated ray tracing intersection shader samples
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 by Sascha Willems - www.saschawillems.de
|
||||||
|
*
|
||||||
|
* This sample uses intersection shaders for doing prodcedural ray traced geometry
|
||||||
|
* Instead of passing actual geometry, this samples only passes bounding boxes and sphere descriptions
|
||||||
|
* The bounding boxes are used for the ray traversal and the sphere intersections are done
|
||||||
|
* within the intersection shader
|
||||||
|
*
|
||||||
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "VulkanRaytracingSample.h"
|
||||||
|
|
||||||
|
class VulkanExample : public VulkanRaytracingSample
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccelerationStructure bottomLevelAS;
|
||||||
|
AccelerationStructure topLevelAS;
|
||||||
|
|
||||||
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> shaderGroups{};
|
||||||
|
struct ShaderBindingTables {
|
||||||
|
ShaderBindingTable raygen;
|
||||||
|
ShaderBindingTable miss;
|
||||||
|
ShaderBindingTable hit;
|
||||||
|
} shaderBindingTables;
|
||||||
|
|
||||||
|
struct UniformData {
|
||||||
|
glm::mat4 viewInverse;
|
||||||
|
glm::mat4 projInverse;
|
||||||
|
glm::vec4 lightPos;
|
||||||
|
} uniformData;
|
||||||
|
vks::Buffer ubo;
|
||||||
|
|
||||||
|
VkPipeline pipeline;
|
||||||
|
VkPipelineLayout pipelineLayout;
|
||||||
|
VkDescriptorSet descriptorSet;
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout;
|
||||||
|
|
||||||
|
struct Sphere {
|
||||||
|
glm::vec3 center;
|
||||||
|
float radius;
|
||||||
|
glm::vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AABB {
|
||||||
|
glm::vec3 min;
|
||||||
|
glm::vec3 max;
|
||||||
|
};
|
||||||
|
|
||||||
|
vks::Buffer spheresBuffer;
|
||||||
|
vks::Buffer aabbsBuffer;
|
||||||
|
uint32_t aabbCount{ 0 };
|
||||||
|
|
||||||
|
// This sample is derived from an extended base class that saves most of the ray tracing setup boiler plate
|
||||||
|
VulkanExample() : VulkanRaytracingSample()
|
||||||
|
{
|
||||||
|
title = "Ray tracing intersection shaders";
|
||||||
|
timerSpeed *= 0.25f;
|
||||||
|
camera.type = Camera::CameraType::lookat;
|
||||||
|
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
|
||||||
|
camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
|
camera.setTranslation(glm::vec3(0.0f, 0.0f, -10.0f));
|
||||||
|
enableExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
~VulkanExample()
|
||||||
|
{
|
||||||
|
vkDestroyPipeline(device, pipeline, nullptr);
|
||||||
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||||
|
deleteStorageImage();
|
||||||
|
deleteAccelerationStructure(bottomLevelAS);
|
||||||
|
deleteAccelerationStructure(topLevelAS);
|
||||||
|
shaderBindingTables.raygen.destroy();
|
||||||
|
shaderBindingTables.miss.destroy();
|
||||||
|
shaderBindingTables.hit.destroy();
|
||||||
|
ubo.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void createBuffers()
|
||||||
|
{
|
||||||
|
// We'll be using two buffers to describe the procedural geometry
|
||||||
|
|
||||||
|
// A buffer with sphere descriptions (center, radius, material) that'll be passed to the ray tracing shaders as a shader storage buffer object
|
||||||
|
std::vector<Sphere> spheres{};
|
||||||
|
spheres.push_back({ glm::vec3(0.0f), 2.5f, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f) });
|
||||||
|
spheres.push_back({ glm::vec3(2.0f), 1.5f, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f) });
|
||||||
|
|
||||||
|
// A buffer with the (axis aligned) bounding boxes of our sphere, which is used during the ray tracing traversal for hit detection
|
||||||
|
std::vector<AABB> aabbs{};
|
||||||
|
for (auto& sphere : spheres) {
|
||||||
|
aabbs.push_back({ sphere.center - glm::vec3(sphere.radius), sphere.center + glm::vec3(sphere.radius) });
|
||||||
|
}
|
||||||
|
aabbCount = static_cast<uint32_t>(aabbs.size());
|
||||||
|
|
||||||
|
// Copy the buffer to the device for performance reasons
|
||||||
|
vks::Buffer stagingBuffer{};
|
||||||
|
VkBufferUsageFlags usageFlags = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
|
// Spheres
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffer, sizeof(Sphere)* spheres.size(), spheres.data()));
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(usageFlags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &spheresBuffer, sizeof(Sphere)* spheres.size()));
|
||||||
|
vulkanDevice->copyBuffer(&stagingBuffer, &spheresBuffer, queue);
|
||||||
|
stagingBuffer.destroy();
|
||||||
|
|
||||||
|
// AABBs
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffer, sizeof(AABB)* aabbs.size(), aabbs.data()));
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(usageFlags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &aabbsBuffer, sizeof(AABB)* aabbs.size()));
|
||||||
|
vulkanDevice->copyBuffer(&stagingBuffer, &aabbsBuffer, queue);
|
||||||
|
stagingBuffer.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the bottom level acceleration structure only containing axis aligned bounding boxes for our procedural geometry
|
||||||
|
*/
|
||||||
|
void createBottomLevelAccelerationStructure()
|
||||||
|
{
|
||||||
|
// Build
|
||||||
|
VkAccelerationStructureGeometryKHR accelerationStructureGeometry = vks::initializers::accelerationStructureGeometryKHR();
|
||||||
|
accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
|
// Instead of providing actual geometry (e.g. triangles), we only provide the axis aligned bounding boxes (AABBs) of the spheres
|
||||||
|
// The data for the actual spheres is passed elsewhere as a shader storage buffer object
|
||||||
|
accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
|
||||||
|
accelerationStructureGeometry.geometry.aabbs.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR;
|
||||||
|
accelerationStructureGeometry.geometry.aabbs.data.deviceAddress = getBufferDeviceAddress(aabbsBuffer.buffer);
|
||||||
|
accelerationStructureGeometry.geometry.aabbs.stride = sizeof(AABB);
|
||||||
|
|
||||||
|
// Get size info
|
||||||
|
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR();
|
||||||
|
accelerationStructureBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||||
|
accelerationStructureBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||||
|
accelerationStructureBuildGeometryInfo.geometryCount = 1;
|
||||||
|
accelerationStructureBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||||
|
|
||||||
|
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo = vks::initializers::accelerationStructureBuildSizesInfoKHR();
|
||||||
|
vkGetAccelerationStructureBuildSizesKHR(
|
||||||
|
device,
|
||||||
|
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
|
||||||
|
&accelerationStructureBuildGeometryInfo,
|
||||||
|
&aabbCount,
|
||||||
|
&accelerationStructureBuildSizesInfo);
|
||||||
|
|
||||||
|
createAccelerationStructure(bottomLevelAS, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, accelerationStructureBuildSizesInfo);
|
||||||
|
|
||||||
|
// Create a small scratch buffer used during build of the bottom level acceleration structure
|
||||||
|
ScratchBuffer scratchBuffer = createScratchBuffer(accelerationStructureBuildSizesInfo.buildScratchSize);
|
||||||
|
|
||||||
|
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR();
|
||||||
|
accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||||
|
accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||||
|
accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
||||||
|
accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.handle;
|
||||||
|
accelerationBuildGeometryInfo.geometryCount = 1;
|
||||||
|
accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||||
|
accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
|
||||||
|
|
||||||
|
VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{};
|
||||||
|
accelerationStructureBuildRangeInfo.primitiveCount = aabbCount;
|
||||||
|
std::vector<VkAccelerationStructureBuildRangeInfoKHR*> accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo };
|
||||||
|
|
||||||
|
// Build the acceleration structure on the device via a one-time command buffer submission
|
||||||
|
// Some implementations may support acceleration structure building on the host (VkPhysicalDeviceAccelerationStructureFeaturesKHR->accelerationStructureHostCommands), but we prefer device builds
|
||||||
|
VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
|
vkCmdBuildAccelerationStructuresKHR(
|
||||||
|
commandBuffer,
|
||||||
|
1,
|
||||||
|
&accelerationBuildGeometryInfo,
|
||||||
|
accelerationBuildStructureRangeInfos.data());
|
||||||
|
vulkanDevice->flushCommandBuffer(commandBuffer, queue);
|
||||||
|
|
||||||
|
deleteScratchBuffer(scratchBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The top level acceleration structure contains the scene's object instances
|
||||||
|
*/
|
||||||
|
void createTopLevelAccelerationStructure()
|
||||||
|
{
|
||||||
|
VkTransformMatrixKHR transformMatrix = {
|
||||||
|
1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f };
|
||||||
|
|
||||||
|
VkAccelerationStructureInstanceKHR instance{};
|
||||||
|
instance.transform = transformMatrix;
|
||||||
|
instance.instanceCustomIndex = 0;
|
||||||
|
instance.mask = 0xFF;
|
||||||
|
instance.instanceShaderBindingTableRecordOffset = 0;
|
||||||
|
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
|
instance.accelerationStructureReference = bottomLevelAS.deviceAddress;
|
||||||
|
|
||||||
|
// Buffer for instance data
|
||||||
|
vks::Buffer instancesBuffer;
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&instancesBuffer,
|
||||||
|
sizeof(VkAccelerationStructureInstanceKHR),
|
||||||
|
&instance));
|
||||||
|
|
||||||
|
VkDeviceOrHostAddressConstKHR instanceDataDeviceAddress{};
|
||||||
|
instanceDataDeviceAddress.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer);
|
||||||
|
|
||||||
|
VkAccelerationStructureGeometryKHR accelerationStructureGeometry = vks::initializers::accelerationStructureGeometryKHR();
|
||||||
|
accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
|
||||||
|
accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
|
accelerationStructureGeometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
|
||||||
|
accelerationStructureGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
|
||||||
|
accelerationStructureGeometry.geometry.instances.data = instanceDataDeviceAddress;
|
||||||
|
|
||||||
|
// Get size info
|
||||||
|
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR();
|
||||||
|
accelerationStructureBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||||
|
accelerationStructureBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||||
|
accelerationStructureBuildGeometryInfo.geometryCount = 1;
|
||||||
|
accelerationStructureBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||||
|
|
||||||
|
uint32_t primitive_count = 1;
|
||||||
|
|
||||||
|
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo = vks::initializers::accelerationStructureBuildSizesInfoKHR();
|
||||||
|
vkGetAccelerationStructureBuildSizesKHR(
|
||||||
|
device,
|
||||||
|
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
|
||||||
|
&accelerationStructureBuildGeometryInfo,
|
||||||
|
&primitive_count,
|
||||||
|
&accelerationStructureBuildSizesInfo);
|
||||||
|
|
||||||
|
createAccelerationStructure(topLevelAS, VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, accelerationStructureBuildSizesInfo);
|
||||||
|
|
||||||
|
// Create a small scratch buffer used during build of the top level acceleration structure
|
||||||
|
ScratchBuffer scratchBuffer = createScratchBuffer(accelerationStructureBuildSizesInfo.buildScratchSize);
|
||||||
|
|
||||||
|
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR();
|
||||||
|
accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||||
|
accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||||
|
accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
||||||
|
accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.handle;
|
||||||
|
accelerationBuildGeometryInfo.geometryCount = 1;
|
||||||
|
accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||||
|
accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
|
||||||
|
|
||||||
|
VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{};
|
||||||
|
accelerationStructureBuildRangeInfo.primitiveCount = 1;
|
||||||
|
accelerationStructureBuildRangeInfo.primitiveOffset = 0;
|
||||||
|
accelerationStructureBuildRangeInfo.firstVertex = 0;
|
||||||
|
accelerationStructureBuildRangeInfo.transformOffset = 0;
|
||||||
|
std::vector<VkAccelerationStructureBuildRangeInfoKHR*> accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo };
|
||||||
|
|
||||||
|
// Build the acceleration structure on the device via a one-time command buffer submission
|
||||||
|
// Some implementations may support acceleration structure building on the host (VkPhysicalDeviceAccelerationStructureFeaturesKHR->accelerationStructureHostCommands), but we prefer device builds
|
||||||
|
VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
|
vkCmdBuildAccelerationStructuresKHR(
|
||||||
|
commandBuffer,
|
||||||
|
1,
|
||||||
|
&accelerationBuildGeometryInfo,
|
||||||
|
accelerationBuildStructureRangeInfos.data());
|
||||||
|
vulkanDevice->flushCommandBuffer(commandBuffer, queue);
|
||||||
|
|
||||||
|
deleteScratchBuffer(scratchBuffer);
|
||||||
|
instancesBuffer.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the Shader Binding Tables that binds the programs and top-level acceleration structure
|
||||||
|
|
||||||
|
SBT Layout used in this sample:
|
||||||
|
|
||||||
|
/-----------\
|
||||||
|
| raygen |
|
||||||
|
|-----------|
|
||||||
|
| miss |
|
||||||
|
|-----------|
|
||||||
|
| hit + int |
|
||||||
|
\-----------/
|
||||||
|
|
||||||
|
*/
|
||||||
|
void createShaderBindingTables() {
|
||||||
|
const uint32_t handleSize = rayTracingPipelineProperties.shaderGroupHandleSize;
|
||||||
|
const uint32_t handleSizeAligned = vks::tools::alignedSize(rayTracingPipelineProperties.shaderGroupHandleSize, rayTracingPipelineProperties.shaderGroupHandleAlignment);
|
||||||
|
const uint32_t groupCount = static_cast<uint32_t>(shaderGroups.size());
|
||||||
|
const uint32_t sbtSize = groupCount * handleSizeAligned;
|
||||||
|
|
||||||
|
std::vector<uint8_t> shaderHandleStorage(sbtSize);
|
||||||
|
VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()));
|
||||||
|
|
||||||
|
createShaderBindingTable(shaderBindingTables.raygen, 1);
|
||||||
|
createShaderBindingTable(shaderBindingTables.miss, 1);
|
||||||
|
createShaderBindingTable(shaderBindingTables.hit, 1);
|
||||||
|
|
||||||
|
// Copy handles
|
||||||
|
memcpy(shaderBindingTables.raygen.mapped, shaderHandleStorage.data(), handleSize);
|
||||||
|
memcpy(shaderBindingTables.miss.mapped, shaderHandleStorage.data() + handleSizeAligned, handleSize);
|
||||||
|
memcpy(shaderBindingTables.hit.mapped, shaderHandleStorage.data() + handleSizeAligned * 2, handleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the descriptor sets used for the ray tracing dispatch
|
||||||
|
*/
|
||||||
|
void createDescriptorSets()
|
||||||
|
{
|
||||||
|
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||||
|
{ VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 }
|
||||||
|
};
|
||||||
|
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
|
||||||
|
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
||||||
|
|
||||||
|
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
|
||||||
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
|
||||||
|
|
||||||
|
VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo = vks::initializers::writeDescriptorSetAccelerationStructureKHR();
|
||||||
|
descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
|
||||||
|
descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.handle;
|
||||||
|
|
||||||
|
VkWriteDescriptorSet accelerationStructureWrite{};
|
||||||
|
accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
// The specialized acceleration structure descriptor has to be chained
|
||||||
|
accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
|
||||||
|
accelerationStructureWrite.dstSet = descriptorSet;
|
||||||
|
accelerationStructureWrite.dstBinding = 0;
|
||||||
|
accelerationStructureWrite.descriptorCount = 1;
|
||||||
|
accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
|
||||||
|
|
||||||
|
// We pass the sphere descriptions as shader storage buffer, so the ray tracing shaders can source properties from it
|
||||||
|
VkDescriptorImageInfo storageImageDescriptor{ VK_NULL_HANDLE, storageImage.view, VK_IMAGE_LAYOUT_GENERAL };
|
||||||
|
VkDescriptorBufferInfo spheresBufferDescriptor{ spheresBuffer.buffer, 0, VK_WHOLE_SIZE };
|
||||||
|
|
||||||
|
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
|
||||||
|
// Binding 0: Top level acceleration structure
|
||||||
|
accelerationStructureWrite,
|
||||||
|
// Binding 1: Ray tracing result image
|
||||||
|
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor),
|
||||||
|
// Binding 2: Uniform data
|
||||||
|
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor),
|
||||||
|
// Binding 3: Spheres buffer
|
||||||
|
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &spheresBufferDescriptor),
|
||||||
|
};
|
||||||
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create our ray tracing pipeline
|
||||||
|
*/
|
||||||
|
void createRayTracingPipeline()
|
||||||
|
{
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
|
||||||
|
// Binding 0: Acceleration structure
|
||||||
|
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 0),
|
||||||
|
// Binding 1: Storage image
|
||||||
|
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_RAYGEN_BIT_KHR, 1),
|
||||||
|
// Binding 2: Uniform buffer
|
||||||
|
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR, 2),
|
||||||
|
// Binding 3: Spheres buffer
|
||||||
|
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR, 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
|
||||||
|
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayout));
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pPipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
|
||||||
|
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCI, nullptr, &pipelineLayout));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup ray tracing shader groups
|
||||||
|
*/
|
||||||
|
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||||
|
|
||||||
|
// Ray generation group
|
||||||
|
{
|
||||||
|
shaderStages.push_back(loadShader(getShadersPath() + "raytracingintersection/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR));
|
||||||
|
VkRayTracingShaderGroupCreateInfoKHR shaderGroup{};
|
||||||
|
shaderGroup.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||||
|
shaderGroup.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
|
shaderGroup.generalShader = static_cast<uint32_t>(shaderStages.size()) - 1;
|
||||||
|
shaderGroup.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroup.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroup.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroups.push_back(shaderGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miss group
|
||||||
|
{
|
||||||
|
shaderStages.push_back(loadShader(getShadersPath() + "raytracingintersection/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR));
|
||||||
|
VkRayTracingShaderGroupCreateInfoKHR shaderGroup{};
|
||||||
|
shaderGroup.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||||
|
shaderGroup.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
|
shaderGroup.generalShader = static_cast<uint32_t>(shaderStages.size()) - 1;
|
||||||
|
shaderGroup.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroup.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroup.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroups.push_back(shaderGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closest hit group (procedural)
|
||||||
|
{
|
||||||
|
shaderStages.push_back(loadShader(getShadersPath() + "raytracingintersection/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR));
|
||||||
|
VkRayTracingShaderGroupCreateInfoKHR shaderGroup{};
|
||||||
|
shaderGroup.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||||
|
shaderGroup.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
|
||||||
|
shaderGroup.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
shaderGroup.closestHitShader = static_cast<uint32_t>(shaderStages.size()) - 1;
|
||||||
|
shaderGroup.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
// This group als uses an intersection shader for proedural geometry (see interseciton.rint for details)
|
||||||
|
shaderStages.push_back(loadShader(getShadersPath() + "raytracingintersection/intersection.rint.spv", VK_SHADER_STAGE_INTERSECTION_BIT_KHR));
|
||||||
|
shaderGroup.intersectionShader = static_cast<uint32_t>(shaderStages.size()) - 1;
|
||||||
|
shaderGroups.push_back(shaderGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI = vks::initializers::rayTracingPipelineCreateInfoKHR();
|
||||||
|
rayTracingPipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||||
|
rayTracingPipelineCI.pStages = shaderStages.data();
|
||||||
|
rayTracingPipelineCI.groupCount = static_cast<uint32_t>(shaderGroups.size());
|
||||||
|
rayTracingPipelineCI.pGroups = shaderGroups.data();
|
||||||
|
rayTracingPipelineCI.maxPipelineRayRecursionDepth = 2;
|
||||||
|
rayTracingPipelineCI.layout = pipelineLayout;
|
||||||
|
VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
|
||||||
|
*/
|
||||||
|
void createUniformBuffer()
|
||||||
|
{
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&ubo,
|
||||||
|
sizeof(uniformData),
|
||||||
|
&uniformData));
|
||||||
|
VK_CHECK_RESULT(ubo.map());
|
||||||
|
|
||||||
|
updateUniformBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the window has been resized, we need to recreate the storage image and it's descriptor
|
||||||
|
*/
|
||||||
|
void handleResize()
|
||||||
|
{
|
||||||
|
// Recreate image
|
||||||
|
createStorageImage(swapChain.colorFormat, { width, height, 1 });
|
||||||
|
// Update descriptor
|
||||||
|
VkDescriptorImageInfo storageImageDescriptor{ VK_NULL_HANDLE, storageImage.view, VK_IMAGE_LAYOUT_GENERAL };
|
||||||
|
VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
|
||||||
|
vkUpdateDescriptorSets(device, 1, &resultImageWrite, 0, VK_NULL_HANDLE);
|
||||||
|
resized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Command buffer generation
|
||||||
|
*/
|
||||||
|
void buildCommandBuffers()
|
||||||
|
{
|
||||||
|
if (resized)
|
||||||
|
{
|
||||||
|
handleResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
||||||
|
|
||||||
|
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
|
||||||
|
{
|
||||||
|
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dispatch the ray tracing commands
|
||||||
|
*/
|
||||||
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
|
||||||
|
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
|
||||||
|
|
||||||
|
VkStridedDeviceAddressRegionKHR emptySbtEntry = {};
|
||||||
|
vkCmdTraceRaysKHR(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
&shaderBindingTables.raygen.stridedDeviceAddressRegion,
|
||||||
|
&shaderBindingTables.miss.stridedDeviceAddressRegion,
|
||||||
|
&shaderBindingTables.hit.stridedDeviceAddressRegion,
|
||||||
|
&emptySbtEntry,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copy ray tracing output to swap chain image
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Prepare current swap chain image as transfer destination
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
swapChain.images[i],
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
// Prepare ray tracing output image as transfer source
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
storageImage.image,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
VkImageCopy copyRegion{};
|
||||||
|
copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||||
|
copyRegion.srcOffset = { 0, 0, 0 };
|
||||||
|
copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||||
|
copyRegion.dstOffset = { 0, 0, 0 };
|
||||||
|
copyRegion.extent = { width, height, 1 };
|
||||||
|
vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
|
||||||
|
|
||||||
|
// Transition swap chain image back for presentation
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
swapChain.images[i],
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
// Transition ray tracing output image back to general layout
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
storageImage.image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
drawUI(drawCmdBuffers[i], frameBuffers[i]);
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateUniformBuffers()
|
||||||
|
{
|
||||||
|
uniformData.projInverse = glm::inverse(camera.matrices.perspective);
|
||||||
|
uniformData.viewInverse = glm::inverse(camera.matrices.view);
|
||||||
|
uniformData.lightPos = glm::vec4(cos(glm::radians(timer * 360.0f)) * 40.0f, -50.0f + sin(glm::radians(timer * 360.0f)) * 20.0f, 25.0f + sin(glm::radians(timer * 360.0f)) * 5.0f, 0.0f);
|
||||||
|
// Pass the vertex size to the shader for unpacking vertices
|
||||||
|
//uniformData.vertexSize = sizeof(vkglTF::Vertex);
|
||||||
|
memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void getEnabledFeatures()
|
||||||
|
{
|
||||||
|
// Enable features required for ray tracing using feature chaining via pNext
|
||||||
|
enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
|
||||||
|
enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE;
|
||||||
|
|
||||||
|
enabledRayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
|
||||||
|
enabledRayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE;
|
||||||
|
enabledRayTracingPipelineFeatures.pNext = &enabledBufferDeviceAddresFeatures;
|
||||||
|
|
||||||
|
enabledAccelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
|
||||||
|
enabledAccelerationStructureFeatures.accelerationStructure = VK_TRUE;
|
||||||
|
enabledAccelerationStructureFeatures.pNext = &enabledRayTracingPipelineFeatures;
|
||||||
|
|
||||||
|
deviceCreatepNextChain = &enabledAccelerationStructureFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
VulkanRaytracingSample::prepare();
|
||||||
|
|
||||||
|
createBuffers();
|
||||||
|
|
||||||
|
// Create the acceleration structures used to render the ray traced scene
|
||||||
|
createBottomLevelAccelerationStructure();
|
||||||
|
createTopLevelAccelerationStructure();
|
||||||
|
|
||||||
|
createStorageImage(swapChain.colorFormat, { width, height, 1 });
|
||||||
|
createUniformBuffer();
|
||||||
|
createRayTracingPipeline();
|
||||||
|
createShaderBindingTables();
|
||||||
|
createDescriptorSets();
|
||||||
|
buildCommandBuffers();
|
||||||
|
prepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw()
|
||||||
|
{
|
||||||
|
VulkanExampleBase::prepareFrame();
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||||
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
|
VulkanExampleBase::submitFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void render()
|
||||||
|
{
|
||||||
|
if (!prepared)
|
||||||
|
return;
|
||||||
|
draw();
|
||||||
|
if (!paused || camera.updated)
|
||||||
|
updateUniformBuffers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VULKAN_EXAMPLE_MAIN()
|
||||||
35
shaders/glsl/raytracingintersection/closesthit.rchit
Normal file
35
shaders/glsl/raytracingintersection/closesthit.rchit
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#version 460
|
||||||
|
#extension GL_EXT_ray_tracing : require
|
||||||
|
#extension GL_EXT_nonuniform_qualifier : enable
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadInEXT vec3 hitValue;
|
||||||
|
layout(location = 2) rayPayloadEXT bool shadowed;
|
||||||
|
hitAttributeEXT vec2 attribs;
|
||||||
|
|
||||||
|
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
|
||||||
|
layout(binding = 2, set = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 viewInverse;
|
||||||
|
mat4 projInverse;
|
||||||
|
vec4 lightPos;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
struct Sphere {
|
||||||
|
vec3 center;
|
||||||
|
float radius;
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
layout(binding = 3, set = 0) buffer Spheres { Sphere s[]; } spheres;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
Sphere sphere = spheres.s[gl_PrimitiveID];
|
||||||
|
|
||||||
|
vec3 worldPos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
||||||
|
vec3 worldNrm = normalize(worldPos - sphere.center);
|
||||||
|
|
||||||
|
// Basic lighting
|
||||||
|
vec3 lightVector = normalize(ubo.lightPos.xyz);
|
||||||
|
float dot_product = max(dot(lightVector, worldNrm), 0.2);
|
||||||
|
hitValue = sphere.color.rgb * dot_product;
|
||||||
|
}
|
||||||
BIN
shaders/glsl/raytracingintersection/closesthit.rchit.spv
Normal file
BIN
shaders/glsl/raytracingintersection/closesthit.rchit.spv
Normal file
Binary file not shown.
9
shaders/glsl/raytracingintersection/miss.rmiss
Normal file
9
shaders/glsl/raytracingintersection/miss.rmiss
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 460
|
||||||
|
#extension GL_EXT_ray_tracing : require
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadInEXT vec3 hitValue;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
hitValue = vec3(0.0, 0.0, 0.2);
|
||||||
|
}
|
||||||
BIN
shaders/glsl/raytracingintersection/miss.rmiss.spv
Normal file
BIN
shaders/glsl/raytracingintersection/miss.rmiss.spv
Normal file
Binary file not shown.
33
shaders/glsl/raytracingintersection/raygen.rgen
Normal file
33
shaders/glsl/raytracingintersection/raygen.rgen
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#version 460
|
||||||
|
#extension GL_EXT_ray_tracing : require
|
||||||
|
|
||||||
|
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
|
||||||
|
layout(binding = 1, set = 0, rgba8) uniform image2D image;
|
||||||
|
layout(binding = 2, set = 0) uniform CameraProperties
|
||||||
|
{
|
||||||
|
mat4 viewInverse;
|
||||||
|
mat4 projInverse;
|
||||||
|
vec4 lightPos;
|
||||||
|
} cam;
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadEXT vec3 hitValue;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
|
||||||
|
const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.xy);
|
||||||
|
vec2 d = inUV * 2.0 - 1.0;
|
||||||
|
|
||||||
|
vec4 origin = cam.viewInverse * vec4(0,0,0,1);
|
||||||
|
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ;
|
||||||
|
vec4 direction = cam.viewInverse*vec4(normalize(target.xyz / target.w), 0) ;
|
||||||
|
|
||||||
|
uint rayFlags = gl_RayFlagsOpaqueEXT;
|
||||||
|
uint cullMask = 0xff;
|
||||||
|
float tmin = 0.001;
|
||||||
|
float tmax = 10000.0;
|
||||||
|
|
||||||
|
traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
|
||||||
|
|
||||||
|
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 0.0));
|
||||||
|
}
|
||||||
BIN
shaders/glsl/raytracingintersection/raygen.rgen.spv
Normal file
BIN
shaders/glsl/raytracingintersection/raygen.rgen.spv
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue