Refactoring
This commit is contained in:
parent
3e399adf0a
commit
d90ce79135
222 changed files with 9045 additions and 5734 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,2 +1,4 @@
|
||||||
**/spv/*.spv
|
**/spv/*.spv
|
||||||
/build/*
|
/build/*
|
||||||
|
/out/build/x64-Debug
|
||||||
|
/.vs
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
tlas.emplace_back(rayInst);
|
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
|
||||||
|
tlas.emplace_back(rayInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add lantern instances.
|
||||||
|
for(int i = 0; i < static_cast<int>(m_lanterns.size()); ++i)
|
||||||
|
{
|
||||||
|
VkAccelerationStructureInstanceKHR lanternInstance;
|
||||||
|
lanternInstance.transform = nvvk::toTransformMatrixKHR(nvmath::translation_mat4(m_lanterns[i].position));
|
||||||
|
lanternInstance.instanceCustomIndex = i;
|
||||||
|
lanternInstance.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(uint32_t(m_lanternBlasId));
|
||||||
|
lanternInstance.instanceShaderBindingTableRecordOffset = 1; // Next hit group is for lanterns.
|
||||||
|
lanternInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
|
lanternInstance.mask = 0xFF;
|
||||||
|
tlas.emplace_back(lanternInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add lantern instances.
|
|
||||||
for(int i = 0; i < static_cast<int>(m_lanterns.size()); ++i)
|
|
||||||
{
|
|
||||||
nvvk::RaytracingBuilderKHR::Instance lanternInstance;
|
|
||||||
lanternInstance.transform = nvmath::translation_mat4(m_lanterns[i].position);
|
|
||||||
lanternInstance.instanceCustomId = i;
|
|
||||||
lanternInstance.blasId = m_lanternBlasId;
|
|
||||||
lanternInstance.hitGroupId = 1; // Next hit group is for lanterns.
|
|
||||||
lanternInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
||||||
tlas.emplace_back(lanternInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
@ -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
|
||||||
|
|
|
||||||
41
media/scenes/cube_modif.obj
Normal file
41
media/scenes/cube_modif.obj
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
|
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)
|
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.mask = 0xFF;
|
|
||||||
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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
126
ray_tracing__advance/shaders/host_device.h
Normal file
126
ray_tracing__advance/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|

|
||||||
|
|
||||||
## [**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
|
||||||
|
|
||||||

|
* 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
* 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
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
BIN
ray_tracing__before/images/base_pipeline.png
Normal file
BIN
ray_tracing__before/images/base_pipeline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
ray_tracing__before/images/vk_ray_tracing__before.png
Normal file
BIN
ray_tracing__before/images/vk_ray_tracing__before.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
117
ray_tracing__before/shaders/host_device.h
Normal file
117
ray_tracing__before/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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.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
|
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.mask = 0xFF;
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
117
ray_tracing__simple/shaders/host_device.h
Normal file
117
ray_tracing__simple/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,30 +9,31 @@ The simplest way of defining ray tracing pipelines is by using monolithic `VkRay
|
||||||
|
|
||||||
This sample introduces the [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html) extension to create shader libraries that can be separately compiled and reused in ray tracing pipelines. The compilation of the final pipeline is carried out on multiple threads using the [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html) extension.
|
This sample introduces the [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html) extension to create shader libraries that can be separately compiled and reused in ray tracing pipelines. The compilation of the final pipeline is carried out on multiple threads using the [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html) extension.
|
||||||
|
|
||||||
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:
|
||||||

|

|
||||||
|
|
||||||
Pipeline libraries are `VkPipeline` objects that cannot be bound directly. Instead, they can be compiled once and linked into as many pipelines as necessary. The Shader Binding Table of the resulting pipeline references the shader groups of the library as if they had been appended to the groups and stages in the main `VkRayTracingPipelineCreateInfo`
|
Pipeline libraries are `VkPipeline` objects that cannot be bound directly. Instead, they can be compiled once and linked into as many pipelines as necessary. The Shader Binding Table of the resulting pipeline references the shader groups of the library as if they had been appended to the groups and stages in the main `VkRayTracingPipelineCreateInfo`
|
||||||

|

|
||||||
|
|
||||||
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,12 +172,13 @@ 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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
As an exercise, it is possible to create another library containing the other shader stages, and link those libraries together into the pipeline.
|
As an exercise, it is possible to create another library containing the other shader stages, and link those libraries together into the pipeline.
|
||||||
|
|
||||||
## Parallel Compilation Using Deferred Host Operations
|
## Parallel Compilation Using Deferred Host Operations
|
||||||
|
|
||||||
|
|
@ -173,11 +189,13 @@ Ray tracing pipelines are often complex, and can benefit from multithreaded comp
|
||||||

|

|
||||||
|
|
||||||
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,17 +261,17 @@ 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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Congratulations! The ray tracing pipeline is now built using explicit stages and a pipeline library, and the final compilation is executed on multiple threads. As an exercise, the pipeline library described at the beginning of this tutorial can also be compiled in parallel.
|
Congratulations! The ray tracing pipeline is now built using explicit stages and a pipeline library, and the final compilation is executed on multiple threads. As an exercise, the pipeline library described at the beginning of this tutorial can also be compiled in parallel.
|
||||||
This approach can be extended to compile multiple pipelines sharing some components using multiple threads:
|
This approach can be extended to compile multiple pipelines sharing some components using multiple threads:
|
||||||

|

|
||||||
|
|
||||||
## 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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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.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
|
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.mask = 0xFF;
|
|
||||||
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, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1);
|
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
ray_tracing_advanced_compilation/shaders/host_device.h
Normal file
118
ray_tracing_advanced_compilation/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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,106 +56,73 @@ 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, ®ion);
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Inside the `while` loop, just before calling `appBase.prepareFrame()`, invoke the animation function.
|
Inside the `while` loop, just before calling `appBase.prepareFrame()`, invoke the animation function.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
std::chrono::duration<float> diff = std::chrono::system_clock::now() - start;
|
std::chrono::duration<float> diff = std::chrono::system_clock::now() - start;
|
||||||
helloVk.animationInstances(diff.count());
|
helloVk.animationInstances(diff.count());
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
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;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Make sure to rename it to `m_tlas`, instead of `tlas`.
|
Make sure to rename it to `m_tlas`, instead of `tlas`.
|
||||||
|
|
||||||
One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag.
|
One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag.
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
|
m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
|
||||||
m_rtBuilder.buildTlas(m_tlas, m_rtFlags);
|
m_rtBuilder.buildTlas(m_tlas, m_rtFlags);
|
||||||
}
|
}
|
||||||
~~~~
|
|
||||||
|
|
||||||
Back in `HelloVulkan::animationInstances()`, we need to copy the new computed transformation
|
|
||||||
matrices to the vector of `nvvk::RaytracingBuilder::Instance` objects.
|
|
||||||
|
|
||||||
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.
|
Back in `HelloVulkan::animationInstances()`, we need to update the TLAS by calling
|
||||||
|
`buildTlas` with the update to `true`.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true);
|
m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true);
|
||||||
|
|
@ -167,9 +138,9 @@ differences are:
|
||||||
|
|
||||||
* The `VkAccelerationStructureBuildGeometryInfoKHR` mode will be set to `VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR`
|
* The `VkAccelerationStructureBuildGeometryInfoKHR` mode will be set to `VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR`
|
||||||
* We will **not** create the acceleration structure, but reuse it.
|
* We will **not** create the acceleration structure, but reuse it.
|
||||||
* The source and destination of `VkAccelerationStructureCreateInfoKHR` will both use the previously created acceleration structure.
|
* The source and destination of `VkAccelerationStructureCreateInfoKHR` will both use the previously created acceleration structure.
|
||||||
|
|
||||||
What is happening is the buffer containing all matrices will be updated and the `vkCmdBuildAccelerationStructuresKHR` will update the acceleration in place.
|
What is happening is the buffer containing all matrices will be updated and the `vkCmdBuildAccelerationStructuresKHR` will update the acceleration in place.
|
||||||
|
|
||||||
## BLAS Animation
|
## BLAS Animation
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -279,7 +253,7 @@ Finally, destroy the resources in `HelloVulkan::destroyResources()`:
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### `anim.comp`
|
### `anim.comp`
|
||||||
|
|
||||||
The compute shader will be simple. We need to add a new shader file, `anim.comp`, to the `shaders` filter in the solution.
|
The compute shader will be simple. We need to add a new shader file, `anim.comp`, to the `shaders` filter in the solution.
|
||||||
|
|
||||||
|
|
@ -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++)
|
||||||
|
|
@ -440,7 +413,7 @@ void nvvk::RaytracingBuilderKHR::updateBlas(uint32_t blasIdx, BlasInput& blas, V
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The previous function (`updateBlas`) uses geometry information stored in `m_blas`.
|
The previous function (`updateBlas`) uses geometry information stored in `m_blas`.
|
||||||
To be able to re-use this information, we need to keep the structure of `nvvk::RaytracingBuilderKHR::Blas` objects
|
To be able to re-use this information, we need to keep the structure of `nvvk::RaytracingBuilderKHR::Blas` objects
|
||||||
used for its creation.
|
used for its creation.
|
||||||
|
|
||||||
|
|
@ -450,8 +423,8 @@ Move the `nvvk::RaytracingBuilderKHR::Blas` vector from `HelloVulkan::createBott
|
||||||
std::vector<nvvk::RaytracingBuilderKHR::Blas> m_blas;
|
std::vector<nvvk::RaytracingBuilderKHR::Blas> m_blas;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
As with the TLAS, the BLAS needs to allow updates. We will also enable the
|
As with the TLAS, the BLAS needs to allow updates. We will also enable the
|
||||||
`VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR` flag, which indicates that the given
|
`VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR` flag, which indicates that the given
|
||||||
acceleration structure build should prioritize build time over trace performance.
|
acceleration structure build should prioritize build time over trace performance.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
|
|
@ -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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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.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
|
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.mask = 0xFF;
|
|
||||||
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));
|
||||||
|
|
@ -883,40 +885,25 @@ 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, ®ion);
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -150,16 +146,11 @@ public:
|
||||||
VkPipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
117
ray_tracing_animation/shaders/host_device.h
Normal file
117
ray_tracing_animation/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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.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
|
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.mask = 0xFF;
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
ray_tracing_anyhit/shaders/host_device.h
Normal file
118
ray_tracing_anyhit/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# G-Buffer and Ambient Occlusion - Tutorial
|
# G-Buffer and Ambient Occlusion - Tutorial
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Tutorial ([Setup](../docs/setup.md))
|
## Tutorial ([Setup](../docs/setup.md))
|
||||||
|
|
@ -10,17 +9,16 @@ This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.
|
||||||
This extension to the tutorial is showing how G-Buffers from the fragment shader, can be used in a compute shader to cast ambient occlusion rays using
|
This extension to the tutorial is showing how G-Buffers from the fragment shader, can be used in a compute shader to cast ambient occlusion rays using
|
||||||
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.
|
||||||
Then a compute shader takes the G-buffer and sends random ambient occlusion rays into the hemisphere formed by position and normal.
|
Then a compute shader takes the G-buffer and sends random ambient occlusion rays into the hemisphere formed by position and normal.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -32,11 +30,9 @@ The following are the buffers are they can be seen in [NSight Graphics](https://
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||||
|
|
@ -77,7 +73,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
||||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||||
m_gBuffer.descriptor.imageView,
|
m_gBuffer.descriptor.imageView,
|
||||||
m_offscreenDepth.descriptor.imageView};
|
m_offscreenDepth.descriptor.imageView};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Renderpass
|
### Renderpass
|
||||||
|
|
||||||
|
|
@ -87,7 +83,7 @@ This means that the renderpass in `main()` will have to be modified as well. The
|
||||||
std::array<VkClearValue, 3> clearValues{};
|
std::array<VkClearValue, 3> clearValues{};
|
||||||
```
|
```
|
||||||
|
|
||||||
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
|
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
|
||||||
|
|
||||||
```
|
```
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
|
|
@ -110,21 +106,20 @@ 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
|
||||||
|
|
||||||
As for the [ray_tracing_rayquery](../ray_tracing_rayquery) sample, we use the VK_KHR_acceleration_structure extension to generate the ray tracing acceleration structure, while the ray tracing itself is carried out in a compute shader. This section remains unchanged compared to the rayquery example.
|
As for the [ray_tracing_rayquery](../ray_tracing_rayquery) sample, we use the VK_KHR_acceleration_structure extension to generate the ray tracing acceleration structure, while the ray tracing itself is carried out in a compute shader. This section remains unchanged compared to the rayquery example.
|
||||||
|
|
||||||
## Compute Shader
|
## Compute Shader
|
||||||
|
|
||||||
The compute shader will take the G-Buffer containing the position and normal and will randomly shot rays in the hemisphere defined by the normal.
|
The compute shader will take the G-Buffer containing the position and normal and will randomly shot rays in the hemisphere defined by the normal.
|
||||||
|
|
||||||
### Descriptor
|
### Descriptor
|
||||||
|
|
||||||
|
|
@ -147,7 +142,8 @@ 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.
|
||||||
|
|
||||||
|
|
@ -169,16 +165,14 @@ void HelloVulkan::updateCompDescriptors()
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
||||||
### 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++
|
||||||
struct AoControl
|
struct AoControl
|
||||||
|
|
@ -191,13 +185,12 @@ 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)).
|
||||||
This sets the current frame index, which allows us to accumulate AO samples over time.
|
This sets the current frame index, which allows us to accumulate AO samples over time.
|
||||||
|
|
||||||
Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||||
|
|
@ -215,7 +208,7 @@ Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is re
|
||||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Folowing is the call to dispatch the compute shader
|
Folowing is the call to dispatch the compute shader
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Preparing for the compute shader
|
// Preparing for the compute shader
|
||||||
|
|
@ -231,7 +224,7 @@ Folowing is the call to dispatch the compute shader
|
||||||
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Then we are adding a final barrier to make sure the compute shader is done
|
Then we are adding a final barrier to make sure the compute shader is done
|
||||||
writing the AO so that the fragment shader (post) can use it.
|
writing the AO so that the fragment shader (post) can use it.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
|
|
@ -247,7 +240,7 @@ writing the AO so that the fragment shader (post) can use it.
|
||||||
The following functions were added to tell which frame we are rendering.
|
The following functions were added to tell which frame we are rendering.
|
||||||
The function `updateFrame()` is called only once per frame, and we are doing this in runCompute()/
|
The function `updateFrame()` is called only once per frame, and we are doing this in runCompute()/
|
||||||
|
|
||||||
And the `resetFrame()` should be called whenever the image is changed, like in `onResize()` or
|
And the `resetFrame()` should be called whenever the image is changed, like in `onResize()` or
|
||||||
after modifying the GUI related to the AO.
|
after modifying the GUI related to the AO.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
|
|
@ -275,14 +268,15 @@ void HelloVulkan::resetFrame()
|
||||||
{
|
{
|
||||||
m_frame = -1;
|
m_frame = -1;
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## 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;
|
||||||
|
|
@ -291,34 +285,33 @@ void main()
|
||||||
// Check if not outside boundaries
|
// Check if not outside boundaries
|
||||||
if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
|
if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
|
||||||
return;
|
return;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The seed of the random number sequence is initialized using the TEA algorithm, while the random number themselves will be generated using PCG.
|
The seed of the random number sequence is initialized using the TEA algorithm, while the random number themselves will be generated using PCG.
|
||||||
This is a fine when many random numbers are generated from this seed, but tea isn't a random
|
This is a fine when many random numbers are generated from this seed, but tea isn't a random
|
||||||
number generator and if you use only one sample per pixel, you will see correlation and the AO will not look fine because it won't
|
number generator and if you use only one sample per pixel, you will see correlation and the AO will not look fine because it won't
|
||||||
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));
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The G-Buffer was cleared and we will sample the hemisphere only if a fragment was rendered. In `w`
|
The G-Buffer was cleared and we will sample the hemisphere only if a fragment was rendered. In `w`
|
||||||
we stored the compressed normal, which is nonzero only if a normal was actually stored into the pixel.
|
we stored the compressed normal, which is nonzero only if a normal was actually stored into the pixel.
|
||||||
Note that while this compression introduces some level of quantization, it does not result in visible artifacts in this example.
|
Note that while this compression introduces some level of quantization, it does not result in visible artifacts in this example.
|
||||||
|
|
||||||
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,15 +326,15 @@ 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);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
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++)
|
||||||
{
|
{
|
||||||
|
|
@ -359,16 +352,16 @@ Then we are sampling the hemisphere `rtao_samples` time, using a [cosine weighte
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The function `TraceRay` is a very simple way to send a shadow ray using ray query.
|
The function `TraceRay` is a very simple way to send a shadow ray using ray query.
|
||||||
For any type of shadow, we don't care which object we hit as long as the ray hit something
|
For any type of shadow, we don't care which object we hit as long as the ray hit something
|
||||||
before maximum length. For this, we can set the flag to `gl_RayFlagsTerminateOnFirstHitEXT`.
|
before maximum length. For this, we can set the flag to `gl_RayFlagsTerminateOnFirstHitEXT`.
|
||||||
But there is a case where we may want to know the distance of the hit from the closest hit, in this case
|
But there is a case where we may want to know the distance of the hit from the closest hit, in this case
|
||||||
the flag is set to `gl_RayFlagsNoneEXT`.
|
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);
|
||||||
|
|
@ -450,16 +443,16 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th
|
||||||
|
|
||||||
## Post shader
|
## Post shader
|
||||||
|
|
||||||
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));
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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.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
|
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.mask = 0xFF;
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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)));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
117
ray_tracing_ao/shaders/host_device.h
Normal file
117
ray_tracing_ao/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
m_instances.push_back(instance);
|
||||||
instance.txtOffset = txtOffset;
|
|
||||||
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_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
||||||
m_pushConstant.instanceId = i; // Telling which instance 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.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
|
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.mask = 0xFF;
|
|
||||||
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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
123
ray_tracing_callable/shaders/host_device.h
Normal file
123
ray_tracing_callable/shaders/host_device.h
Normal 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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue