This commit is contained in:
bird_egop
2026-06-05 20:47:57 +03:00
parent 195e6d71bd
commit 614787789e
11 changed files with 446 additions and 42 deletions
+81 -8
View File
@@ -4,31 +4,104 @@ namespace NResUI.Rendering.Viewport;
public sealed class ViewportCamera
{
public const float FieldOfViewDegrees = 60.0f;
public float YawDegrees { get; set; } = 35.0f;
public float PitchDegrees { get; set; } = 25.0f;
public float Distance { get; set; } = 4.0f;
public Vector3 Target { get; set; } = Vector3.Zero;
public Matrix4x4 GetSceneRotationMatrix()
{
return Matrix4x4.CreateRotationY(ToRadians(YawDegrees)) *
Matrix4x4.CreateRotationX(ToRadians(PitchDegrees));
// Kept as an explicit hook for future scene-wide transforms.
// Camera orbit is handled by GetViewMatrix().
return Matrix4x4.Identity;
}
public Matrix4x4 GetViewMatrix()
{
return Matrix4x4.CreateLookAt(
new Vector3(0.0f, 0.0f, Distance),
Vector3.Zero,
Vector3.UnitY);
return Matrix4x4.CreateLookAt(GetEyePosition(), Target, Vector3.UnitY);
}
public Matrix4x4 GetProjectionMatrix(float aspectRatio)
{
return Matrix4x4.CreatePerspectiveFieldOfView(
ToRadians(60.0f),
ToRadians(FieldOfViewDegrees),
aspectRatio,
0.01f,
100.0f);
1000.0f);
}
public Vector3 GetEyePosition()
{
return Target + GetOrbitDirection() * Distance;
}
public Vector3 GetForwardDirection()
{
return Vector3.Normalize(Target - GetEyePosition());
}
public Vector3 GetRightDirection()
{
var forward = GetForwardDirection();
var right = Vector3.Cross(forward, Vector3.UnitY);
if (right.LengthSquared() < 1e-8f)
return Vector3.UnitX;
return Vector3.Normalize(right);
}
public Vector3 GetUpDirection()
{
var right = GetRightDirection();
var forward = GetForwardDirection();
return Vector3.Normalize(Vector3.Cross(right, forward));
}
public void Pan(Vector2 mouseDelta, Vector2 viewportSize)
{
if (viewportSize.Y <= 1.0f)
return;
var worldUnitsPerPixel = 2.0f * Distance * MathF.Tan(ToRadians(FieldOfViewDegrees) * 0.5f) / viewportSize.Y;
var right = GetRightDirection();
var up = GetUpDirection();
Target -= right * (mouseDelta.X * worldUnitsPerPixel);
Target += up * (mouseDelta.Y * worldUnitsPerPixel);
}
public void Reset()
{
YawDegrees = 35.0f;
PitchDegrees = 25.0f;
Distance = 4.0f;
Target = Vector3.Zero;
}
public void FrameBounds(Vector3 boundsMin, Vector3 boundsMax)
{
var center = (boundsMin + boundsMax) * 0.5f;
var extents = (boundsMax - boundsMin) * 0.5f;
var radius = MathF.Max(extents.Length(), 0.25f);
Target = center;
Distance = Math.Clamp(radius * 2.8f, 1.5f, 200.0f);
}
private Vector3 GetOrbitDirection()
{
var yaw = ToRadians(YawDegrees);
var pitch = ToRadians(PitchDegrees);
var cosPitch = MathF.Cos(pitch);
return Vector3.Normalize(new Vector3(
MathF.Sin(yaw) * cosPitch,
MathF.Sin(pitch),
MathF.Cos(yaw) * cosPitch));
}
public static float ToRadians(float degrees)