From f4fd6e78f356ccbc2120d0cfae8e2d24fa40c857 Mon Sep 17 00:00:00 2001 From: antopilo Date: Mon, 14 Apr 2025 10:38:53 -0400 Subject: [PATCH] Added spotlight gizmo + yellow gizmo when selected --- Data/Shaders/Vulkan/gizmo.frag | 3 +- Data/Shaders/Vulkan/gizmo.vert | 1 + Data/Shaders/Vulkan/shading.frag | 2 +- .../SceneEditor/Widgets/ViewportWidget.cpp | 79 ++++++++++++++++--- .../Rendering/Vulkan/Constant/DebugConstant.h | 1 + .../Nuake/Rendering/Vulkan/DebugCmd.cpp | 54 ++++++------- .../Source/Nuake/Rendering/Vulkan/DebugCmd.h | 3 +- .../Rendering/Vulkan/SceneRenderPipeline.cpp | 2 +- .../Rendering/Vulkan/VulkanSceneRenderer.cpp | 51 +++++++++++- .../Rendering/Vulkan/VulkanSceneRenderer.h | 1 + .../Nuake/Scene/Components/LightComponent.h | 2 +- 11 files changed, 154 insertions(+), 45 deletions(-) diff --git a/Data/Shaders/Vulkan/gizmo.frag b/Data/Shaders/Vulkan/gizmo.frag index 23e8c6c6..0f087f4b 100644 --- a/Data/Shaders/Vulkan/gizmo.frag +++ b/Data/Shaders/Vulkan/gizmo.frag @@ -91,6 +91,7 @@ struct PSOutput { struct DebugConstant { + float4 Color; float4x4 Transform; int TextureID; }; @@ -117,7 +118,7 @@ PSOutput main(PSInput input) discard; } - output.oColor0 = textureSample; + output.oColor0 = textureSample * pushConstants.Color; } return output; diff --git a/Data/Shaders/Vulkan/gizmo.vert b/Data/Shaders/Vulkan/gizmo.vert index a75de037..e27c227c 100644 --- a/Data/Shaders/Vulkan/gizmo.vert +++ b/Data/Shaders/Vulkan/gizmo.vert @@ -82,6 +82,7 @@ StructuredBuffer cameras; struct DebugConstant { + float4 Color; float4x4 Transform; int TextureID; }; diff --git a/Data/Shaders/Vulkan/shading.frag b/Data/Shaders/Vulkan/shading.frag index a51053f2..ef1451d9 100644 --- a/Data/Shaders/Vulkan/shading.frag +++ b/Data/Shaders/Vulkan/shading.frag @@ -322,7 +322,7 @@ PSOutput main(PSInput input) float theta = dot(L, normalize(-light.direction)); float epsilon = light.innerConeAngle - light.outerConeAngle; float intensity = clamp((theta - light.outerConeAngle) / epsilon, 0.0, 1.0); - radiance = light.color * intensity; + radiance = light.color * intensity * attenuation; } float3 H = normalize(V + L); diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp b/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp index 3825f8bc..e68774a7 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp @@ -234,7 +234,7 @@ float GetGizmoScale(const Vector3& camPosition, const Nuake::Vector3& position) } template -void DrawIconGizmo(DebugCmd& debugCmd, const std::string& icon) +void DrawIconGizmo(DebugCmd& debugCmd, const std::string& icon, const EditorContext& context) { auto scene = debugCmd.GetScene(); auto cam = scene->GetCurrentCamera(); @@ -247,12 +247,15 @@ void DrawIconGizmo(DebugCmd& debugCmd, const std::string& icon) { auto [transform, cam] = scene->m_Registry.get(e); + auto selection = context.GetSelection(); + bool isSelected = selection.Type == EditorSelectionType::Entity && selection.Entity.GetHandle() == (int)e; + Matrix4 initialTransform = transform.GetGlobalTransform(); Matrix4 gizmoTransform = initialTransform; gizmoTransform = glm::inverse(scene->GetCurrentCamera()->GetTransform()); gizmoTransform[3] = initialTransform[3]; gizmoTransform = glm::scale(gizmoTransform, gizmoSize * GetGizmoScale(cameraPosition, initialTransform[3])); - debugCmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2(icon)); + debugCmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2(icon), isSelected ? Color(1, 1, 0, 1) : Color(1, 1, 1, 1)); } } @@ -284,6 +287,57 @@ void ViewportWidget::OnLineDraw(DebugLineCmd& lineCmd) lineCmd.DrawBox(proj * boxTransform, Color(1, 0, 0, 1.0f), 1.5f, false); } + auto lightView = scene->m_Registry.view(); + for (auto e : lightView) + { + auto [transformComp, lightComp] = scene->m_Registry.get(e); + + const int32_t type = lightComp.Type; + const Quat& rotationOffset = QuatFromEuler(-90.0f, 0, 0); + const Quat& globalRotation = glm::normalize(transformComp.GetGlobalRotation()) * rotationOffset; + const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation); + + Matrix4 transform = Matrix4(1.0f); + transform = glm::translate(view, Vector3(transformComp.GetGlobalTransform()[3])); + transform = transform * rotationMatrix; + transform = glm::translate(transform, { 0, -1.0, 0.0 }); + + if (type == LightType::Spot) + { + const Quat& rotationOffset = QuatFromEuler(90.0f, 0, 0); + const Quat& globalRotation = glm::normalize(transformComp.GetGlobalRotation()) * rotationOffset; + const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation); + + Matrix4 transform = Matrix4(1.0f); + transform = glm::translate(view, Vector3(transformComp.GetGlobalTransform()[3])); + transform = transform * rotationMatrix; + + float length = 1.0f; + float scaleDistance = glm::sqrt(lightComp.Strength); + length *= scaleDistance; + + transform = glm::translate(transform, { 0, -length, 0.0 }); + + float radiusScale = (length) * glm::tan(Rad(lightComp.OuterCutoff)) / 0.25f; + Vector3 coneScale = Vector3(radiusScale, length, radiusScale); + transform = glm::scale(transform, coneScale); + + lineCmd.DrawCone(proj * transform, Color{ lightComp.Color, 1.0f }, 1.5f, false); + } + else if (type == LightType::Directional) + { + const Quat& rotationOffset = QuatFromEuler(-90.0f, 0, 0); + const Quat& globalRotation = glm::normalize(transformComp.GetGlobalRotation()) * rotationOffset; + const Matrix4& rotationMatrix = glm::mat4_cast(globalRotation); + + Matrix4 transform = Matrix4(1.0f); + transform = glm::translate(view, Vector3(transformComp.GetGlobalTransform()[3])); + transform = transform * rotationMatrix; + transform = glm::translate(transform, { 0, -1.0, 0.0 }); + lineCmd.DrawCylinder(proj * transform, Color { lightComp.Color, 1.0f }, 1.5f, false); + } + } + auto boxColliderView = scene->m_Registry.view(); for (auto e : boxColliderView) { @@ -344,14 +398,14 @@ void ViewportWidget::OnDebugDraw(DebugCmd& debugCmd) auto view = cam->GetTransform(); auto proj = cam->GetPerspective(); - static auto drawGizmoIcon = [&](TransformComponent& transform, const std::string& icon) + static auto drawGizmoIcon = [&](TransformComponent& transform, const std::string& icon, const Color& color) { Matrix4 initialTransform = transform.GetGlobalTransform(); Matrix4 gizmoTransform = initialTransform; gizmoTransform = glm::inverse(scene->GetCurrentCamera()->GetTransform()); gizmoTransform[3] = initialTransform[3]; gizmoTransform = glm::scale(gizmoTransform, gizmoSize * GetGizmoScale(cameraPosition, initialTransform[3])); - debugCmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2(icon)); + debugCmd.DrawTexturedQuad(proj * view * gizmoTransform, TextureManager::Get()->GetTexture2(icon), color); }; debugCmd.DrawQuad(proj * view * glm::translate(Matrix4(1.0f), { 0, 4, 0 })); @@ -361,6 +415,9 @@ void ViewportWidget::OnDebugDraw(DebugCmd& debugCmd) { auto [transform, light] = scene->m_Registry.get(e); + auto selection = editorContext.GetSelection(); + bool isSelected = selection.Type == EditorSelectionType::Entity && selection.Entity.GetHandle() == (int)e; + std::string texturePath = "Resources/Gizmos/"; switch (light.Type) { @@ -378,15 +435,15 @@ void ViewportWidget::OnDebugDraw(DebugCmd& debugCmd) } // Billboard + scaling logic - drawGizmoIcon(transform, texturePath); + drawGizmoIcon(transform, texturePath, isSelected ? Color(1, 1, 0, 1) : Color(1, 1, 1, 1)); } - DrawIconGizmo(debugCmd, "Resources/Gizmos/Camera.png"); - DrawIconGizmo(debugCmd, "Resources/Gizmos/player.png"); - DrawIconGizmo(debugCmd, "Resources/Gizmos/bone.png"); - DrawIconGizmo(debugCmd, "Resources/Gizmos/sound_emitter.png"); - DrawIconGizmo(debugCmd, "Resources/Gizmos/rigidbody.png"); - DrawIconGizmo(debugCmd, "Resources/Gizmos/particles.png"); + DrawIconGizmo(debugCmd, "Resources/Gizmos/Camera.png", editorContext); + DrawIconGizmo(debugCmd, "Resources/Gizmos/player.png", editorContext); + DrawIconGizmo(debugCmd, "Resources/Gizmos/bone.png", editorContext); + DrawIconGizmo(debugCmd, "Resources/Gizmos/sound_emitter.png", editorContext); + DrawIconGizmo(debugCmd, "Resources/Gizmos/rigidbody.png", editorContext); + DrawIconGizmo(debugCmd, "Resources/Gizmos/particles.png", editorContext); } diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/Constant/DebugConstant.h b/Nuake/Source/Nuake/Rendering/Vulkan/Constant/DebugConstant.h index e98c8d01..6241e17c 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/Constant/DebugConstant.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/Constant/DebugConstant.h @@ -5,6 +5,7 @@ namespace Nuake { struct DebugConstant { + Vector4 Color = Vector4(1, 1, 1, 1); Matrix4 Transform; int TextureID; }; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp index e3b37d77..ea6fa740 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.cpp @@ -18,7 +18,7 @@ Ref DebugCmd::GetScene() const void DebugCmd::DrawQuad(const Matrix4& transform) { - debugConstant.Transform = transform; + debugConstant.Transform = transform; debugConstant.TextureID = -1; cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(DebugConstant), &debugConstant); @@ -28,10 +28,11 @@ void DebugCmd::DrawQuad(const Matrix4& transform) cmd.DrawIndexed(6); } -void DebugCmd::DrawTexturedQuad(const Matrix4& transform, Ref texture) +void DebugCmd::DrawTexturedQuad(const Matrix4& transform, Ref texture, const Color& color) { debugConstant.Transform = transform; debugConstant.TextureID = GPUResources::Get().GetBindlessTextureID(texture->GetID()); + debugConstant.Color = color; cmd.PushConstants(ctx.renderPass->PipelineLayout, sizeof(DebugConstant), &debugConstant); @@ -41,8 +42,6 @@ void DebugCmd::DrawTexturedQuad(const Matrix4& transform, Ref textu cmd.DrawIndexed(6); } - - DebugLineCmd::DebugLineCmd(Cmd& inCmd, PassRenderContext& inCtx) : cmd(inCmd), ctx(inCtx), lineConstant({}) { @@ -182,29 +181,6 @@ void DebugLineCmd::DrawArrow(const Vector3& from, const Vector3& to, const Matri 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; @@ -214,4 +190,28 @@ void DebugLineCmd::DrawArrow(const Vector3& from, const Vector3& to, const Matri cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, sphereMesh->GetDescriptorSet(), 1); cmd.BindIndexBuffer(sphereMesh->GetIndexBuffer()->GetBuffer()); cmd.DrawIndexed(sphereMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t)); +} + +void DebugLineCmd::DrawCone(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& coneMesh = VkSceneRenderer::ConeMesh; + cmd.BindDescriptorSet(ctx.renderPass->PipelineLayout, coneMesh->GetDescriptorSet(), 1); + cmd.BindIndexBuffer(coneMesh->GetIndexBuffer()->GetBuffer()); + cmd.DrawIndexed(coneMesh->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 350aef88..2f52a32e 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/DebugCmd.h @@ -26,7 +26,7 @@ namespace Nuake Ref GetScene() const; void DrawQuad(const Matrix4& transform); - void DrawTexturedQuad(const Matrix4& transform, Ref texture); + void DrawTexturedQuad(const Matrix4& transform, Ref texture, const Color& color = Color(1, 1, 1 ,1)); void DrawSphere(const Vector2& position, float radius, const Color& color) const; void DrawCube(const Vector3& position, const Vector3& size, const Color& color) const; @@ -59,5 +59,6 @@ namespace Nuake 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); + void DrawCone(const Matrix4& transform, 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 72dbe652..309b73c4 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp @@ -606,7 +606,7 @@ void SceneRenderPipeline::RecreatePipeline() auto& gizmoPass = GBufferPipeline.AddPass("Gizmo"); gizmoPass.SetShaders(shaderMgr.GetShader("gizmo_vert"), shaderMgr.GetShader("gizmo_frag")); - gizmoPass.SetPushConstant(debugConstant); + gizmoPass.SetPushConstant(debugConstant); gizmoPass.AddInput("Depth"); gizmoPass.AddAttachment("GizmoOutput", GizmoOutput->GetFormat()); gizmoPass.AddAttachment("GizmoDepth", GBufferDepth->GetFormat(), ImageUsage::Depth, false); diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp index 14f4b91a..ecd19911 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -28,6 +28,7 @@ Ref VkSceneRenderer::CapsuleMesh; Ref VkSceneRenderer::SphereMesh; Ref VkSceneRenderer::CylinderMesh; Ref VkSceneRenderer::ArrowMesh; +Ref VkSceneRenderer::ConeMesh; void VkSceneRenderer::Init() { @@ -293,7 +294,7 @@ void VkSceneRenderer::Init() std::vector cylinderIndices; const int segments = 16; - const float radius = 0.5f; + const float radius = 0.25f; const float halfHeight = 1.0f; // Vertex pairs: top and bottom @@ -340,7 +341,53 @@ void VkSceneRenderer::Init() // Final creation of the cylinder outline mesh CylinderMesh = CreateRef(cylinderVertices, cylinderIndices); } - + + { + std::vector coneVertices; + std::vector coneIndices; + + const int segments = 16; + const float radius = 0.5f; + const float height = 2.0f; + const float halfHeight = height * 0.5f; + + // Tip vertex at the top center + Vector3 tipPosition = Vector3(0.0f, +halfHeight, 0.0f); + coneVertices.push_back({ tipPosition, 0.0f, Vector3(), 0.0f }); + uint32_t tipIndex = 0; + + // Base ring vertices + 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; + + Vector3 pos = Vector3(x, -halfHeight, z); + coneVertices.push_back({ pos, 0.0f, Vector3(), 0.0f }); + } + + // Circle outline on base + for (int i = 0; i < segments; ++i) + { + uint32_t currIdx = tipIndex + 1 + i; + uint32_t nextIdx = tipIndex + 1 + ((i + 1) % segments); + + coneIndices.push_back(currIdx); + coneIndices.push_back(nextIdx); + } + + // Lines from base to tip + for (int i = 0; i < segments; ++i) + { + uint32_t baseIdx = tipIndex + 1 + i; + coneIndices.push_back(tipIndex); // tip + coneIndices.push_back(baseIdx); // base + } + + // Final creation of the cone outline mesh + ConeMesh = CreateRef(coneVertices, coneIndices); + } } void VkSceneRenderer::LoadShaders() diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h index 675d54b8..db24c1b6 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanSceneRenderer.h @@ -30,6 +30,7 @@ namespace Nuake static Ref SphereMesh; static Ref CylinderMesh; static Ref ArrowMesh; + static Ref ConeMesh; public: //RenderContext Context; diff --git a/Nuake/Source/Nuake/Scene/Components/LightComponent.h b/Nuake/Source/Nuake/Scene/Components/LightComponent.h index d80c1267..c258aa92 100644 --- a/Nuake/Source/Nuake/Scene/Components/LightComponent.h +++ b/Nuake/Source/Nuake/Scene/Components/LightComponent.h @@ -15,7 +15,7 @@ namespace Nuake { - enum LightType + enum LightType : int32_t { Directional, Point, Spot };