using System; using System.Numerics; namespace AcDream.App.Rendering; /// /// Fixed camera for the paperdoll mini-scene — retail-exact, ported from the gmPaperDollUI viewport /// setup (decomp 0x004a5a39–0x004a5a69). The viewport (element 0x100001d5) is configured by /// UIElement_Viewport::SetCamera(position, direction) with: /// /// position = (0.12, −2.4, 0.88) [hex 0x3df5c28f, 0xc019999a, 0x3f6147ae] /// direction = (0, 0, 0) ⇒ CreatureMode::SetCameraDirection resets the view frame to /// IDENTITY (euler_set_rotate(0,0,0) then rotate(0,0,0)), so the camera looks /// straight down +Y with +Z up — NO yaw, NO pitch. /// /// The doll is framed purely by camera POSITION + FOV, NOT by aiming at the body: at distance 2.4 with /// a π/4 (45°) vertical FOV the visible vertical band is z≈[−0.11, 1.87], which covers the whole ~1.6 m /// figure even though the model origin sits at the FEET (z=0). FOV π/4 is CreatureMode's default /// m_fFOVRadians (ctor 0x004543cf, hex 0x3f490fdb); default ambient is (0.3,0.3,0.3); the /// paperdoll uses UseSharpMode (not SmartboxFOV) so Render::SetFOVRad(m_fFOVRadians) applies. /// /// An earlier hand-tune aimed the camera at mid-body to "fit the figure", which introduced a /// spurious yaw (Target.x ≠ Eye.x) that rotated the view and turned the doll's face away from the /// viewer. This restores retail's zero-yaw frame, where full-body framing comes from the eye height + /// FOV, not from aiming. /// /// Uses the same / /// convention as so the doll's triangle winding + back-face culling match the /// world render pass. AC up-axis = +Z. /// public sealed class DollCamera : ICamera { // Retail paperdoll camera origin (decomp 0x004a5a51–0x004a5a61). private static readonly Vector3 Eye = new(0.12f, -2.4f, 0.88f); // Identity view orientation ⇒ look straight down +Y (no yaw/pitch). Target = Eye + (0,1,0). private static readonly Vector3 Target = new(0.12f, -1.4f, 0.88f); private static readonly Vector3 Up = Vector3.UnitZ; // AC up-axis = +Z, same as ChaseCamera /// Vertical field of view — retail CreatureMode default m_fFOVRadians = π/4 (45°). public float FovRadians { get; set; } = MathF.PI / 4f; public float Near { get; set; } = 0.1f; // same near plane as ChaseCamera / retail znear public float Far { get; set; } = 50f; // doll scene is small; 50 m is ample public float Aspect { get; set; } = 1f; /// public Matrix4x4 View => Matrix4x4.CreateLookAt(Eye, Target, Up); /// public Matrix4x4 Projection => Matrix4x4.CreatePerspectiveFieldOfView(FovRadians, Aspect <= 0f ? 1f : Aspect, Near, Far); }