From 7aca8199be15c767a27439cc2fbfbf4730f9db8e Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Mon, 30 Mar 2026 00:48:15 +0800 Subject: [PATCH] Refactor scene viewport orientation gizmo --- editor/CMakeLists.txt | 1 + .../SceneViewportOrientationGizmo.cpp | 456 ++++++++++++++++++ .../Viewport/SceneViewportOrientationGizmo.h | 17 + .../Viewport/SceneViewportOverlayRenderer.cpp | 70 +-- 4 files changed, 483 insertions(+), 61 deletions(-) create mode 100644 editor/src/Viewport/SceneViewportOrientationGizmo.cpp create mode 100644 editor/src/Viewport/SceneViewportOrientationGizmo.h diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index baf5bd4c..7ccc2b7b 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -84,6 +84,7 @@ add_executable(${PROJECT_NAME} WIN32 src/Viewport/SceneViewportInfiniteGridPass.cpp src/Viewport/SceneViewportSelectionMaskPass.cpp src/Viewport/SceneViewportSelectionOutlinePass.cpp + src/Viewport/SceneViewportOrientationGizmo.cpp src/Viewport/SceneViewportOverlayRenderer.cpp src/panels/GameViewPanel.cpp src/panels/InspectorPanel.cpp diff --git a/editor/src/Viewport/SceneViewportOrientationGizmo.cpp b/editor/src/Viewport/SceneViewportOrientationGizmo.cpp new file mode 100644 index 00000000..0ff16cf8 --- /dev/null +++ b/editor/src/Viewport/SceneViewportOrientationGizmo.cpp @@ -0,0 +1,456 @@ +#include "SceneViewportOrientationGizmo.h" + +#include + +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Editor { + +namespace { + +constexpr float kViewerDistance = 112.0f; +constexpr float kWidgetInset = 70.0f; +constexpr float kCubeHalfExtent = 8.5f; +constexpr float kPositiveAxisLength = 31.5f; +constexpr float kNegativeAxisLength = kPositiveAxisLength; +constexpr int kConeCapSegments = 20; +constexpr float kTau = 6.28318530718f; + +ImU32 ToImGuiColor(const Math::Color& color) { + const auto toChannel = [](float value) -> int { + return static_cast(std::clamp(value, 0.0f, 1.0f) * 255.0f + 0.5f); + }; + + return IM_COL32( + toChannel(color.r), + toChannel(color.g), + toChannel(color.b), + toChannel(color.a)); +} + +float Saturate(float value) { + return std::clamp(value, 0.0f, 1.0f); +} + +Math::Color LerpColor(const Math::Color& a, const Math::Color& b, float t) { + const float clamped = Saturate(t); + return Math::Color( + a.r + (b.r - a.r) * clamped, + a.g + (b.g - a.g) * clamped, + a.b + (b.b - a.b) * clamped, + a.a + (b.a - a.a) * clamped); +} + +Math::Color MultiplyColor(const Math::Color& color, float factor) { + return Math::Color( + Saturate(color.r * factor), + Saturate(color.g * factor), + Saturate(color.b * factor), + color.a); +} + +Math::Vector3 NormalizeVector3(const Math::Vector3& value, const Math::Vector3& fallback) { + return value.SqrMagnitude() <= Math::EPSILON ? fallback : value.Normalized(); +} + +ImVec2 NormalizeImVec2(const ImVec2& value) { + const float lengthSq = value.x * value.x + value.y * value.y; + if (lengthSq <= 1e-6f) { + return ImVec2(0.0f, -1.0f); + } + + const float invLength = 1.0f / std::sqrt(lengthSq); + return ImVec2(value.x * invLength, value.y * invLength); +} + +ImVec2 LerpImVec2(const ImVec2& a, const ImVec2& b, float t) { + return ImVec2( + a.x + (b.x - a.x) * t, + a.y + (b.y - a.y) * t); +} + +void BuildPerpendicularBasis( + const Math::Vector3& axis, + Math::Vector3& outTangent, + Math::Vector3& outBitangent) { + const Math::Vector3 normalizedAxis = NormalizeVector3(axis, Math::Vector3::Forward()); + Math::Vector3 reference = std::abs(normalizedAxis.y) < 0.85f + ? Math::Vector3::Up() + : Math::Vector3::Right(); + if (std::abs(Math::Vector3::Dot(normalizedAxis, reference)) > 0.95f) { + reference = Math::Vector3::Forward(); + } + + outTangent = Math::Vector3::Cross(normalizedAxis, reference); + if (outTangent.SqrMagnitude() <= Math::EPSILON) { + outTangent = Math::Vector3::Right(); + } else { + outTangent = outTangent.Normalized(); + } + + outBitangent = Math::Vector3::Cross(outTangent, normalizedAxis); + if (outBitangent.SqrMagnitude() <= Math::EPSILON) { + outBitangent = Math::Vector3::Up(); + } else { + outBitangent = outBitangent.Normalized(); + } +} + +Math::Vector3 TransformToCameraSpace( + const SceneViewportOverlayData& overlay, + const Math::Vector3& localPoint) { + const Math::Vector3 cameraRight = NormalizeVector3(overlay.cameraRight, Math::Vector3::Right()); + const Math::Vector3 cameraUp = NormalizeVector3(overlay.cameraUp, Math::Vector3::Up()); + const Math::Vector3 cameraForward = NormalizeVector3(overlay.cameraForward, Math::Vector3::Forward()); + + return Math::Vector3( + Math::Vector3::Dot(localPoint, cameraRight), + Math::Vector3::Dot(localPoint, cameraUp), + Math::Vector3::Dot(localPoint, cameraForward)); +} + +struct ProjectedPoint { + ImVec2 position = ImVec2(0.0f, 0.0f); + float scale = 1.0f; + float depth = 0.0f; +}; + +ProjectedPoint ProjectPoint(const ImVec2& center, const Math::Vector3& point) { + const float scale = kViewerDistance / std::max(34.0f, kViewerDistance + point.z); + return { + ImVec2(center.x + point.x * scale, center.y - point.y * scale), + scale, + point.z + }; +} + +struct AxisHandleVisual { + Math::Vector3 cameraDirection = Math::Vector3::Zero(); + Math::Color baseColor = Math::Color::White(); + const char* label = nullptr; + bool positive = false; + float sortDepth = 0.0f; +}; + +struct CubeFaceVisual { + std::array points = {}; + Math::Vector3 cameraNormal = Math::Vector3::Zero(); + float averageDepth = 0.0f; +}; + +float ComputePolygonSignedArea(const ImVec2* points, int pointCount) { + if (points == nullptr || pointCount < 3) { + return 0.0f; + } + + float area = 0.0f; + for (int i = 0; i < pointCount; ++i) { + const ImVec2& a = points[i]; + const ImVec2& b = points[(i + 1) % pointCount]; + area += a.x * b.y - b.x * a.y; + } + return area * 0.5f; +} + +void DrawAxisLabel(ImDrawList* drawList, const ImVec2& position, const char* label) { + if (drawList == nullptr || label == nullptr) { + return; + } + + ImVec2 textPosition = position; + const ImVec2 labelSize = ImGui::CalcTextSize(label); + textPosition.x -= labelSize.x * 0.5f; + textPosition.y -= labelSize.y * 0.5f; + + drawList->AddText( + ImVec2(textPosition.x + 1.0f, textPosition.y + 1.0f), + IM_COL32(0, 0, 0, 120), + label); + drawList->AddText(textPosition, IM_COL32(245, 245, 245, 255), label); +} + +void DrawCenterCube( + ImDrawList* drawList, + const SceneViewportOverlayData& overlay, + const ImVec2& center) { + if (drawList == nullptr) { + return; + } + + const std::array cubeVertices = {{ + Math::Vector3(-kCubeHalfExtent, -kCubeHalfExtent, -kCubeHalfExtent), + Math::Vector3(kCubeHalfExtent, -kCubeHalfExtent, -kCubeHalfExtent), + Math::Vector3(kCubeHalfExtent, kCubeHalfExtent, -kCubeHalfExtent), + Math::Vector3(-kCubeHalfExtent, kCubeHalfExtent, -kCubeHalfExtent), + Math::Vector3(-kCubeHalfExtent, -kCubeHalfExtent, kCubeHalfExtent), + Math::Vector3(kCubeHalfExtent, -kCubeHalfExtent, kCubeHalfExtent), + Math::Vector3(kCubeHalfExtent, kCubeHalfExtent, kCubeHalfExtent), + Math::Vector3(-kCubeHalfExtent, kCubeHalfExtent, kCubeHalfExtent) + }}; + + struct FaceDefinition { + std::array indices; + Math::Vector3 normal; + }; + + const std::array faces = {{ + { { 1, 5, 6, 2 }, Math::Vector3::Right() }, + { { 4, 0, 3, 7 }, Math::Vector3::Left() }, + { { 3, 2, 6, 7 }, Math::Vector3::Up() }, + { { 0, 4, 5, 1 }, Math::Vector3::Down() }, + { { 4, 5, 6, 7 }, Math::Vector3::Forward() }, + { { 0, 1, 2, 3 }, Math::Vector3::Back() } + }}; + + std::array projectedVertices = {}; + for (size_t i = 0; i < cubeVertices.size(); ++i) { + projectedVertices[i] = ProjectPoint(center, TransformToCameraSpace(overlay, cubeVertices[i])); + } + + std::vector visibleFaces; + visibleFaces.reserve(3); + for (const FaceDefinition& face : faces) { + const Math::Vector3 cameraNormal = TransformToCameraSpace(overlay, face.normal); + if (cameraNormal.z >= -0.02f) { + continue; + } + + CubeFaceVisual visual = {}; + visual.cameraNormal = cameraNormal; + for (size_t i = 0; i < face.indices.size(); ++i) { + const ProjectedPoint& projected = projectedVertices[face.indices[i]]; + visual.points[i] = projected.position; + visual.averageDepth += projected.depth; + } + visual.averageDepth /= 4.0f; + visibleFaces.push_back(visual); + } + + std::sort( + visibleFaces.begin(), + visibleFaces.end(), + [](const CubeFaceVisual& lhs, const CubeFaceVisual& rhs) { + return lhs.averageDepth > rhs.averageDepth; + }); + + const Math::Vector3 lightDirection = NormalizeVector3( + Math::Vector3(-0.35f, 0.80f, -0.90f), + Math::Vector3(-0.35f, 0.80f, -0.90f)); + for (const CubeFaceVisual& face : visibleFaces) { + const float lightFactor = std::max(0.0f, Math::Vector3::Dot(face.cameraNormal.Normalized(), lightDirection)); + const Math::Color faceColor = LerpColor( + Math::Color(0.42f, 0.44f, 0.47f, 1.0f), + Math::Color(0.72f, 0.74f, 0.78f, 1.0f), + 0.22f + lightFactor * 0.78f); + const float projectedArea = std::abs(ComputePolygonSignedArea(face.points.data(), 4)); + + if (projectedArea <= 5.0f) { + for (int i = 0; i < 4; ++i) { + const ImVec2& a = face.points[i]; + const ImVec2& b = face.points[(i + 1) % 4]; + drawList->AddLine( + ImVec2(a.x + 1.0f, a.y + 1.2f), + ImVec2(b.x + 1.0f, b.y + 1.2f), + IM_COL32(0, 0, 0, 42), + 1.6f); + drawList->AddLine(a, b, ToImGuiColor(faceColor), 1.2f); + } + } else { + const ImVec2 shadowPoints[] = { + ImVec2(face.points[0].x + 1.5f, face.points[0].y + 1.7f), + ImVec2(face.points[1].x + 1.5f, face.points[1].y + 1.7f), + ImVec2(face.points[2].x + 1.5f, face.points[2].y + 1.7f), + ImVec2(face.points[3].x + 1.5f, face.points[3].y + 1.7f) + }; + drawList->AddConvexPolyFilled(shadowPoints, 4, IM_COL32(0, 0, 0, 52)); + drawList->AddConvexPolyFilled(face.points.data(), 4, ToImGuiColor(faceColor)); + drawList->AddPolyline(face.points.data(), 4, IM_COL32(255, 255, 255, 44), true, 1.0f); + } + } +} + +void DrawAxisHandle( + ImDrawList* drawList, + const ImVec2& center, + const AxisHandleVisual& handle) { + if (drawList == nullptr || handle.cameraDirection.SqrMagnitude() <= Math::EPSILON) { + return; + } + + const float frontFactor = Saturate((-handle.cameraDirection.z + 1.0f) * 0.5f); + const float tipDistance = kCubeHalfExtent + 0.65f; + const float capDistance = handle.positive ? kPositiveAxisLength : kNegativeAxisLength; + const float capRadius = 7.1f; + + const Math::Vector3 tipPoint3 = handle.cameraDirection * tipDistance; + const Math::Vector3 capCenter3 = handle.cameraDirection * capDistance; + + const ProjectedPoint tip = ProjectPoint(center, tipPoint3); + const ProjectedPoint capCenter = ProjectPoint(center, capCenter3); + const ImVec2 axisVector( + capCenter.position.x - tip.position.x, + capCenter.position.y - tip.position.y); + const float axisLengthSq = axisVector.x * axisVector.x + axisVector.y * axisVector.y; + const float axisLength = std::sqrt(axisLengthSq); + const ImVec2 axisDirection = axisLength > 1e-4f + ? ImVec2(axisVector.x / axisLength, axisVector.y / axisLength) + : ImVec2(0.0f, 0.0f); + const ImVec2 sideDirection(-axisDirection.y, axisDirection.x); + + Math::Vector3 capTangent = Math::Vector3::Right(); + Math::Vector3 capBitangent = Math::Vector3::Up(); + BuildPerpendicularBasis(handle.cameraDirection, capTangent, capBitangent); + + std::array capPoints = {}; + ImVec2 leftPoint = capCenter.position; + ImVec2 rightPoint = capCenter.position; + float maxSide = std::numeric_limits::lowest(); + float minSide = std::numeric_limits::max(); + float maxAxis = std::numeric_limits::lowest(); + float minAxis = std::numeric_limits::max(); + for (int i = 0; i < kConeCapSegments; ++i) { + const float angle = (static_cast(i) / static_cast(kConeCapSegments)) * kTau; + const Math::Vector3 ringPoint = + capCenter3 + + capTangent * (std::cos(angle) * capRadius) + + capBitangent * (std::sin(angle) * capRadius); + capPoints[i] = ProjectPoint(center, ringPoint).position; + + const ImVec2 offset( + capPoints[i].x - capCenter.position.x, + capPoints[i].y - capCenter.position.y); + const float sideValue = offset.x * sideDirection.x + offset.y * sideDirection.y; + const float axisValue = offset.x * axisDirection.x + offset.y * axisDirection.y; + if (sideValue > maxSide) { + maxSide = sideValue; + leftPoint = capPoints[i]; + } + if (sideValue < minSide) { + minSide = sideValue; + rightPoint = capPoints[i]; + } + maxAxis = std::max(maxAxis, axisValue); + minAxis = std::min(minAxis, axisValue); + } + + const Math::Color bodyColor = handle.positive + ? LerpColor(MultiplyColor(handle.baseColor, 0.82f), Math::Color(0.98f, 0.98f, 0.98f, 1.0f), frontFactor * 0.16f) + : LerpColor(Math::Color(0.66f, 0.66f, 0.66f, 1.0f), Math::Color(0.95f, 0.95f, 0.95f, 1.0f), frontFactor); + const Math::Color lightColor = LerpColor(bodyColor, Math::Color::White(), handle.positive ? 0.14f : 0.20f); + const Math::Color darkColor = MultiplyColor(bodyColor, handle.positive ? 0.76f : 0.86f); + const Math::Color capColor = handle.positive + ? LerpColor(bodyColor, Math::Color::White(), 0.08f + frontFactor * 0.12f) + : LerpColor(bodyColor, Math::Color::White(), 0.16f + frontFactor * 0.14f); + + const ImVec2 shadowTriangle[] = { + ImVec2(tip.position.x + 1.2f, tip.position.y + 1.4f), + ImVec2(leftPoint.x + 1.2f, leftPoint.y + 1.4f), + ImVec2(rightPoint.x + 1.2f, rightPoint.y + 1.4f) + }; + const ImVec2 leftFacet[] = { + tip.position, + leftPoint, + capCenter.position + }; + const ImVec2 rightFacet[] = { + tip.position, + capCenter.position, + rightPoint + }; + + drawList->AddConvexPolyFilled(shadowTriangle, 3, IM_COL32(0, 0, 0, 58)); + drawList->AddConvexPolyFilled(leftFacet, 3, ToImGuiColor(lightColor)); + drawList->AddConvexPolyFilled(rightFacet, 3, ToImGuiColor(darkColor)); + drawList->AddLine(tip.position, leftPoint, IM_COL32(255, 255, 255, handle.positive ? 34 : 44), 1.0f); + drawList->AddLine(tip.position, rightPoint, IM_COL32(0, 0, 0, 38), 1.0f); + const float capMinorSpan = maxAxis - minAxis; + if (capMinorSpan <= 1.35f) { + drawList->AddLine( + ImVec2(rightPoint.x + 1.0f, rightPoint.y + 1.2f), + ImVec2(leftPoint.x + 1.0f, leftPoint.y + 1.2f), + IM_COL32(0, 0, 0, 52), + 2.4f); + drawList->AddLine( + rightPoint, + leftPoint, + ToImGuiColor(capColor), + 2.0f); + drawList->AddLine( + rightPoint, + leftPoint, + IM_COL32(255, 255, 255, handle.positive ? 56 : 68), + 1.0f); + } else { + drawList->AddConvexPolyFilled(capPoints.data(), static_cast(capPoints.size()), ToImGuiColor(capColor)); + drawList->AddPolyline( + capPoints.data(), + static_cast(capPoints.size()), + IM_COL32(255, 255, 255, handle.positive ? 60 : 72), + true, + 1.0f); + } + + if (handle.positive && handle.label != nullptr) { + const float labelOffset = 9.0f * Saturate((axisLength - 2.0f) / 12.0f); + const ImVec2 labelPosition( + capCenter.position.x + axisDirection.x * labelOffset, + capCenter.position.y + axisDirection.y * labelOffset); + DrawAxisLabel(drawList, labelPosition, handle.label); + } +} + +} // namespace + +void DrawSceneViewportOrientationGizmo( + ImDrawList* drawList, + const SceneViewportOverlayData& overlay, + const ImVec2& viewportMin, + const ImVec2& viewportMax) { + if (drawList == nullptr || !overlay.valid) { + return; + } + + const ImVec2 center(viewportMax.x - kWidgetInset, viewportMin.y + kWidgetInset); + const std::array handles = {{ + { TransformToCameraSpace(overlay, Math::Vector3::Right()), Math::Color(0.91f, 0.09f, 0.05f, 1.0f), "x", true, 0.0f }, + { TransformToCameraSpace(overlay, Math::Vector3::Left()), Math::Color(1.0f, 1.0f, 1.0f, 1.0f), nullptr, false, 0.0f }, + { TransformToCameraSpace(overlay, Math::Vector3::Up()), Math::Color(0.45f, 1.0f, 0.12f, 1.0f), "y", true, 0.0f }, + { TransformToCameraSpace(overlay, Math::Vector3::Down()), Math::Color(1.0f, 1.0f, 1.0f, 1.0f), nullptr, false, 0.0f }, + { TransformToCameraSpace(overlay, Math::Vector3::Forward()), Math::Color(0.11f, 0.29f, 1.0f, 1.0f), "z", true, 0.0f }, + { TransformToCameraSpace(overlay, Math::Vector3::Back()), Math::Color(1.0f, 1.0f, 1.0f, 1.0f), nullptr, false, 0.0f } + }}; + + std::vector sortedHandles(handles.begin(), handles.end()); + for (AxisHandleVisual& handle : sortedHandles) { + handle.sortDepth = handle.cameraDirection.z; + } + + std::sort( + sortedHandles.begin(), + sortedHandles.end(), + [](const AxisHandleVisual& lhs, const AxisHandleVisual& rhs) { + return lhs.sortDepth > rhs.sortDepth; + }); + + for (const AxisHandleVisual& handle : sortedHandles) { + if (handle.sortDepth > 0.0f) { + DrawAxisHandle(drawList, center, handle); + } + } + + DrawCenterCube(drawList, overlay, center); + + for (const AxisHandleVisual& handle : sortedHandles) { + if (handle.sortDepth <= 0.0f) { + DrawAxisHandle(drawList, center, handle); + } + } +} + +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/Viewport/SceneViewportOrientationGizmo.h b/editor/src/Viewport/SceneViewportOrientationGizmo.h new file mode 100644 index 00000000..3917ab93 --- /dev/null +++ b/editor/src/Viewport/SceneViewportOrientationGizmo.h @@ -0,0 +1,17 @@ +#pragma once + +#include "IViewportHostService.h" + +#include + +namespace XCEngine { +namespace Editor { + +void DrawSceneViewportOrientationGizmo( + ImDrawList* drawList, + const SceneViewportOverlayData& overlay, + const ImVec2& viewportMin, + const ImVec2& viewportMax); + +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/Viewport/SceneViewportOverlayRenderer.cpp b/editor/src/Viewport/SceneViewportOverlayRenderer.cpp index a198e839..d001c4e2 100644 --- a/editor/src/Viewport/SceneViewportOverlayRenderer.cpp +++ b/editor/src/Viewport/SceneViewportOverlayRenderer.cpp @@ -1,15 +1,13 @@ #include "SceneViewportOverlayRenderer.h" -#include "SceneViewportMath.h" +#include "SceneViewportOrientationGizmo.h" + +#include namespace XCEngine { namespace Editor { namespace { -Math::Matrix4x4 BuildOverlayViewMatrix(const SceneViewportOverlayData& overlay) { - return BuildSceneViewportViewMatrix(overlay); -} - ImU32 ToImGuiColor(const Math::Color& color) { const auto toChannel = [](float value) -> int { return static_cast(std::clamp(value, 0.0f, 1.0f) * 255.0f + 0.5f); @@ -22,65 +20,15 @@ ImU32 ToImGuiColor(const Math::Color& color) { toChannel(color.a)); } -void DrawAxisLabel(ImDrawList* drawList, const ImVec2& position, const char* label, ImU32 color) { - if (drawList == nullptr || label == nullptr) { - return; - } - - const ImVec2 labelSize = ImGui::CalcTextSize(label); - drawList->AddText( - ImVec2(position.x - labelSize.x * 0.5f, position.y - labelSize.y * 0.5f), - color, - label); -} - -void DrawSceneAxisWidget( - ImDrawList* drawList, - const SceneViewportOverlayData& overlay, - const ImVec2& viewportMin, - const ImVec2& viewportMax) { - if (drawList == nullptr || !overlay.valid) { - return; - } - - const Math::Matrix4x4 view = BuildOverlayViewMatrix(overlay); - const ImVec2 center(viewportMax.x - 52.0f, viewportMin.y + 52.0f); - const float radius = 25.0f; - - drawList->AddCircleFilled(center, radius + 12.0f, IM_COL32(17, 19, 22, 178), 24); - drawList->AddCircle(center, radius + 12.0f, IM_COL32(255, 255, 255, 30), 24, 1.0f); - - struct AxisLine { - Math::Vector3 axis; - const char* label; - ImU32 color; - }; - - const AxisLine axes[] = { - { Math::Vector3::Right(), "x", IM_COL32(239, 83, 80, 255) }, - { Math::Vector3::Up(), "y", IM_COL32(102, 187, 106, 255) }, - { Math::Vector3::Forward(), "z", IM_COL32(66, 165, 245, 255) } - }; - - for (const AxisLine& axis : axes) { - const Math::Vector3 viewAxis = view.MultiplyVector(axis.axis); - const ImVec2 end( - center.x + viewAxis.x * radius, - center.y - viewAxis.y * radius); - drawList->AddLine(center, end, axis.color, 2.0f); - drawList->AddCircleFilled(end, 6.0f, axis.color, 16); - DrawAxisLabel(drawList, end, axis.label, IM_COL32(245, 245, 245, 255)); - } -} - void DrawSceneMoveGizmo( ImDrawList* drawList, + const ImVec2& viewportMin, const SceneViewportMoveGizmoDrawData& moveGizmo) { if (drawList == nullptr || !moveGizmo.visible) { return; } - const ImVec2 pivot(moveGizmo.pivot.x, moveGizmo.pivot.y); + const ImVec2 pivot(viewportMin.x + moveGizmo.pivot.x, viewportMin.y + moveGizmo.pivot.y); drawList->AddCircleFilled(pivot, moveGizmo.pivotRadius + 1.0f, IM_COL32(20, 22, 24, 220), 20); drawList->AddCircle(pivot, moveGizmo.pivotRadius + 1.0f, IM_COL32(255, 255, 255, 48), 20, 1.0f); @@ -91,8 +39,8 @@ void DrawSceneMoveGizmo( const ImU32 color = ToImGuiColor(handle.color); const float thickness = handle.active ? 4.0f : (handle.hovered ? 3.0f : 2.0f); - const ImVec2 start(handle.start.x, handle.start.y); - const ImVec2 end(handle.end.x, handle.end.y); + const ImVec2 start(viewportMin.x + handle.start.x, viewportMin.y + handle.start.y); + const ImVec2 end(viewportMin.x + handle.end.x, viewportMin.y + handle.end.y); drawList->AddLine(start, end, color, thickness); drawList->AddCircleFilled(end, handle.active ? 6.5f : 5.5f, color, 20); } @@ -113,10 +61,10 @@ void DrawSceneViewportOverlay( drawList->PushClipRect(viewportMin, viewportMax, true); if (overlay.valid) { - DrawSceneAxisWidget(drawList, overlay, viewportMin, viewportMax); + DrawSceneViewportOrientationGizmo(drawList, overlay, viewportMin, viewportMax); } if (moveGizmo != nullptr) { - DrawSceneMoveGizmo(drawList, *moveGizmo); + DrawSceneMoveGizmo(drawList, viewportMin, *moveGizmo); } drawList->PopClipRect(); }