Refactoring
This commit is contained in:
parent
3e399adf0a
commit
d90ce79135
222 changed files with 9045 additions and 5734 deletions
|
|
@ -1,6 +1,5 @@
|
|||
# G-Buffer and Ambient Occlusion - Tutorial
|
||||
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
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 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)
|
||||
|
||||
|
||||
|
||||
## 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.
|
||||
Then a compute shader takes the G-buffer and sends random ambient occlusion rays into the hemisphere formed by position and normal.
|
||||
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.
|
||||
|
||||

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

|
||||
|
||||
|
||||
|
||||
## 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++
|
||||
// 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,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
```
|
||||
```
|
||||
|
||||
### 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{};
|
||||
```
|
||||
|
||||
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
|
||||
|
|
@ -110,21 +106,20 @@ We are omitting the code to compress and decompress the XYZ normal to and from a
|
|||
|
||||
```
|
||||
// Outgoing
|
||||
layout(location = 0) out vec4 outColor;
|
||||
layout(location = 1) out vec4 outGbuffer;
|
||||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
layout(location = 1) out vec4 o_gbuffer;
|
||||
...
|
||||
|
||||
outGbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
|
||||
o_gbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
|
|
@ -147,7 +142,8 @@ void HelloVulkan::createCompDescriptors()
|
|||
~~~
|
||||
|
||||
### 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,
|
||||
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);
|
||||
}
|
||||
~~~~
|
||||
|
||||
~~~~
|
||||
|
||||
### 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.
|
||||
|
||||
|
||||
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++
|
||||
struct AoControl
|
||||
|
|
@ -191,13 +185,12 @@ struct AoControl
|
|||
};
|
||||
~~~~
|
||||
|
||||
|
||||
### 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.
|
||||
|
||||
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++
|
||||
// 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);
|
||||
~~~~
|
||||
|
||||
Folowing is the call to dispatch the compute shader
|
||||
Folowing is the call to dispatch the compute shader
|
||||
|
||||
~~~~ C++
|
||||
// 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);
|
||||
~~~~
|
||||
|
||||
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.
|
||||
|
||||
~~~~ 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 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.
|
||||
|
||||
~~~~ C++
|
||||
|
|
@ -275,14 +268,15 @@ void HelloVulkan::resetFrame()
|
|||
{
|
||||
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 first thing in `main()` is to check if the invocation is not exceeding the size of the image.
|
||||
~~~~
|
||||
|
||||
~~~~C
|
||||
void main()
|
||||
{
|
||||
float occlusion = 0.0;
|
||||
|
|
@ -291,34 +285,33 @@ void main()
|
|||
// Check if not outside boundaries
|
||||
if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
|
||||
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
|
||||
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
|
||||
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
|
||||
this simple technique.
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
// Initialize the random 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.
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
// Retrieving position and normal
|
||||
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`
|
||||
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.
|
||||
|
||||
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
|
||||
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.
|
||||
The function `compute_default_basis` is also in [raycommon.glsl](shaders/raycommon.glsl)
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
// Finding the basis (tangent and bitangent) from the normal
|
||||
vec3 n, 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/)
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
// Sampling hemiphere n-time
|
||||
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
|
||||
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
|
||||
the flag is set to `gl_RayFlagsNoneEXT`.
|
||||
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 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`
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
//----------------------------------------------------------------------------
|
||||
// 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.
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
// Writting out the AO
|
||||
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.
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
// Rendering Scene
|
||||
{
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
~~~~
|
||||
|
||||
And the equivalent in `updatePostDescriptorSet()`
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
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
|
||||
|
||||
~~~~
|
||||
~~~~C
|
||||
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);
|
||||
float ao = texture(aoTxt, uv).x;
|
||||
|
||||
fragColor = pow(color * ao, vec4(gamma));
|
||||
~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -40,15 +40,6 @@
|
|||
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
|
||||
// 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.
|
||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||
CameraMatrices hostUBO = {};
|
||||
hostUBO.view = CameraManip.getMatrix();
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||
GlobalUniforms hostUBO = {};
|
||||
const auto& view = CameraManip.getMatrix();
|
||||
const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
// proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||
|
||||
hostUBO.viewProj = proj * view;
|
||||
hostUBO.viewInverse = nvmath::invert(view);
|
||||
hostUBO.projInverse = nvmath::invert(proj);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
|
|
@ -111,12 +105,13 @@ void HelloVulkan::createDescriptorSetLayout()
|
|||
{
|
||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||
|
||||
// Camera matrices (binding = 0)
|
||||
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||
// Scene description (binding = 1)
|
||||
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Textures (binding = 3)
|
||||
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Camera matrices
|
||||
m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||
// Obj descriptions
|
||||
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | 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);
|
||||
|
|
@ -132,11 +127,11 @@ void HelloVulkan::updateDescriptorSet()
|
|||
std::vector<VkWriteDescriptorSet> writes;
|
||||
|
||||
// Camera matrices and scene description
|
||||
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||
VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
|
||||
|
||||
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 1, &dbiSceneDesc));
|
||||
VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
|
||||
|
||||
// All texture samplers
|
||||
std::vector<VkDescriptorImageInfo> diit;
|
||||
|
|
@ -144,7 +139,7 @@ void HelloVulkan::updateDescriptorSet()
|
|||
{
|
||||
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
|
||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
|
|
@ -156,7 +151,7 @@ void HelloVulkan::updateDescriptorSet()
|
|||
//
|
||||
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
|
||||
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.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);
|
||||
// Creates all textures found
|
||||
uint32_t txtOffset = static_cast<uint32_t>(m_textures.size());
|
||||
// Creates all textures found and find the offset for this model
|
||||
auto txtOffset = static_cast<uint32_t>(m_textures.size());
|
||||
createTextureImages(cmdBuf, loader.m_textures);
|
||||
cmdBufGet.submitAndWait(cmdBuf);
|
||||
m_alloc.finalizeAndReleaseStaging();
|
||||
|
||||
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.indexBuffer.buffer, (std::string("index_" + objNb).c_str()));
|
||||
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb).c_str()));
|
||||
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb).c_str()));
|
||||
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
|
||||
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
|
||||
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
|
||||
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
|
||||
|
||||
// Keeping transformation matrix of the instance
|
||||
ObjInstance instance;
|
||||
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||
instance.transform = transform;
|
||||
instance.transformIT = nvmath::transpose(nvmath::invert(transform));
|
||||
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);
|
||||
instance.transform = transform;
|
||||
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
|
||||
m_instances.push_back(instance);
|
||||
|
||||
// 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_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()
|
||||
{
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||
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);
|
||||
m_debug.setObjectName(m_bGlobals.buffer, "Globals");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -265,15 +265,15 @@ void HelloVulkan::createUniformBuffer()
|
|||
// - Transformation
|
||||
// - Offset for texture
|
||||
//
|
||||
void HelloVulkan::createSceneDescriptionBuffer()
|
||||
void HelloVulkan::createObjDescriptionBuffer()
|
||||
{
|
||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||
|
||||
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);
|
||||
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);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||
|
||||
m_alloc.destroy(m_cameraMat);
|
||||
m_alloc.destroy(m_sceneDesc);
|
||||
m_alloc.destroy(m_bGlobals);
|
||||
m_alloc.destroy(m_bObjDesc);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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];
|
||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||
auto& model = m_objModel[inst.objIndex];
|
||||
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,
|
||||
sizeof(ObjPushConstant), &m_pushConstant);
|
||||
sizeof(PushConstantRaster), &m_pcRaster);
|
||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||
|
|
@ -441,10 +441,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/)
|
|||
resetFrame();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Post-processing
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// 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.
|
||||
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.vertexStride = sizeof(VertexObj);
|
||||
// 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);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
void HelloVulkan::createTopLevelAS()
|
||||
{
|
||||
std::vector<VkAccelerationStructureInstanceKHR> tlas;
|
||||
tlas.reserve(m_objInstance.size());
|
||||
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
|
||||
tlas.reserve(m_instances.size());
|
||||
for(const HelloVulkan::ObjInstance& inst : m_instances)
|
||||
{
|
||||
VkAccelerationStructureInstanceKHR rayInst;
|
||||
rayInst.transform = nvvk::toTransformMatrixKHR(m_objInstance[i].transform); // Position of the instance
|
||||
rayInst.instanceCustomIndex = i; // gl_InstanceCustomIndexEXT
|
||||
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[i].objIndex);
|
||||
VkAccelerationStructureInstanceKHR rayInst{};
|
||||
rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
|
||||
rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
|
||||
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.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
rayInst.mask = 0xFF;
|
||||
tlas.emplace_back(rayInst);
|
||||
}
|
||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
#include "shaders/host_device.h"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -55,7 +56,7 @@ public:
|
|||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createObjDescriptionBuffer();
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
|
|
@ -73,32 +74,27 @@ public:
|
|||
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
|
||||
};
|
||||
|
||||
// Instance of the OBJ
|
||||
struct ObjInstance
|
||||
{
|
||||
nvmath::mat4f transform{1}; // Position of the instance
|
||||
nvmath::mat4f transformIT{1}; // Inverse transpose
|
||||
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;
|
||||
nvmath::mat4f transform; // Matrix of the instance
|
||||
uint32_t objIndex{0}; // Model index reference
|
||||
};
|
||||
|
||||
|
||||
// Information pushed at each draw call
|
||||
struct ObjPushConstant
|
||||
{
|
||||
nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
|
||||
int instanceId{0}; // To retrieve the transformation matrix
|
||||
float lightIntensity{100.f};
|
||||
int lightType{0}; // 0: point, 1: infinite
|
||||
PushConstantRaster m_pcRaster{
|
||||
{1}, // Identity matrix
|
||||
{10.f, 15.f, 8.f}, // light position
|
||||
0, // instance Id
|
||||
100.f, // light intensity
|
||||
0 // light type
|
||||
};
|
||||
ObjPushConstant m_pushConstant;
|
||||
|
||||
// Array of objects and instances in the scene
|
||||
std::vector<ObjModel> m_objModel;
|
||||
std::vector<ObjInstance> m_objInstance;
|
||||
std::vector<ObjModel> m_objModel; // Model on host
|
||||
std::vector<ObjDesc> m_objDesc; // Model description for device access
|
||||
std::vector<ObjInstance> m_instances; // Scene model instances
|
||||
|
||||
|
||||
// Graphic pipeline
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
|
|
@ -108,8 +104,8 @@ public:
|
|||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
|
||||
|
||||
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
|
||||
|
||||
|
||||
// #Post
|
||||
// #Post - Draw the rendered image on a quad using a tonemapper
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
|
|
|
|||
|
|
@ -57,12 +57,12 @@ void renderUI(HelloVulkan& helloVk)
|
|||
ImGuiH::CameraWidget();
|
||||
if(ImGui::CollapsingHeader("Light"))
|
||||
{
|
||||
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
|
||||
ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
|
||||
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::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f);
|
||||
ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.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);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
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.createGraphicsPipeline();
|
||||
helloVk.createUniformBuffer();
|
||||
helloVk.createSceneDescriptionBuffer();
|
||||
helloVk.createObjDescriptionBuffer();
|
||||
|
||||
// #VKRay
|
||||
helloVk.initRayTracing();
|
||||
|
|
|
|||
|
|
@ -30,62 +30,58 @@
|
|||
#include "wavefront.glsl"
|
||||
|
||||
|
||||
layout(push_constant) uniform shaderInformation
|
||||
layout(push_constant) uniform _PushConstantRaster
|
||||
{
|
||||
vec3 lightPosition;
|
||||
uint instanceId;
|
||||
float lightIntensity;
|
||||
int lightType;
|
||||
}
|
||||
pushC;
|
||||
PushConstantRaster pcRaster;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// Incoming
|
||||
layout(location = 1) in vec2 fragTexCoord;
|
||||
layout(location = 2) in vec3 fragNormal;
|
||||
layout(location = 3) in vec3 viewDir;
|
||||
layout(location = 4) in vec3 worldPos;
|
||||
layout(location = 1) in vec3 i_worldPos;
|
||||
layout(location = 2) in vec3 i_worldNrm;
|
||||
layout(location = 3) in vec3 i_viewDir;
|
||||
layout(location = 4) in vec2 i_texCoord;
|
||||
// Outgoing
|
||||
layout(location = 0) out vec4 outColor;
|
||||
layout(location = 1) out vec4 outGbuffer;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
layout(location = 1) out vec4 o_gbuffer;
|
||||
|
||||
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 Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
||||
|
||||
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
|
||||
layout(binding = 2) uniform sampler2D[] textureSamplers;
|
||||
layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
||||
layout(binding = eTextures) uniform sampler2D[] textureSamplers;
|
||||
// clang-format on
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// Material of the object
|
||||
SceneDesc objResource = sceneDesc.i[pushC.instanceId];
|
||||
ObjDesc objResource = objDesc.i[pcRaster.objIndex];
|
||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
||||
Materials materials = Materials(objResource.materialAddress);
|
||||
|
||||
int matIndex = matIndices.i[gl_PrimitiveID];
|
||||
WaveFrontMaterial mat = materials.m[matIndex];
|
||||
|
||||
vec3 N = normalize(fragNormal);
|
||||
vec3 N = normalize(i_worldNrm);
|
||||
|
||||
// Vector toward light
|
||||
vec3 L;
|
||||
float lightDistance;
|
||||
float lightIntensity = pushC.lightIntensity;
|
||||
if(pushC.lightType == 0)
|
||||
float lightIntensity = pcRaster.lightIntensity;
|
||||
if(pcRaster.lightType == 0)
|
||||
{
|
||||
vec3 lDir = pushC.lightPosition - worldPos;
|
||||
vec3 lDir = pcRaster.lightPosition - i_worldPos;
|
||||
float d = length(lDir);
|
||||
lightIntensity = pushC.lightIntensity / (d * d);
|
||||
lightIntensity = pcRaster.lightIntensity / (d * d);
|
||||
L = normalize(lDir);
|
||||
lightDistance = d;
|
||||
}
|
||||
else
|
||||
{
|
||||
L = normalize(pushC.lightPosition - vec3(0));
|
||||
L = normalize(pcRaster.lightPosition - vec3(0));
|
||||
lightDistance = 10000;
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +91,7 @@ void main()
|
|||
diffuse = vec3(1);
|
||||
// if(mat.textureId >= 0)
|
||||
// {
|
||||
// int txtOffset = sceneDesc.i[pushC.instanceId].txtOffset;
|
||||
// int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
|
||||
// uint txtId = txtOffset + mat.textureId;
|
||||
// vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz;
|
||||
// diffuse *= diffuseTxt;
|
||||
|
|
@ -104,9 +100,8 @@ void main()
|
|||
// Specular
|
||||
vec3 specular = vec3(0); //computeSpecular(mat, viewDir, L, N);
|
||||
lightIntensity = 1;
|
||||
|
||||
// Result
|
||||
outColor = vec4(lightIntensity * (diffuse + specular), 1);
|
||||
|
||||
|
||||
outGbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N)));
|
||||
o_color = vec4(lightIntensity * (diffuse + specular), 1);
|
||||
o_gbuffer.rgba = vec4(i_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"
|
||||
|
||||
// clang-format off
|
||||
layout(binding = 1, scalar) buffer SceneDesc_ { SceneDesc i[]; } sceneDesc;
|
||||
// clang-format on
|
||||
|
||||
layout(binding = 0) uniform UniformBufferObject
|
||||
layout(binding = 0) uniform _GlobalUniforms
|
||||
{
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
mat4 viewI;
|
||||
}
|
||||
ubo;
|
||||
GlobalUniforms uni;
|
||||
};
|
||||
|
||||
layout(push_constant) uniform shaderInformation
|
||||
layout(push_constant) uniform _PushConstantRaster
|
||||
{
|
||||
vec3 lightPosition;
|
||||
uint instanceId;
|
||||
float lightIntensity;
|
||||
int lightType;
|
||||
}
|
||||
pushC;
|
||||
PushConstantRaster pcRaster;
|
||||
};
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
layout(location = 3) in vec2 inTexCoord;
|
||||
layout(location = 0) in vec3 i_position;
|
||||
layout(location = 1) in vec3 i_normal;
|
||||
layout(location = 2) in vec3 i_color;
|
||||
layout(location = 3) in vec2 i_texCoord;
|
||||
|
||||
|
||||
//layout(location = 0) flat out int matIndex;
|
||||
layout(location = 1) out vec2 fragTexCoord;
|
||||
layout(location = 2) out vec3 fragNormal;
|
||||
layout(location = 3) out vec3 viewDir;
|
||||
layout(location = 4) out vec3 worldPos;
|
||||
layout(location = 1) out vec3 o_worldPos;
|
||||
layout(location = 2) out vec3 o_worldNrm;
|
||||
layout(location = 3) out vec3 o_viewDir;
|
||||
layout(location = 4) out vec2 o_texCoord;
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
|
|
@ -67,16 +55,12 @@ out gl_PerVertex
|
|||
|
||||
void main()
|
||||
{
|
||||
mat4 objMatrix = sceneDesc.i[pushC.instanceId].transfo;
|
||||
mat4 objMatrixIT = sceneDesc.i[pushC.instanceId].transfoIT;
|
||||
vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
|
||||
|
||||
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));
|
||||
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);
|
||||
gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,41 +17,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
#include "host_device.h"
|
||||
|
||||
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue