diff --git a/Data/Shaders/Vulkan/gizmo.frag b/Data/Shaders/Vulkan/gizmo.frag new file mode 100644 index 00000000..c925a5f7 --- /dev/null +++ b/Data/Shaders/Vulkan/gizmo.frag @@ -0,0 +1,161 @@ +// 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 OutlinePushConstant +{ + float4 Color; + float Thickness; + int SourceTextureID; + int EntityIDTextureID; + int DepthTextureID; + float SelectedEntity; +}; + +[[vk::push_constant]] +OutlinePushConstant pushConstants; + +PSOutput main(PSInput input) +{ + PSOutput output; + + float4 outlineColor = pushConstants.Color; + float target = pushConstants.SelectedEntity; + float radius = pushConstants.Thickness; + float2 uv = input.UV; + + int entityIDTextureID = pushConstants.EntityIDTextureID; + float hasHit = 0.0f; + + float sampleValue = textures[entityIDTextureID].Sample(mySampler, uv).r; + + if(abs(sampleValue - target) < 0.0001) + { + output.oColor0 = outlineColor; + output.oColor0.a = 1.0; + return output; + } + + float4 fragColor = float4(0, 0, 0, 0); + const float TAU = 6.28318530; + const float steps = 32.0; + for(float i = 0.0f; i < TAU; i += TAU / steps) + { + float2 uvOffset = float2(sin(i), cos(i)) * radius; + + float2 sampleUV = uv + uvOffset; + sampleUV.x = clamp(sampleUV.x, 0.0, 0.999); + sampleUV.y = clamp(sampleUV.y, 0.0, 0.999); + + int sampleValue = (int)textures[entityIDTextureID].Sample(mySampler, sampleUV).r; + if(sampleValue == target) + { + hasHit = 1.0f; + } + + float alpha = smoothstep(0.5, 0.9, int(sampleValue != target) * hasHit * 10.0f); + float4 outputColor = float4( + lerp(fragColor.r, outlineColor.r, alpha), + lerp(fragColor.g, outlineColor.g, alpha), + lerp(fragColor.b, outlineColor.b, alpha), + lerp(fragColor.a, outlineColor.a, alpha) + ); + + fragColor = outputColor; + } + + if(fragColor.a > 0.1) + { + fragColor.a = 1.0f; + } + + output.oColor0 = fragColor; + return output; +} \ No newline at end of file diff --git a/Data/Shaders/Vulkan/gizmo.vert b/Data/Shaders/Vulkan/gizmo.vert new file mode 100644 index 00000000..cbd3c87c --- /dev/null +++ b/Data/Shaders/Vulkan/gizmo.vert @@ -0,0 +1,112 @@ +// 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 OutlinePushConstant +{ + float4 Color; + float Thickness; + int SourceTextureID; + int EntityIDTextureID; + int DepthTextureID; + float SelectedEntity; +}; + +[[vk::push_constant]] +OutlinePushConstant 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/Nuake/Source/Engine.cpp b/Nuake/Source/Engine.cpp index aa4949d1..2f9304bf 100644 --- a/Nuake/Source/Engine.cpp +++ b/Nuake/Source/Engine.cpp @@ -378,7 +378,6 @@ namespace Nuake currentProject = project; // TODO(antopilo) only generate manifest in editor context - FileSystem::SetRootDirectory(FileSystem::GetParentPath(project->FullPath)); GenerateManifest(); diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp index 2a7842cd..befc5e75 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp @@ -339,6 +339,8 @@ void RenderPipeline::Execute(PassRenderContext& ctx, PipelineAttachments& inputs return; } + assert(std::size(RenderPasses) == std::size(inputs) && "Did you forget to an input?"); + int passIndex = 0; for (auto& pass : RenderPasses) { diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp index 30435595..943e0d25 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp @@ -106,9 +106,12 @@ SceneRenderPipeline::SceneRenderPipeline() GBufferEntityID = CreateRef(ImageFormat::R32F, defaultSize); GBufferEntityID->SetDebugName("GBufferEntityID"); - OutlineOutput =CreateRef(ImageFormat::RGBA8, defaultSize); + OutlineOutput = CreateRef(ImageFormat::RGBA8, defaultSize); OutlineOutput->SetDebugName("OutlineOutput"); + GizmoOutput = CreateRef(ImageFormat::RGBA8, defaultSize); + GizmoOutput->SetDebugName("GizmoOutput"); + // Setup bloom targets BloomOutput = CreateRef(ImageFormat::RGBA16F, defaultSize); BloomThreshold = CreateRef(ImageFormat::RGBA16F, defaultSize); @@ -274,6 +277,30 @@ SceneRenderPipeline::SceneRenderPipeline() cmd.DrawIndexed(6); }); + auto& gizmoPass = GBufferPipeline.AddPass("Gizmo"); + gizmoPass.SetShaders(shaderMgr.GetShader("gizmo_vert"), shaderMgr.GetShader("gizmo_frag")); + gizmoPass.AddAttachment("GizmoOutput", GizmoOutput->GetFormat()); + gizmoPass.AddInput("Depth"); + gizmoPass.SetPreRender([&](PassRenderContext& ctx) { + 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); + }); + gizmoPass.SetRender([&](PassRenderContext& ctx) + { + auto& cmd = ctx.commandBuffer; + DebugCmd debugCmd = DebugCmd(cmd); + OnDebugDraw().Broadcast(debugCmd); + }); + auto& outlinePass = GBufferPipeline.AddPass("Outline"); outlinePass.SetShaders(shaderMgr.GetShader("outline_vert"), shaderMgr.GetShader("outline_frag")); outlinePass.SetPushConstant(outlineConstant); @@ -343,6 +370,7 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx) { GBufferAlbedo, GBufferDepth, GBufferNormal, GBufferMaterial, GBufferEntityID }, // GBuffer { ShadingOutput }, // Shading { TonemappedOutput }, // Tonemap + { OutlineOutput }, { OutlineOutput } }; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h index 8edafa6a..5d004b38 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h @@ -90,6 +90,8 @@ namespace Nuake // Attachments Shading Ref ShadingOutput; + Ref GizmoOutput; + Ref TonemappedOutput; Ref OutlineOutput; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.h b/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.h index a46a9bab..b9c04157 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.h @@ -1,12 +1,14 @@ #pragma once #include "Nuake/Core/Core.h" #include "Nuake/Core/Maths.h" +#include "Nuake/Core/MulticastDelegate.h" #include "Nuake/Resource/UUID.h" namespace Nuake { class VulkanImage; + class DebugCmd; class Viewport { @@ -17,6 +19,7 @@ namespace Nuake UUID viewId; Ref renderTarget; + MulticastDelegate debugDrawDelegate; int selectedEntityID; public: @@ -45,5 +48,15 @@ namespace Nuake Ref GetRenderTarget() const { return renderTarget; } bool Resize(); + + void OnDebugDraw(DebugCmd& debugCmd) + { + debugDrawDelegate.Broadcast(debugCmd); + } + + MulticastDelegate& GetOnDebugDraw() + { + return debugDrawDelegate; + } }; } \ No newline at end of file diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp index 6e4a9c67..019d19f7 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp @@ -19,6 +19,7 @@ #include "SceneViewport.h" #include "Nuake/Rendering/Vertex.h" #include "VulkanSceneRenderer.h" +#include "SceneRenderPipeline.h" #include "DescriptorLayoutBuilder.h" @@ -466,6 +467,9 @@ void VkRenderer::RegisterSceneViewport(const Ref& scene, const UUID& view Ref sceneRenderer = CreateRef(); sceneRenderer->Init(); + // Register the viewport to the onDebugDraw event for custom drawing + sceneRenderer->sceneRenderPipeline->OnDebugDraw().AddRaw(Viewports[viewportId].get(), &Viewport::OnDebugDraw); + SceneRenderers[viewportId] = std::move(sceneRenderer); } diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp index 400e3cd4..478de976 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -65,6 +65,8 @@ void VkSceneRenderer::LoadShaders() shaderMgr.AddShader("tonemap_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/tonemap.vert")); shaderMgr.AddShader("outline_frag", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/outline.frag")); shaderMgr.AddShader("outline_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/outline.vert")); + shaderMgr.AddShader("gizmo_frag", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/gizmo.frag")); + shaderMgr.AddShader("gizmo_vert", shaderCompiler.CompileShader("Resources/Shaders/Vulkan/gizmo.vert")); } void VkSceneRenderer::PrepareScenes(const std::vector>& scenes, RenderContext inContext)