Added back volumetric

This commit is contained in:
antopilo
2025-04-23 20:11:42 -04:00
parent e18298a8cb
commit aeac3a4e47
10 changed files with 457 additions and 7 deletions

View File

@@ -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;
}

View File

@@ -84,6 +84,7 @@ struct CopyPushConstant
{
int SourceTextureID;
int Source2TextureID;
int Mode;
};
[[vk::push_constant]]

View File

@@ -0,0 +1,201 @@
// Transforms
struct ModelData
{
float4x4 model;
};
[[vk::binding(0, 0)]]
StructuredBuffer<ModelData> 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<Vertex> 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> 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<Light> 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<CameraView> 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;
}

View File

@@ -0,0 +1,114 @@
// Transforms
struct ModelData
{
float4x4 model;
};
[[vk::binding(0, 0)]]
StructuredBuffer<ModelData> 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<Vertex> 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> 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<Light> 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<CameraView> 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;
}

View File

@@ -891,6 +891,24 @@ void SelectionPropertyWidget::DrawFile(Ref<Nuake::File> 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

View File

@@ -15,6 +15,7 @@ namespace Nuake {
float mFogExponant = 1.0f;
Vector2 mSize;
Texture* mDepth;
float mBaseAmbient = 0.1f;
Scope<FrameBuffer> mVolumetricFramebuffer;
Scope<FrameBuffer> 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; }

View File

@@ -225,12 +225,15 @@ SceneRenderPipeline::SceneRenderPipeline()
BloomOutput = CreateRef<VulkanImage>(ImageFormat::RGBA16F, defaultSize);
BloomThreshold = CreateRef<VulkanImage>(ImageFormat::RGBA16F, defaultSize);
VolumetricOutput = CreateRef<VulkanImage>(ImageFormat::RGBA8, defaultSize);
VolumetricCombineOutput = CreateRef<VulkanImage>(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), &copyConstant);
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>(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), &copyConstant);
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>(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), &copyConstant);
auto& quadMesh = VkSceneRenderer::QuadMesh;

View File

@@ -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<VulkanImage> GizmoCombineOutput;
Ref<VulkanImage> TonemappedOutput;
Ref<VulkanImage> VolumetricOutput;
Ref<VulkanImage> VolumetricCombineOutput;
Ref<VulkanImage> OutlineOutput;
@@ -183,6 +197,7 @@ namespace Nuake
CopyConstant copyConstant;
OutlineConstant outlineConstant;
BloomConstant bloomConstant;
VolumetricConstant volumetricConstant;
RenderPipeline GBufferPipeline;

View File

@@ -127,7 +127,7 @@ Ref<VulkanShader> 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<VulkanShader> ShaderCompiler::CompileShader(const std::string& path)
Ref<VulkanShader> shader = CreateRef<VulkanShader>(
static_cast<uint32_t*>(code->GetBufferPointer()),
static_cast<uint32_t>(code->GetBufferSize()), shaderType);
static_cast<uint32_t>(code->GetBufferSize()), shaderType);
shader->SetSourcePath(path);
return shader;

View File

@@ -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<Ref<Scene>>& scenes, RenderContext inContext)