using OpenTK.Mathematics; namespace VoxelEngine.Rendering; public sealed class Camera { private static readonly Vector3 WorldUp = Vector3.UnitY; public Vector3 Position { get; private set; } public float Yaw { get; private set; } = -90f; // degrees; -90 looks down -Z public float Pitch { get; private set; } = 0f; // degrees public float Fov { get; set; } = 60f; // degrees public float AspectRatio { get; set; } public Vector3 Front { get; private set; } = -Vector3.UnitZ; public Vector3 Right { get; private set; } = Vector3.UnitX; public Vector3 Up { get; private set; } = Vector3.UnitY; public Camera(Vector3 position, float aspectRatio) { Position = position; AspectRatio = aspectRatio; UpdateVectors(); } public void Move(Vector3 delta) => Position += delta; public void AddRotation(float yawDelta, float pitchDelta) { Yaw += yawDelta; Pitch = MathHelper.Clamp(Pitch + pitchDelta, -89f, 89f); UpdateVectors(); } public Matrix4 GetViewMatrix() => Matrix4.LookAt(Position, Position + Front, Up); public Matrix4 GetProjectionMatrix() => Matrix4.CreatePerspectiveFieldOfView( MathHelper.DegreesToRadians(Fov), AspectRatio, 0.1f, 100f); private void UpdateVectors() { float yaw = MathHelper.DegreesToRadians(Yaw); float pitch = MathHelper.DegreesToRadians(Pitch); Front = Vector3.Normalize(new Vector3( MathF.Cos(yaw) * MathF.Cos(pitch), MathF.Sin(pitch), MathF.Sin(yaw) * MathF.Cos(pitch))); Right = Vector3.Normalize(Vector3.Cross(Front, WorldUp)); Up = Vector3.Normalize(Vector3.Cross(Right, Front)); } }