using UnityEngine; namespace Luneraria.View { /// /// The game camera of the reference (scripts/luneraria/view/lune_camera.gd): a perspective /// three-quarter view whose angle steepens as it zooms out. `zoom` is the visible ground height /// at the focus; yaw 0 shows Blau's base bottom-left and Rot's top-right, as in Godot. /// Positions are computed in Godot's frame and converted, so the picture matches Godot's. /// public static class LuneCameraMath { public const float FieldOfView = 34f; public const float MinZoom = 11f; public const float MaxZoom = 100f; public const float DefaultZoom = 34f; public const float OverviewZoom = 92f; public const float PitchNear = -48f; public const float PitchFar = -70f; public const float FocusLimit = 42f; public static float PitchFor(float zoom) { return Mathf.Lerp(PitchNear, PitchFar, SmoothStep(14f, MaxZoom, zoom)) * Mathf.Deg2Rad; } public static float DistanceFor(float zoom) { return zoom / (2f * Mathf.Tan(FieldOfView * .5f * Mathf.Deg2Rad)); } /// Camera position and rotation for a Unity focus point, zoom and Godot yaw (radians). public static void Pose(Vector3 focus, float zoom, float yaw, out Vector3 position, out Quaternion rotation) { float pitch = PitchFor(zoom); // Godot: Vector3(0, 0, 1).rotated(RIGHT, pitch).rotated(UP, yaw). var back = new Vector3(0f, -Mathf.Sin(pitch), Mathf.Cos(pitch)); back = new Vector3(back.x * Mathf.Cos(yaw) + back.z * Mathf.Sin(yaw), back.y, -back.x * Mathf.Sin(yaw) + back.z * Mathf.Cos(yaw)); Vector3 godotFocus = LuneSpace.FromGodot(focus); Vector3 godotPosition = godotFocus + back * DistanceFor(zoom); position = LuneSpace.FromGodot(godotPosition); rotation = Quaternion.LookRotation(focus - position, Vector3.up); } static float SmoothStep(float from, float to, float value) { float t = Mathf.Clamp01((value - from) / (to - from)); return t * t * (3f - 2f * t); } } }