Refactoring

This commit is contained in:
mklefrancois 2021-09-07 09:42:21 +02:00
parent 3e399adf0a
commit d90ce79135
222 changed files with 9045 additions and 5734 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
**/spv/*.spv **/spv/*.spv
/build/* /build/*
/out/build/x64-Debug
/.vs

View file

@ -59,6 +59,7 @@ add_subdirectory(ray_tracing_ao)
add_subdirectory(ray_tracing_indirect_scissor) add_subdirectory(ray_tracing_indirect_scissor)
add_subdirectory(ray_tracing_specialization) add_subdirectory(ray_tracing_specialization)
add_subdirectory(ray_tracing_advanced_compilation) add_subdirectory(ray_tracing_advanced_compilation)
add_subdirectory(ray_tracing_motionblur)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------

View file

@ -671,42 +671,47 @@ write `m_lanternCount`.
// that all ObjInstance and lanterns have been added. One instance with hitGroupId=0 // that all ObjInstance and lanterns have been added. One instance with hitGroupId=0
// is created for every OBJ instance, and one instance with hitGroupId=1 for each lantern. // is created for every OBJ instance, and one instance with hitGroupId=1 for each lantern.
// //
// gl_InstanceCustomIndexEXT will be the index of the instance or lantern in m_objInstance or // gl_InstanceCustomIndexEXT will be the index of the instance or lantern in m_instances or
// m_lanterns respectively. // m_lanterns respectively.
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
assert(m_lanternCount == 0); assert(m_lanternCount == 0);
m_lanternCount = m_lanterns.size(); m_lanternCount = m_lanterns.size();
std::vector<nvvk::RaytracingBuilderKHR::Instance> tlas; std::vector<VkAccelerationStructureInstanceKHR> tlas;
tlas.reserve(m_objInstance.size() + m_lanternCount); tlas.reserve(m_instances.size() + m_lanternCount);
// Add the OBJ instances. // Add the OBJ instances.
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.blasId = m_objInstance[i].objIndex; rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.hitGroupId = 0; // We will use the same hit group for all OBJ
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
// Add lantern instances. // Add lantern instances.
for(int i = 0; i < static_cast<int>(m_lanterns.size()); ++i) for(int i = 0; i < static_cast<int>(m_lanterns.size()); ++i)
{ {
nvvk::RaytracingBuilderKHR::Instance lanternInstance; VkAccelerationStructureInstanceKHR lanternInstance;
lanternInstance.transform = nvmath::translation_mat4(m_lanterns[i].position); lanternInstance.transform = nvvk::toTransformMatrixKHR(nvmath::translation_mat4(m_lanterns[i].position));
lanternInstance.instanceCustomId = i; lanternInstance.instanceCustomIndex = i;
lanternInstance.blasId = m_lanternBlasId; lanternInstance.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(uint32_t(m_lanternBlasId));
lanternInstance.hitGroupId = 1; // Next hit group is for lanterns. lanternInstance.instanceShaderBindingTableRecordOffset = 1; // Next hit group is for lanterns.
lanternInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; lanternInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
lanternInstance.mask = 0xFF;
tlas.emplace_back(lanternInstance); tlas.emplace_back(lanternInstance);
} }
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
```` ````
The principle differences are: The principle differences are:
@ -761,7 +766,7 @@ void HelloVulkan::createRtDescriptorSet()
// ... // ...
// Lantern buffer (binding = 2) // Lantern buffer (binding = 2)
m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, m_rtDescSetLayoutBind.addBinding(eLanterns, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
assert(m_lanternCount > 0); assert(m_lanternCount > 0);
@ -771,7 +776,7 @@ void HelloVulkan::createRtDescriptorSet()
// ... // ...
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, eLanterns, &lanternBufferInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
```` ````
@ -858,7 +863,7 @@ screen. As this is no longer the case for scissor rectangles, we communicate the
size through push constant instead. In addition, we also add to the push constants a number size through push constant instead. In addition, we also add to the push constants a number
indicating which lantern pass is currently being drawn (-1 for the original full screen pass). indicating which lantern pass is currently being drawn (-1 for the original full screen pass).
Modify `m_rtPushConstants` in `hello_vulkan.h`. Modify `m_pcRay` in `hello_vulkan.h`.
```` C ```` C
// Push constant for ray trace pipeline. // Push constant for ray trace pipeline.
@ -883,7 +888,7 @@ Modify `m_rtPushConstants` in `hello_vulkan.h`.
// See m_lanternDebug. // See m_lanternDebug.
int32_t lanternDebug; int32_t lanternDebug;
} m_rtPushConstants; } m_pcRay;
```` ````
We also update the GLSL push constant to match. Since the raygen shader now needs We also update the GLSL push constant to match. Since the raygen shader now needs
@ -1391,14 +1396,14 @@ pass. There are minimal changes from before, we just have to
```` C ```` C
// Initialize push constant values // Initialize push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; m_pcRay.lightPosition = m_pushConstant.lightPosition;
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_pcRay.lightIntensity = m_pushConstant.lightIntensity;
m_rtPushConstants.lightType = m_pushConstant.lightType; m_pcRay.lightType = m_pushConstant.lightType;
m_rtPushConstants.lanternPassNumber = -1; // Global non-lantern pass m_pcRay.lanternPassNumber = -1; // Global non-lantern pass
m_rtPushConstants.screenX = m_size.width; m_pcRay.screenX = m_size.width;
m_rtPushConstants.screenY = m_size.height; m_pcRay.screenY = m_size.height;
m_rtPushConstants.lanternDebug = m_lanternDebug; m_pcRay.lanternDebug = m_lanternDebug;
```` ````
* Update the addresses of the raygen, miss, and hit group sections of the SBT * Update the addresses of the raygen, miss, and hit group sections of the SBT
@ -1457,10 +1462,10 @@ is the first member of `LanternIndirectEntry`.
```` C ```` C
// Set lantern pass number. // Set lantern pass number.
m_rtPushConstants.lanternPassNumber = i; m_pcRay.lanternPassNumber = i;
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant), &m_rtPushConstants); 0, sizeof(RtPushConstant), &m_pcRay);
VkDeviceAddress indirectDeviceAddress = VkDeviceAddress indirectDeviceAddress =

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,3 @@
# NVIDIA Iray Viewer OBJ exporter
#Error: Object scnCamera of type ELEMENT_TYPE_CAMERA cannot be exported
mtllib cube.mtl mtllib cube.mtl
o cube o cube

View file

@ -0,0 +1,41 @@
mtllib cube.mtl
o cube
v -0.5 -0.5 -0.5
v -0.5 -0.5 0.5
v -0.5 0.5 -0.5
v -0.5 0.5 0.5
v 0.5 -0.5 -0.5
v 0.5 -0.5 0.5
v 1.0 1.0 -1.0
v 1.0 1.0 1.0
vn -1 0 0
vn 0 0 1
vn 1 0 0
vn 0 0 -1
vn 0 -1 0
vn 0 1 0
vt 0 0 0
vt 1 0 0
vt 1 1 0
vt 0 1 0
f 1/1/1 2/2/1 4/3/1
f 1/1/1 4/3/1 3/4/1
f 2/1/2 6/2/2 8/3/2
f 2/1/2 8/3/2 4/4/2
f 6/1/3 5/2/3 7/3/3
f 6/1/3 7/3/3 8/4/3
f 5/1/4 1/2/4 3/3/4
f 5/1/4 3/3/4 7/4/4
f 5/1/5 6/2/5 2/3/5
f 5/1/5 2/3/5 1/4/5
f 3/1/6 4/2/6 8/3/6
f 3/1/6 8/3/6 7/4/6

View file

@ -1,7 +1,3 @@
# NVIDIA Iray Viewer OBJ exporter
#Error: Object scnCamera of type ELEMENT_TYPE_CAMERA cannot be exported
mtllib cube_multi.mtl mtllib cube_multi.mtl
o cube o cube

View file

@ -1,7 +1,3 @@
# NVIDIA Iray Viewer OBJ exporter
#Error: Object scnCamera of type ELEMENT_TYPE_CAMERA cannot be exported
mtllib sphere.mtl mtllib sphere.mtl
o sphere_3 o sphere_3

View file

@ -42,18 +42,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -76,16 +64,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay hostUBO.viewProj = proj * view;
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -101,7 +90,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -121,18 +110,19 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, // Obj descriptions
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Textures (binding = 2) // Textures
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Storing implicit obj (binding = 3) // Storing implicit obj (binding = 3)
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, m_descSetLayoutBind.addBinding(eImplicits, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
| VK_SHADER_STAGE_ANY_HIT_BIT_KHR); | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
@ -150,11 +140,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -162,7 +152,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 3, &dbiImplDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 3, &dbiImplDesc));
@ -177,7 +167,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstants)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -237,30 +227,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -270,9 +265,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -281,15 +276,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -375,8 +370,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
m_alloc.destroy(m_implObjects.implBuf); m_alloc.destroy(m_implObjects.implBuf);
m_alloc.destroy(m_implObjects.implMatBuf); m_alloc.destroy(m_implObjects.implMatBuf);
@ -418,15 +413,16 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
uint32_t nbInst = static_cast<uint32_t>(m_objInstance.size() - 1); // Remove the implicit object auto nbInst = static_cast<uint32_t>(m_instances.size() - 1); // Remove the implicit object
for(uint32_t i = 0; i < nbInst; ++i) for(uint32_t i = 0; i < nbInst; ++i)
{ {
auto& inst = m_objInstance[i]; auto& inst = m_instances[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstants.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstants), &m_pushConstants); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -462,7 +458,7 @@ void HelloVulkan::initOffscreen()
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
m_raytrace.createBottomLevelAS(m_objModel, m_implObjects); m_raytrace.createBottomLevelAS(m_objModel, m_implObjects);
m_raytrace.createTopLevelAS(m_objInstance, m_implObjects); m_raytrace.createTopLevelAS(m_instances, m_implObjects);
m_raytrace.createRtDescriptorSet(m_offscreen.colorTexture().descriptor.imageView); m_raytrace.createRtDescriptorSet(m_offscreen.colorTexture().descriptor.imageView);
m_raytrace.createRtPipeline(m_descSetLayout); m_raytrace.createRtPipeline(m_descSetLayout);
} }
@ -473,10 +469,10 @@ void HelloVulkan::initRayTracing()
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
{ {
updateFrame(); updateFrame();
if(m_pushConstants.frame >= m_maxFrames) if(m_pcRaster.frame >= m_maxFrames)
return; return;
m_raytrace.raytrace(cmdBuf, clearColor, m_descSet, m_size, m_pushConstants); m_raytrace.raytrace(cmdBuf, clearColor, m_descSet, m_size, m_pcRaster);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -497,12 +493,12 @@ void HelloVulkan::updateFrame()
refCamMatrix = m; refCamMatrix = m;
refFov = fov; refFov = fov;
} }
m_pushConstants.frame++; m_pcRaster.frame++;
} }
void HelloVulkan::resetFrame() void HelloVulkan::resetFrame()
{ {
m_pushConstants.frame = -1; m_pcRaster.frame = -1;
} }
@ -560,9 +556,13 @@ void HelloVulkan::createImplictBuffers()
m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj"); m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj");
m_debug.setObjectName(m_implObjects.implMatBuf.buffer, "implicitMat"); m_debug.setObjectName(m_implObjects.implMatBuf.buffer, "implicitMat");
// Adding an instance to hold the buffer address of implicit materials
// Adding an extra instance to get access to the material buffers
ObjDesc objDesc{};
objDesc.materialAddress = nvvk::getBufferDeviceAddress(m_device, m_implObjects.implMatBuf.buffer);
m_objDesc.emplace_back(objDesc);
ObjInstance instance{}; ObjInstance instance{};
instance.objIndex = static_cast<uint32_t>(m_objModel.size()); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.materials = nvvk::getBufferDeviceAddress(m_device, m_implObjects.implMatBuf.buffer); m_instances.emplace_back(instance);
m_objInstance.emplace_back(instance);
} }

View file

@ -22,6 +22,7 @@
#include "nvvk/appbase_vk.hpp" #include "nvvk/appbase_vk.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -65,7 +66,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -76,11 +77,22 @@ public:
Raytracer& raytracer() { return m_raytrace; } Raytracer& raytracer() { return m_raytrace; }
ObjPushConstants m_pushConstants; // Information pushed at each draw call
PushConstantRaster m_pcRaster{
{1}, // Identity matrix
{10.f, 15.f, 8.f}, // light position
0, // instance Id
{1, 0, 0}, // lightDirection;
{cos(deg2rad(12.5f))}, // lightSpotCutoff;
{cos(deg2rad(17.5f))}, // lightSpotOuterCutoff;
100.f, // light intensity
0 // light type
};
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
@ -91,18 +103,18 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
int m_maxFrames{10}; int m_maxFrames{500};
void resetFrame(); void resetFrame();
void updateFrame(); void updateFrame();
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::DebugUtil m_debug; // Utility to name objects
Allocator m_alloc; // Allocator for buffer, images, acceleration structures Allocator m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
Offscreen m_offscreen; Offscreen m_offscreen;

View file

@ -59,35 +59,37 @@ void renderUI(HelloVulkan& helloVk)
changed |= ImGuiH::CameraWidget(); changed |= ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstants.lightType, 0); auto& pc = helloVk.m_pcRaster;
changed |= ImGui::RadioButton("Point", &pc.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
changed |= ImGui::RadioButton("Spot", &helloVk.m_pushConstants.lightType, 1); changed |= ImGui::RadioButton("Spot", &pc.lightType, 1);
ImGui::SameLine(); ImGui::SameLine();
changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstants.lightType, 2); changed |= ImGui::RadioButton("Infinite", &pc.lightType, 2);
if(helloVk.m_pushConstants.lightType < 2) if(pc.lightType < 2)
{ {
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, -20.f, 20.f); changed |= ImGui::SliderFloat3("Light Position", &pc.lightPosition.x, -20.f, 20.f);
} }
if(helloVk.m_pushConstants.lightType > 0) if(pc.lightType > 0)
{ {
changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, -1.f, 1.f); changed |= ImGui::SliderFloat3("Light Direction", &pc.lightDirection.x, -1.f, 1.f);
} }
if(helloVk.m_pushConstants.lightType < 2) if(pc.lightType < 2)
{ {
changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f); changed |= ImGui::SliderFloat("Light Intensity", &pc.lightIntensity, 0.f, 500.f);
} }
if(helloVk.m_pushConstants.lightType == 1) if(pc.lightType == 1)
{ {
float dCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotCutoff)); float dCutoff = rad2deg(acos(pc.lightSpotCutoff));
float dOutCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotOuterCutoff)); float dOutCutoff = rad2deg(acos(pc.lightSpotOuterCutoff));
changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f);
changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f);
dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff;
helloVk.m_pushConstants.lightSpotCutoff = cos(deg2rad(dCutoff)); pc.lightSpotCutoff = cos(deg2rad(dCutoff));
helloVk.m_pushConstants.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); pc.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff));
} }
} }
@ -196,20 +198,19 @@ int main(int argc, char** argv)
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
std::normal_distribution<float> dis(2.0f, 2.0f); std::normal_distribution<float> dis(2.0f, 2.0f);
std::normal_distribution<float> disn(0.5f, 0.2f); std::normal_distribution<float> disn(0.5f, 0.2f);
int wusonIndex = static_cast<int>(helloVk.m_objModel.size() - 1); auto wusonIndex = static_cast<int>(helloVk.m_objModel.size() - 1);
for(int n = 0; n < 50; ++n) for(int n = 0; n < 50; ++n)
{ {
ObjInstance inst = helloVk.m_objInstance[wusonIndex]; ObjInstance inst;
inst.objIndex = wusonIndex; inst.objIndex = wusonIndex;
inst.txtOffset = 0;
float scale = fabsf(disn(gen)); float scale = fabsf(disn(gen));
nvmath::mat4f mat = nvmath::translation_mat4(nvmath::vec3f{dis(gen), 0.f, dis(gen) + 6}); nvmath::mat4f mat = nvmath::translation_mat4(nvmath::vec3f{dis(gen), 0.f, dis(gen) + 6});
// mat = mat * nvmath::rotation_mat4_x(dis(gen)); // mat = mat * nvmath::rotation_mat4_x(dis(gen));
mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale)); mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale));
inst.transform = mat; inst.transform = mat;
inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
helloVk.m_objInstance.push_back(inst); helloVk.m_instances.push_back(inst);
} }
// Creation of implicit geometry // Creation of implicit geometry
@ -238,7 +239,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
// #VKRay // #VKRay

View file

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "obj_loader.h" #include "obj_loader.h"
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
{ {
@ -31,31 +32,12 @@ struct ObjModel
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices{0};
VkDeviceAddress indices{0};
VkDeviceAddress materials{0};
VkDeviceAddress materialIndices{0};
}; };
// Information pushed at each draw call
struct ObjPushConstants
{
nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
float lightIntensity{100.f};
nvmath::vec3f lightDirection{-1, -1, -1};
float lightSpotCutoff{cos(deg2rad(12.5f))};
float lightSpotOuterCutoff{cos(deg2rad(17.5f))};
int instanceId{0}; // To retrieve the transformation matrix
int lightType{0}; // 0: point, 1: infinite
int frame{0};
};
enum EObjType enum EObjType
{ {

View file

@ -69,7 +69,7 @@ auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
triangles.indexType = VK_INDEX_TYPE_UINT32; triangles.indexType = VK_INDEX_TYPE_UINT32;
@ -163,26 +163,26 @@ void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst&
tlas.reserve(instances.size()); tlas.reserve(instances.size());
for(uint32_t i = 0; i < nbObj; i++) for(uint32_t i = 0; i < nbObj; i++)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(instances[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(instances[i].transform); // Position of the instance
rayInst.instanceCustomIndex = instances[i].objIndex; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = instances[i].objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(instances[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(instances[i].objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
// Add the blas containing all implicit // Add the blas containing all implicit
if(!implicitObj.objImpl.empty()) if(!implicitObj.objImpl.empty())
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(implicitObj.transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(implicitObj.transform); // Position of the instance
rayInst.instanceCustomIndex = nbObj; // Same for material index rayInst.instanceCustomIndex = instances[nbObj].objIndex;
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(static_cast<uint32_t>(implicitObj.blasId)); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(static_cast<uint32_t>(implicitObj.blasId));
rayInst.instanceShaderBindingTableRecordOffset = 1; // We will use the same hit group for all objects (the second one)
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 1; // We will use the same hit group for all objects (the second one)
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
@ -196,9 +196,9 @@ void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
{ {
using vkDSLB = VkDescriptorSetLayoutBinding; using vkDSLB = VkDescriptorSetLayoutBinding;
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
@ -217,8 +217,8 @@ void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -230,7 +230,7 @@ void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage) void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage)
{ {
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
} }
@ -362,7 +362,7 @@ void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout)
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
| VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR, | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
0, sizeof(RtPushConstants)}; 0, sizeof(PushConstantRay)};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -408,18 +408,18 @@ void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
const nvmath::vec4f& clearColor, const nvmath::vec4f& clearColor,
VkDescriptorSet& sceneDescSet, VkDescriptorSet& sceneDescSet,
VkExtent2D& size, VkExtent2D& size,
ObjPushConstants& sceneConstants) PushConstantRaster& sceneConstants)
{ {
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = sceneConstants.lightPosition; m_pcRay.lightPosition = sceneConstants.lightPosition;
m_rtPushConstants.lightIntensity = sceneConstants.lightIntensity; m_pcRay.lightIntensity = sceneConstants.lightIntensity;
m_rtPushConstants.lightDirection = sceneConstants.lightDirection; m_pcRay.lightDirection = sceneConstants.lightDirection;
m_rtPushConstants.lightSpotCutoff = sceneConstants.lightSpotCutoff; m_pcRay.lightSpotCutoff = sceneConstants.lightSpotCutoff;
m_rtPushConstants.lightSpotOuterCutoff = sceneConstants.lightSpotOuterCutoff; m_pcRay.lightSpotOuterCutoff = sceneConstants.lightSpotOuterCutoff;
m_rtPushConstants.lightType = sceneConstants.lightType; m_pcRay.lightType = sceneConstants.lightType;
m_rtPushConstants.frame = sceneConstants.frame; m_pcRay.frame = sceneConstants.frame;
std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet}; std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet};
@ -429,7 +429,7 @@ void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
| VK_SHADER_STAGE_CALLABLE_BIT_KHR, | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
0, sizeof(RtPushConstants), &m_rtPushConstants); 0, sizeof(PushConstantRay), &m_pcRay);
auto& regions = m_sbtWrapper.getRegions(); auto& regions = m_sbtWrapper.getRegions();

View file

@ -24,6 +24,8 @@
#include "nvvk/sbtwrapper_vk.hpp" #include "nvvk/sbtwrapper_vk.hpp"
#include "obj.hpp" #include "obj.hpp"
#include "shaders/host_device.h"
class Raytracer class Raytracer
{ {
public: public:
@ -41,7 +43,7 @@ public:
const nvmath::vec4f& clearColor, const nvmath::vec4f& clearColor,
VkDescriptorSet& sceneDescSet, VkDescriptorSet& sceneDescSet,
VkExtent2D& size, VkExtent2D& size,
ObjPushConstants& sceneConstants); PushConstantRaster& sceneConstants);
private: private:
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
@ -62,15 +64,6 @@ private:
VkPipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstants
{ PushConstantRay m_pcRay{};
nvmath::vec4f clearColor;
nvmath::vec3f lightPosition;
float lightIntensity{100.0f};
nvmath::vec3f lightDirection{-1, -1, -1};
float lightSpotCutoff{deg2rad(12.5f)};
float lightSpotOuterCutoff{deg2rad(17.5f)};
int lightType{0};
int frame{0};
} m_rtPushConstants;
}; };

View file

@ -29,91 +29,86 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
float lightIntensity; };
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
uint instanceId;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 LightDir; vec3 LightDir;
float lightIntensity; float lightIntensity;
// Point light // Point light
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float lightDistance = length(lDir); float lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance);
LightDir = normalize(lDir); LightDir = normalize(lDir);
} }
else if(pushC.lightType == 1) else if(pcRaster.lightType == 1)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float lightDistance = length(lDir); float lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance);
LightDir = normalize(lDir); LightDir = normalize(lDir);
float theta = dot(LightDir, normalize(-pushC.lightDirection)); float theta = dot(LightDir, normalize(-pcRaster.lightDirection));
float epsilon = pushC.lightSpotCutoff - pushC.lightSpotOuterCutoff; float epsilon = pcRaster.lightSpotCutoff - pcRaster.lightSpotOuterCutoff;
float spotIntensity = clamp((theta - pushC.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); float spotIntensity = clamp((theta - pcRaster.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
lightIntensity *= spotIntensity; lightIntensity *= spotIntensity;
} }
else // Directional light else // Directional light
{ {
LightDir = normalize(-pushC.lightDirection); LightDir = normalize(-pcRaster.lightDirection);
lightIntensity = 1.0; lightIntensity = 1.0;
} }
// Diffuse // Diffuse
vec3 diffuse = computeDiffuse(mat, LightDir, N); vec3 diffuse = computeDiffuse(mat, LightDir, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, LightDir, N); vec3 specular = computeSpecular(mat, i_viewDir, LightDir, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2, // Access to textures
eImplicits = 3 // Implicit objects
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
float lightIntensity;
int lightType;
int frame;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
uint objIndex;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
float lightIntensity;
int lightType;
int frame;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -20,24 +20,21 @@
#version 460 core #version 460 core
#extension GL_EXT_ray_tracing : enable #extension GL_EXT_ray_tracing : enable
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "host_device.h"
layout(location = 3) callableDataInEXT rayLight cLight; layout(location = 3) callableDataInEXT rayLight cLight;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
}; };
void main() void main()
{ {
cLight.outLightDistance = 10000000; cLight.outLightDistance = 10000000;
cLight.outIntensity = 1.0; cLight.outIntensity = 1.0;
cLight.outLightDir = normalize(-lightDirection); cLight.outLightDir = normalize(-pcRay.lightDirection);
} }

View file

@ -20,25 +20,23 @@
#version 460 core #version 460 core
#extension GL_EXT_ray_tracing : enable #extension GL_EXT_ray_tracing : enable
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "host_device.h"
layout(location = 3) callableDataInEXT rayLight cLight; layout(location = 3) callableDataInEXT rayLight cLight;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
}; };
void main() void main()
{ {
vec3 lDir = lightPosition - cLight.inHitPosition; vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
cLight.outLightDistance = length(lDir); cLight.outLightDistance = length(lDir);
cLight.outIntensity = lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
cLight.outLightDir = normalize(lDir); cLight.outLightDir = normalize(lDir);
} }

View file

@ -20,29 +20,26 @@
#version 460 core #version 460 core
#extension GL_EXT_ray_tracing : enable #extension GL_EXT_ray_tracing : enable
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "host_device.h"
layout(location = 3) callableDataInEXT rayLight cLight; layout(location = 3) callableDataInEXT rayLight cLight;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
}; };
void main() void main()
{ {
vec3 lDir = lightPosition - cLight.inHitPosition; vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
cLight.outLightDistance = length(lDir); cLight.outLightDistance = length(lDir);
cLight.outIntensity = lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
cLight.outLightDir = normalize(lDir); cLight.outLightDir = normalize(lDir);
float theta = dot(cLight.outLightDir, normalize(-lightDirection)); float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection));
float epsilon = lightSpotCutoff - lightSpotOuterCutoff; float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff;
float spotIntensity = clamp((theta - lightSpotOuterCutoff) / epsilon, 0.0, 1.0); float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
cLight.outIntensity *= spotIntensity; cLight.outIntensity *= spotIntensity;
} }

View file

@ -36,13 +36,13 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
// clang-format on // clang-format on
void main() void main()
{ {
// Object of this instance // Object of this instance
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);

View file

@ -22,7 +22,6 @@
#extension GL_EXT_nonuniform_qualifier : enable #extension GL_EXT_nonuniform_qualifier : enable
#extension GL_EXT_scalar_block_layout : enable #extension GL_EXT_scalar_block_layout : enable
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_buffer_reference2 : require #extension GL_EXT_buffer_reference2 : require
@ -39,22 +38,13 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2, set = 1) uniform sampler2D textureSamplers[]; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
// clang-format on // clang-format on
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
}
pushC;
layout(location = 3) callableDataEXT rayLight cLight; layout(location = 3) callableDataEXT rayLight cLight;
@ -62,7 +52,7 @@ layout(location = 3) callableDataEXT rayLight cLight;
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
Indices indices = Indices(objResource.indexAddress); Indices indices = Indices(objResource.indexAddress);
@ -81,45 +71,44 @@ void main()
// Computing the normal at hit position // Computing the normal at hit position
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
// Transforming the normal to world space // Transforming the normal to world space
normal = normalize(vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0))); normal = normalize(vec3(normal * gl_WorldToObjectEXT));
// Computing the coordinates of the hit position // Computing the coordinates of the hit position
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
// Transforming the position to world space // Transforming the position to world space
worldPos = vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0)); worldPos = vec3(gl_ObjectToWorldEXT * vec4(worldPos, 1.0));
cLight.inHitPosition = worldPos; cLight.inHitPosition = worldPos;
//#define DONT_USE_CALLABLE //#define DONT_USE_CALLABLE
#if defined(DONT_USE_CALLABLE) #if defined(DONT_USE_CALLABLE)
// Point light // Point light
if(pushC.lightType == 0) if(pcRay.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - cLight.inHitPosition; vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
float lightDistance = length(lDir); float lightDistance = length(lDir);
cLight.outIntensity = pushC.lightIntensity / (lightDistance * lightDistance); cLight.outIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
cLight.outLightDir = normalize(lDir); cLight.outLightDir = normalize(lDir);
cLight.outLightDistance = lightDistance; cLight.outLightDistance = lightDistance;
} }
else if(pushC.lightType == 1) else if(pcRay.lightType == 1)
{ {
vec3 lDir = pushC.lightPosition - cLight.inHitPosition; vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
cLight.outLightDistance = length(lDir); cLight.outLightDistance = length(lDir);
cLight.outIntensity = pushC.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
cLight.outLightDir = normalize(lDir); cLight.outLightDir = normalize(lDir);
float theta = dot(cLight.outLightDir, normalize(-pushC.lightDirection)); float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection));
float epsilon = pushC.lightSpotCutoff - pushC.lightSpotOuterCutoff; float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff;
float spotIntensity = clamp((theta - pushC.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
cLight.outIntensity *= spotIntensity; cLight.outIntensity *= spotIntensity;
} }
else // Directional light else // Directional light
{ {
cLight.outLightDir = normalize(-pushC.lightDirection); cLight.outLightDir = normalize(-pcRay.lightDirection);
cLight.outIntensity = 1.0; cLight.outIntensity = 1.0;
cLight.outLightDistance = 10000000; cLight.outLightDistance = 10000000;
} }
#else #else
executeCallableEXT(pushC.lightType, 3); executeCallableEXT(pcRay.lightType, 3);
#endif #endif
// Material of the object // Material of the object
@ -131,7 +120,7 @@ void main()
vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal); vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
uint txtId = mat.textureId + sceneDesc.i[gl_InstanceCustomIndexEXT].txtOffset; uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
} }
@ -183,6 +172,5 @@ void main()
prd.rayDir = rayDir; prd.rayDir = rayDir;
} }
prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular)); prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular));
} }

View file

@ -20,42 +20,27 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "random.glsl" #include "random.glsl"
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; // clang-format off
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
layout(location = 0) rayPayloadEXT hitPayload prd; layout(location = 0) rayPayloadEXT hitPayload prd;
layout(binding = 0, set = 1) uniform CameraProperties layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
{ layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
mat4 view; layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
mat4 proj; layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
mat4 viewInverse; // clang-format on
mat4 projInverse;
}
cam;
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
int frame;
}
pushC;
const int NBSAMPLES = 5; const int NBSAMPLES = 5;
void main() void main()
{ {
// Initialize the random number // Initialize the random number
uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pushC.frame * NBSAMPLES); uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame * NBSAMPLES);
prd.seed = seed; prd.seed = seed;
vec3 hitValues = vec3(0); vec3 hitValues = vec3(0);
@ -67,7 +52,7 @@ void main()
float r2 = rnd(seed); float r2 = rnd(seed);
// Subpixel jitter: send the ray through a different position inside the pixel // Subpixel jitter: send the ray through a different position inside the pixel
// each time, to provide antialiasing. // each time, to provide antialiasing.
vec2 subpixel_jitter = pushC.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2);
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter;
@ -75,9 +60,9 @@ void main()
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0; vec2 d = inUV * 2.0 - 1.0;
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1); vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1); vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0); vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
uint rayFlags = gl_RayFlagsNoneEXT; uint rayFlags = gl_RayFlagsNoneEXT;
float tMin = 0.001; float tMin = 0.001;
@ -120,9 +105,9 @@ void main()
prd.hitValue = hitValues / NBSAMPLES; prd.hitValue = hitValues / NBSAMPLES;
// Do accumulation over time // Do accumulation over time
if(pushC.frame >= 0) if(pcRay.frame >= 0)
{ {
float a = 1.0f / float(pushC.frame + 1); float a = 1.0f / float(pcRay.frame + 1);
vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz;
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f));
} }

View file

@ -30,7 +30,7 @@
hitAttributeEXT vec3 HitAttribute; hitAttributeEXT vec3 HitAttribute;
layout(binding = 3, set = 1, scalar) buffer allImpl_ layout(set = 1, binding = eImplicits, scalar) buffer allImpl_
{ {
Implicit i[]; Implicit i[];
} }
@ -77,6 +77,7 @@ float hitAabb(const Aabb aabb, const Ray r)
void main() void main()
{ {
Ray ray; Ray ray;
ray.origin = gl_WorldRayOriginEXT; ray.origin = gl_WorldRayOriginEXT;
ray.direction = gl_WorldRayDirectionEXT; ray.direction = gl_WorldRayDirectionEXT;

View file

@ -20,16 +20,19 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(location = 0) rayPayloadInEXT hitPayload prd; layout(location = 0) rayPayloadInEXT hitPayload prd;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
}; };
void main() void main()
{ {
prd.hitValue = clearColor.xyz * 0.8; prd.hitValue = pcRay.clearColor.xyz * 0.8;
} }

View file

@ -36,8 +36,8 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 3, set = 1, scalar) buffer allImplicits_ {Implicit i[];} allImplicits; layout(set = 1, binding = eImplicits, scalar) buffer allImplicits_ {Implicit i[];} allImplicits;
// clang-format on // clang-format on
void main() void main()
@ -45,7 +45,7 @@ void main()
// Material of the object // Material of the object
Implicit impl = allImplicits.i[gl_PrimitiveID]; Implicit impl = allImplicits.i[gl_PrimitiveID];
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
WaveFrontMaterial mat = materials.m[impl.matId]; WaveFrontMaterial mat = materials.m[impl.matId];

View file

@ -41,22 +41,12 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 3, set = 1, scalar) buffer allImplicits_ {Implicit i[];} allImplicits; layout(set = 1, binding = eImplicits, scalar) buffer allImplicits_ {Implicit i[];} allImplicits;
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
// clang-format on // clang-format on
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
}
pushC;
layout(location = 3) callableDataEXT rayLight cLight; layout(location = 3) callableDataEXT rayLight cLight;
@ -92,10 +82,10 @@ void main()
} }
cLight.inHitPosition = worldPos; cLight.inHitPosition = worldPos;
executeCallableEXT(pushC.lightType, 3); executeCallableEXT(pcRay.lightType, 3);
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
WaveFrontMaterial mat = materials.m[impl.matId]; WaveFrontMaterial mat = materials.m[impl.matId];

View file

@ -26,41 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
float lightIntensity; };
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
uint instanceId;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -70,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -1,8 +1,142 @@
# NVIDIA Vulkan Ray Tracing Tutorial # NVIDIA Vulkan Ray Tracing Tutorial
This example is a simple OBJ viewer in Vulkan, without any ray tracing functionality. This sample is a simple OBJ viewer in Vulkan, without any ray tracing functionality.
It is the starting point of the ray tracing tutorial, the source of the application in which ray tracing will be added. It is the starting point of the [ray tracing tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/),
the source of the application where ray tracing will be added.
![](images/vk_ray_tracing__before.png)
## [**Start Ray Tracing Tutorial**](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/) Before starting the tutorial and adding what is necessary to enable ray tracing, here is a brief description of how this basic example was created.
## Structure
![resultRaytraceShadowMedieval](../docs/Images/resultRasterCube.png) * main.cpp : creates a Vulkan context, call for loading OBJ files, drawing loop
* hello_vulkan.[cpp|h]: example class that loads and store OBJ in Vulkan buffers, load textures, creates pipelines and render the scene
* [nvvk](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk): library of independent Vulkan helpers.
## Overview
The following describes the function calls in main(). The helpers will not be described here, but following the link should give more details on how they work.
### Window and Vulkan Setup
* Creates a window using [GLFW](https://www.glfw.org/).
* Creates a Vulkan context using the [`nvvk::Context`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#context_vkhpp)
helper. The result is a `VkInstance`, `VkDevice`, `VkPhisicalDevice`, the queues and the extensions initialized.
* The window was created, but not the surface to draw in this window. This is done using the information from `VkInstance` and `GLFWwindow`. The
`VkSurfaceKHR` will be used to find the proper queue.
### Sample Setup
* Hello vulkan setup:
* [base] Keep a copy of `VkInstance`, `VkDevice`, `VkPhysicalDevice` and graphics Queue Index.
* [base] Create a command pool
* Initialize the [Vulkan resource allocator](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#resourceallocator_vkhpp) (nvvk::alloc).
* Create Swapchain [base]:
* Using the base class method and the help of [`nvvk::Swapchain`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#swapchain_vkhpp),
initialize the swapchain for rendering onto the surface.
* Finds the surface color and depth format.
* Create *n* `VkFence` for synchronization.
* Create depth buffer [base]: depth buffer image with the format query in the swapchain
* Create render pass [base]:
* Simple render pass, with two attachments: color and depth
* Using swapchain color and depth format.
* Create frame buffers [base]:
* Create *n images* of the number returned by the swapchain
* Create as many frame buffers and attach the images
* Initialize GUI [base]: we are using [Dear ImGui](https://github.com/ocornut/imgui) and
this is doing the initialization for Vulkan.
* Loading [Wavefront .obj file](https://en.wikipedia.org/wiki/Wavefront_.obj_file):
* This is a very simple format, but it allows us to make manual modifications in the file, to load several .obj files and to combine them to obtain a more complex scene. We can also easily create several instances of the loaded objects.
* Loading the .obj is done through the [ObjLoader](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/3e399adf0a3e991795fbdf91e0e6c23b9f492bb8/common/obj_loader.cpp#L26) which is using [tinyobjloader](https://github.com/tinyobjloader/tinyobjloader).
* All vertices are in the form of: position, normal, color, texture coordinates
* Every 3 vertex indices are creating a triangle.
* Every triangle has an index of the material it is using.
* There are M materials and T textures.
* We allocate buffers and staging the transfer to the GPU using our resource allocator.
* We create an instance of the loaded model.
* :warning: We keep the addresses of the created buffers and append this to a vector of `ObjDesc`, which allows easy access to the model information from a shader.
### Offscreen image & Graphic Pipeline
We have a swapchain and window frame buffers, but we will not render the scene directly to them. Instead, we will render to an RGBA32F image, and then render that image to a full screen triangle using a tone mapper. We could have rendered directly to one of the swapchain framebuffers and applied a tone mapper, but this separation will be very useful for rendering G-Buffers and doing something similar with ray tracing.
* Create offscreen render:
* Create a color and depth image, format are VK_FORMAT_R32G32B32A32_SFLOAT and best depth for the physical device using [`nvvk::findDepthFormat`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#renderpasses_vkhpp).
* Create a render pass to render using those images [`nvvk::createRenderPass`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#renderpasses_vkhpp).
* Create a frame buffer, to use as a target when rendering offline.
* Create descriptor set layout:
* Using the [`nvvk::DescriptorSetBindings`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkdescriptorsetbindings), describing the resources that will be used in the vertex and fragment shader.
* Create graphic pipeline:
* Using [`nvvk::GraphicsPipelineGeneratorCombined`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkgraphicspipelinegeneratorcombined)
* Load both vertex and fragment SpirV shaders
* Describe the vertex attributes: pos, nrm, color, uv
* Create uniform buffer:
* The uniform buffer is holding global scene information and is updated at each frame.
* The information in this sample consist of camera matrices and will be
updated in the drawing loop using `updateUniformBuffer()`.
* Create Obj description buffer:
* When loading .obj, we stored the addresses of the OBJ buffers.
* If we have loaded many .obj, the array will be as large as the number of obj loaded.
* Each instance has the index of the OBJ, therefore the information of the model will be easily retrievable in the shader.
* This function creates the buffer holding the vector of `ObjDesc`.
* Update descriptor set:
* The descriptor set has been created, but here we are writing the information, meaning all the buffers and textures we have created.
At this point, the OBJs are loaded and their information is uploaded to the GPU. The graphic pipeline and the information describing the resources are also created.
### Post Pipeline
We need to create a "post pipeline". This is specific to the raster of this sample. As mentioned before, we render in a full screen triangle, the result of the raster and apply a tonemapper. This step will be rendered directly into the framebuffer of the swapchain.
![](images/base_pipeline.png)
* Create post descriptor:
* Adding the image input (result of rendering)
* Create post pipeline:
* Passtrough vertex shader (full screen triangle)
* Fragment tone-mapper shader
* Update post descriptor:
* Writing the image (RGB32F) address
At this point we are ready to start the rendering loop.
* Setup Glfw callback:
* Our base class has many functions to react on Glfw, such as change of window size, mouse and keyboard inputs.
* All callback functions are virtual, which allow to override the base functionality, but for most there isn't anything to do.
* Except for `onResize`, since we render to an intermediate image (RGB32F), this image will need to be re-created with the new size and the post pipeline will need the address of this image. Therefore, there is an overload of this function.
### Rendering Loop
* Render indefinitely until Glfw receive a close action
* Glfw pulling events
* Imgui new frame and rendering (not drawing)
* Prepare Frame
* This is part of the swapchain, we can have a double or triple buffer and
this call will be waiting (fence) to make sure that one swapchain frame buffer
is available.
* Get current frame
* Depending if we have a double or triple buffer, it will return: 0 or 1, or 0, 1 or 2.
* Resources in the base class exist in that amount: color images, frame buffer, command buffer, fence
* Get the command buffer for the current frame (better to re-use command buffers than creating new ones)
* Update the uniform buffer:
* Push the current camera matrices
#### Offscreen
* Start offscreen rendering pass
* We will be rendering (raster) in the RGBA32F image using the offscreen render pass and frame buffer.
* Rasterize
* This is rasterizing the entire scene, all instances of each object.
#### Final
Start another rendering, this time in the swapchain frame buffer
* Use the base class render pass
* Use the swapchain frame buffer
* Render a full-screen triangle with the raster image and tone-mapping it.
* Actually rendering Imgui in Vulkan
* Submit the frame for execution and display
### Clean up
The rest is clean up all allocations

View file

@ -40,14 +40,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -67,14 +59,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
hostUBO.viewProj = proj * view;
hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -90,7 +85,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -110,12 +105,15 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); // Obj descriptions
// Textures (binding = 2) m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT); VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Textures
m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
@ -131,11 +129,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -143,7 +141,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -155,7 +153,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -213,30 +211,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | flag); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | flag);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -246,9 +249,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -257,15 +260,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -351,8 +354,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -397,14 +400,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Simple rasterizer of OBJ objects // Simple rasterizer of OBJ objects
@ -41,7 +42,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -59,32 +60,27 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices;
VkDeviceAddress indices;
VkDeviceAddress materials;
VkDeviceAddress materialIndices;
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // Identity matrix
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // light position
int instanceId{0}; // To retrieve the transformation matrix 0, // instance Id
float lightIntensity{100.f}; 100.f, // light intensity
int lightType{0}; // 0: point, 1: infinite 0 // light type
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -94,8 +90,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -104,7 +100,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -56,12 +56,12 @@ void renderUI(HelloVulkan& helloVk)
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
} }
} }
@ -156,7 +156,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
helloVk.createPostDescriptor(); helloVk.createPostDescriptor();

View file

@ -29,62 +29,55 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Object of this instance
int objId = sceneDesc.i[pushC.instanceId].objId;
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRaster.lightIntensity;
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float d = length(lDir); float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d); lightIntensity = pcRaster.lightIntensity / (d * d);
L = normalize(lDir); L = normalize(lDir);
} }
else else
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRaster.lightPosition);
} }
@ -92,15 +85,15 @@ void main()
vec3 diffuse = computeDiffuse(mat, L, N); vec3 diffuse = computeDiffuse(mat, L, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, L, N); vec3 specular = computeSpecular(mat, i_viewDir, L, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -26,38 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -67,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -39,18 +39,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -70,16 +58,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay hostUBO.viewProj = proj * view;
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -95,7 +84,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -115,13 +104,14 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, // Obj descriptions
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Textures (binding = 2) // Textures
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
@ -138,11 +128,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -150,7 +140,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -162,7 +152,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -222,30 +212,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -255,9 +250,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -266,15 +261,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -360,8 +355,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -415,14 +410,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -612,7 +607,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Describe buffer as array of VertexObj. // Describe buffer as array of VertexObj.
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
@ -661,19 +656,22 @@ void HelloVulkan::createBottomLevelAS()
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
std::vector<VkAccelerationStructureInstanceKHR> tlas; std::vector<VkAccelerationStructureInstanceKHR> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_instances.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
@ -684,11 +682,10 @@ void HelloVulkan::createTopLevelAS()
// //
void HelloVulkan::createRtDescriptorSet() void HelloVulkan::createRtDescriptorSet()
{ {
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays)
// shoot shadow rays) m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
@ -708,8 +705,8 @@ void HelloVulkan::createRtDescriptorSet()
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -722,7 +719,7 @@ void HelloVulkan::updateRtDescriptorSet()
{ {
// (1) Output buffer // (1) Output buffer
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
} }
@ -794,7 +791,7 @@ void HelloVulkan::createRtPipeline()
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant)}; 0, sizeof(PushConstantRay)};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -866,7 +863,7 @@ void HelloVulkan::createRtShaderBindingTable()
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
| VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT"));
// Map the SBT buffer and write in the handles. // Map the SBT buffer and write in the handles.
void* mapped = m_alloc.map(m_rtSBTBuffer); void* mapped = m_alloc.map(m_rtSBTBuffer);
@ -887,11 +884,10 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
{ {
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; m_pcRay.lightPosition = m_pcRaster.lightPosition;
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_pcRay.lightIntensity = m_pcRaster.lightIntensity;
m_rtPushConstants.lightType = m_pushConstant.lightType; m_pcRay.lightType = m_pcRaster.lightType;
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet}; std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
@ -899,14 +895,15 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
(uint32_t)descSets.size(), descSets.data(), 0, nullptr); (uint32_t)descSets.size(), descSets.data(), 0, nullptr);
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant), &m_rtPushConstants); 0, sizeof(PushConstantRay), &m_pcRay);
// Size of a program identifier // Size of a program identifier
uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
uint32_t groupStride = groupSize; uint32_t groupStride = groupSize;
VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer};
VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info);
using Stride = VkStridedDeviceAddressRegionKHR; using Stride = VkStridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen std::array<Stride, 4> strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -44,7 +45,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -62,32 +63,27 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices{0};
VkDeviceAddress indices{0};
VkDeviceAddress materials{0};
VkDeviceAddress materialIndices{0};
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // Identity matrix
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // light position
int instanceId{0}; // To retrieve the transformation matrix 0, // instance Id
float lightIntensity{100.f}; 100.f, // light intensity
int lightType{0}; // 0: point, 1: infinite 0 // light type
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -97,8 +93,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -107,7 +103,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
@ -150,11 +146,6 @@ public:
VkPipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstant // Push constant for ray tracer
{ PushConstantRay m_pcRay{};
nvmath::vec4f clearColor;
nvmath::vec3f lightPosition;
float lightIntensity{100.0f};
int lightType{0};
} m_rtPushConstants;
}; };

View file

@ -56,12 +56,12 @@ void renderUI(HelloVulkan& helloVk)
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
} }
} }
@ -164,7 +164,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
// #VKRay // #VKRay

View file

@ -29,59 +29,55 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRaster.lightIntensity;
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float d = length(lDir); float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d); lightIntensity = pcRaster.lightIntensity / (d * d);
L = normalize(lDir); L = normalize(lDir);
} }
else else
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRaster.lightPosition);
} }
@ -89,15 +85,15 @@ void main()
vec3 diffuse = computeDiffuse(mat, L, N); vec3 diffuse = computeDiffuse(mat, L, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, L, N); vec3 specular = computeSpecular(mat, i_viewDir, L, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -39,25 +39,18 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2, set = 1) uniform sampler2D textureSamplers[]; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
// clang-format on
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
{ // clang-format on
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
}
pushC;
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
Indices indices = Indices(objResource.indexAddress); Indices indices = Indices(objResource.indexAddress);
@ -73,32 +66,29 @@ void main()
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
// Computing the normal at hit position
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
// Transforming the normal to world space
normal = normalize(vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0)));
// Computing the coordinates of the hit position // Computing the coordinates of the hit position
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
// Transforming the position to world space const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
worldPos = vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0));
// Computing the normal at hit position
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
// Vector toward the light // Vector toward the light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRay.lightIntensity;
float lightDistance = 100000.0; float lightDistance = 100000.0;
// Point light // Point light
if(pushC.lightType == 0) if(pcRay.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRay.lightPosition - worldPos;
lightDistance = length(lDir); lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
L = normalize(lDir); L = normalize(lDir);
} }
else // Directional light else // Directional light
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRay.lightPosition);
} }
// Material of the object // Material of the object
@ -107,10 +97,10 @@ void main()
// Diffuse // Diffuse
vec3 diffuse = computeDiffuse(mat, L, normal); vec3 diffuse = computeDiffuse(mat, L, worldNrm);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
uint txtId = mat.textureId + sceneDesc.i[gl_InstanceCustomIndexEXT].txtOffset; uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
} }
@ -119,7 +109,7 @@ void main()
float attenuation = 1; float attenuation = 1;
// Tracing shadow ray only if the light is visible from the surface // Tracing shadow ray only if the light is visible from the surface
if(dot(normal, L) > 0) if(dot(worldNrm, L) > 0)
{ {
float tMin = 0.001; float tMin = 0.001;
float tMax = lightDistance; float tMax = lightDistance;
@ -147,7 +137,7 @@ void main()
else else
{ {
// Specular // Specular
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm);
} }
} }

View file

@ -20,21 +20,21 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "host_device.h"
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; // clang-format off
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
layout(location = 0) rayPayloadEXT hitPayload prd; layout(location = 0) rayPayloadEXT hitPayload prd;
layout(binding = 0, set = 1) uniform CameraProperties layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
{ layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
mat4 view; layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
mat4 proj; layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
mat4 viewInverse; // clang-format on
mat4 projInverse;
}
cam;
void main() void main()
{ {
@ -42,9 +42,9 @@ void main()
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0; vec2 d = inUV * 2.0 - 1.0;
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1); vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1); vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0); vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
uint rayFlags = gl_RayFlagsOpaqueEXT; uint rayFlags = gl_RayFlagsOpaqueEXT;
float tMin = 0.001; float tMin = 0.001;

View file

@ -20,16 +20,19 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(location = 0) rayPayloadInEXT hitPayload prd; layout(location = 0) rayPayloadInEXT hitPayload prd;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
}; };
void main() void main()
{ {
prd.hitValue = clearColor.xyz * 0.8; prd.hitValue = pcRay.clearColor.xyz * 0.8;
} }

View file

@ -26,38 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -67,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -11,10 +11,8 @@ This sample introduces the [VK_KHR_pipeline_library](https://www.khronos.org/reg
The code below is based on the [`ray_tracing_specialization`](../ray_tracing_specialization) sample, which introduces compile-time variations of a hit shader. The code below is based on the [`ray_tracing_specialization`](../ray_tracing_specialization) sample, which introduces compile-time variations of a hit shader.
## Pipeline Library ## Pipeline Library
Using monolithic pipeline definitions all stages are compiled for each pipeline, regardless of potential reuse. The shader groups are then referenced in the Shader Binding Table using their indices: Using monolithic pipeline definitions all stages are compiled for each pipeline, regardless of potential reuse. The shader groups are then referenced in the Shader Binding Table using their indices:
![](images/regular_pipeline.png) ![](images/regular_pipeline.png)
@ -22,17 +20,20 @@ Pipeline libraries are `VkPipeline` objects that cannot be bound directly. Inste
![](images/library.png) ![](images/library.png)
We start by adding the device extension in main() We start by adding the device extension in main()
~~~~ C ~~~~ C
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
~~~~ ~~~~
Following by adding a new member in the `HelloVulkan` class: Following by adding a new member in the `HelloVulkan` class:
~~~~ C ~~~~ C
// Ray tracing shader library // Ray tracing shader library
VkPipeline m_rtShaderLibrary; VkPipeline m_rtShaderLibrary;
~~~~ ~~~~
In `HelloVulkan::createRtPipeline()` the `StageIndices` enumeration describes the indices of the stages defined in the pipeline creation structure. The hit groups will be moved to our library, hence we remove them from the enumeration: In `HelloVulkan::createRtPipeline()` the `StageIndices` enumeration describes the indices of the stages defined in the pipeline creation structure. The hit groups will be moved to our library, hence we remove them from the enumeration:
~~~~ C ~~~~ C
enum StageIndices enum StageIndices
{ {
@ -44,16 +45,20 @@ In `HelloVulkan::createRtPipeline()` the `StageIndices` enumeration describes th
~~~~ ~~~~
The shader modules will be referenced partly in the main pipeline, and partly in the pipeline library. To ensure proper deletion of the modules after use, we will store their handles in The shader modules will be referenced partly in the main pipeline, and partly in the pipeline library. To ensure proper deletion of the modules after use, we will store their handles in
~~~~ C ~~~~ C
// Store the created modules for later cleanup // Store the created modules for later cleanup
std::vector<VkShaderModule> modules; std::vector<VkShaderModule> modules;
~~~~ ~~~~
Then, after each call to `nvvk::createShaderModule` we store the resulting module: Then, after each call to `nvvk::createShaderModule` we store the resulting module:
~~~~ C ~~~~ C
modules.push_back(stage.module); modules.push_back(stage.module);
~~~~ ~~~~
The specialization constants sample creates one shader module per specialization. Instead, we load that module once and reuse it for each specialization. Those specializations are then stored in the stages of the pipeline library: The specialization constants sample creates one shader module per specialization. Instead, we load that module once and reuse it for each specialization. Those specializations are then stored in the stages of the pipeline library:
~~~~ C ~~~~ C
// Hit Group - Closest Hit // Hit Group - Closest Hit
// Create many variation of the closest hit // Create many variation of the closest hit
@ -72,6 +77,7 @@ The specialization constants sample creates one shader module per specialization
~~~~ ~~~~
Similarly, the hit groups will be stored in the library by replacing the storage of the hit groups in `m_rtShaderGroups` by: Similarly, the hit groups will be stored in the library by replacing the storage of the hit groups in `m_rtShaderGroups` by:
~~~~ C ~~~~ C
// Shader groups for the pipeline library containing the closest hit shaders // Shader groups for the pipeline library containing the closest hit shaders
std::vector<VkRayTracingShaderGroupCreateInfoKHR> libraryShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> libraryShaderGroups;
@ -92,9 +98,11 @@ Similarly, the hit groups will be stored in the library by replacing the storage
libraryShaderGroups.push_back(libraryGroup); libraryShaderGroups.push_back(libraryGroup);
} }
~~~~ ~~~~
It is important to note that the stage indices are local to the pipeline library, regardless of where they will be used in the final pipeline. Those indices will be later offset depending on the contents of the pipeline. It is important to note that the stage indices are local to the pipeline library, regardless of where they will be used in the final pipeline. Those indices will be later offset depending on the contents of the pipeline.
Once the groups and stages are defined we can create the pipeline library. After the creation of the ray tracing pipeline layout, we define the base of the library creation information: Once the groups and stages are defined we can create the pipeline library. After the creation of the ray tracing pipeline layout, we define the base of the library creation information:
~~~~ C ~~~~ C
// Creation of the pipeline library object // Creation of the pipeline library object
VkRayTracingPipelineCreateInfoKHR pipelineLibraryInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; VkRayTracingPipelineCreateInfoKHR pipelineLibraryInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
@ -105,9 +113,11 @@ Once the groups and stages are defined we can create the pipeline library. After
// As for the interface the maximum recursion depth must also be consistent across the pipeline // As for the interface the maximum recursion depth must also be consistent across the pipeline
pipelineLibraryInfo.maxPipelineRayRecursionDepth = 2; pipelineLibraryInfo.maxPipelineRayRecursionDepth = 2;
~~~~ ~~~~
Pipeline libraries are technically independent from the pipeline they will be linked into. However, linking can only be achieved by enforcing strong consistency constraints, such as having the same pipeline layout and maximum recursion depth. If the recursion depth differs the compilation of the final pipeline will fail. Pipeline libraries are technically independent from the pipeline they will be linked into. However, linking can only be achieved by enforcing strong consistency constraints, such as having the same pipeline layout and maximum recursion depth. If the recursion depth differs the compilation of the final pipeline will fail.
In addition, the pipeline libraries need to have the same pipeline interface. This interface defines the maximum amount of data passed across stages: In addition, the pipeline libraries need to have the same pipeline interface. This interface defines the maximum amount of data passed across stages:
~~~~ C ~~~~ C
// Pipeline libraries need to define an interface, defined by the maximum hit attribute size (typically 2 for // Pipeline libraries need to define an interface, defined by the maximum hit attribute size (typically 2 for
// the built-in triangle intersector) and the maximum payload size (3 floating-point values in this sample). // the built-in triangle intersector) and the maximum payload size (3 floating-point values in this sample).
@ -119,6 +129,7 @@ In addition, the pipeline libraries need to have the same pipeline interface. Th
~~~~ ~~~~
Finally we provide the stage and shader groups information to the library creation information, and create the pipeline library in the same way as any other pipeline: Finally we provide the stage and shader groups information to the library creation information, and create the pipeline library in the same way as any other pipeline:
~~~~ C ~~~~ C
// Shader groups and stages for the library // Shader groups and stages for the library
pipelineLibraryInfo.groupCount = static_cast<uint32_t>(libraryShaderGroups.size()); pipelineLibraryInfo.groupCount = static_cast<uint32_t>(libraryShaderGroups.size());
@ -129,7 +140,9 @@ Finally we provide the stage and shader groups information to the library creati
// Creation of the pipeline library // Creation of the pipeline library
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &pipelineLibraryInfo, nullptr, &m_rtShaderLibrary); vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &pipelineLibraryInfo, nullptr, &m_rtShaderLibrary);
~~~~ ~~~~
The pipeline library is now created, but the application cannot run yet: we still need to indicate that the final pipeline will link with our library. Before calling `vkCreateRayTracingPipelinesKHR` for the final pipeline, we insert the reference to the library: The pipeline library is now created, but the application cannot run yet: we still need to indicate that the final pipeline will link with our library. Before calling `vkCreateRayTracingPipelinesKHR` for the final pipeline, we insert the reference to the library:
~~~~ C ~~~~ C
// The library will be linked into the final pipeline by specifying its handle and shared interface // The library will be linked into the final pipeline by specifying its handle and shared interface
VkPipelineLibraryCreateInfoKHR inputLibrary{VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR}; VkPipelineLibraryCreateInfoKHR inputLibrary{VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR};
@ -142,6 +155,7 @@ The pipeline library is now created, but the application cannot run yet: we stil
The pipeline is now built from the specified shader groups and stages as well as the library containing the hit groups. The groups and stages are linked together using indices, and indices are local to each library. To avoid collisions the pipeline creation will consider the stages of the libraries as if they had been appended to the stage list of the original `VkRayTracingPipelineCreateInfoKHR`, in the order in which the libraries are defined in `pLibraries`. The pipeline is now built from the specified shader groups and stages as well as the library containing the hit groups. The groups and stages are linked together using indices, and indices are local to each library. To avoid collisions the pipeline creation will consider the stages of the libraries as if they had been appended to the stage list of the original `VkRayTracingPipelineCreateInfoKHR`, in the order in which the libraries are defined in `pLibraries`.
Therefore, the Shader Binding Table needs to be updated accordingly, by making the wrapper aware of the contents of the library: Therefore, the Shader Binding Table needs to be updated accordingly, by making the wrapper aware of the contents of the library:
~~~~ C ~~~~ C
// The Shader Binding Table is built accounting for the entire pipeline, including the // The Shader Binding Table is built accounting for the entire pipeline, including the
// stages contained in the library. Passing the library information allows the wrapper // stages contained in the library. Passing the library information allows the wrapper
@ -150,6 +164,7 @@ Therefore, the Shader Binding Table needs to be updated accordingly, by making t
~~~~ ~~~~
At the end of the function we destroy the shader modules using our vector of modules instead of iterating over the stages of the main pipeline: At the end of the function we destroy the shader modules using our vector of modules instead of iterating over the stages of the main pipeline:
~~~~ C ~~~~ C
// Destroy all the created modules, for both libraries and main pipeline // Destroy all the created modules, for both libraries and main pipeline
for(auto& m : modules) for(auto& m : modules)
@ -157,6 +172,7 @@ At the end of the function we destroy the shader modules using our vector of mod
~~~~ ~~~~
The pipeline library has the same lifetime as the pipeline that uses it. The final step of this Section is the destruction of the library in the `HelloVulkan::destroy()` method: The pipeline library has the same lifetime as the pipeline that uses it. The final step of this Section is the destruction of the library in the `HelloVulkan::destroy()` method:
~~~~ C ~~~~ C
// Pipeline libraries have the same lifetime as the pipelines that uses them // Pipeline libraries have the same lifetime as the pipelines that uses them
vkDestroyPipeline(m_device, m_rtShaderLibrary, nullptr); vkDestroyPipeline(m_device, m_rtShaderLibrary, nullptr);
@ -173,11 +189,13 @@ Ray tracing pipelines are often complex, and can benefit from multithreaded comp
![Deferred Host Operations use app-provided threads to parallelize the compilation](images/deferred_host_operations.png) ![Deferred Host Operations use app-provided threads to parallelize the compilation](images/deferred_host_operations.png)
We start by including the support of C++ threading using `std::async` at the beginning of the source file: We start by including the support of C++ threading using `std::async` at the beginning of the source file:
~~~~ C ~~~~ C
#include <future> #include <future>
~~~~ ~~~~
In this sample we will distribute the compilation of the final ray tracing pipeline using a `VkDeferredOperation`, created just before calling `vkCreateRayTracingPipelinesKHR`: In this sample we will distribute the compilation of the final ray tracing pipeline using a `VkDeferredOperation`, created just before calling `vkCreateRayTracingPipelinesKHR`:
~~~~ C ~~~~ C
// Deferred operations allow the driver to parallelize the pipeline compilation on several threads // Deferred operations allow the driver to parallelize the pipeline compilation on several threads
// Create a deferred operation // Create a deferred operation
@ -187,14 +205,17 @@ In this sample we will distribute the compilation of the final ray tracing pipel
~~~~ ~~~~
Then we modify the pipeline creation to indicate we defer the operation: Then we modify the pipeline creation to indicate we defer the operation:
~~~~ C ~~~~ C
// The pipeline creation is called with the deferred operation. Instead of blocking until // The pipeline creation is called with the deferred operation. Instead of blocking until
// the compilation is done, the call returns immediately // the compilation is done, the call returns immediately
vkCreateRayTracingPipelinesKHR(m_device, deferredOperation, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); vkCreateRayTracingPipelinesKHR(m_device, deferredOperation, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
~~~~ ~~~~
Instead of immediately launching the compilation and blocking execution until completion, this call will return immediately with value `VK_OPERATION_DEFERRED_KHR` if deferred operations are supported by the system. Instead of immediately launching the compilation and blocking execution until completion, this call will return immediately with value `VK_OPERATION_DEFERRED_KHR` if deferred operations are supported by the system.
Threading control is left to the application. Therefore, our application will allocate a number of threads for compilation: Threading control is left to the application. Therefore, our application will allocate a number of threads for compilation:
~~~~ C ~~~~ C
// The compilation will be split into a maximum of 8 threads, or the maximum supported by the // The compilation will be split into a maximum of 8 threads, or the maximum supported by the
// driver for that operation // driver for that operation
@ -203,6 +224,7 @@ Threading control is left to the application. Therefore, our application will al
~~~~ ~~~~
We then launch those threads using `std::async`: We then launch those threads using `std::async`:
~~~~ C ~~~~ C
std::vector<std::future<void>> joins; std::vector<std::future<void>> joins;
for(uint32_t i = 0; i < threadCount; i++) for(uint32_t i = 0; i < threadCount; i++)
@ -222,9 +244,11 @@ We then launch those threads using `std::async`:
})); }));
} }
~~~~ ~~~~
Each thread executes a blocking function taking care of a subset of the compilation. When a thread has finished its task, the pipeline compilation may be complete (`VK_SUCCESS`) or there may be no more work for this thread. In this case one could consider executing more work using those threads, such as compiling another pipeline. Each thread executes a blocking function taking care of a subset of the compilation. When a thread has finished its task, the pipeline compilation may be complete (`VK_SUCCESS`) or there may be no more work for this thread. In this case one could consider executing more work using those threads, such as compiling another pipeline.
Since there is only one pipeline to compile, we wait for all threads to finish and check whether the pipeline compilation succeeded: Since there is only one pipeline to compile, we wait for all threads to finish and check whether the pipeline compilation succeeded:
~~~~ C ~~~~ C
// Wait for all threads to finish // Wait for all threads to finish
for(auto& f : joins) for(auto& f : joins)
@ -237,6 +261,7 @@ Since there is only one pipeline to compile, we wait for all threads to finish a
~~~~ ~~~~
Once the compilation is finished we can destroy the deferred operation: Once the compilation is finished we can destroy the deferred operation:
~~~~ C ~~~~ C
// Destroy the deferred operation // Destroy the deferred operation
vkDestroyDeferredOperationKHR(m_device, deferredOperation, nullptr); vkDestroyDeferredOperationKHR(m_device, deferredOperation, nullptr);
@ -248,6 +273,5 @@ This approach can be extended to compile multiple pipelines sharing some compone
## References ## References
* [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html) * [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html)
* [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html) * [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html)

View file

@ -43,17 +43,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -73,16 +62,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay hostUBO.viewProj = proj * view;
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -98,7 +88,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -118,13 +108,14 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, // Obj descriptions
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Textures (binding = 3) // Textures
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
@ -141,11 +132,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -153,7 +144,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -165,7 +156,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -225,30 +216,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -258,9 +254,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -269,15 +265,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -363,8 +359,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -420,14 +416,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -618,7 +614,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Describe buffer as array of VertexObj. // Describe buffer as array of VertexObj.
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
@ -667,19 +663,22 @@ void HelloVulkan::createBottomLevelAS()
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
std::vector<VkAccelerationStructureInstanceKHR> tlas; std::vector<VkAccelerationStructureInstanceKHR> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_instances.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
@ -692,9 +691,9 @@ void HelloVulkan::createRtDescriptorSet()
{ {
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to // Top-level acceleration structure, usable by both the ray generation and the closest hit (to
// shoot shadow rays) // shoot shadow rays)
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
@ -714,8 +713,8 @@ void HelloVulkan::createRtDescriptorSet()
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -728,7 +727,7 @@ void HelloVulkan::updateRtDescriptorSet()
{ {
// (1) Output buffer // (1) Output buffer
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
} }
@ -767,7 +766,7 @@ public:
private: private:
std::vector<int32_t> spec_values; std::vector<int32_t> spec_values;
std::vector<VkSpecializationMapEntry> spec_entries; std::vector<VkSpecializationMapEntry> spec_entries;
VkSpecializationInfo spec_info; VkSpecializationInfo spec_info{};
}; };
@ -825,10 +824,10 @@ void HelloVulkan::createRtPipeline()
modules.push_back(stage.module); modules.push_back(stage.module);
// Store the hit groups for compilation in a separate pipeline library object // Store the hit groups for compilation in a separate pipeline library object
std::vector<VkPipelineShaderStageCreateInfo> libraryStages{}; std::vector<VkPipelineShaderStageCreateInfo> libraryStages{};
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) for(auto& specialization : specializations)
{ {
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stage.pSpecializationInfo = specializations[s].getSpecialization(); stage.pSpecializationInfo = specialization.getSpecialization();
libraryStages.push_back(stage); libraryStages.push_back(stage);
} }
@ -876,7 +875,7 @@ void HelloVulkan::createRtPipeline()
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant)}; 0, sizeof(PushConstantRay)};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -1008,11 +1007,10 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
{ {
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; m_pcRay.lightPosition = m_pcRaster.lightPosition;
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_pcRay.lightIntensity = m_pcRaster.lightIntensity;
m_rtPushConstants.lightType = m_pushConstant.lightType; m_pcRay.lightType = m_pcRaster.lightType;
m_rtPushConstants.specialization = m_pushConstant.specialization;
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet}; std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
@ -1020,7 +1018,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
(uint32_t)descSets.size(), descSets.data(), 0, nullptr); (uint32_t)descSets.size(), descSets.data(), 0, nullptr);
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant), &m_rtPushConstants); 0, sizeof(PushConstantRay), &m_pcRay);
auto& regions = m_sbtWrapper.getRegions(); auto& regions = m_sbtWrapper.getRegions();
vkCmdTraceRaysKHR(cmdBuf, &regions[0], &regions[1], &regions[2], &regions[3], m_size.width, m_size.height, 1); vkCmdTraceRaysKHR(cmdBuf, &regions[0], &regions[1], &regions[2], &regions[3], m_size.width, m_size.height, 1);

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -45,7 +46,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -63,33 +64,28 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices;
VkDeviceAddress indices;
VkDeviceAddress materials;
VkDeviceAddress materialIndices;
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // Identity matrix
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // light position
int instanceId{0}; // To retrieve the transformation matrix 0, // instance Id
float lightIntensity{100.f}; 100.f, // light intensity
int lightType{0}; // 0: point, 1: infinite 0 // light type
int specialization{7}; // all in use
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -99,8 +95,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ instances
nvvk::Buffer m_bufReference; // Buffer references of the OBJ nvvk::Buffer m_bufReference; // Buffer references of the OBJ
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -110,7 +106,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
@ -151,15 +147,9 @@ public:
VkPipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
VkPipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::SBTWrapper m_sbtWrapper; nvvk::SBTWrapper m_sbtWrapper;
// Ray tracing shader library // Push constant for ray tracer
VkPipeline m_rtShaderLibrary; VkPipeline m_rtShaderLibrary;
struct RtPushConstant
{ PushConstantRay m_pcRay{{}, {}, 0, 0, 7};
nvmath::vec4f clearColor;
nvmath::vec3f lightPosition;
float lightIntensity{100.0f};
int lightType{0};
int specialization{7};
} m_rtPushConstants;
}; };

View file

@ -56,24 +56,24 @@ void renderUI(HelloVulkan& helloVk)
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
} }
// Specialization // Specialization
ImGui::SliderInt("Specialization", &helloVk.m_pushConstant.specialization, 0, 7); ImGui::SliderInt("Specialization", &helloVk.m_pcRay.specialization, 0, 7);
int s = helloVk.m_pushConstant.specialization; int s = helloVk.m_pcRay.specialization;
int a = ((s >> 2) % 2) == 1; int a = ((s >> 2) % 2) == 1;
int b = ((s >> 1) % 2) == 1; int b = ((s >> 1) % 2) == 1;
int c = ((s >> 0) % 2) == 1; int c = ((s >> 0) % 2) == 1;
ImGui::Checkbox("Use Diffuse", (bool*)&a); ImGui::Checkbox("Use Diffuse", (bool*)&a);
ImGui::Checkbox("Use Specular", (bool*)&b); ImGui::Checkbox("Use Specular", (bool*)&b);
ImGui::Checkbox("Trace shadow", (bool*)&c); ImGui::Checkbox("Trace shadow", (bool*)&c);
helloVk.m_pushConstant.specialization = (a << 2) + (b << 1) + c; helloVk.m_pcRay.specialization = (a << 2) + (b << 1) + c;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -175,7 +175,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
// #VKRay // #VKRay

View file

@ -29,62 +29,55 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Object of this instance
int objId = sceneDesc.i[pushC.instanceId].objId;
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRaster.lightIntensity;
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float d = length(lDir); float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d); lightIntensity = pcRaster.lightIntensity / (d * d);
L = normalize(lDir); L = normalize(lDir);
} }
else else
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRaster.lightPosition);
} }
@ -92,15 +85,15 @@ void main()
vec3 diffuse = computeDiffuse(mat, L, N); vec3 diffuse = computeDiffuse(mat, L, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, L, N); vec3 specular = computeSpecular(mat, i_viewDir, L, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
int specialization;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -39,30 +39,21 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2, set = 1) uniform sampler2D textureSamplers[]; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
layout(constant_id = 0) const int USE_DIFFUSE = 1; layout(constant_id = 0) const int USE_DIFFUSE = 1;
layout(constant_id = 1) const int USE_SPECULAR = 1; layout(constant_id = 1) const int USE_SPECULAR = 1;
layout(constant_id = 2) const int TRACE_SHADOW = 1; layout(constant_id = 2) const int TRACE_SHADOW = 1;
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
// clang-format on // clang-format on
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
int specialization;
}
pushC;
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
Indices indices = Indices(objResource.indexAddress); Indices indices = Indices(objResource.indexAddress);
@ -78,32 +69,29 @@ void main()
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
// Computing the normal at hit position
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
// Transforming the normal to world space
normal = normalize(vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0)));
// Computing the coordinates of the hit position // Computing the coordinates of the hit position
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
// Transforming the position to world space const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
worldPos = vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0));
// Computing the normal at hit position
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
// Vector toward the light // Vector toward the light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRay.lightIntensity;
float lightDistance = 100000.0; float lightDistance = 100000.0;
// Point light // Point light
if(pushC.lightType == 0) if(pcRay.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRay.lightPosition - worldPos;
lightDistance = length(lDir); lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
L = normalize(lDir); L = normalize(lDir);
} }
else // Directional light else // Directional light
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRay.lightPosition);
} }
// Material of the object // Material of the object
@ -115,10 +103,10 @@ void main()
vec3 diffuse = vec3(0); vec3 diffuse = vec3(0);
if(USE_DIFFUSE == 1) if(USE_DIFFUSE == 1)
{ {
diffuse = computeDiffuse(mat, L, normal); diffuse = computeDiffuse(mat, L, worldNrm);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
uint txtId = mat.textureId + sceneDesc.i[gl_InstanceCustomIndexEXT].txtOffset; uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
} }
@ -128,7 +116,7 @@ void main()
float attenuation = 1; float attenuation = 1;
// Tracing shadow ray only if the light is visible from the surface // Tracing shadow ray only if the light is visible from the surface
if(dot(normal, L) > 0) if(dot(worldNrm, L) > 0)
{ {
if(TRACE_SHADOW == 1) if(TRACE_SHADOW == 1)
{ {
@ -163,7 +151,7 @@ void main()
// Specular // Specular
if(USE_SPECULAR == 1) if(USE_SPECULAR == 1)
{ {
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm);
} }
} }
} }

View file

@ -20,31 +20,21 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; // clang-format off
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
layout(location = 0) rayPayloadEXT hitPayload prd; layout(location = 0) rayPayloadEXT hitPayload prd;
layout(binding = 0, set = 1) uniform CameraProperties layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
{ layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
mat4 view; layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
mat4 proj; layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
mat4 viewInverse; // clang-format on
mat4 projInverse;
}
cam;
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
int specialization;
}
pushC;
void main() void main()
{ {
@ -52,9 +42,9 @@ void main()
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0; vec2 d = inUV * 2.0 - 1.0;
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1); vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1); vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0); vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
uint rayFlags = gl_RayFlagsOpaqueEXT; uint rayFlags = gl_RayFlagsOpaqueEXT;
float tMin = 0.001; float tMin = 0.001;
@ -63,7 +53,7 @@ void main()
traceRayEXT(topLevelAS, // acceleration structure traceRayEXT(topLevelAS, // acceleration structure
rayFlags, // rayFlags rayFlags, // rayFlags
0xFF, // cullMask 0xFF, // cullMask
pushC.specialization, // sbtRecordOffset pcRay.specialization, // sbtRecordOffset
0, // sbtRecordStride 0, // sbtRecordStride
0, // missIndex 0, // missIndex
origin.xyz, // ray origin origin.xyz, // ray origin

View file

@ -20,16 +20,19 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(location = 0) rayPayloadInEXT hitPayload prd; layout(location = 0) rayPayloadInEXT hitPayload prd;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
}; };
void main() void main()
{ {
prd.hitValue = clearColor.xyz * 0.8; prd.hitValue = pcRay.clearColor.xyz * 0.8;
} }

View file

@ -26,38 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -67,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -8,8 +8,8 @@ This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.
We will implement two animation methods: only the transformation matrices, and animating the geometry itself. We will implement two animation methods: only the transformation matrices, and animating the geometry itself.
## Animating the Matrices ## Animating the Matrices
This first example shows how we can update the matrices used for instances in the TLAS. This first example shows how we can update the matrices used for instances in the TLAS.
### Creating a Scene ### Creating a Scene
@ -24,26 +24,30 @@ and the acceleration structure does not deal with this well.
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths),
nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f))); nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f)));
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths));
HelloVulkan::ObjInstance inst = helloVk.m_objInstance.back(); uint32_t wusonId = 1;
nvmath::mat4f identity{1};
for(int i = 0; i < 20; i++) for(int i = 0; i < 20; i++)
helloVk.m_objInstance.push_back(inst); helloVk.m_instances.push_back({identity, wusonId});
~~~~ ~~~~
### Animation Function ### Animation Function
We want to have all of the Wuson models running in a circle, and we will first modify the rasterizer to handle this. We want to have all of the Wuson models running in a circle, and we will first modify the rasterizer to handle this.
Animating the transformation matrices will be done entirely on the CPU, and we will copy the computed transformation to the GPU. Animating the transformation matrices will be done entirely on the CPU, and we will copy the computed transformation to the GPU.
In the next example, the animation will be done on the GPU using a compute shader. In the next example, the animation will be done on the GPU using a compute shader.
Add the declaration of the animation to the `HelloVulkan` class. Add the declaration of the animation to the `HelloVulkan` class.
~~~~ C++ ~~~~ C++
void animationInstances(float time); void animationInstances(float time);
~~~~ ~~~~
The first part computes the transformations for all of the Wuson models, placing each one behind another. The first part computes the transformations for all of the Wuson models, placing each one behind another.
~~~~ C++ ~~~~ C++
void HelloVulkan::animationInstances(float time) void HelloVulkan::animationInstances(float time)
{ {
const int32_t nbWuson = static_cast<int32_t>(m_objInstance.size() - 1); const int32_t nbWuson = static_cast<int32_t>(m_instances.size() - 1);
const float deltaAngle = 6.28318530718f / static_cast<float>(nbWuson); const float deltaAngle = 6.28318530718f / static_cast<float>(nbWuson);
const float wusonLength = 3.f; const float wusonLength = 3.f;
const float radius = wusonLength / (2.f * sin(deltaAngle / 2.0f)); const float radius = wusonLength / (2.f * sin(deltaAngle / 2.0f));
@ -52,42 +56,14 @@ void HelloVulkan::animationInstances(float time)
for(int i = 0; i < nbWuson; i++) for(int i = 0; i < nbWuson; i++)
{ {
int wusonIdx = i + 1; int wusonIdx = i + 1;
ObjInstance& inst = m_objInstance[wusonIdx]; auto& transform = m_instances[wusonIdx].transform;
inst.transform = nvmath::rotation_mat4_y(i * deltaAngle + offset) transform = nvmath::rotation_mat4_y(i * deltaAngle + offset)
* nvmath::translation_mat4(radius, 0.f, 0.f); * nvmath::translation_mat4(radius, 0.f, 0.f);
inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform));
} }
~~~~ ~~~~
Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals.
~~~~ C++
// Update the buffer
VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
nvvk::Buffer stagingBuffer =
m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
// Copy data to staging buffer
auto* gInst = m_alloc.map(stagingBuffer);
memcpy(gInst, m_objInstance.data(), bufferSize);
m_alloc.unmap(stagingBuffer);
// Copy staging buffer to the Scene Description buffer
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
VkBufferCopy region{0, 0, bufferSize};
vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, &region);
m_debug.endLabel(cmdBuf);
genCmdBuf.submitAndWait(cmdBuf);
m_alloc.destroy(stagingBuffer);
}
~~~~
**Note:**
We could have used `cmdBuf.updateBuffer<ObjInstance>(m_sceneDesc.buffer, 0, m_objInstance)` to
update the buffer, but this function only works for buffers with less than 65,536 bytes. If we had 2000 Wuson models, this
call wouldn't work.
### Loop Animation ### Loop Animation
In `main()`, just before the main loop, add a variable to hold the start time. In `main()`, just before the main loop, add a variable to hold the start time.
We will use this time in our animation function. We will use this time in our animation function.
@ -105,13 +81,13 @@ Inside the `while` loop, just before calling `appBase.prepareFrame()`, invoke th
If you run the application, the Wuson models will be running in a circle when using the rasterizer, but If you run the application, the Wuson models will be running in a circle when using the rasterizer, but
they will still be at their original positions in the ray traced version. We will need to update the TLAS for this. they will still be at their original positions in the ray traced version. We will need to update the TLAS for this.
## Update TLAS ## Update TLAS
Since we want to update the transformation matrices in the TLAS, we need to keep some of the objects used to create it. Since we want to update the transformation matrices in the TLAS, we need to keep some of the objects used to create it.
First, move the vector of `nvvk::RaytracingBuilder::Instance` objects from `HelloVulkan::createTopLevelAS()` to the First, move the vector of `nvvk::RaytracingBuilder::Instance` objects from `HelloVulkan::createTopLevelAS()` to the
`HelloVulkan` class. `HelloVulkan` class.
~~~~ C++ ~~~~ C++
std::vector<nvvk::RaytracingBuilder::Instance> m_tlas; std::vector<nvvk::RaytracingBuilder::Instance> m_tlas;
~~~~ ~~~~
@ -122,17 +98,21 @@ One important point is that we need to set the TLAS build flags to allow updates
This is absolutely needed, since otherwise the TLAS cannot be updated. This is absolutely needed, since otherwise the TLAS cannot be updated.
~~~~ C++ ~~~~ C++
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
m_tlas.reserve(m_objInstance.size()); m_tlas.reserve(m_instances.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.blasId = m_objInstance[i].objIndex; rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.hitGroupId = 0;
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
m_tlas.emplace_back(rayInst); m_tlas.emplace_back(rayInst);
} }
@ -141,17 +121,8 @@ void HelloVulkan::createTopLevelAS()
} }
~~~~ ~~~~
Back in `HelloVulkan::animationInstances()`, we need to copy the new computed transformation Back in `HelloVulkan::animationInstances()`, we need to update the TLAS by calling
matrices to the vector of `nvvk::RaytracingBuilder::Instance` objects. `buildTlas` with the update to `true`.
In the `for` loop, add at the end
~~~~ C++
nvvk::RaytracingBuilder::Instance& tinst = m_tlas[wusonIdx];
tinst.transform = inst.transform;
~~~~
The last point is to call the update at the end of the function.
~~~~ C++ ~~~~ C++
m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true); m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true);
@ -180,19 +151,22 @@ In the previous chapter, we updated the transformation matrices. In this one we
In this chapter, we will animate a sphere. In `main.cpp`, set up the scene like this: In this chapter, we will animate a sphere. In `main.cpp`, set up the scene like this:
~~~~ C++ ~~~~ C++
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f))); nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f)));
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
HelloVulkan::ObjInstance inst = helloVk.m_objInstance.back(); uint32_t wusonId = 1;
nvmath::mat4f identity{1};
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
helloVk.m_objInstance.push_back(inst); {
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths)); helloVk.m_instances.push_back({identity, wusonId});
}
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true));
~~~~ ~~~~
Because we now have a new instance, we have to adjust the calculation of the number of Wuson models in `HelloVulkan::animationInstances()`. Because we now have a new instance, we have to adjust the calculation of the number of Wuson models in `HelloVulkan::animationInstances()`.
~~~~ C++ ~~~~ C++
const int32_t nbWuson = static_cast<int32_t>(m_objInstance.size() - 2); const int32_t nbWuson = static_cast<int32_t>(m_instances.size() - 2); // All except sphere and plane
~~~~ ~~~~
### Compute Shader ### Compute Shader
@ -347,7 +321,8 @@ The implementation only pushes the current time and calls the compute shader (`d
~~~~ C++ ~~~~ C++
void HelloVulkan::animationObject(float time) void HelloVulkan::animationObject(float time)
{ {
ObjModel& model = m_objModel[2]; const uint32_t sphereId = 2;
ObjModel& model = m_objModel[sphereId];
updateCompDescriptors(model.vertexBuffer); updateCompDescriptors(model.vertexBuffer);
@ -378,17 +353,16 @@ In the rendering loop, **before** the call to `animationInstances`, call the obj
helloVk.animationObject(diff.count()); helloVk.animationObject(diff.count());
~~~~ ~~~~
**Note:** Always update the TLAS when BLAS are modified. This will make sure that the TLAS knows about the new bounding box sizes. **:warning: Note:** Always update the TLAS when BLAS are modified. This will make sure that the TLAS knows about the new bounding box sizes.
**Note:** At this point, the object should be animated when using the rasterizer, but should still be immobile when using the ray tracer.
**:warning: Note:** At this point, the object should be animated when using the rasterizer, but should still be immobile when using the ray tracer.
## Update BLAS ## Update BLAS
In `nvvk::RaytracingBuilder` in `raytrace_vkpp.hpp`, we can add a function to update a BLAS whose vertex buffer was previously updated. This function is very similar to the one used for instances, but in this case, there is no buffer transfer to do. In `nvvk::RaytracingBuilder` in `raytrace_vkpp.hpp`, we can add a function to update a BLAS whose vertex buffer was previously updated. This function is very similar to the one used for instances, but in this case, there is no buffer transfer to do.
~~~~ C++ ~~~~ C++
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Refit BLAS number blasIdx from updated buffer contents. // Refit BLAS number blasIdx from updated buffer contents.
// //
void nvvk::RaytracingBuilderKHR::updateBlas(uint32_t blasIdx, BlasInput& blas, VkBuildAccelerationStructureFlagsKHR flags) void nvvk::RaytracingBuilderKHR::updateBlas(uint32_t blasIdx, BlasInput& blas, VkBuildAccelerationStructureFlagsKHR flags)
@ -415,12 +389,11 @@ void nvvk::RaytracingBuilderKHR::updateBlas(uint32_t blasIdx, BlasInput& blas, V
// Allocate the scratch buffer and setting the scratch info // Allocate the scratch buffer and setting the scratch info
nvvk::Buffer scratchBuffer = nvvk::Buffer scratchBuffer =
m_alloc->createBuffer(sizeInfo.buildScratchSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR m_alloc->createBuffer(sizeInfo.buildScratchSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
bufferInfo.buffer = scratchBuffer.buffer; bufferInfo.buffer = scratchBuffer.buffer;
buildInfos.scratchData.deviceAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo); buildInfos.scratchData.deviceAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo);
NAME_VK(scratchBuffer.buffer);
std::vector<const VkAccelerationStructureBuildRangeInfoKHR*> pBuildOffset(blas.asBuildOffsetInfo.size()); std::vector<const VkAccelerationStructureBuildRangeInfoKHR*> pBuildOffset(blas.asBuildOffsetInfo.size());
for(size_t i = 0; i < blas.asBuildOffsetInfo.size(); i++) for(size_t i = 0; i < blas.asBuildOffsetInfo.size(); i++)
@ -474,7 +447,8 @@ void HelloVulkan::createBottomLevelAS()
Finally, we can add a line at the end of `HelloVulkan::animationObject()` to update the BLAS. Finally, we can add a line at the end of `HelloVulkan::animationObject()` to update the BLAS.
~~~~ C++ ~~~~ C++
m_rtBuilder.updateBlas(2, m_blas[2], VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); m_rtBuilder.updateBlas(sphereId, m_blas[sphereId],
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
~~~~ ~~~~
![](images/animation2.gif) ![](images/animation2.gif)

View file

@ -40,17 +40,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -70,16 +59,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay hostUBO.viewProj = proj * view;
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -95,7 +85,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -115,13 +105,14 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, // Obj descriptions
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Textures (binding = 3) // Textures
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
@ -138,11 +129,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -150,7 +141,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -162,7 +153,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -222,30 +213,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -255,9 +251,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -266,15 +262,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -360,8 +356,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -422,14 +418,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -620,7 +616,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Describe buffer as array of VertexObj. // Describe buffer as array of VertexObj.
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
@ -669,17 +665,20 @@ void HelloVulkan::createBottomLevelAS()
| VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
} }
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
m_tlas.emplace_back(rayInst); m_tlas.emplace_back(rayInst);
} }
@ -694,9 +693,9 @@ void HelloVulkan::createRtDescriptorSet()
{ {
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to // Top-level acceleration structure, usable by both the ray generation and the closest hit (to
// shoot shadow rays) // shoot shadow rays)
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
@ -716,8 +715,8 @@ void HelloVulkan::createRtDescriptorSet()
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -730,7 +729,7 @@ void HelloVulkan::updateRtDescriptorSet()
{ {
// (1) Output buffer // (1) Output buffer
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
} }
@ -801,7 +800,7 @@ void HelloVulkan::createRtPipeline()
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant)}; 0, sizeof(PushConstantRay)};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -849,10 +848,10 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
{ {
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; m_pcRay.lightPosition = m_pcRaster.lightPosition;
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_pcRay.lightIntensity = m_pcRaster.lightIntensity;
m_rtPushConstants.lightType = m_pushConstant.lightType; m_pcRay.lightType = m_pcRaster.lightType;
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet}; std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
@ -861,7 +860,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
(uint32_t)descSets.size(), descSets.data(), 0, nullptr); (uint32_t)descSets.size(), descSets.data(), 0, nullptr);
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant), &m_rtPushConstants); 0, sizeof(PushConstantRay), &m_pcRay);
auto& regions = m_sbtWrapper.getRegions(); auto& regions = m_sbtWrapper.getRegions();
@ -873,9 +872,12 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// #VK_animation // #VK_animation
//--------------------------------------------------------------------------------------------------
// Making the Wuson running in circle
//
void HelloVulkan::animationInstances(float time) void HelloVulkan::animationInstances(float time)
{ {
const auto nbWuson = static_cast<int32_t>(m_objInstance.size() - 2); const auto nbWuson = static_cast<int32_t>(m_instances.size() - 2); // All except sphere and plane
const float deltaAngle = 6.28318530718f / static_cast<float>(nbWuson); const float deltaAngle = 6.28318530718f / static_cast<float>(nbWuson);
const float wusonLength = 3.f; const float wusonLength = 3.f;
const float radius = wusonLength / (2.f * sin(deltaAngle / 2.0f)); const float radius = wusonLength / (2.f * sin(deltaAngle / 2.0f));
@ -884,39 +886,24 @@ void HelloVulkan::animationInstances(float time)
for(int i = 0; i < nbWuson; i++) for(int i = 0; i < nbWuson; i++)
{ {
int wusonIdx = i + 1; int wusonIdx = i + 1;
ObjInstance& inst = m_objInstance[wusonIdx]; auto& transform = m_instances[wusonIdx].transform;
inst.transform = nvmath::rotation_mat4_y(i * deltaAngle + offset) * nvmath::translation_mat4(radius, 0.f, 0.f); transform = nvmath::rotation_mat4_y(i * deltaAngle + offset) * nvmath::translation_mat4(radius, 0.f, 0.f);
inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform));
VkAccelerationStructureInstanceKHR& tinst = m_tlas[wusonIdx]; VkAccelerationStructureInstanceKHR& tinst = m_tlas[wusonIdx];
tinst.transform = nvvk::toTransformMatrixKHR(inst.transform); tinst.transform = nvvk::toTransformMatrixKHR(transform);
} }
// Update the buffer // Updating the top level acceleration structure
VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
nvvk::Buffer stagingBuffer =
m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
// Copy data to staging buffer
auto* gInst = m_alloc.map(stagingBuffer);
memcpy(gInst, m_objInstance.data(), bufferSize);
m_alloc.unmap(stagingBuffer);
// Copy staging buffer to the Scene Description buffer
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
VkBufferCopy region{0, 0, bufferSize};
vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, &region);
m_debug.endLabel(cmdBuf);
genCmdBuf.submitAndWait(cmdBuf);
m_alloc.destroy(stagingBuffer);
m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true); m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true);
} }
//--------------------------------------------------------------------------------------------------
// Animating the sphere vertices using a compute shader
//
void HelloVulkan::animationObject(float time) void HelloVulkan::animationObject(float time)
{ {
ObjModel& model = m_objModel[2]; const uint32_t sphereId = 2;
ObjModel& model = m_objModel[sphereId];
updateCompDescriptors(model.vertexBuffer); updateCompDescriptors(model.vertexBuffer);
@ -929,7 +916,8 @@ void HelloVulkan::animationObject(float time)
vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1); vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
m_rtBuilder.updateBlas(2, m_blas[2], VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); m_rtBuilder.updateBlas(sphereId, m_blas[sphereId],
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -45,7 +46,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -63,32 +64,27 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices;
VkDeviceAddress indices;
VkDeviceAddress materials;
VkDeviceAddress materialIndices;
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // Identity matrix
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // light position
int instanceId{0}; // To retrieve the transformation matrix 0, // instance Id
float lightIntensity{100.f}; 100.f, // light intensity
int lightType{0}; // 0: point, 1: infinite 0 // light type
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -98,8 +94,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -108,7 +104,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
@ -153,13 +149,8 @@ public:
std::vector<VkAccelerationStructureInstanceKHR> m_tlas; std::vector<VkAccelerationStructureInstanceKHR> m_tlas;
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas;
struct RtPushConstant // Push constant for ray tracer
{ PushConstantRay m_pcRay{};
nvmath::vec4f clearColor;
nvmath::vec3f lightPosition;
float lightIntensity{100.0f};
int lightType{0};
} m_rtPushConstants;
// #VK_animation // #VK_animation
void animationInstances(float time); void animationInstances(float time);

View file

@ -56,12 +56,12 @@ void renderUI(HelloVulkan& helloVk)
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
} }
} }
@ -88,6 +88,7 @@ int main(int argc, char** argv)
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
@ -159,16 +160,19 @@ int main(int argc, char** argv)
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f))); nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f)));
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
HelloVulkan::ObjInstance inst = helloVk.m_objInstance.back(); uint32_t wusonId = 1;
nvmath::mat4f identity{1};
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
helloVk.m_objInstance.push_back(inst); {
helloVk.m_instances.push_back({identity, wusonId});
}
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
// #VKRay // #VKRay

View file

@ -29,60 +29,55 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRaster.lightIntensity;
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float d = length(lDir); float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d); lightIntensity = pcRaster.lightIntensity / (d * d);
L = normalize(lDir); L = normalize(lDir);
} }
else else
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRaster.lightPosition);
} }
@ -90,15 +85,15 @@ void main()
vec3 diffuse = computeDiffuse(mat, L, N); vec3 diffuse = computeDiffuse(mat, L, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, L, N); vec3 specular = computeSpecular(mat, i_viewDir, L, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -39,25 +39,18 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2, set = 1) uniform sampler2D textureSamplers[]; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
// clang-format on
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
{ // clang-format on
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
}
pushC;
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
Indices indices = Indices(objResource.indexAddress); Indices indices = Indices(objResource.indexAddress);
@ -73,32 +66,29 @@ void main()
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
// Computing the normal at hit position
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
// Transforming the normal to world space
normal = normalize(vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0)));
// Computing the coordinates of the hit position // Computing the coordinates of the hit position
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
// Transforming the position to world space const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
worldPos = vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0));
// Computing the normal at hit position
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
// Vector toward the light // Vector toward the light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRay.lightIntensity;
float lightDistance = 100000.0; float lightDistance = 100000.0;
// Point light // Point light
if(pushC.lightType == 0) if(pcRay.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRay.lightPosition - worldPos;
lightDistance = length(lDir); lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
L = normalize(lDir); L = normalize(lDir);
} }
else // Directional light else // Directional light
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRay.lightPosition);
} }
// Material of the object // Material of the object
@ -107,10 +97,10 @@ void main()
// Diffuse // Diffuse
vec3 diffuse = computeDiffuse(mat, L, normal); vec3 diffuse = computeDiffuse(mat, L, worldNrm);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
uint txtId = mat.textureId + sceneDesc.i[gl_InstanceCustomIndexEXT].txtOffset; uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
} }
@ -119,7 +109,7 @@ void main()
float attenuation = 1; float attenuation = 1;
// Tracing shadow ray only if the light is visible from the surface // Tracing shadow ray only if the light is visible from the surface
if(dot(normal, L) > 0) if(dot(worldNrm, L) > 0)
{ {
float tMin = 0.001; float tMin = 0.001;
float tMax = lightDistance; float tMax = lightDistance;
@ -147,7 +137,7 @@ void main()
else else
{ {
// Specular // Specular
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm);
} }
} }

View file

@ -20,21 +20,21 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; // clang-format off
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
layout(location = 0) rayPayloadEXT hitPayload prd; layout(location = 0) rayPayloadEXT hitPayload prd;
layout(binding = 0, set = 1) uniform CameraProperties layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
{ layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
mat4 view; layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
mat4 proj; layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
mat4 viewInverse; // clang-format on
mat4 projInverse;
}
cam;
void main() void main()
{ {
@ -42,9 +42,9 @@ void main()
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0; vec2 d = inUV * 2.0 - 1.0;
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1); vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1); vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0); vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
uint rayFlags = gl_RayFlagsOpaqueEXT; uint rayFlags = gl_RayFlagsOpaqueEXT;
float tMin = 0.001; float tMin = 0.001;

View file

@ -20,16 +20,19 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(location = 0) rayPayloadInEXT hitPayload prd; layout(location = 0) rayPayloadInEXT hitPayload prd;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
}; };
void main() void main()
{ {
prd.hitValue = clearColor.xyz * 0.8; prd.hitValue = pcRay.clearColor.xyz * 0.8;
} }

View file

@ -26,38 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -67,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -30,7 +30,6 @@ This shader starts like `raytrace.chit`, but uses less information.
~~~~ C++ ~~~~ C++
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_EXT_scalar_block_layout : enable #extension GL_EXT_scalar_block_layout : enable
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
@ -47,11 +46,11 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
// clang-format on // clang-format on
~~~~ ~~~~
**Note:** **:warning: Note:**
You can find the source of `random.glsl` in the Antialiasing Tutorial [here](../ray_tracing_jitter_cam/README.md#toc1.1). You can find the source of `random.glsl` in the Antialiasing Tutorial [here](../ray_tracing_jitter_cam/README.md#toc1.1).
@ -62,7 +61,7 @@ opaque, we simply return, which means that the hit will be accepted.
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
@ -139,8 +138,8 @@ add the Any Hit stage index and push back the shader module to the stages.
In `createDescriptorSetLayout()`, we need to allow the Any Hit shader to access the scene description buffer In `createDescriptorSetLayout()`, we need to allow the Any Hit shader to access the scene description buffer
~~~~ C++ ~~~~ C++
// Scene description (binding = 1) // Obj descriptions
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, m_descSetLayoutBind.addBinding(eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
~~~~ ~~~~
@ -392,7 +391,7 @@ is added. We are skipping the closest hit shader in the trace call, so we can ig
~~~~ ~~~~
**Note:** Re-Run **:warning: Note:** Re-Run
Everything should work as before, but now it does it right. Everything should work as before, but now it does it right.

View file

@ -40,17 +40,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -70,16 +59,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay hostUBO.viewProj = proj * view;
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -95,7 +85,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -115,14 +105,15 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, // Obj descriptions
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Textures (binding = 3) // Textures
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
@ -139,11 +130,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -151,7 +142,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -163,7 +154,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -223,30 +214,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -256,9 +252,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -267,15 +263,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -361,8 +357,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -416,14 +412,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -614,7 +610,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Describe buffer as array of VertexObj. // Describe buffer as array of VertexObj.
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
@ -663,19 +659,22 @@ void HelloVulkan::createBottomLevelAS()
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
std::vector<VkAccelerationStructureInstanceKHR> tlas; std::vector<VkAccelerationStructureInstanceKHR> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_instances.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
@ -688,9 +687,9 @@ void HelloVulkan::createRtDescriptorSet()
{ {
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to // Top-level acceleration structure, usable by both the ray generation and the closest hit (to
// shoot shadow rays) // shoot shadow rays)
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
@ -710,8 +709,8 @@ void HelloVulkan::createRtDescriptorSet()
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -724,7 +723,7 @@ void HelloVulkan::updateRtDescriptorSet()
{ {
// (1) Output buffer // (1) Output buffer
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
} }
@ -816,7 +815,7 @@ void HelloVulkan::createRtPipeline()
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant)}; 0, sizeof(PushConstantRay)};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -901,15 +900,15 @@ void HelloVulkan::createRtShaderBindingTable()
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
{ {
updateFrame(); updateFrame();
if(m_rtPushConstants.frame >= m_maxFrames) if(m_pcRay.frame >= m_maxFrames)
return; return;
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; m_pcRay.lightPosition = m_pcRaster.lightPosition;
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_pcRay.lightIntensity = m_pcRaster.lightIntensity;
m_rtPushConstants.lightType = m_pushConstant.lightType; m_pcRay.lightType = m_pcRaster.lightType;
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet}; std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
@ -918,7 +917,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
(uint32_t)descSets.size(), descSets.data(), 0, nullptr); (uint32_t)descSets.size(), descSets.data(), 0, nullptr);
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
0, sizeof(RtPushConstant), &m_rtPushConstants); 0, sizeof(PushConstantRay), &m_pcRay);
// Size of a program identifier // Size of a program identifier
@ -959,10 +958,10 @@ void HelloVulkan::updateFrame()
refCamMatrix = m; refCamMatrix = m;
refFov = fov; refFov = fov;
} }
m_rtPushConstants.frame++; m_pcRay.frame++;
} }
void HelloVulkan::resetFrame() void HelloVulkan::resetFrame()
{ {
m_rtPushConstants.frame = -1; m_pcRay.frame = -1;
} }

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -44,7 +45,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -62,32 +63,27 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices{0};
VkDeviceAddress indices{0};
VkDeviceAddress materials{0};
VkDeviceAddress materialIndices{0};
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // Identity matrix
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // light position
int instanceId{0}; // To retrieve the transformation matrix 0, // instance Id
float lightIntensity{100.f}; 100.f, // light intensity
int lightType{0}; // 0: point, 1: infinite 0 // light type
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -97,8 +93,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -107,7 +103,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
@ -152,12 +148,6 @@ public:
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
int m_maxFrames{10000}; int m_maxFrames{10000};
struct RtPushConstant // Push constant for ray tracer
{ PushConstantRay m_pcRay{};
nvmath::vec4f clearColor;
nvmath::vec3f lightPosition;
float lightIntensity{100.0f};
int lightType{0};
int frame{0};
} m_rtPushConstants;
}; };

View file

@ -56,12 +56,12 @@ void renderUI(HelloVulkan& helloVk)
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
} }
} }
@ -166,7 +166,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
// #VKRay // #VKRay

View file

@ -29,59 +29,55 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRaster.lightIntensity;
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float d = length(lDir); float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d); lightIntensity = pcRaster.lightIntensity / (d * d);
L = normalize(lDir); L = normalize(lDir);
} }
else else
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRaster.lightPosition);
} }
@ -89,15 +85,15 @@ void main()
vec3 diffuse = computeDiffuse(mat, L, N); vec3 diffuse = computeDiffuse(mat, L, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, L, N); vec3 specular = computeSpecular(mat, i_viewDir, L, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
int frame;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -35,13 +35,13 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
// clang-format on // clang-format on
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);

View file

@ -39,25 +39,18 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2, set = 1) uniform sampler2D textureSamplers[]; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
// clang-format on
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
{ // clang-format on
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
}
pushC;
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
Indices indices = Indices(objResource.indexAddress); Indices indices = Indices(objResource.indexAddress);
@ -73,32 +66,29 @@ void main()
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
// Computing the normal at hit position
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
// Transforming the normal to world space
normal = normalize(vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0)));
// Computing the coordinates of the hit position // Computing the coordinates of the hit position
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
// Transforming the position to world space const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
worldPos = vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0));
// Computing the normal at hit position
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
// Vector toward the light // Vector toward the light
vec3 L; vec3 L;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRay.lightIntensity;
float lightDistance = 100000.0; float lightDistance = 100000.0;
// Point light // Point light
if(pushC.lightType == 0) if(pcRay.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRay.lightPosition - worldPos;
lightDistance = length(lDir); lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
L = normalize(lDir); L = normalize(lDir);
} }
else // Directional light else // Directional light
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRay.lightPosition);
} }
// Material of the object // Material of the object
@ -107,10 +97,10 @@ void main()
// Diffuse // Diffuse
vec3 diffuse = computeDiffuse(mat, L, normal); vec3 diffuse = computeDiffuse(mat, L, worldNrm);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
uint txtId = mat.textureId + sceneDesc.i[gl_InstanceCustomIndexEXT].txtOffset; uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
} }
@ -119,7 +109,7 @@ void main()
float attenuation = 1; float attenuation = 1;
// Tracing shadow ray only if the light is visible from the surface // Tracing shadow ray only if the light is visible from the surface
if(dot(normal, L) > 0) if(dot(worldNrm, L) > 0)
{ {
float tMin = 0.001; float tMin = 0.001;
float tMax = lightDistance; float tMax = lightDistance;
@ -149,7 +139,7 @@ void main()
else else
{ {
// Specular // Specular
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm);
} }
} }

View file

@ -20,39 +20,26 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "random.glsl" #include "random.glsl"
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; // clang-format off
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
layout(location = 0) rayPayloadEXT hitPayload prd; layout(location = 0) rayPayloadEXT hitPayload prd;
layout(binding = 0, set = 1) uniform CameraProperties layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
{ layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
mat4 view; layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
mat4 proj; layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
mat4 viewInverse; // clang-format on
mat4 projInverse;
}
cam;
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
int frame;
}
pushC;
const int NBSAMPLES = 10; const int NBSAMPLES = 10;
void main() void main()
{ {
// Initialize the random number // Initialize the random number
uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pushC.frame); uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame);
vec3 hitValues = vec3(0); vec3 hitValues = vec3(0);
@ -63,21 +50,21 @@ void main()
// Subpixel jitter: send the ray through a different position inside the pixel // Subpixel jitter: send the ray through a different position inside the pixel
// each time, to provide antialiasing. // each time, to provide antialiasing.
vec2 subpixel_jitter = pushC.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2);
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter;
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0; vec2 d = inUV * 2.0 - 1.0;
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1); vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1); vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0); vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
uint rayFlags = gl_RayFlagsNoneEXT; uint rayFlags = gl_RayFlagsNoneEXT;
float tMin = 0.001; float tMin = 0.001;
float tMax = 10000.0; float tMax = 10000.0;
prd.seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pushC.frame); prd.seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame);
traceRayEXT(topLevelAS, // acceleration structure traceRayEXT(topLevelAS, // acceleration structure
rayFlags, // rayFlags rayFlags, // rayFlags
@ -97,9 +84,9 @@ void main()
prd.hitValue = hitValues / NBSAMPLES; prd.hitValue = hitValues / NBSAMPLES;
// Do accumulation over time // Do accumulation over time
if(pushC.frame > 0) if(pcRay.frame > 0)
{ {
float a = 1.0f / float(pushC.frame + 1); float a = 1.0f / float(pcRay.frame + 1);
vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz;
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f));
} }

View file

@ -20,16 +20,19 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(location = 0) rayPayloadInEXT hitPayload prd; layout(location = 0) rayPayloadInEXT hitPayload prd;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
}; };
void main() void main()
{ {
prd.hitValue = clearColor.xyz * 0.8; prd.hitValue = pcRay.clearColor.xyz * 0.8;
} }

View file

@ -39,13 +39,13 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
// clang-format on // clang-format on
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);

View file

@ -26,38 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -67,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -1,6 +1,5 @@
# G-Buffer and Ambient Occlusion - Tutorial # G-Buffer and Ambient Occlusion - Tutorial
![](images/ray_tracing_ao.png) ![](images/ray_tracing_ao.png)
## Tutorial ([Setup](../docs/setup.md)) ## Tutorial ([Setup](../docs/setup.md))
@ -11,12 +10,11 @@ This extension to the tutorial is showing how G-Buffers from the fragment shader
ray queries [(GLSL_EXT_ray_query)](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt). ray queries [(GLSL_EXT_ray_query)](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt).
We are using some previous extensions of the tutorial to create this one. We are using some previous extensions of the tutorial to create this one.
* The usage of `ray query` is from [ray_tracing_rayquery](../ray_tracing_rayquery) * The usage of `ray query` is from [ray_tracing_rayquery](../ray_tracing_rayquery)
* The notion of accumulated frames, is comming from [ray_tracing_jitter_cam](../ray_tracing_jitter_cam) * The notion of accumulated frames, is comming from [ray_tracing_jitter_cam](../ray_tracing_jitter_cam)
* The creation and dispatch of compute shader was inspired from [ray_tracing_animation](../ray_tracing_animation) * The creation and dispatch of compute shader was inspired from [ray_tracing_animation](../ray_tracing_animation)
## Workflow ## Workflow
The fragment shader no longer just writes to an RGBA buffer for the colored image, but also writes to a G-buffer the position and normal for each fragment. The fragment shader no longer just writes to an RGBA buffer for the colored image, but also writes to a G-buffer the position and normal for each fragment.
@ -32,8 +30,6 @@ The following are the buffers are they can be seen in [NSight Graphics](https://
![](images/buffers.png) ![](images/buffers.png)
## G-Buffer ## G-Buffer
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion. The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion.
@ -110,12 +106,11 @@ We are omitting the code to compress and decompress the XYZ normal to and from a
``` ```
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(location = 1) out vec4 outGbuffer; layout(location = 1) out vec4 o_gbuffer;
... ...
outGbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N))); o_gbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
``` ```
## Ray Tracing ## Ray Tracing
@ -147,6 +142,7 @@ void HelloVulkan::createCompDescriptors()
~~~ ~~~
### Descriptor Update ### Descriptor Update
The function `updateCompDescriptors()` is done separately from the descriptor, because it can happen that some resources The function `updateCompDescriptors()` is done separately from the descriptor, because it can happen that some resources
are re-created, therefore their address isn't valid and we need to set those values back to the decriptors. For example, are re-created, therefore their address isn't valid and we need to set those values back to the decriptors. For example,
when resizing the window and the G-Buffer and AO buffer are resized. when resizing the window and the G-Buffer and AO buffer are resized.
@ -171,13 +167,11 @@ void HelloVulkan::updateCompDescriptors()
} }
~~~~ ~~~~
### Pipeline ### Pipeline
The creation of the pipeline is identical to the animation tutorial, but we will push a structure to the pushConstant The creation of the pipeline is identical to the animation tutorial, but we will push a structure to the pushConstant
instead of a single float. instead of a single float.
The information we will push, will allow us to play with the AO algorithm. The information we will push, will allow us to play with the AO algorithm.
~~~~ C++ ~~~~ C++
@ -191,7 +185,6 @@ struct AoControl
}; };
~~~~ ~~~~
### Dispatch Compute ### Dispatch Compute
The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)). The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)).
@ -277,12 +270,13 @@ void HelloVulkan::resetFrame()
} }
~~~~ ~~~~
## Compute Shader ## Compute Shader (code)
The compute shader, which can be found under [ao.comp](shaders/ao.comp) is using the [ray query](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt) extension. The compute shader, which can be found under [ao.comp](shaders/ao.comp) is using the [ray query](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt) extension.
The first thing in `main()` is to check if the invocation is not exceeding the size of the image. The first thing in `main()` is to check if the invocation is not exceeding the size of the image.
~~~~
~~~~C
void main() void main()
{ {
float occlusion = 0.0; float occlusion = 0.0;
@ -299,14 +293,14 @@ number generator and if you use only one sample per pixel, you will see correlat
sample uniformly the entire hemisphere. This could be resolved if the seed was kept over frame, but for this example, we will use sample uniformly the entire hemisphere. This could be resolved if the seed was kept over frame, but for this example, we will use
this simple technique. this simple technique.
~~~~ ~~~~C
// Initialize the random number // Initialize the random number
uint seed = tea(size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, frame_number); uint seed = tea(size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, frame_number);
~~~~ ~~~~
Secondly, we are retrieving the position and normal stored in the fragment shader. Secondly, we are retrieving the position and normal stored in the fragment shader.
~~~~ ~~~~C
// Retrieving position and normal // Retrieving position and normal
vec4 gBuffer = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy)); vec4 gBuffer = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy));
~~~~ ~~~~
@ -317,8 +311,7 @@ Note that while this compression introduces some level of quantization, it does
The `OffsetRay` can be found in [raycommon.glsl](shaders/raycommon.glsl), and was taken from [Ray Tracing Gems, Ch. 6](http://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.7.pdf). This is a convenient way to avoid finding manually the appropriate minimum offset. The `OffsetRay` can be found in [raycommon.glsl](shaders/raycommon.glsl), and was taken from [Ray Tracing Gems, Ch. 6](http://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.7.pdf). This is a convenient way to avoid finding manually the appropriate minimum offset.
~~~~C
~~~~
// Shooting rays only if a fragment was rendered // Shooting rays only if a fragment was rendered
if(gBuffer != vec4(0)) if(gBuffer != vec4(0))
{ {
@ -333,7 +326,7 @@ The `OffsetRay` can be found in [raycommon.glsl](shaders/raycommon.glsl), and wa
From the normal, we generate the basis (tangent and bitangent) which will be used for sampling. From the normal, we generate the basis (tangent and bitangent) which will be used for sampling.
The function `compute_default_basis` is also in [raycommon.glsl](shaders/raycommon.glsl) The function `compute_default_basis` is also in [raycommon.glsl](shaders/raycommon.glsl)
~~~~ ~~~~C
// Finding the basis (tangent and bitangent) from the normal // Finding the basis (tangent and bitangent) from the normal
vec3 n, tangent, bitangent; vec3 n, tangent, bitangent;
compute_default_basis(normal, tangent, bitangent); compute_default_basis(normal, tangent, bitangent);
@ -341,7 +334,7 @@ The function `compute_default_basis` is also in [raycommon.glsl](shaders/raycomm
Then we are sampling the hemisphere `rtao_samples` time, using a [cosine weighted sampling](https://people.cs.kuleuven.be/~philip.dutre/GI/) Then we are sampling the hemisphere `rtao_samples` time, using a [cosine weighted sampling](https://people.cs.kuleuven.be/~philip.dutre/GI/)
~~~~ ~~~~C
// Sampling hemiphere n-time // Sampling hemiphere n-time
for(int i = 0; i < rtao_samples; i++) for(int i = 0; i < rtao_samples; i++)
{ {
@ -368,7 +361,7 @@ the flag is set to `gl_RayFlagsNoneEXT`.
The function returns 0 if it didn't hit anything or a value between 0 and 1, depending on how close the The function returns 0 if it didn't hit anything or a value between 0 and 1, depending on how close the
hit was. It will return 1 if `rtao_distance_based == 0` hit was. It will return 1 if `rtao_distance_based == 0`
~~~~ ~~~~C
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Tracing a ray and returning the weight based on the distance of the hit // Tracing a ray and returning the weight based on the distance of the hit
// //
@ -401,7 +394,7 @@ float TraceRay(in rayQueryEXT rayQuery, in vec3 origin, in vec3 direction)
Similar to the camera jitter example, the result is stored at frame 0 and accumulate over time. Similar to the camera jitter example, the result is stored at frame 0 and accumulate over time.
~~~~ ~~~~C
// Writting out the AO // Writting out the AO
if(frame_number == 0) if(frame_number == 0)
{ {
@ -438,7 +431,7 @@ if(ImGui::CollapsingHeader("Ambient Occlusion"))
We have also have added `AoControl aoControl;` somwhere in main() and passing the information to the execution of the compute shader. We have also have added `AoControl aoControl;` somwhere in main() and passing the information to the execution of the compute shader.
~~~~ ~~~~C
// Rendering Scene // Rendering Scene
{ {
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
@ -453,13 +446,13 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th
The post shader will combine the result of the fragment (color) and the result of the compute shader (ao). The post shader will combine the result of the fragment (color) and the result of the compute shader (ao).
In `createPostDescriptor` we will need to add the descriptor In `createPostDescriptor` we will need to add the descriptor
~~~~ ~~~~C
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
~~~~ ~~~~
And the equivalent in `updatePostDescriptorSet()` And the equivalent in `updatePostDescriptorSet()`
~~~~ ~~~~C
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
~~~~ ~~~~
@ -467,16 +460,15 @@ writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer
Then in the fragment shader of the post process, we need to add the layout for the AO image Then in the fragment shader of the post process, we need to add the layout for the AO image
~~~~ ~~~~C
layout(set = 0, binding = 1) uniform sampler2D aoTxt; layout(set = 0, binding = 1) uniform sampler2D aoTxt;
~~~~ ~~~~
And the image will now be returned as the following And the image will now be returned as the following
~~~~ ~~~~C
vec4 color = texture(noisyTxt, uv); vec4 color = texture(noisyTxt, uv);
float ao = texture(aoTxt, uv).x; float ao = texture(aoTxt, uv).x;
fragColor = pow(color * ao, vec4(gamma)); fragColor = pow(color * ao, vec4(gamma));
~~~~ ~~~~

View file

@ -40,15 +40,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -68,14 +59,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
hostUBO.viewProj = proj * view;
hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -91,7 +85,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -111,12 +105,13 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
// Scene description (binding = 1) // Obj descriptions
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
// Textures (binding = 3) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT); // Textures
m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
@ -132,11 +127,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -144,7 +139,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -156,7 +151,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -221,30 +216,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -254,9 +254,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -265,15 +265,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -359,8 +359,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -415,14 +415,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -441,10 +441,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/)
resetFrame(); resetFrame();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Post-processing // Post-processing
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating an offscreen frame buffer and the associated render pass // Creating an offscreen frame buffer and the associated render pass
// //
@ -649,7 +651,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Describe buffer as array of VertexObj. // Describe buffer as array of VertexObj.
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
@ -698,19 +700,22 @@ void HelloVulkan::createBottomLevelAS()
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
std::vector<VkAccelerationStructureInstanceKHR> tlas; std::vector<VkAccelerationStructureInstanceKHR> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_instances.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -55,7 +56,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -73,32 +74,27 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices;
VkDeviceAddress indices;
VkDeviceAddress materials;
VkDeviceAddress materialIndices;
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // Identity matrix
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // light position
int instanceId{0}; // To retrieve the transformation matrix 0, // instance Id
float lightIntensity{100.f}; 100.f, // light intensity
int lightType{0}; // 0: point, 1: infinite 0 // light type
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -108,8 +104,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -118,7 +114,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();

View file

@ -57,12 +57,12 @@ void renderUI(HelloVulkan& helloVk)
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
} }
} }
@ -89,6 +89,7 @@ int main(int argc, char** argv)
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
@ -166,7 +167,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
// #VKRay // #VKRay
helloVk.initRayTracing(); helloVk.initRayTracing();

View file

@ -30,62 +30,58 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(location = 1) out vec4 outGbuffer; layout(location = 1) out vec4 o_gbuffer;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 L; vec3 L;
float lightDistance; float lightDistance;
float lightIntensity = pushC.lightIntensity; float lightIntensity = pcRaster.lightIntensity;
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float d = length(lDir); float d = length(lDir);
lightIntensity = pushC.lightIntensity / (d * d); lightIntensity = pcRaster.lightIntensity / (d * d);
L = normalize(lDir); L = normalize(lDir);
lightDistance = d; lightDistance = d;
} }
else else
{ {
L = normalize(pushC.lightPosition - vec3(0)); L = normalize(pcRaster.lightPosition - vec3(0));
lightDistance = 10000; lightDistance = 10000;
} }
@ -95,7 +91,7 @@ void main()
diffuse = vec3(1); diffuse = vec3(1);
// if(mat.textureId >= 0) // if(mat.textureId >= 0)
// { // {
// int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; // int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
// uint txtId = txtOffset + mat.textureId; // uint txtId = txtOffset + mat.textureId;
// vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; // vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz;
// diffuse *= diffuseTxt; // diffuse *= diffuseTxt;
@ -104,9 +100,8 @@ void main()
// Specular // Specular
vec3 specular = vec3(0); //computeSpecular(mat, viewDir, L, N); vec3 specular = vec3(0); //computeSpecular(mat, viewDir, L, N);
lightIntensity = 1; lightIntensity = 1;
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
o_gbuffer.rgba = vec4(i_worldPos, uintBitsToFloat(CompressUnitVec(N)));
outGbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
} }

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
int lightType;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -26,38 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
uint instanceId; };
float lightIntensity;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -67,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

View file

@ -17,41 +17,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
struct Vertex #include "host_device.h"
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
struct SceneDesc
{
mat4 transfo;
mat4 transfoIT;
int objId;
int txtOffset;
uint64_t vertexAddress;
uint64_t indexAddress;
uint64_t materialAddress;
uint64_t materialIndexAddress;
};
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
{ {

View file

@ -40,17 +40,6 @@
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices
struct CameraMatrices
{
nvmath::mat4f view;
nvmath::mat4f proj;
nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
};
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
@ -70,16 +59,17 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; GlobalUniforms hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); const auto& view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay hostUBO.viewProj = proj * view;
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_bGlobals.buffer;
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
@ -95,7 +85,7 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
@ -115,13 +105,14 @@ void HelloVulkan::createDescriptorSetLayout()
{ {
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
// Camera matrices (binding = 0) // Camera matrices
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
// Scene description (binding = 1) VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, // Obj descriptions
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Textures (binding = 3) // Textures
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
@ -138,11 +129,11 @@ void HelloVulkan::updateDescriptorSet()
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
// All texture samplers // All texture samplers
std::vector<VkDescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
@ -150,7 +141,7 @@ void HelloVulkan::updateDescriptorSet()
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 2, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
// Writing the information // Writing the information
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
@ -162,7 +153,7 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -222,30 +213,35 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
// Creates all textures found // Creates all textures found and find the offset for this model
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size()); auto txtOffset = static_cast<uint32_t>(m_textures.size());
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
std::string objNb = std::to_string(m_objModel.size()); std::string objNb = std::to_string(m_objModel.size());
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb).c_str())); m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb).c_str())); m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str())); m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str())); m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
// Keeping transformation matrix of the instance
ObjInstance instance; ObjInstance instance;
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.transform = transform; instance.transform = transform;
instance.transformIT = nvmath::transpose(nvmath::invert(transform)); instance.objIndex = static_cast<uint32_t>(m_objModel.size());
instance.txtOffset = txtOffset; m_instances.push_back(instance);
instance.vertices = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
instance.indices = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
instance.materials = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
instance.materialIndices = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Creating information for device access
ObjDesc desc;
desc.txtOffset = txtOffset;
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
// Keeping the obj host model and device description
m_objModel.emplace_back(model); m_objModel.emplace_back(model);
m_objInstance.emplace_back(instance); m_objDesc.emplace_back(desc);
} }
@ -255,9 +251,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_bGlobals.buffer, "Globals");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -266,15 +262,15 @@ void HelloVulkan::createUniformBuffer()
// - Transformation // - Transformation
// - Offset for texture // - Offset for texture
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createObjDescriptionBuffer()
{ {
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -360,8 +356,8 @@ void HelloVulkan::destroyResources()
vkDestroyDescriptorPool(m_device, m_descPool, nullptr); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_bGlobals);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_bObjDesc);
for(auto& m : m_objModel) for(auto& m : m_objModel)
{ {
@ -415,14 +411,14 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
m_pcRaster.modelMatrix = inst.transform;
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
sizeof(ObjPushConstant), &m_pushConstant); sizeof(PushConstantRaster), &m_pcRaster);
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
@ -440,10 +436,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/)
updateRtDescriptorSet(); updateRtDescriptorSet();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Post-processing // Post-processing
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating an offscreen frame buffer and the associated render pass // Creating an offscreen frame buffer and the associated render pass
// //
@ -552,6 +550,7 @@ void HelloVulkan::createPostDescriptor()
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Update the output // Update the output
// //
@ -611,7 +610,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Describe buffer as array of VertexObj. // Describe buffer as array of VertexObj.
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress; triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(VertexObj); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
@ -660,19 +659,22 @@ void HelloVulkan::createBottomLevelAS()
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
//--------------------------------------------------------------------------------------------------
//
//
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
{ {
std::vector<VkAccelerationStructureInstanceKHR> tlas; std::vector<VkAccelerationStructureInstanceKHR> tlas;
tlas.reserve(m_objInstance.size()); tlas.reserve(m_instances.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(const HelloVulkan::ObjInstance& inst : m_instances)
{ {
VkAccelerationStructureInstanceKHR rayInst; VkAccelerationStructureInstanceKHR rayInst{};
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex); rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.mask = 0xFF; rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
@ -685,9 +687,9 @@ void HelloVulkan::createRtDescriptorSet()
{ {
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to // Top-level acceleration structure, usable by both the ray generation and the closest hit (to
// shoot shadow rays) // shoot shadow rays)
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
@ -707,8 +709,8 @@ void HelloVulkan::createRtDescriptorSet()
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
std::vector<VkWriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -721,7 +723,7 @@ void HelloVulkan::updateRtDescriptorSet()
{ {
// (1) Output buffer // (1) Output buffer
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
} }
@ -731,7 +733,6 @@ void HelloVulkan::updateRtDescriptorSet()
// //
void HelloVulkan::createRtPipeline() void HelloVulkan::createRtPipeline()
{ {
enum StageIndices enum StageIndices
{ {
eRaygen, eRaygen,
@ -821,7 +822,7 @@ void HelloVulkan::createRtPipeline()
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
| VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR, | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
0, sizeof(RtPushConstant)}; 0, sizeof(PushConstantRay)};
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
@ -867,13 +868,13 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
{ {
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
m_rtPushConstants.clearColor = clearColor; m_pcRay.clearColor = clearColor;
m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; m_pcRay.lightPosition = m_pcRaster.lightPosition;
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_pcRay.lightIntensity = m_pcRaster.lightIntensity;
m_rtPushConstants.lightDirection = m_pushConstant.lightDirection; m_pcRay.lightDirection = m_pcRaster.lightDirection;
m_rtPushConstants.lightSpotCutoff = m_pushConstant.lightSpotCutoff; m_pcRay.lightSpotCutoff = m_pcRaster.lightSpotCutoff;
m_rtPushConstants.lightSpotOuterCutoff = m_pushConstant.lightSpotOuterCutoff; m_pcRay.lightSpotOuterCutoff = m_pcRaster.lightSpotOuterCutoff;
m_rtPushConstants.lightType = m_pushConstant.lightType; m_pcRay.lightType = m_pcRaster.lightType;
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet}; std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
@ -883,7 +884,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
| VK_SHADER_STAGE_CALLABLE_BIT_KHR, | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
0, sizeof(RtPushConstant), &m_rtPushConstants); 0, sizeof(PushConstantRay), &m_pcRay);
auto& regions = m_sbtWrapper.getRegions(); auto& regions = m_sbtWrapper.getRegions();

View file

@ -24,6 +24,7 @@
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
#include "shaders/host_device.h"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -45,7 +46,7 @@ public:
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures); void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
@ -63,35 +64,30 @@ public:
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
}; };
// Instance of the OBJ
struct ObjInstance struct ObjInstance
{ {
nvmath::mat4f transform{1}; // Position of the instance nvmath::mat4f transform; // Matrix of the instance
nvmath::mat4f transformIT{1}; // Inverse transpose uint32_t objIndex{0}; // Model index reference
uint32_t objIndex{0}; // Reference to the `m_objModel`
uint32_t txtOffset{0}; // Offset in `m_textures`
VkDeviceAddress vertices{0};
VkDeviceAddress indices{0};
VkDeviceAddress materials{0};
VkDeviceAddress materialIndices{0};
}; };
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant PushConstantRaster m_pcRaster{
{ {1}, // model identity
nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; {10.f, 15.f, 8.f}, // lightPosition
float lightIntensity{100.f}; {0}, // instanceId to retrieve the transformation matrix
nvmath::vec3f lightDirection{-1, -1, -1}; {100.f}, // lightIntensity
float lightSpotCutoff{cos(deg2rad(12.5f))}; {-1.f, -1.f, -1.f}, // lightDirection
float lightSpotOuterCutoff{cos(deg2rad(17.5f))}; {cos(deg2rad(12.5f))}, // lightSpotCutoff
int instanceId{0}; // To retrieve the transformation matrix {cos(deg2rad(17.5f))}, // lightSpotOuterCutoff
int lightType{0}; // 0: point, 1: infinite {0} // lightType 0: point, 1: infinite
}; };
ObjPushConstant m_pushConstant;
// Array of objects and instances in the scene // Array of objects and instances in the scene
std::vector<ObjModel> m_objModel; std::vector<ObjModel> m_objModel; // Model on host
std::vector<ObjInstance> m_objInstance; std::vector<ObjDesc> m_objDesc; // Model description for device access
std::vector<ObjInstance> m_instances; // Scene model instances
// Graphic pipeline // Graphic pipeline
VkPipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
@ -101,8 +97,8 @@ public:
VkDescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
VkDescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -111,7 +107,7 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post - Draw the rendered image on a quad using a tonemapper
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
@ -152,16 +148,7 @@ public:
VkPipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
VkPipeline m_rtPipeline; VkPipeline m_rtPipeline;
struct RtPushConstant PushConstantRay m_pcRay{};
{
nvmath::vec4f clearColor;
nvmath::vec3f lightPosition;
float lightIntensity;
nvmath::vec3f lightDirection{-1, -1, -1};
float lightSpotCutoff{deg2rad(12.5f)};
float lightSpotOuterCutoff{deg2rad(17.5f)};
int lightType;
} m_rtPushConstants;
nvvk::SBTWrapper m_sbtWrapper; nvvk::SBTWrapper m_sbtWrapper;
}; };

View file

@ -54,30 +54,31 @@ static void onErrorCallback(int error, const char* description)
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once);
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Spot", &helloVk.m_pushConstant.lightType, 1); ImGui::RadioButton("Spot", &helloVk.m_pcRaster.lightType, 1);
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 2); ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 2);
if(helloVk.m_pushConstant.lightType < 2) if(helloVk.m_pcRaster.lightType < 2)
ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); ImGui::SliderFloat3("Light Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
if(helloVk.m_pushConstant.lightType > 0) if(helloVk.m_pcRaster.lightType > 0)
ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstant.lightDirection.x, -1.f, 1.f); ImGui::SliderFloat3("Light Direction", &helloVk.m_pcRaster.lightDirection.x, -1.f, 1.f);
if(helloVk.m_pushConstant.lightType < 2) if(helloVk.m_pcRaster.lightType < 2)
ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 500.f); ImGui::SliderFloat("Light Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 500.f);
if(helloVk.m_pushConstant.lightType == 1) if(helloVk.m_pcRaster.lightType == 1)
{ {
float dCutoff = rad2deg(acos(helloVk.m_pushConstant.lightSpotCutoff)); float dCutoff = rad2deg(acos(helloVk.m_pcRaster.lightSpotCutoff));
float dOutCutoff = rad2deg(acos(helloVk.m_pushConstant.lightSpotOuterCutoff)); float dOutCutoff = rad2deg(acos(helloVk.m_pcRaster.lightSpotOuterCutoff));
ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f);
ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f);
dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff;
helloVk.m_pushConstant.lightSpotCutoff = cos(deg2rad(dCutoff)); helloVk.m_pcRaster.lightSpotCutoff = cos(deg2rad(dCutoff));
helloVk.m_pushConstant.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); helloVk.m_pcRaster.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff));
} }
} }
} }
@ -88,6 +89,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -180,7 +182,7 @@ int main(int argc, char** argv)
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
helloVk.createUniformBuffer(); helloVk.createUniformBuffer();
helloVk.createSceneDescriptionBuffer(); helloVk.createObjDescriptionBuffer();
helloVk.updateDescriptorSet(); helloVk.updateDescriptorSet();
// #VKRay // #VKRay

View file

@ -29,75 +29,68 @@
#include "wavefront.glsl" #include "wavefront.glsl"
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
float lightIntensity; };
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
uint instanceId;
int lightType;
}
pushC;
// clang-format off // clang-format off
// Incoming // Incoming
layout(location = 1) in vec2 fragTexCoord; layout(location = 1) in vec3 i_worldPos;
layout(location = 2) in vec3 fragNormal; layout(location = 2) in vec3 i_worldNrm;
layout(location = 3) in vec3 viewDir; layout(location = 3) in vec3 i_viewDir;
layout(location = 4) in vec3 worldPos; layout(location = 4) in vec2 i_texCoord;
// Outgoing // Outgoing
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 o_color;
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2) uniform sampler2D[] textureSamplers; layout(binding = eTextures) uniform sampler2D[] textureSamplers;
// clang-format on // clang-format on
void main() void main()
{ {
// Material of the object // Material of the object
SceneDesc objResource = sceneDesc.i[pushC.instanceId]; ObjDesc objResource = objDesc.i[pcRaster.objIndex];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
int matIndex = matIndices.i[gl_PrimitiveID]; int matIndex = matIndices.i[gl_PrimitiveID];
WaveFrontMaterial mat = materials.m[matIndex]; WaveFrontMaterial mat = materials.m[matIndex];
vec3 N = normalize(fragNormal); vec3 N = normalize(i_worldNrm);
// Vector toward light // Vector toward light
vec3 LightDir; vec3 LightDir;
float lightIntensity; float lightIntensity;
// Point light // Point light
if(pushC.lightType == 0) if(pcRaster.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float lightDistance = length(lDir); float lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance);
LightDir = normalize(lDir); LightDir = normalize(lDir);
} }
else if(pushC.lightType == 1) else if(pcRaster.lightType == 1)
{ {
vec3 lDir = pushC.lightPosition - worldPos; vec3 lDir = pcRaster.lightPosition - i_worldPos;
float lightDistance = length(lDir); float lightDistance = length(lDir);
lightIntensity = pushC.lightIntensity / (lightDistance * lightDistance); lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance);
LightDir = normalize(lDir); LightDir = normalize(lDir);
float theta = dot(LightDir, normalize(-pushC.lightDirection)); float theta = dot(LightDir, normalize(-pcRaster.lightDirection));
float epsilon = pushC.lightSpotCutoff - pushC.lightSpotOuterCutoff; float epsilon = pcRaster.lightSpotCutoff - pcRaster.lightSpotOuterCutoff;
float spotIntensity = clamp((theta - pushC.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); float spotIntensity = clamp((theta - pcRaster.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
lightIntensity *= spotIntensity; lightIntensity *= spotIntensity;
} }
else // Directional light else // Directional light
{ {
LightDir = normalize(-pushC.lightDirection); LightDir = normalize(-pcRaster.lightDirection);
lightIntensity = 1.0; lightIntensity = 1.0;
} }
@ -106,15 +99,15 @@ void main()
vec3 diffuse = computeDiffuse(mat, LightDir, N); vec3 diffuse = computeDiffuse(mat, LightDir, N);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset; int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
uint txtId = txtOffset + mat.textureId; uint txtId = txtOffset + mat.textureId;
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
diffuse *= diffuseTxt; diffuse *= diffuseTxt;
} }
// Specular // Specular
vec3 specular = computeSpecular(mat, viewDir, LightDir, N); vec3 specular = computeSpecular(mat, i_viewDir, LightDir, N);
// Result // Result
outColor = vec4(lightIntensity * (diffuse + specular), 1); o_color = vec4(lightIntensity * (diffuse + specular), 1);
} }

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_HOST_DEVICE
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using uint = unsigned int;
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SceneBindings)
eGlobals = 0, // Global uniform containing camera matrices
eObjDescs = 1, // Access to the object descriptions
eTextures = 2 // Access to textures
END_BINDING();
START_BINDING(RtxBindings)
eTlas = 0, // Top-level acceleration structure
eOutImage = 1 // Ray tracer output image
END_BINDING();
// clang-format on
// Information of a obj model when referenced in a shader
struct ObjDesc
{
int txtOffset; // Texture index offset in the array of textures
uint64_t vertexAddress; // Address of the Vertex buffer
uint64_t indexAddress; // Address of the index buffer
uint64_t materialAddress; // Address of the material buffer
uint64_t materialIndexAddress; // Address of the triangle material index buffer
};
// Uniform buffer set at each frame
struct GlobalUniforms
{
mat4 viewProj; // Camera view * projection
mat4 viewInverse; // Camera inverse view matrix
mat4 projInverse; // Camera inverse projection matrix
};
// Push constant structure for the raster
struct PushConstantRaster
{
mat4 modelMatrix; // matrix of the instance
vec3 lightPosition;
uint objIndex;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
};
// Push constant structure for the ray tracer
struct PushConstantRay
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
};
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
{
vec3 pos;
vec3 nrm;
vec3 color;
vec2 texCoord;
};
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 transmittance;
vec3 emission;
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
int illum; // illumination model (see http://www.fileformat.info/format/material/)
int textureId;
};
#endif

View file

@ -39,29 +39,20 @@ layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc; layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
layout(binding = 2, set = 1) uniform sampler2D textureSamplers[]; layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
// clang-format on // clang-format on
layout(push_constant) uniform Constants
{
vec4 clearColor;
vec3 lightPosition;
float lightIntensity;
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
int lightType;
}
pushC;
layout(location = 0) callableDataEXT rayLight cLight; layout(location = 0) callableDataEXT rayLight cLight;
void main() void main()
{ {
// Object data // Object data
SceneDesc objResource = sceneDesc.i[gl_InstanceCustomIndexEXT]; ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
MatIndices matIndices = MatIndices(objResource.materialIndexAddress); MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
Materials materials = Materials(objResource.materialAddress); Materials materials = Materials(objResource.materialAddress);
Indices indices = Indices(objResource.indexAddress); Indices indices = Indices(objResource.indexAddress);
@ -77,48 +68,46 @@ void main()
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
// Computing the normal at hit position
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
// Transforming the normal to world space
normal = normalize(vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0)));
// Computing the coordinates of the hit position // Computing the coordinates of the hit position
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
// Transforming the position to world space const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
worldPos = vec3(sceneDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0));
// Computing the normal at hit position
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
cLight.inHitPosition = worldPos; cLight.inHitPosition = worldPos;
//#define DONT_USE_CALLABLE //#define DONT_USE_CALLABLE
#if defined(DONT_USE_CALLABLE) #if defined(DONT_USE_CALLABLE)
// Point light // Point light
if(pushC.lightType == 0) if(pcRay.lightType == 0)
{ {
vec3 lDir = pushC.lightPosition - cLight.inHitPosition; vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
float lightDistance = length(lDir); float lightDistance = length(lDir);
cLight.outIntensity = pushC.lightIntensity / (lightDistance * lightDistance); cLight.outIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
cLight.outLightDir = normalize(lDir); cLight.outLightDir = normalize(lDir);
cLight.outLightDistance = lightDistance; cLight.outLightDistance = lightDistance;
} }
else if(pushC.lightType == 1) else if(pcRay.lightType == 1)
{ {
vec3 lDir = pushC.lightPosition - cLight.inHitPosition; vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
cLight.outLightDistance = length(lDir); cLight.outLightDistance = length(lDir);
cLight.outIntensity = pushC.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
cLight.outLightDir = normalize(lDir); cLight.outLightDir = normalize(lDir);
float theta = dot(cLight.outLightDir, normalize(-pushC.lightDirection)); float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection));
float epsilon = pushC.lightSpotCutoff - pushC.lightSpotOuterCutoff; float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff;
float spotIntensity = clamp((theta - pushC.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
cLight.outIntensity *= spotIntensity; cLight.outIntensity *= spotIntensity;
} }
else // Directional light else // Directional light
{ {
cLight.outLightDir = normalize(-pushC.lightDirection); cLight.outLightDir = normalize(-pcRay.lightDirection);
cLight.outIntensity = 1.0; cLight.outIntensity = 1.0;
cLight.outLightDistance = 10000000; cLight.outLightDistance = 10000000;
} }
#else #else
executeCallableEXT(pushC.lightType, 0); executeCallableEXT(pcRay.lightType, 0);
#endif #endif
// Material of the object // Material of the object
@ -127,10 +116,10 @@ void main()
// Diffuse // Diffuse
vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal); vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, worldNrm);
if(mat.textureId >= 0) if(mat.textureId >= 0)
{ {
uint txtId = mat.textureId + sceneDesc.i[gl_InstanceCustomIndexEXT].txtOffset; uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
} }
@ -139,7 +128,7 @@ void main()
float attenuation = 1; float attenuation = 1;
// Tracing shadow ray only if the light is visible from the surface // Tracing shadow ray only if the light is visible from the surface
if(dot(normal, cLight.outLightDir) > 0) if(dot(worldNrm, cLight.outLightDir) > 0)
{ {
float tMin = 0.001; float tMin = 0.001;
float tMax = cLight.outLightDistance; float tMax = cLight.outLightDistance;
@ -167,7 +156,7 @@ void main()
else else
{ {
// Specular // Specular
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, normal); specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, worldNrm);
} }
} }

View file

@ -20,21 +20,21 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; // clang-format off
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
layout(location = 0) rayPayloadEXT hitPayload prd; layout(location = 0) rayPayloadEXT hitPayload prd;
layout(binding = 0, set = 1) uniform CameraProperties layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
{ layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
mat4 view; layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
mat4 proj; layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
mat4 viewInverse; // clang-format on
mat4 projInverse;
}
cam;
void main() void main()
{ {
@ -42,9 +42,9 @@ void main()
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0; vec2 d = inUV * 2.0 - 1.0;
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1); vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1); vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0); vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
uint rayFlags = gl_RayFlagsOpaqueEXT; uint rayFlags = gl_RayFlagsOpaqueEXT;
float tMin = 0.001; float tMin = 0.001;

View file

@ -20,16 +20,19 @@
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "raycommon.glsl" #include "raycommon.glsl"
#include "wavefront.glsl"
layout(location = 0) rayPayloadInEXT hitPayload prd; layout(location = 0) rayPayloadInEXT hitPayload prd;
layout(push_constant) uniform Constants layout(push_constant) uniform _PushConstantRay
{ {
vec4 clearColor; PushConstantRay pcRay;
}; };
void main() void main()
{ {
prd.hitValue = clearColor.xyz * 0.8; prd.hitValue = pcRay.clearColor.xyz * 0.8;
} }

View file

@ -26,41 +26,26 @@
#include "wavefront.glsl" #include "wavefront.glsl"
// clang-format off layout(binding = 0) uniform _GlobalUniforms
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
// clang-format on
layout(binding = 0) uniform UniformBufferObject
{ {
mat4 view; GlobalUniforms uni;
mat4 proj; };
mat4 viewI;
}
ubo;
layout(push_constant) uniform shaderInformation layout(push_constant) uniform _PushConstantRaster
{ {
vec3 lightPosition; PushConstantRaster pcRaster;
float lightIntensity; };
vec3 lightDirection;
float lightSpotCutoff;
float lightSpotOuterCutoff;
uint instanceId;
int lightType;
}
pushC;
layout(location = 0) in vec3 inPosition; layout(location = 0) in vec3 i_position;
layout(location = 1) in vec3 inNormal; layout(location = 1) in vec3 i_normal;
layout(location = 2) in vec3 inColor; layout(location = 2) in vec3 i_color;
layout(location = 3) in vec2 inTexCoord; layout(location = 3) in vec2 i_texCoord;
//layout(location = 0) flat out int matIndex; layout(location = 1) out vec3 o_worldPos;
layout(location = 1) out vec2 fragTexCoord; layout(location = 2) out vec3 o_worldNrm;
layout(location = 2) out vec3 fragNormal; layout(location = 3) out vec3 o_viewDir;
layout(location = 3) out vec3 viewDir; layout(location = 4) out vec2 o_texCoord;
layout(location = 4) out vec3 worldPos;
out gl_PerVertex out gl_PerVertex
{ {
@ -70,16 +55,12 @@ out gl_PerVertex
void main() void main()
{ {
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo; vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1)); o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
o_viewDir = vec3(o_worldPos - origin);
o_texCoord = i_texCoord;
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
worldPos = vec3(objMatrix * vec4(inPosition, 1.0)); gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
viewDir = vec3(worldPos - origin);
fragTexCoord = inTexCoord;
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
// matIndex = inMatID;
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
} }

Some files were not shown because too many files have changed in this diff Show more