diff --git a/Data/Shaders/Vulkan/copy.frag b/Data/Shaders/Vulkan/copy.frag index e14916d4..5bd8421c 100644 --- a/Data/Shaders/Vulkan/copy.frag +++ b/Data/Shaders/Vulkan/copy.frag @@ -94,6 +94,7 @@ struct CopyPushConstant { int SourceTextureID; int Source2TextureID; + int Mode; }; [[vk::push_constant]] @@ -110,6 +111,14 @@ PSOutput main(PSInput input) float4 sampleValue = textures[sourceTextureID].Sample(mySampler, input.UV); float4 sampleValue2 = textures[source2TextureID].Sample(mySampler, input.UV); - output.oColor0 = lerp(sampleValue, sampleValue2, 1.0 - sampleValue.a); + if(pushConstants.Mode == 0) + { + output.oColor0 = lerp(sampleValue, sampleValue2, 1.0 - sampleValue.a); + } + else if(pushConstants.Mode == 1) + { + output.oColor0 = sampleValue; + output.oColor0 = sampleValue + sampleValue2; + } return output; } \ No newline at end of file diff --git a/Data/Shaders/Vulkan/copy.vert b/Data/Shaders/Vulkan/copy.vert index 70d6d173..2c233ab7 100644 --- a/Data/Shaders/Vulkan/copy.vert +++ b/Data/Shaders/Vulkan/copy.vert @@ -84,6 +84,7 @@ struct CopyPushConstant { int SourceTextureID; int Source2TextureID; + int Mode; }; [[vk::push_constant]] diff --git a/Data/Shaders/Vulkan/volumetric.frag b/Data/Shaders/Vulkan/volumetric.frag new file mode 100644 index 00000000..43e2b29b --- /dev/null +++ b/Data/Shaders/Vulkan/volumetric.frag @@ -0,0 +1,201 @@ +// Transforms +struct ModelData +{ + float4x4 model; +}; +[[vk::binding(0, 0)]] +StructuredBuffer model : register(t1); + +// Vertex +struct Vertex +{ + float3 position; + float uv_x; + float3 normal; + float uv_y; + float3 tangent; + float3 bitangent; +}; + +[[vk::binding(0, 1)]] +StructuredBuffer vertexBuffer : register(t2); + +// Samplers +[[vk::binding(0, 2)]] +SamplerState mySampler : register(s0); + +// Materials +struct Material +{ + bool hasAlbedo; + float3 albedo; + bool hasNormal; + bool hasMetalness; + bool hasRoughness; + bool hasAO; + float metalnessValue; + float roughnessValue; + float aoValue; + int albedoTextureId; + int normalTextureId; + int metalnessTextureId; + int roughnessTextureId; + int aoTextureId; +}; +[[vk::binding(0, 3)]] +StructuredBuffer material; + +// Textures +[[vk::binding(0, 4)]] +Texture2D textures[]; + +// Lights +struct Light +{ + float3 position; + int type; + float4 color; + float3 direction; + float outerConeAngle; + float innerConeAngle; + bool castShadow; + int shadowMapTextureId[4]; + int transformId[4]; +}; + +[[vk::binding(0, 5)]] +StructuredBuffer lights; + +// Cameras +struct CameraView { + float4x4 View; + float4x4 Projection; + float4x4 ViewProjection; + float4x4 InverseView; + float4x4 InverseProjection; + float3 Position; + float Near; + float Far; +}; +[[vk::binding(0, 6)]] +StructuredBuffer cameras; + +struct PSInput +{ + float4 Position : SV_Position; + float2 UV : TEXCOORD0; +}; + +struct PSOutput { + float4 oColor0 : SV_TARGET; +}; + +struct VolumetricConstant +{ + int DepthTextureID; + int StepCount; + float FogAmount; + float Exponant; + int CamViewID; + int LightCount; + float Ambient; +}; + +[[vk::push_constant]] +VolumetricConstant pushConstants; + +float2 GetTexelSize(Texture2D tex) +{ + uint width, height; + tex.GetDimensions(width, height); + return 1.0 / float2(width, height); +} + +float LinearizeDepth(float depth, float nearPlane, float farPlane) +{ + return (2.0 * nearPlane) / (farPlane + nearPlane - (1.0 - depth) * (farPlane - nearPlane)); +} + +float ComputeScattering(float lightDotView) +{ + float PI = 3.141592653589793f; + float result = 1.0f - pushConstants.FogAmount; + result /= (4.0f * PI * pow(1.0f + pushConstants.FogAmount * pushConstants.FogAmount - (1.0f * pushConstants.FogAmount) * lightDotView, 1.5f)); + return result; +} + +float3 WorldPosFromDepth(float depth, float2 uv, float4x4 invProj, float4x4 invView) +{ + float z = depth; + float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f); + float4 viewSpacePosition = mul(invProj, clipSpacePosition); + viewSpacePosition /= viewSpacePosition.w; + + float4 worldSpacePosition = mul(invView, viewSpacePosition); + return worldSpacePosition.xyz; +} + +PSOutput main(PSInput input) +{ + CameraView camView = cameras[pushConstants.CamViewID]; + float3 startPosition = camView.Position; + + int depthTexture = pushConstants.DepthTextureID; + float depth = textures[depthTexture].Sample(mySampler, input.UV).r; + + float3 worldPos = WorldPosFromDepth(depth, input.UV, camView.InverseProjection, camView.InverseView); + + float3 rayVector = worldPos - startPosition; + + float rayLength = length(rayVector); + + PSOutput output; + if(rayLength > 1000.0) + { + output.oColor0 = float4(0.0f, 0.0f, 0, 0.0f); + return output; + } + + float stepLength = rayLength / pushConstants.StepCount; + float3 rayDirection = rayVector / rayLength; + float3 step = rayDirection * stepLength; + + float3 accumFog = float3(0, 0, 0); + float3 currentPosition = startPosition; + for(int i = 0; i < pushConstants.StepCount; i++) + { + for(int l = 0; l < pushConstants.LightCount; l++) + { + Light light = lights[l]; + if(light.type != 0) + { + continue; + } + + CameraView lightView = cameras[light.transformId[0]]; + float4 fragPosLightSpace = mul(lightView.Projection, mul(lightView.View, float4(currentPosition, 1.0))); + float3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; + projCoords.xy = projCoords.xy * 0.5 + 0.5; + + float currentDepth = projCoords.z; + float closestDepth = textures[light.shadowMapTextureId[0]].Sample(mySampler, projCoords.xy).r; + + if(closestDepth < currentDepth) + { + accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color) * pushConstants.Exponant; + } + else + { + accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color) * pushConstants.Ambient; + } + } + + currentPosition += step; + + } + + accumFog /= pushConstants.StepCount; + + output.oColor0 = float4(accumFog.x, accumFog.y, accumFog.z, 1.0f); + return output; +} \ No newline at end of file diff --git a/Data/Shaders/Vulkan/volumetric.vert b/Data/Shaders/Vulkan/volumetric.vert new file mode 100644 index 00000000..eade2f67 --- /dev/null +++ b/Data/Shaders/Vulkan/volumetric.vert @@ -0,0 +1,114 @@ +// Transforms +struct ModelData +{ + float4x4 model; +}; +[[vk::binding(0, 0)]] +StructuredBuffer model : register(t1); + +// Vertex +struct Vertex +{ + float3 position; + float uv_x; + float3 normal; + float uv_y; + float3 tangent; + float3 bitangent; +}; + +[[vk::binding(0, 1)]] +StructuredBuffer vertexBuffer : register(t2); + +// Samplers +[[vk::binding(0, 2)]] +SamplerState mySampler : register(s0); + +// Materials +struct Material +{ + bool hasAlbedo; + float3 albedo; + bool hasNormal; + bool hasMetalness; + bool hasRoughness; + bool hasAO; + float metalnessValue; + float roughnessValue; + float aoValue; + int albedoTextureId; + int normalTextureId; + int metalnessTextureId; + int roughnessTextureId; + int aoTextureId; +}; +[[vk::binding(0, 3)]] +StructuredBuffer material; + +// Textures +[[vk::binding(0, 4)]] +Texture2D textures[]; + +// Lights +struct Light +{ + float3 position; + int type; + float4 color; + float3 direction; + float outerConeAngle; + float innerConeAngle; + bool castShadow; + int shadowMapTextureId[4]; + int transformId[4]; +}; + +[[vk::binding(0, 5)]] +StructuredBuffer lights; + +// Cameras +struct CameraView { + float4x4 View; + float4x4 Projection; + float4x4 ViewProjection; + float4x4 InverseView; + float4x4 InverseProjection; + float3 Position; + float Near; + float Far; +}; +[[vk::binding(0, 6)]] +StructuredBuffer cameras; + +struct VolumetricConstant +{ + int DepthTextureID; + int StepCount; + float FogAmount; + float Exponant; + int CamViewID; + int LightCount; + float Ambient; +}; + +[[vk::push_constant]] +VolumetricConstant pushConstants; + +// Outputs +struct VSOutput +{ + float4 Position : SV_Position; + float2 UV : TEXCOORD0; +}; + +// Main vertex shader +VSOutput main(uint vertexIndex : SV_VertexID) +{ + VSOutput output; + + Vertex v = vertexBuffer[vertexIndex]; + output.UV = float2(v.uv_x, v.uv_y); + output.Position = float4(v.position, 1.0f); + + return output; +} \ No newline at end of file diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp b/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp index dcfced7f..3c409ff8 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp @@ -891,6 +891,24 @@ void SelectionPropertyWidget::DrawFile(Ref file) ImGui::PopStyleColor(); } + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Base Ambient"); + ImGui::TableNextColumn(); + + float fogAmount = env->mVolumetric->GetBaseAmbient(); + ImGui::DragFloat("##Base Ambient", &fogAmount, .001f, 0.f, 1.0f); + env->mVolumetric->SetBaseAmbient(fogAmount); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetBase"); + if (ImGui::Button(resetBloomThreshold.c_str())) env->mVolumetric->SetBaseAmbient(0.1f); + ImGui::PopStyleColor(); + } + ImGui::TableNextColumn(); { // Title diff --git a/Nuake/Source/Nuake/Rendering/PostFX/Volumetric.h b/Nuake/Source/Nuake/Rendering/PostFX/Volumetric.h index 884fe3d7..abac35f2 100644 --- a/Nuake/Source/Nuake/Rendering/PostFX/Volumetric.h +++ b/Nuake/Source/Nuake/Rendering/PostFX/Volumetric.h @@ -15,6 +15,7 @@ namespace Nuake { float mFogExponant = 1.0f; Vector2 mSize; Texture* mDepth; + float mBaseAmbient = 0.1f; Scope mVolumetricFramebuffer; Scope mFinalFramebuffer; @@ -31,6 +32,8 @@ namespace Nuake { inline void SetStepCount(unsigned int amount) { mStepCount = amount; } + void SetBaseAmbient(float value) { mBaseAmbient = value; } + float GetBaseAmbient() const { return mBaseAmbient; } void SetFogExponant(float expo) { mFogExponant = expo; } float GetFogExponant() const { return mFogExponant; } diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp index d3b626fb..3654d0c1 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp @@ -225,12 +225,15 @@ SceneRenderPipeline::SceneRenderPipeline() BloomOutput = CreateRef(ImageFormat::RGBA16F, defaultSize); BloomThreshold = CreateRef(ImageFormat::RGBA16F, defaultSize); + VolumetricOutput = CreateRef(ImageFormat::RGBA8, defaultSize); + VolumetricCombineOutput = CreateRef(ImageFormat::RGBA8, defaultSize); + RecreatePipeline(); } SceneRenderPipeline::~SceneRenderPipeline() { - auto& res = GPUResources::Get(); + auto& res = GPUResources::Get(); res.RemoveTexture(GBufferAlbedo); res.RemoveTexture(GBufferNormal); res.RemoveTexture(GBufferMaterial); @@ -246,6 +249,8 @@ SceneRenderPipeline::~SceneRenderPipeline() res.RemoveTexture(GizmoCombineOutput); res.RemoveTexture(BloomOutput); res.RemoveTexture(BloomThreshold); + res.RemoveTexture(VolumetricOutput); + res.RemoveTexture(VolumetricCombineOutput); } void SceneRenderPipeline::SetCamera(UUID camera) @@ -274,6 +279,9 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx) SSAOOutput = ResizeImage(ctx, SSAOOutput, ctx.resolution); SSAOBlurOutput = ResizeImage(ctx, SSAOBlurOutput, ctx.resolution); + VolumetricOutput = ResizeImage(ctx, VolumetricOutput, ctx.resolution); + VolumetricCombineOutput = ResizeImage(ctx, VolumetricCombineOutput, ctx.resolution); + OutlineOutput = ResizeImage(ctx, OutlineOutput, ctx.resolution); Color clearColor = ctx.scene->GetEnvironment()->AmbientColor; @@ -286,6 +294,8 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx) { SSAOBlurOutput }, { ShadingOutput }, // Shading { TonemappedOutput }, // Tonemap + { VolumetricOutput }, + { VolumetricCombineOutput }, { GizmoOutput, GBufferEntityID, GBufferDepth }, // Reusing depth from gBuffer { GizmoCombineOutput }, { OutlineOutput }, @@ -599,6 +609,81 @@ void SceneRenderPipeline::RecreatePipeline() cmd.DrawIndexed(6); }); + auto& volumetricPass = GBufferPipeline.AddPass("Volumetric"); + volumetricPass.SetShaders(shaderMgr.GetShader("volumetric_vert"), shaderMgr.GetShader("volumetric_frag")); + volumetricPass.SetPushConstant(volumetricConstant); + volumetricPass.AddInput("Depth"); + volumetricPass.AddAttachment("VolumetricOutput", VolumetricOutput->GetFormat()); + volumetricPass.SetDepthTest(false); + volumetricPass.SetPreRender([&](PassRenderContext& ctx) + { + Cmd& cmd = ctx.commandBuffer; + auto& layout = ctx.renderPass->PipelineLayout; + auto& res = GPUResources::Get(); + + //ctx.renderPass->SetClearColor({0, 0, 0, 0}); + + cmd.BindDescriptorSet(layout, res.ModelDescriptor, 0); + cmd.BindDescriptorSet(layout, res.SamplerDescriptor, 2); + cmd.BindDescriptorSet(layout, res.MaterialDescriptor, 3); + cmd.BindDescriptorSet(layout, res.TexturesDescriptor, 4); + cmd.BindDescriptorSet(layout, res.LightsDescriptor, 5); + cmd.BindDescriptorSet(layout, res.CamerasDescriptor, 6); + }); + volumetricPass.SetRender([&](PassRenderContext& ctx) + { + auto& cmd = ctx.commandBuffer; + auto env = ctx.scene->GetEnvironment(); + volumetricConstant.FogAmount = env->mVolumetric->GetFogAmount(); + volumetricConstant.StepCount = env->mVolumetric->GetStepCount(); + volumetricConstant.Exponant = env->mVolumetric->GetFogExponant(); + volumetricConstant.Ambient = env->mVolumetric->GetBaseAmbient(); + auto& res = GPUResources::Get(); + volumetricConstant.DepthTextureID = res.GetBindlessTextureID(GBufferDepth->GetID()); + volumetricConstant.CamViewID = ctx.cameraID; + volumetricConstant.LightCount = res.LightCount; + + cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(VolumetricConstant), &volumetricConstant); + + auto& quadMesh = VkSceneRenderer::QuadMesh; + cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1); + cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer()); + cmd.DrawIndexed(6); + }); + + auto& volumetricCombinePass = GBufferPipeline.AddPass("VolumetricCombine"); + volumetricCombinePass.SetPushConstant(copyConstant); + volumetricCombinePass.SetShaders(shaderMgr.GetShader("copy_vert"), shaderMgr.GetShader("copy_frag")); + volumetricCombinePass.AddAttachment("VolumetricCombineOutput", VolumetricCombineOutput->GetFormat()); + volumetricCombinePass.SetDepthTest(false); + volumetricCombinePass.SetPreRender([&](PassRenderContext& ctx) + { + Cmd& cmd = ctx.commandBuffer; + auto& layout = ctx.renderPass->PipelineLayout; + auto& res = GPUResources::Get(); + + cmd.BindDescriptorSet(layout, res.ModelDescriptor, 0); + cmd.BindDescriptorSet(layout, res.SamplerDescriptor, 2); + cmd.BindDescriptorSet(layout, res.MaterialDescriptor, 3); + cmd.BindDescriptorSet(layout, res.TexturesDescriptor, 4); + cmd.BindDescriptorSet(layout, res.LightsDescriptor, 5); + cmd.BindDescriptorSet(layout, res.CamerasDescriptor, 6); + }); + volumetricCombinePass.SetRender([&](PassRenderContext& ctx) + { + auto& cmd = ctx.commandBuffer; + + copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(VolumetricOutput->GetID()); + copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(TonemappedOutput->GetID()); + copyConstant.Mode = 1; + cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), ©Constant); + + auto& quadMesh = VkSceneRenderer::QuadMesh; + cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1); + cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer()); + cmd.DrawIndexed(6); + }); + auto& gizmoPass = GBufferPipeline.AddPass("Gizmo"); gizmoPass.SetShaders(shaderMgr.GetShader("gizmo_vert"), shaderMgr.GetShader("gizmo_frag")); gizmoPass.SetPushConstant(debugConstant); @@ -640,7 +725,7 @@ void SceneRenderPipeline::RecreatePipeline() cmd.BindDescriptorSet(layout, res.ModelDescriptor, 0); cmd.BindDescriptorSet(layout, res.SamplerDescriptor, 2); - cmd.BindDescriptorSet(layout, res.MaterialDescriptor, 3); + cmd.BindDescriptorSet(layout, res.MaterialDescriptor, 3); cmd.BindDescriptorSet(layout, res.TexturesDescriptor, 4); cmd.BindDescriptorSet(layout, res.LightsDescriptor, 5); cmd.BindDescriptorSet(layout, res.CamerasDescriptor, 6); @@ -650,7 +735,8 @@ void SceneRenderPipeline::RecreatePipeline() auto& cmd = ctx.commandBuffer; copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(GizmoOutput->GetID()); - copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(TonemappedOutput->GetID()); + copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(VolumetricCombineOutput->GetID()); + copyConstant.Mode = 0; cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), ©Constant); auto& quadMesh = VkSceneRenderer::QuadMesh; @@ -662,7 +748,7 @@ void SceneRenderPipeline::RecreatePipeline() auto& outlinePass = GBufferPipeline.AddPass("Outline"); outlinePass.SetShaders(shaderMgr.GetShader("outline_vert"), shaderMgr.GetShader("outline_frag")); outlinePass.SetPushConstant(outlineConstant); - outlinePass.AddAttachment("GizmoCombineOutput", ImageFormat::RGBA8); + outlinePass.AddAttachment("GizmoCombineOutput", GizmoCombineOutput->GetFormat()); outlinePass.SetDepthTest(false); outlinePass.AddInput("ShadingOutput"); outlinePass.AddInput("EntityID"); @@ -751,6 +837,7 @@ void SceneRenderPipeline::RecreatePipeline() copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(LineOutput->GetID()); copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(OutlineOutput->GetID()); + copyConstant.Mode = 0; cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), ©Constant); auto& quadMesh = VkSceneRenderer::QuadMesh; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h index c86d8c3e..35559ff1 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h @@ -89,10 +89,22 @@ namespace Nuake int SourceTextureID; }; + struct VolumetricConstant + { + int DepthTextureID; + int StepCount; + float FogAmount; + float Exponant; + int CamViewID; + int LightCount; + float Ambient; + }; + struct CopyConstant { int SourceTextureID; int Source2TextureID; + int Mode; }; struct OutlineConstant @@ -158,6 +170,8 @@ namespace Nuake Ref GizmoCombineOutput; Ref TonemappedOutput; + Ref VolumetricOutput; + Ref VolumetricCombineOutput; Ref OutlineOutput; @@ -183,6 +197,7 @@ namespace Nuake CopyConstant copyConstant; OutlineConstant outlineConstant; BloomConstant bloomConstant; + VolumetricConstant volumetricConstant; RenderPipeline GBufferPipeline; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp index cf909727..eed2b10d 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp @@ -127,7 +127,7 @@ Ref ShaderCompiler::CompileShader(const std::string& path) Logger::Log("Shader compilation failed: " + errorMsgStr, "DXC", CRITICAL); - throw std::runtime_error("Shader compilation failed: " + errorMsgStr); + throw std::runtime_error("Shader compilation failed: " + errorMsgStr); } else { @@ -141,7 +141,7 @@ Ref ShaderCompiler::CompileShader(const std::string& path) Ref shader = CreateRef( static_cast(code->GetBufferPointer()), - static_cast(code->GetBufferSize()), shaderType); + static_cast(code->GetBufferSize()), shaderType); shader->SetSourcePath(path); return shader; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp index ecd19911..c7fa7491 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -415,6 +415,8 @@ void VkSceneRenderer::LoadShaders() shaderMgr.AddShader("ssao_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/ssao.vert")); shaderMgr.AddShader("blur_frag", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/blur.frag")); shaderMgr.AddShader("blur_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/blur.vert")); + shaderMgr.AddShader("volumetric_frag", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/volumetric.frag")); + shaderMgr.AddShader("volumetric_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/volumetric.vert")); } void VkSceneRenderer::PrepareScenes(const std::vector>& scenes, RenderContext inContext)