Finished SSAO and debug lines rendering

This commit is contained in:
antopilo
2025-04-13 18:16:12 -04:00
parent ad581b1d4e
commit b2510a4365
9 changed files with 631 additions and 110 deletions

View File

@@ -262,7 +262,24 @@ void ViewportWidget::OnLineDraw(DebugLineCmd& lineCmd)
Matrix4 transform = Matrix4(1.0f);
transform = glm::translate(transform, { 0, 2, 0 });
lineCmd.DrawLine(proj * view * transform, Color(1, 0, 0, 1), 4.0f);
//lineCmd.DrawLine(proj * view * transform, Color(1, 0, 0, 1), 2.0f);
auto camView = scene->m_Registry.view<TransformComponent, CameraComponent>();
for (auto e : camView)
{
auto [transform, camera] = scene->m_Registry.get<TransformComponent, CameraComponent>(e);
const Quat& globalRotation = glm::normalize(transform.GetGlobalRotation());
const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation);
const float aspectRatio = camera.CameraInstance->AspectRatio;
const float fov = camera.CameraInstance->Fov;
Matrix4 clampedProj = glm::perspectiveFov(glm::radians(fov), 9.0f * aspectRatio, 9.0f, 0.05f, 3.0f);
Matrix4 boxTransform = glm::translate(scene->m_EditorCamera->GetTransform(), Vector3(transform.GetGlobalTransform()[3])) * rotationMatrix * glm::inverse(clampedProj);
lineCmd.DrawBox(proj * boxTransform, Color(1, 0, 0, 1.0f), 1.5f, false);
}
//lineCmd.DrawArrow({3, 3, 0}, {7, 3, 0}, proj, view, Color(1, 0, 0, 1), 3.0f);
}
void ViewportWidget::OnDebugDraw(DebugCmd& debugCmd)

View File

@@ -41,6 +41,8 @@ void DebugCmd::DrawTexturedQuad(const Matrix4& transform, Ref<VulkanImage> textu
cmd.DrawIndexed(6);
}
DebugLineCmd::DebugLineCmd(Cmd& inCmd, PassRenderContext& inCtx) :
cmd(inCmd), ctx(inCtx), lineConstant({})
{
@@ -69,3 +71,147 @@ void DebugLineCmd::DrawLine(const Matrix4& transform, const Color& inColor, floa
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
}
void DebugLineCmd::DrawBox(const Matrix4& transform, const Color& inColor, float lineWidth, bool stippled)
{
cmd.SetPolygonMode(VK_POLYGON_MODE_LINE);
cmd.SetLineRasterizationMode(VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH);
cmd.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
cmd.SetLineStippleEnabled(stippled);
if (stippled)
{
cmd.SetLineStipple(2, 0b1111111100000000);
}
cmd.SetLineWidth(lineWidth);
lineConstant.LineColor = inColor;
lineConstant.Transform = transform;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(LineConstant), &lineConstant);
auto& boxMesh = VkSceneRenderer::BoxMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, boxMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(boxMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(24);
}
void DebugLineCmd::DrawCapsule(const Matrix4& transform, const Color& inColor, float lineWidth, bool stippled)
{
cmd.SetPolygonMode(VK_POLYGON_MODE_LINE);
cmd.SetLineRasterizationMode(VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH);
cmd.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
cmd.SetLineStippleEnabled(stippled);
if (stippled)
{
cmd.SetLineStipple(2, 0b1111111100000000);
}
cmd.SetLineWidth(lineWidth);
lineConstant.LineColor = inColor;
lineConstant.Transform = transform;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(LineConstant), &lineConstant);
auto& capsuleMesh = VkSceneRenderer::CapsuleMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, capsuleMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(capsuleMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(capsuleMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t));
}
void DebugLineCmd::DrawSphere(const Matrix4& transform, const Color& inColor, float lineWidth, bool stippled)
{
cmd.SetPolygonMode(VK_POLYGON_MODE_LINE);
cmd.SetLineRasterizationMode(VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH);
cmd.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
cmd.SetLineStippleEnabled(stippled);
if (stippled)
{
cmd.SetLineStipple(2, 0b1111111100000000);
}
cmd.SetLineWidth(lineWidth);
lineConstant.LineColor = inColor;
lineConstant.Transform = transform;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(LineConstant), &lineConstant);
auto& sphereMesh = VkSceneRenderer::SphereMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, sphereMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(sphereMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(sphereMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t));
}
void DebugLineCmd::DrawCylinder(const Matrix4& transform, const Color& inColor, float lineWidth, bool stippled)
{
cmd.SetPolygonMode(VK_POLYGON_MODE_LINE);
cmd.SetLineRasterizationMode(VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH);
cmd.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
cmd.SetLineStippleEnabled(stippled);
if (stippled)
{
cmd.SetLineStipple(2, 0b1111111100000000);
}
cmd.SetLineWidth(lineWidth);
lineConstant.LineColor = inColor;
lineConstant.Transform = transform;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(LineConstant), &lineConstant);
auto& sphereMesh = VkSceneRenderer::CylinderMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, sphereMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(sphereMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(sphereMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t));
}
void DebugLineCmd::DrawArrow(const Vector3& from, const Vector3& to, const Matrix4& view, const Matrix4& proj, const Color& inColor, float lineWidth, bool stippled)
{
cmd.SetPolygonMode(VK_POLYGON_MODE_LINE);
cmd.SetLineRasterizationMode(VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH);
cmd.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
cmd.SetLineStippleEnabled(stippled);
if (stippled)
{
cmd.SetLineStipple(2, 0b1111111100000000);
}
cmd.SetLineWidth(lineWidth);
// Shaft direction (normalized)
glm::vec3 dir = glm::normalize(to - from);
// Get camera position from inverse of view
glm::vec3 cameraPos = glm::vec3(glm::inverse(view)[3]);
glm::vec3 toCamera = glm::normalize(cameraPos - to);
// Billboard basis
glm::vec3 right = glm::normalize(glm::cross(dir, toCamera));
glm::vec3 up = glm::normalize(glm::cross(right, dir));
//// Build arrowhead transform
//glm::mat4 arrowTransform(1.0f);
//arrowTransform[0] = glm::vec4(right, 0.0f); // X axis
//arrowTransform[1] = glm::vec4(up, 0.0f); // Y axis
//arrowTransform[2] = glm::vec4(dir, 0.0f); // Z axis (forward)
//arrowTransform[3] = glm::vec4(to, 1.0f); // Position
// Optional: scale arrowhead size
//float arrowScale = 0.2f; // You can tweak this
//arrowTransform = arrowTransform * glm::scale(glm::mat4(1.0f), glm::vec3(arrowScale));
// Final matrix
lineConstant.Transform = proj * view;
lineConstant.LineColor = inColor;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(LineConstant), &lineConstant);
auto& sphereMesh = VkSceneRenderer::ArrowMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, sphereMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(sphereMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(sphereMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t));
}

