diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp b/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp index 03db3efd..99ed832c 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp @@ -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(); + for (auto e : camView) + { + auto [transform, camera] = scene->m_Registry.get(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) diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp index af24e1d2..e3b37d77 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp @@ -41,6 +41,8 @@ void DebugCmd::DrawTexturedQuad(const Matrix4& transform, Ref 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)); +} \ No newline at end of file diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.h b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.h index 6a997bff..350aef88 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.h @@ -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 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); }; } \ No newline at end of file diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp index 1bb734da..f725959e 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp @@ -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 noiseData; + std::vector 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(noiseData.data(), ImageFormat::RG16F, Vector2{4, 4}); + ssaoNoiseTexture = CreateRef(noiseData.data(), ImageFormat::RG32F, Vector2{4, 4}); resources.AddTexture(ssaoNoiseTexture); initKernels = true; @@ -215,6 +209,9 @@ SceneRenderPipeline::SceneRenderPipeline() SSAOOutput = CreateRef(ImageFormat::RGBA8, defaultSize); SSAOOutput->SetDebugName("SSAOOutput"); + SSAOBlurOutput = CreateRef(ImageFormat::RGBA8, defaultSize); + SSAOBlurOutput->SetDebugName("SSAOBlurOutput"); + GizmoOutput = CreateRef(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); - 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); + 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); @@ -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), ©Constant); + copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(LineOutput->GetID()); + copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(TonemappedOutput->GetID()); + cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), ©Constant); - // 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), ©Constant); + copyConstant.SourceTextureID = GPUResources::Get().GetBindlessTextureID(GizmoOutput->GetID()); + copyConstant.Source2TextureID = GPUResources::Get().GetBindlessTextureID(LineCombineOutput->GetID()); + cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(copyConstant), ©Constant); - // 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")); diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h index 12d91f7a..45f14f0b 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h @@ -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 ShadingOutput; Ref SSAOOutput; + Ref SSAOBlurOutput; Ref LineOutput; Ref LineCombineOutput; @@ -141,6 +147,7 @@ namespace Nuake GBufferConstant gbufferConstant; ShadingConstant shadingConstant; SSAOConstant ssaoConstant; + BlurConstant blurConstant; TonemapConstant tonemapConstant; DebugConstant debugConstant; LineConstant lineConstant; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp index 3f6adc84..d2b0679e 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp @@ -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; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.h b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.h index 529ac29f..1ab49bc1 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.h @@ -19,6 +19,7 @@ namespace Nuake RGBA16F = 97, RGB16F = 90, RG16F = 83, + RG32F = 103, RGBA32F = 109, D32F = 126, R32UINT = 98, diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp index 30fd61fd..b30edb87 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -23,6 +23,11 @@ using namespace Nuake; Ref VkSceneRenderer::QuadMesh; +Ref VkSceneRenderer::BoxMesh; +Ref VkSceneRenderer::CapsuleMesh; +Ref VkSceneRenderer::SphereMesh; +Ref VkSceneRenderer::CylinderMesh; +Ref VkSceneRenderer::ArrowMesh; void VkSceneRenderer::Init() { @@ -47,6 +52,295 @@ void VkSceneRenderer::Init() }; QuadMesh = CreateRef(quadVertices, quadIndices); + + const std::vector 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 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(boxVertices, boxIndices); + + { + std::vector arrowVertices; + std::vector 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(arrowVertices, arrowIndices); + } + + { + std::vector capsuleVertices; + std::vector 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() * 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°, 180°, 270° + 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() * 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() * 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() * 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(capsuleVertices, capsuleIndices); + } + { + std::vector sphereVertices; + std::vector 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() * 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() * 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() * 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(sphereVertices, sphereIndices); + } + + { + std::vector cylinderVertices; + std::vector 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() * 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(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>& scenes, RenderContext inContext) diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h index 33abf036..675d54b8 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h @@ -25,6 +25,11 @@ namespace Nuake { public: static Ref QuadMesh; + static Ref BoxMesh; + static Ref CapsuleMesh; + static Ref SphereMesh; + static Ref CylinderMesh; + static Ref ArrowMesh; public: //RenderContext Context;