mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2026-08-15 15:07:48 +04:00
112 lines
2.9 KiB
C#
112 lines
2.9 KiB
C#
using System.Numerics;
|
|
|
|
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()
|
|
{
|
|
// 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(GetEyePosition(), Target, Vector3.UnitY);
|
|
}
|
|
|
|
public Matrix4x4 GetProjectionMatrix(float aspectRatio)
|
|
{
|
|
return Matrix4x4.CreatePerspectiveFieldOfView(
|
|
ToRadians(FieldOfViewDegrees),
|
|
aspectRatio,
|
|
0.01f,
|
|
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)
|
|
{
|
|
return degrees * MathF.PI / 180.0f;
|
|
}
|
|
}
|