View File

@@ -33,6 +33,13 @@ namespace Nuake
void DrawAABB(const Vector3& min, const Vector3& max, const Color& color) const;
};
struct DrawLineRequest
{
Vector3 Start;
Vector3 End;
Color Color;
};
class DebugLineCmd
{
private:
@@ -47,5 +54,10 @@ namespace Nuake
Ref<Scene> GetScene() const;
void DrawLine(const Matrix4& transform, const Color& color, float lineWidth = 1.0f);
void DrawBox(const Matrix4& transform, const Color& color, float lineWidth = 1.0f, bool stippled = false);
void DrawCapsule(const Matrix4& transform, const Color& color, float lineWidth = 1.0f, bool stippled = false);
void DrawSphere(const Matrix4& transform, const Color& color, float lineWidth = 1.0f, bool stippled = false);
void DrawCylinder(const Matrix4& transform, const Color& color, float lineWidth = 1.0f, bool stippled = false);
void DrawArrow(const Vector3& from, const Vector3& to, const Matrix4& view, const Matrix4& proj, const Color& color, float lineWidth = 1.0f, bool stippled = false);
};
}

View File

@@ -158,23 +158,17 @@ SceneRenderPipeline::SceneRenderPipeline()
vkUpdateDescriptorSets(VkRenderer::Get().GetDevice(), 1, &bufferWriteModel, 0, nullptr);
// Generate noise texture
struct Vector2H
{
uint16_t x;
uint16_t y;
};
std::vector<Vector2H> noiseData;
std::vector<Vector2> noiseData;
for (unsigned int i = 0; i < 16; i++)
{
Vector2H noise(
glm::packHalf1x16(randomFloats(generator) * 2.0 - 1.0),
glm::packHalf1x16(randomFloats(generator) * 2.0 - 1.0 )
Vector2 noise(
randomFloats(generator),
randomFloats(generator)
);
noiseData.push_back(noise);
}
ssaoNoiseTexture = CreateRef<VulkanImage>(noiseData.data(), ImageFormat::RG16F, Vector2{4, 4});
ssaoNoiseTexture = CreateRef<VulkanImage>(noiseData.data(), ImageFormat::RG32F, Vector2{4, 4});
resources.AddTexture(ssaoNoiseTexture);
initKernels = true;
@@ -215,6 +209,9 @@ SceneRenderPipeline::SceneRenderPipeline()
SSAOOutput = CreateRef<VulkanImage>(ImageFormat::RGBA8, defaultSize);
SSAOOutput->SetDebugName("SSAOOutput");
SSAOBlurOutput = CreateRef<VulkanImage>(ImageFormat::RGBA8, defaultSize);
SSAOBlurOutput->SetDebugName("SSAOBlurOutput");
GizmoOutput = CreateRef<VulkanImage>(ImageFormat::RGBA8, defaultSize);
GizmoOutput->SetDebugName("GizmoOutput");
@@ -252,6 +249,7 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx)
LineCombineOutput = ResizeImage(ctx, LineCombineOutput, ctx.resolution);
SSAOOutput = ResizeImage(ctx, SSAOOutput, ctx.resolution);
SSAOBlurOutput = ResizeImage(ctx, SSAOBlurOutput, ctx.resolution);
OutlineOutput = ResizeImage(ctx, OutlineOutput, ctx.resolution);
@@ -262,9 +260,10 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx)
{
{ GBufferAlbedo, GBufferDepth, GBufferNormal, GBufferMaterial, GBufferEntityID }, // GBuffer
{ SSAOOutput },
{ SSAOBlurOutput },
{ ShadingOutput }, // Shading
{ TonemappedOutput }, // Tonemap
{ LineOutput },
{ LineOutput, GBufferDepth },
{ LineCombineOutput },
{ GizmoOutput, GBufferDepth }, // Reusing depth from gBuffer
{ GizmoCombineOutput },
@@ -287,7 +286,8 @@ void SceneRenderPipeline::RecreatePipeline()
gBufferPass.AddAttachment("EntityID", GBufferEntityID->GetFormat());
gBufferPass.AddAttachment("Depth", GBufferDepth->GetFormat(), ImageUsage::Depth);
gBufferPass.SetPushConstant<GBufferConstant>(gbufferConstant);
gBufferPass.SetPreRender([&](PassRenderContext& ctx) {
gBufferPass.SetPreRender([&](PassRenderContext& ctx)
{
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
@@ -298,7 +298,7 @@ void SceneRenderPipeline::RecreatePipeline()
cmd.BindDescriptorSet(layout, res.TexturesDescriptor, 4);
cmd.BindDescriptorSet(layout, res.LightsDescriptor, 5);
cmd.BindDescriptorSet(layout, res.CamerasDescriptor, 6);
});
});
gBufferPass.SetRender([&](PassRenderContext& ctx) {
Cmd& cmd = ctx.commandBuffer;
@@ -379,6 +379,38 @@ void SceneRenderPipeline::RecreatePipeline()
cmd.DrawIndexed(6);
});
auto& ssaoBlurPass = GBufferPipeline.AddPass("SSAOBlurPass");
ssaoBlurPass.SetShaders(shaderMgr.GetShader("blur_vert"), shaderMgr.GetShader("blur_frag"));
ssaoBlurPass.SetPushConstant<BlurConstant>(blurConstant);
ssaoBlurPass.AddAttachment("SSAOBlurOutput", SSAOBlurOutput->GetFormat());
ssaoBlurPass.AddInput("Input");
ssaoBlurPass.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);
blurConstant.sourceTextureID = res.GetBindlessTextureID(SSAOOutput->GetID());
blurConstant.sourceSize = SSAOOutput->GetSize();
cmd.PushConstants(layout, sizeof(BlurConstant), &blurConstant);
});
ssaoBlurPass.SetRender([&](PassRenderContext& ctx)
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& quadMesh = VkSceneRenderer::QuadMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
auto& shadingPass = GBufferPipeline.AddPass("Shading");
shadingPass.SetShaders(shaderMgr.GetShader("shading_vert"), shaderMgr.GetShader("shading_frag"));
shadingPass.SetPushConstant<ShadingConstant>(shadingConstant);
@@ -407,7 +439,7 @@ void SceneRenderPipeline::RecreatePipeline()
shadingConstant.NormalTextureID = res.GetBindlessTextureID(GBufferNormal->GetID());
shadingConstant.MaterialTextureID = res.GetBindlessTextureID(GBufferMaterial->GetID());
shadingConstant.AmbientTerm = ctx.scene->GetEnvironment()->AmbientTerm;
shadingConstant.SSAOTextureID = res.GetBindlessTextureID(SSAOOutput->GetID());
shadingConstant.SSAOTextureID = res.GetBindlessTextureID(SSAOBlurOutput->GetID());
// Camera
shadingConstant.CameraID = ctx.cameraID;
@@ -418,7 +450,7 @@ void SceneRenderPipeline::RecreatePipeline()
{
shadingConstant.CascadeSplits[i] = LightComponent::mCascadeSplitDepth[i];
}
});
});
shadingPass.SetRender([&](PassRenderContext& ctx) {
auto& cmd = ctx.commandBuffer;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(ShadingConstant), &shadingConstant);
@@ -430,7 +462,7 @@ void SceneRenderPipeline::RecreatePipeline()
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
});
auto& tonemapPass = GBufferPipeline.AddPass("Tonemap");
tonemapPass.SetShaders(shaderMgr.GetShader("tonemap_vert"), shaderMgr.GetShader("tonemap_frag"));
@@ -455,49 +487,50 @@ void SceneRenderPipeline::RecreatePipeline()
tonemapConstant.Exposure = ctx.scene->GetEnvironment()->Exposure;
tonemapConstant.SourceTextureID = res.GetBindlessTextureID(ShadingOutput->GetID());
tonemapConstant.Gamma = ctx.scene->GetEnvironment()->Gamma;
});
});
tonemapPass.SetRender([&](PassRenderContext& ctx)
{
auto& cmd = ctx.commandBuffer;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(TonemapConstant), &tonemapConstant);
{
auto& cmd = ctx.commandBuffer;
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(TonemapConstant), &tonemapConstant);
ctx.renderPass->SetClearColor(ctx.scene->GetEnvironment()->AmbientColor);
ctx.renderPass->SetClearColor(ctx.scene->GetEnvironment()->AmbientColor);
// Draw full screen quad
auto& quadMesh = VkSceneRenderer::QuadMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
// Draw full screen quad
auto& quadMesh = VkSceneRenderer::QuadMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
RenderPass& linePass = GBufferPipeline.AddPass("Line");
linePass.SetIsLinePass(true);
linePass.SetTopology(PolygonTopology::LINE_LIST);
linePass.SetShaders(shaderMgr.GetShader("line_vert"), shaderMgr.GetShader("line_frag"));
linePass.AddAttachment("LineOutput", LineOutput->GetFormat());
linePass.AddAttachment("LineDepth", GBufferDepth->GetFormat(), ImageUsage::Depth, false);
linePass.SetPushConstant(lineConstant);
linePass.SetDepthTest(false);
linePass.SetDepthTest(true);
linePass.SetIsLinePass(true);
linePass.SetPreRender([&](PassRenderContext& ctx)
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
// Bindless
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);
});
// Bindless
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);
});
linePass.SetRender([&](PassRenderContext& ctx)
{
auto& cmd = ctx.commandBuffer;
DebugLineCmd debugCmd = DebugLineCmd(cmd, ctx);
OnLineDraw().Broadcast(debugCmd);
});
{
auto& cmd = ctx.commandBuffer;
DebugLineCmd debugCmd = DebugLineCmd(cmd, ctx);
OnLineDraw().Broadcast(debugCmd);
});
auto& lineCombinePass = GBufferPipeline.AddPass("LineCombine");
lineCombinePass.SetPushConstant(copyConstant);
@@ -505,33 +538,33 @@ void SceneRenderPipeline::RecreatePipeline()
lineCombinePass.AddAttachment("LineCombineOutput", LineCombineOutput->GetFormat());
lineCombinePass.AddInput("lineCombinePassOutput");
lineCombinePass.SetPreRender([&](PassRenderContext& ctx)
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
// Bindless
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);
});
// Bindless
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);
});
lineCombinePass.SetRender([&](PassRenderContext& ctx)
{
auto& cmd = ctx.commandBuffer;
{
auto& cmd = ctx.commandBuffer;
copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(LineOutput->GetID());
copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(TonemappedOutput->GetID());
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), &copyConstant);
copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(LineOutput->GetID());
copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(TonemappedOutput->GetID());
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), &copyConstant);
// Draw full screen quad
auto& quadMesh = VkSceneRenderer::QuadMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
// Draw full screen quad
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"));
@@ -541,25 +574,25 @@ void SceneRenderPipeline::RecreatePipeline()
gizmoPass.AddAttachment("GizmoDepth", GBufferDepth->GetFormat(), ImageUsage::Depth, false);
gizmoPass.SetDepthTest(true);
gizmoPass.SetPreRender([&](PassRenderContext& ctx)
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
// Bindless
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);
});
// Bindless
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);
});
gizmoPass.SetRender([&](PassRenderContext& ctx)
{
auto& cmd = ctx.commandBuffer;
DebugCmd debugCmd = DebugCmd(cmd, ctx);
OnDebugDraw().Broadcast(debugCmd);
});
{
auto& cmd = ctx.commandBuffer;
DebugCmd debugCmd = DebugCmd(cmd, ctx);
OnDebugDraw().Broadcast(debugCmd);
});
auto& gizmoCombinePass = GBufferPipeline.AddPass("GizmoCombine");
gizmoCombinePass.SetPushConstant(copyConstant);
@@ -567,33 +600,33 @@ void SceneRenderPipeline::RecreatePipeline()
gizmoCombinePass.AddAttachment("GizmoCombineOutput", GizmoCombineOutput->GetFormat());
gizmoCombinePass.AddInput("GizmoCombineOutput");
gizmoCombinePass.SetPreRender([&](PassRenderContext& ctx)
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
{
Cmd& cmd = ctx.commandBuffer;
auto& layout = ctx.renderPass->PipelineLayout;
auto& res = GPUResources::Get();
// Bindless
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);
});
// Bindless
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);
});
gizmoCombinePass.SetRender([&](PassRenderContext& ctx)
{
auto& cmd = ctx.commandBuffer;
{
auto& cmd = ctx.commandBuffer;
copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(GizmoOutput->GetID());
copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(LineCombineOutput->GetID());
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), &copyConstant);
copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(GizmoOutput->GetID());
copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(LineCombineOutput->GetID());
cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), &copyConstant);
// Draw full screen quad
auto& quadMesh = VkSceneRenderer::QuadMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
// Draw full screen quad
auto& quadMesh = VkSceneRenderer::QuadMesh;
cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, quadMesh->GetDescriptorSet(), 1);
cmd.BindIndexBuffer(quadMesh->GetIndexBuffer()->GetBuffer());
cmd.DrawIndexed(6);
});
auto& outlinePass = GBufferPipeline.AddPass("Outline");
outlinePass.SetShaders(shaderMgr.GetShader("outline_vert"), shaderMgr.GetShader("outline_frag"));

