diff --git a/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs b/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs index c6ac9e18..76778d58 100644 --- a/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs +++ b/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs @@ -19,16 +19,28 @@ namespace AcDream.App.Tests.Rendering.Walk; /// public sealed class WalkTraceReplayContext : IWalkFrameContext, IRetailFrameWalkContext { - private sealed class BasisRayCaster( - Vector3 right, Vector3 forward, Vector3 up, - float halfWidth, float halfHeight, float focal) : IWalkRayCaster + // Retail projection globals, dumped live from the capture client + // (recon 2026-08-30 evening: Render::bw/bh/xinvscale/yinvscale/tx/ty/vdst). + public const float RetailViewportWidth = 1024f; + public const float RetailViewportHeight = 720f; + public const float RetailXInvScale = 0.00025f; + public const float RetailYInvScale = 0.00025f; + public const float RetailTx = 0.127875f; + public const float RetailTy = 0.089875f; + public const float RetailVdst = 0.1330766976f; + + private sealed class RetailRayCaster( + Vector3 right, Vector3 forward, Vector3 up) : IWalkRayCaster { + // Retail's unproject (copy_view's ray path; equal to + // ScreenToViewTransform for these globals): + // u = sx·xinvscale − tx; w = sy·yinvscale − ty + // ray = Xaxis·u + Yaxis·vdst − Zaxis·w public Vector3 RayThrough(float screenX, float screenY) { - // Screen origin top-left, y down (the xformStart convention). - float nx = (screenX - halfWidth) / halfWidth; - float ny = (halfHeight - screenY) / halfHeight; - return right * (nx / focal) + forward + up * (ny / focal); + float u = screenX * RetailXInvScale - RetailTx; + float w = screenY * RetailYInvScale - RetailTy; + return right * u + forward * RetailVdst - up * w; } } @@ -36,10 +48,7 @@ public sealed class WalkTraceReplayContext : IWalkFrameContext, IRetailFrameWalk private readonly Matrix4x4 _viewProjection; private readonly IWalkRayCaster _rays; - public WalkTraceReplayContext( - WalkOraclePose pose, Dictionary cells, - float viewportWidth = 800f, float viewportHeight = 600f, - float verticalFovRadians = 1.0f) + public WalkTraceReplayContext(WalkOraclePose pose, Dictionary cells) { _cells = cells; WorldViewpoint = pose.Origin; @@ -48,16 +57,16 @@ public sealed class WalkTraceReplayContext : IWalkFrameContext, IRetailFrameWalk Vector3 up = Vector3.Transform(Vector3.UnitZ, rotation); Vector3 right = Vector3.Transform(Vector3.UnitX, rotation); + // The exact retail frustum: tan(halfFovY) = ty/vdst, aspect = tx/ty. + float fovY = 2f * MathF.Atan(RetailTy / RetailVdst); Matrix4x4 view = Matrix4x4.CreateLookAt(pose.Origin, pose.Origin + forward, up); Matrix4x4 projection = Matrix4x4.CreatePerspectiveFieldOfView( - verticalFovRadians, viewportWidth / viewportHeight, 0.1f, 5000f); + fovY, RetailTx / RetailTy, 0.1f, 5000f); _viewProjection = view * projection; - ViewportWidth = viewportWidth; - ViewportHeight = viewportHeight; - float focal = MathF.Tan(verticalFovRadians / 2f); - _rays = new BasisRayCaster( - right, forward, up, viewportWidth / 2f, viewportHeight / 2f, focal); + ViewportWidth = RetailViewportWidth; + ViewportHeight = RetailViewportHeight; + _rays = new RetailRayCaster(right, forward, up); // The retail CY near plane: N = forward, d = −dot(eye, forward) − znear. CyPlane = new WalkPlane(forward, -Vector3.Dot(pose.Origin, forward) - 0.1f); diff --git a/tools/walk-oracle/fw1-proj-recon.cdb b/tools/walk-oracle/fw1-proj-recon.cdb new file mode 100644 index 00000000..73812ce1 --- /dev/null +++ b/tools/walk-oracle/fw1-proj-recon.cdb @@ -0,0 +1,21 @@ +.logopen C:\Users\erikn\AppData\Local\Temp\claude\C--Users-erikn-source-repos-acdream--claude-worktrees-peaceful-blackburn-5333f0\e3dbd387-d947-4f49-964d-d454fc9c7d83\scratchpad\fw1-proj-recon.log +.sympath C:\Users\erikn\source\repos\acdream\refs +.symopt+ 0x40 +.reload /f acclient.exe +x acclient!Render::bw +x acclient!Render::bh +x acclient!Render::xinvscale +x acclient!Render::yinvscale +x acclient!Render::tx +x acclient!Render::ty +x acclient!Render::vdst +x acclient!Render::viewer_world_space +dd acclient!Render::bw L1 +dd acclient!Render::bh L1 +dd acclient!Render::xinvscale L1 +dd acclient!Render::yinvscale L1 +dd acclient!Render::tx L1 +dd acclient!Render::ty L1 +dd acclient!Render::vdst L1 +.logclose +qd