Retail's world-camera FOV is not a constant: the applied vertical FOV is m_fGameFOV / (viewportAspect - 0.1), recomputed on every aspect or game-FOV change (CreatureMode smartbox sites 0x00452b2f/0x00453b14), gated by Render::SetFOVRad's open (0, pi) acceptance (0x0054b2d0 - rejected results keep the previous FOV). m_fGameFOV defaults to pi/2 = 90 degrees (0x00454649) and is what the Field of View option sets in degrees (0x00451e6a; registered range [10,160] default 90 - gmClient::InitUIPreferences @0x004035b0). Net effect: the horizontal view stays ~85-90 degrees across aspect ratios; wide screens trim the vertical slice instead of ballooning the sides. acdream hardcoded FovY = pi/3 = 60 degrees on all four world cameras, aspect-independent, and the Config slider wrote raw vertical-FOV degrees. New: RetailFieldOfView (the law + gate, decomp-cited), CameraController.GameFovRadians + SetGameFov + one ApplyProjection chokepoint recomputing every camera on SetAspect/SetGameFov/ EnterChaseMode/RestoreState; ApplyFieldOfView now feeds the law; DisplaySettings.Default.FieldOfView 60 -> 90 (the retail registered default; the stored number changed MEANING with this commit). The same seam closes a second latent bug the 2026-08-13 "squished" gate report exposed: SetAspect only ever updated Orbit/Fly - the CHASE cameras (the ones the player looks through) kept their creation-time aspect across every mid-session resize, drawing the world at the old shape stretched onto the new viewport. The paperdoll camera stays outside the law by design (retail portrait mode is UseSharpMode, not smartbox - DollCamera's own doc). Tests: RetailFieldOfViewTests (golden law values at 4:3/16:9/21:9, the constant-horizontal property, the rejection gate, controller propagation incl. chase attach/restore + rejected-law aspect-still-propagates); DisplaySettingsTests + RuntimeSettingsControllerTests updated to the new semantics. App suite 4,953/3 skips; UI.Abstractions 916/0. AD-89 retired in this commit; user settings.json migrated 60->90 by hand (stale pre-port default). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
30 lines
1.1 KiB
C#
30 lines
1.1 KiB
C#
using System.Numerics;
|
|
|
|
namespace AcDream.App.Rendering;
|
|
|
|
public sealed class OrbitCamera : ICamera
|
|
{
|
|
public Vector3 Target { get; set; } = new(96, 96, 0); // center of a 192x192 landblock
|
|
public float Distance { get; set; } = 300f;
|
|
public float Yaw { get; set; } = MathF.PI / 4f;
|
|
public float Pitch { get; set; } = MathF.PI / 6f;
|
|
// #389: smartbox law at the 16:9 default aspect — see RetailFieldOfView.
|
|
public float FovY { get; set; } = RetailFieldOfView.DefaultAppliedFovY;
|
|
public float Aspect { get; set; } = 16f / 9f;
|
|
|
|
public Matrix4x4 View
|
|
{
|
|
get
|
|
{
|
|
var eye = Target + new Vector3(
|
|
Distance * MathF.Cos(Pitch) * MathF.Cos(Yaw),
|
|
Distance * MathF.Cos(Pitch) * MathF.Sin(Yaw),
|
|
Distance * MathF.Sin(Pitch));
|
|
return Matrix4x4.CreateLookAt(eye, Target, Vector3.UnitZ);
|
|
}
|
|
}
|
|
|
|
// Near plane 0.1 m = retail Render::znear (see RetailChaseCamera.Projection).
|
|
public Matrix4x4 Projection
|
|
=> Matrix4x4.CreatePerspectiveFieldOfView(FovY, Aspect, 0.1f, 5000f);
|
|
}
|