View File

@@ -43,7 +43,12 @@ namespace Nuake
float bias;
Vector2 noiseScale;
float power;
};
struct BlurConstant
{
int sourceTextureID;
Vector2 sourceSize;
};
struct ShadingConstant
@@ -116,6 +121,7 @@ namespace Nuake
// Attachments Shading
Ref<VulkanImage> ShadingOutput;
Ref<VulkanImage> SSAOOutput;
Ref<VulkanImage> SSAOBlurOutput;
Ref<VulkanImage> LineOutput;
Ref<VulkanImage> LineCombineOutput;
@@ -141,6 +147,7 @@ namespace Nuake
GBufferConstant gbufferConstant;
ShadingConstant shadingConstant;
SSAOConstant ssaoConstant;
BlurConstant blurConstant;
TonemapConstant tonemapConstant;
DebugConstant debugConstant;
LineConstant lineConstant;

View File

@@ -177,6 +177,10 @@ VulkanImage::VulkanImage(void* inData, ImageFormat inFormat, Vector2 inSize) : V
{
data_size *= 4;
}
else if (inFormat == ImageFormat::RG32F)
{
data_size *= 8;
}
else if (inFormat != ImageFormat::A8)
{
data_size *= 4;

View File

@@ -19,6 +19,7 @@ namespace Nuake
RGBA16F = 97,
RGB16F = 90,
RG16F = 83,
RG32F = 103,
RGBA32F = 109,
D32F = 126,
R32UINT = 98,

View File

@@ -23,6 +23,11 @@
using namespace Nuake;
Ref<VkMesh> VkSceneRenderer::QuadMesh;
Ref<VkMesh> VkSceneRenderer::BoxMesh;
Ref<VkMesh> VkSceneRenderer::CapsuleMesh;
Ref<VkMesh> VkSceneRenderer::SphereMesh;
Ref<VkMesh> VkSceneRenderer::CylinderMesh;
Ref<VkMesh> VkSceneRenderer::ArrowMesh;
void VkSceneRenderer::Init()
{
@@ -47,6 +52,295 @@ void VkSceneRenderer::Init()
};
QuadMesh = CreateRef<VkMesh>(quadVertices, quadIndices);
const std::vector<Vertex> boxVertices
{
// Front face
{ Vector3(-1.0f, -1.0f, 1.0f), 0.0f, Vector3(0, 0, 1), 0.0f },
{ Vector3(1.0f, -1.0f, 1.0f), 1.0f, Vector3(0, 0, 1), 0.0f },
{ Vector3(1.0f, 1.0f, 1.0f), 1.0f, Vector3(0, 0, 1), 1.0f },
{ Vector3(-1.0f, 1.0f, 1.0f), 0.0f, Vector3(0, 0, 1), 1.0f },
// Back face
{ Vector3(1.0f, -1.0f, -1.0f), 0.0f, Vector3(0, 0, -1), 0.0f },
{ Vector3(-1.0f, -1.0f, -1.0f), 1.0f, Vector3(0, 0, -1), 0.0f },
{ Vector3(-1.0f, 1.0f, -1.0f), 1.0f, Vector3(0, 0, -1), 1.0f },
{ Vector3(1.0f, 1.0f, -1.0f), 0.0f, Vector3(0, 0, -1), 1.0f },
// Left face
{ Vector3(-1.0f, -1.0f, -1.0f), 0.0f, Vector3(-1, 0, 0), 0.0f },
{ Vector3(-1.0f, -1.0f, 1.0f), 1.0f, Vector3(-1, 0, 0), 0.0f },
{ Vector3(-1.0f, 1.0f, 1.0f), 1.0f, Vector3(-1, 0, 0), 1.0f },
{ Vector3(-1.0f, 1.0f, -1.0f), 0.0f, Vector3(-1, 0, 0), 1.0f },
// Right face
{ Vector3(1.0f, -1.0f, 1.0f), 0.0f, Vector3(1, 0, 0), 0.0f },
{ Vector3(1.0f, -1.0f, -1.0f), 1.0f, Vector3(1, 0, 0), 0.0f },
{ Vector3(1.0f, 1.0f, -1.0f), 1.0f, Vector3(1, 0, 0), 1.0f },
{ Vector3(1.0f, 1.0f, 1.0f), 0.0f, Vector3(1, 0, 0), 1.0f },
// Top face
{ Vector3(-1.0f, 1.0f, 1.0f), 0.0f, Vector3(0, 1, 0), 0.0f },
{ Vector3(1.0f, 1.0f, 1.0f), 1.0f, Vector3(0, 1, 0), 0.0f },
{ Vector3(1.0f, 1.0f, -1.0f), 1.0f, Vector3(0, 1, 0), 1.0f },
{ Vector3(-1.0f, 1.0f, -1.0f), 0.0f, Vector3(0, 1, 0), 1.0f },
// Bottom face
{ Vector3(-1.0f, -1.0f, -1.0f), 0.0f, Vector3(0, -1, 0), 0.0f },
{ Vector3(1.0f, -1.0f, -1.0f), 1.0f, Vector3(0, -1, 0), 0.0f },
{ Vector3(1.0f, -1.0f, 1.0f), 1.0f, Vector3(0, -1, 0), 1.0f },
{ Vector3(-1.0f, -1.0f, 1.0f), 0.0f, Vector3(0, -1, 0), 1.0f },
};
const std::vector<uint32_t> boxIndices
{
// Front face
0, 1, 1, 2, 2, 3, 3, 0,
// Back face
4, 5, 5, 6, 6, 7, 7, 4,
// Side edges
0, 5, 1, 4, 2, 7, 3, 6
};
BoxMesh = CreateRef<VkMesh>(boxVertices, boxIndices);
{
std::vector<Vertex> arrowVertices;
std::vector<uint32_t> arrowIndices;
Vector3 base = Vector3(0.0f, 0.0f, 0.0f); // Start of arrow
Vector3 tip = Vector3(0.0f, 1.0f, 0.0f); // Tip of arrow
float headSize = 0.2f;
float shaftLength = 0.8f;
Vector3 shaftEnd = Vector3(0.0f, shaftLength, 0.0f);
// Shaft line
arrowVertices.push_back({ base, 0.0f, Vector3(), 0.0f }); // 0
arrowVertices.push_back({ shaftEnd, 0.0f, Vector3(), 0.0f }); // 1
arrowIndices.push_back(0);
arrowIndices.push_back(1);
// Arrowhead lines (simple triangle)
Vector3 left = shaftEnd + Vector3(-headSize, headSize, 0.0f); // 2
Vector3 right = shaftEnd + Vector3(headSize, headSize, 0.0f); // 3
Vector3 back = shaftEnd + Vector3(0.0f, headSize, headSize); // 4
arrowVertices.push_back({ left, 0.0f, Vector3(), 0.0f });
arrowVertices.push_back({ right, 0.0f, Vector3(), 0.0f });
arrowVertices.push_back({ back, 0.0f, Vector3(), 0.0f });
// Arrowhead edges
arrowIndices.push_back(1); arrowIndices.push_back(2); // shaftEnd -> left
arrowIndices.push_back(1); arrowIndices.push_back(3); // shaftEnd -> right
arrowIndices.push_back(1); arrowIndices.push_back(4); // shaftEnd -> back
ArrowMesh = CreateRef<VkMesh>(arrowVertices, arrowIndices);
}
{
std::vector<Vertex> capsuleVertices;
std::vector<uint32_t> capsuleIndices;
const int segments = 16;
const int hemisphereSegments = 8;
const float radius = 1.0f;
const float cylinderHeight = 2.0f;
const float halfHeight = cylinderHeight * 0.5f;
// =====
// Circle rings (top and bottom of cylinder)
for (int i = 0; i < segments; ++i)
{
float angle = (2.0f * glm::pi<float>() * i) / segments;
float x = cos(angle) * radius;
float z = sin(angle) * radius;
// Top ring
capsuleVertices.push_back({ Vector3(x, +halfHeight, z), 0.0f, Vector3(), 0.0f });
// Bottom ring
capsuleVertices.push_back({ Vector3(x, -halfHeight, z), 0.0f, Vector3(), 0.0f });
}
// Top/bottom circle outline
for (int i = 0; i < segments; ++i)
{
uint32_t top = i * 2;
uint32_t topNext = ((i + 1) % segments) * 2;
uint32_t bot = i * 2 + 1;
uint32_t botNext = ((i + 1) % segments) * 2 + 1;
capsuleIndices.push_back(top);
capsuleIndices.push_back(topNext);
capsuleIndices.push_back(bot);
capsuleIndices.push_back(botNext);
}
// =====
// 4 vertical lines at 0<>, 90<39>, 180<38>, 270<37>
for (int i : { 0, segments / 4, segments / 2, (3 * segments) / 4 })
{
uint32_t top = i * 2;
uint32_t bot = i * 2 + 1;
capsuleIndices.push_back(top);
capsuleIndices.push_back(bot);
}
// =====
// Hemisphere arcs (vertical arcs at 4 directions)
for (int i : { 0, segments / 4, segments / 2, (3 * segments) / 4 })
{
float angle = (2.0f * glm::pi<float>() * i) / segments;
float x = cos(angle);
float z = sin(angle);
// Top hemisphere arc
uint32_t last = capsuleVertices.size();
for (int j = 0; j <= hemisphereSegments; ++j)
{
float theta = (0.5f * glm::pi<float>() * j) / hemisphereSegments; // from 0 to pi/2
float y = sin(theta) * radius + halfHeight;
float r = cos(theta) * radius;
capsuleVertices.push_back({ Vector3(x * r, y, z * r), 0.0f, Vector3(), 0.0f });
if (j > 0)
{
capsuleIndices.push_back(last + j - 1);
capsuleIndices.push_back(last + j);
}
}
// Bottom hemisphere arc
last = capsuleVertices.size();
for (int j = 0; j <= hemisphereSegments; ++j)
{
float theta = (0.5f * glm::pi<float>() * j) / hemisphereSegments; // from 0 to pi/2
float y = -sin(theta) * radius - halfHeight;
float r = cos(theta) * radius;
capsuleVertices.push_back({ Vector3(x * r, y, z * r), 0.0f, Vector3(), 0.0f });
if (j > 0)
{
capsuleIndices.push_back(last + j - 1);
capsuleIndices.push_back(last + j);
}
}
}
CapsuleMesh = CreateRef<VkMesh>(capsuleVertices, capsuleIndices);
}
{
std::vector<Vertex> sphereVertices;
std::vector<uint32_t> sphereIndices;
const int ringSegments = 32;
const float sphereRadius = 1.0f;
// XY Ring
for (int i = 0; i < ringSegments; ++i)
{
float angle = (2.0f * glm::pi<float>() * i) / ringSegments;
float x = cos(angle) * sphereRadius;
float y = sin(angle) * sphereRadius;
sphereVertices.push_back({ Vector3(x, y, 0.0f), 0.0f, Vector3(), 0.0f });
uint32_t curr = i;
uint32_t next = (i + 1) % ringSegments;
sphereIndices.push_back(curr);
sphereIndices.push_back(next);
}
// XZ Ring
uint32_t baseXZ = sphereVertices.size();
for (int i = 0; i < ringSegments; ++i)
{
float angle = (2.0f * glm::pi<float>() * i) / ringSegments;
float x = cos(angle) * sphereRadius;
float z = sin(angle) * sphereRadius;
sphereVertices.push_back({ Vector3(x, 0.0f, z), 0.0f, Vector3(), 0.0f });
uint32_t curr = baseXZ + i;
uint32_t next = baseXZ + ((i + 1) % ringSegments);
sphereIndices.push_back(curr);
sphereIndices.push_back(next);
}
// YZ Ring
uint32_t baseYZ = sphereVertices.size();
for (int i = 0; i < ringSegments; ++i)
{
float angle = (2.0f * glm::pi<float>() * i) / ringSegments;
float y = cos(angle) * sphereRadius;
float z = sin(angle) * sphereRadius;
sphereVertices.push_back({ Vector3(0.0f, y, z), 0.0f, Vector3(), 0.0f });
uint32_t curr = baseYZ + i;
uint32_t next = baseYZ + ((i + 1) % ringSegments);
sphereIndices.push_back(curr);
sphereIndices.push_back(next);
}
SphereMesh = CreateRef<VkMesh>(sphereVertices, sphereIndices);
}
{
std::vector<Vertex> cylinderVertices;
std::vector<uint32_t> cylinderIndices;
const int segments = 16;
const float radius = 1.0f;
const float halfHeight = 2.0f;
// Vertex pairs: top and bottom
for (int i = 0; i < segments; ++i)
{
float angle = (2.0f * glm::pi<float>() * i) / segments;
float x = cos(angle) * radius;
float z = sin(angle) * radius;
// Top ring
cylinderVertices.push_back({ Vector3(x, +halfHeight, z), 0.0f, Vector3(), 0.0f });
// Bottom ring
cylinderVertices.push_back({ Vector3(x, -halfHeight, z), 0.0f, Vector3(), 0.0f });
}
// Circle edges (top and bottom)
for (int i = 0; i < segments; ++i)
{
uint32_t topIdx = i * 2;
uint32_t nextTopIdx = ((i + 1) % segments) * 2;
uint32_t botIdx = i * 2 + 1;
uint32_t nextBotIdx = ((i + 1) % segments) * 2 + 1;
// Top circle
cylinderIndices.push_back(topIdx);
cylinderIndices.push_back(nextTopIdx);
// Bottom circle
cylinderIndices.push_back(botIdx);
cylinderIndices.push_back(nextBotIdx);
}
// 4 vertical edges at 0, 90, 180, 270 degrees
for (int i : { 0, segments / 4, segments / 2, (3 * segments) / 4 })
{
uint32_t topIdx = i * 2;
uint32_t botIdx = i * 2 + 1;
cylinderIndices.push_back(topIdx);
cylinderIndices.push_back(botIdx);
}
// Final creation of the cylinder outline mesh
CylinderMesh = CreateRef<VkMesh>(cylinderVertices, cylinderIndices);
}
}
void VkSceneRenderer::LoadShaders()
@@ -72,6 +366,8 @@ void VkSceneRenderer::LoadShaders()
shaderMgr.AddShader("line_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/line.vert"));
shaderMgr.AddShader("ssao_frag", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/ssao.frag"));
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"));
}
void VkSceneRenderer::PrepareScenes(const std::vector<Ref<Scene>>& scenes, RenderContext inContext)

View File

@@ -25,6 +25,11 @@ namespace Nuake
{
public:
static Ref<VkMesh> QuadMesh;
static Ref<VkMesh> BoxMesh;
static Ref<VkMesh> CapsuleMesh;
static Ref<VkMesh> SphereMesh;
static Ref<VkMesh> CylinderMesh;
static Ref<VkMesh> ArrowMesh;
public:
//RenderContext Context;