feat: refine scene viewport gizmos and controls

This commit is contained in:
2026-03-31 21:26:40 +08:00
parent be15bc2fc4
commit 6d3a90ef74
16 changed files with 969 additions and 155 deletions

View File

@@ -107,6 +107,70 @@ inline bool ProjectSceneViewportAxisDirection(
return true;
}
inline bool ProjectSceneViewportAxisDirectionAtPoint(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight,
const Math::Vector3& worldPoint,
const Math::Vector3& worldAxis,
Math::Vector2& outScreenDirection,
float sampleDistance = 1.0f) {
const Math::Vector3 axis = worldAxis.Normalized();
if (!overlay.valid ||
viewportWidth <= 1.0f ||
viewportHeight <= 1.0f ||
axis.SqrMagnitude() <= Math::EPSILON ||
sampleDistance <= Math::EPSILON) {
return false;
}
const Math::Matrix4x4 viewProjection =
BuildSceneViewportViewProjectionMatrix(overlay, viewportWidth, viewportHeight);
const Math::Vector4 startClip = viewProjection * Math::Vector4(worldPoint, 1.0f);
const Math::Vector4 endClip = viewProjection * Math::Vector4(worldPoint + axis * sampleDistance, 1.0f);
if (startClip.w <= Math::EPSILON || endClip.w <= Math::EPSILON) {
return ProjectSceneViewportAxisDirection(overlay, axis, outScreenDirection);
}
const Math::Vector3 startNdc = startClip.ToVector3() / startClip.w;
const Math::Vector3 endNdc = endClip.ToVector3() / endClip.w;
const Math::Vector2 startScreen(
(startNdc.x * 0.5f + 0.5f) * viewportWidth,
(1.0f - (startNdc.y * 0.5f + 0.5f)) * viewportHeight);
const Math::Vector2 endScreen(
(endNdc.x * 0.5f + 0.5f) * viewportWidth,
(1.0f - (endNdc.y * 0.5f + 0.5f)) * viewportHeight);
const Math::Vector2 screenDirection = endScreen - startScreen;
if (screenDirection.SqrMagnitude() <= Math::EPSILON) {
return ProjectSceneViewportAxisDirection(overlay, axis, outScreenDirection);
}
outScreenDirection = screenDirection.Normalized();
return true;
}
inline bool ProjectSceneViewportWorldPointClamped(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight,
const Math::Vector3& worldPoint,
float edgePadding,
SceneViewportProjectedPoint& outProjectedPoint) {
outProjectedPoint = ProjectSceneViewportWorldPoint(overlay, viewportWidth, viewportHeight, worldPoint);
if (!overlay.valid || viewportWidth <= 1.0f || viewportHeight <= 1.0f || outProjectedPoint.ndcDepth < 0.0f) {
return false;
}
const float minX = edgePadding;
const float minY = edgePadding;
const float maxX = viewportWidth - edgePadding;
const float maxY = viewportHeight - edgePadding;
outProjectedPoint.screenPosition.x = std::clamp(outProjectedPoint.screenPosition.x, minX, maxX);
outProjectedPoint.screenPosition.y = std::clamp(outProjectedPoint.screenPosition.y, minY, maxY);
return true;
}
inline float DistanceToSegmentSquared(
const Math::Vector2& point,
const Math::Vector2& segmentStart,