Add scene transform toolbar and scale gizmo

This commit is contained in:
2026-04-01 16:42:57 +08:00
parent 4e8ad9a706
commit 3f18530396
23 changed files with 1668 additions and 198 deletions

View File

@@ -5,16 +5,13 @@
#include "SceneViewportPicker.h"
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Components/MeshFilterComponent.h>
#include <XCEngine/Components/MeshRendererComponent.h>
#include <XCEngine/Core/Math/Bounds.h>
namespace XCEngine {
namespace Editor {
namespace {
constexpr float kMoveGizmoHandleLengthPixels = 88.0f;
constexpr float kMoveGizmoHandleLengthPixels = 100.0f;
constexpr float kMoveGizmoHoverThresholdPixels = 10.0f;
Math::Vector3 GetAxisVector(SceneViewportGizmoAxis axis) {
@@ -166,63 +163,6 @@ bool IsMouseInsideViewport(const SceneViewportMoveGizmoContext& context) {
context.mousePosition.y <= context.viewportSize.y;
}
void EncapsulateTransformedBounds(
const Math::Bounds& localBounds,
const Components::TransformComponent& transform,
Math::Bounds& inOutBounds,
bool& inOutHasBounds) {
const Math::Vector3 localMin = localBounds.GetMin();
const Math::Vector3 localMax = localBounds.GetMax();
const Math::Vector3 corners[] = {
Math::Vector3(localMin.x, localMin.y, localMin.z),
Math::Vector3(localMax.x, localMin.y, localMin.z),
Math::Vector3(localMin.x, localMax.y, localMin.z),
Math::Vector3(localMin.x, localMin.y, localMax.z),
Math::Vector3(localMax.x, localMax.y, localMin.z),
Math::Vector3(localMin.x, localMax.y, localMax.z),
Math::Vector3(localMax.x, localMin.y, localMax.z),
Math::Vector3(localMax.x, localMax.y, localMax.z)
};
for (const Math::Vector3& localCorner : corners) {
const Math::Vector3 worldCorner = transform.TransformPoint(localCorner);
if (!inOutHasBounds) {
inOutBounds = Math::Bounds(worldCorner, Math::Vector3::Zero());
inOutHasBounds = true;
} else {
inOutBounds.Encapsulate(worldCorner);
}
}
}
void CollectRenderableWorldBoundsRecursive(
const Components::GameObject& gameObject,
Math::Bounds& inOutBounds,
bool& inOutHasBounds) {
if (!gameObject.IsActiveInHierarchy()) {
return;
}
const auto* meshFilter = gameObject.GetComponent<Components::MeshFilterComponent>();
const auto* meshRenderer = gameObject.GetComponent<Components::MeshRendererComponent>();
if (meshFilter != nullptr &&
meshRenderer != nullptr &&
meshFilter->IsEnabled() &&
meshRenderer->IsEnabled()) {
const auto* mesh = meshFilter->GetMesh();
if (mesh != nullptr) {
EncapsulateTransformedBounds(mesh->GetBounds(), *gameObject.GetTransform(), inOutBounds, inOutHasBounds);
}
}
for (size_t childIndex = 0; childIndex < gameObject.GetChildCount(); ++childIndex) {
const Components::GameObject* child = gameObject.GetChild(childIndex);
if (child != nullptr) {
CollectRenderableWorldBoundsRecursive(*child, inOutBounds, inOutHasBounds);
}
}
}
float ComputeWorldUnitsPerPixel(
const SceneViewportOverlayData& overlay,
const Math::Vector3& worldPoint,
@@ -240,13 +180,6 @@ float ComputeWorldUnitsPerPixel(
return 2.0f * depth * std::tan(overlay.verticalFovDegrees * Math::DEG_TO_RAD * 0.5f) / viewportHeight;
}
Math::Vector3 GetGizmoWorldOrigin(const Components::GameObject& gameObject) {
Math::Bounds worldBounds = {};
bool hasBounds = false;
CollectRenderableWorldBoundsRecursive(gameObject, worldBounds, hasBounds);
return hasBounds ? worldBounds.center : gameObject.GetTransform()->GetPosition();
}
} // namespace
void SceneViewportMoveGizmo::Update(const SceneViewportMoveGizmoContext& context) {
@@ -289,7 +222,7 @@ bool SceneViewportMoveGizmo::TryBeginDrag(const SceneViewportMoveGizmoContext& c
}
const Math::Vector3 objectWorldPosition = context.selectedObject->GetTransform()->GetPosition();
const Math::Vector3 pivotWorldPosition = GetGizmoWorldOrigin(*context.selectedObject);
const Math::Vector3 pivotWorldPosition = context.selectedObject->GetTransform()->GetPosition();
Math::Vector3 dragPlaneNormal = Math::Vector3::Zero();
Math::Vector3 worldAxis = Math::Vector3::Zero();
@@ -442,7 +375,7 @@ void SceneViewportMoveGizmo::BuildDrawData(const SceneViewportMoveGizmoContext&
return;
}
const Math::Vector3 gizmoWorldOrigin = GetGizmoWorldOrigin(*selectedObject);
const Math::Vector3 gizmoWorldOrigin = selectedObject->GetTransform()->GetPosition();
const SceneViewportProjectedPoint projectedPivot = ProjectSceneViewportWorldPoint(
context.overlay,
context.viewportSize.x,