fix(world): match retail portal passage and exit warp
This commit is contained in:
parent
eab23cbdd1
commit
842bd89c16
11 changed files with 355 additions and 28 deletions
98
src/AcDream.App/Rendering/TeleportViewPlaneController.cs
Normal file
98
src/AcDream.App/Rendering/TeleportViewPlaneController.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
using System.Numerics;
|
||||
using AcDream.Core.World;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Ports retail's teleport projection transition. <c>gmSmartBoxUI::UseTime</c>
|
||||
/// (<c>0x004D6E30</c>) eases SmartBox's view-plane distance between the
|
||||
/// active game's value and <c>TRANSITION_VIEW_PLANE_DISTANCE = 0.001</c>.
|
||||
/// <c>Render::set_vdst</c> (<c>0x0054B240</c>) converts that distance back to
|
||||
/// FOV and adjusts the near plane. This is the wide projection warp visible
|
||||
/// while the destination world emerges from black.
|
||||
/// </summary>
|
||||
public sealed class TeleportViewPlaneController
|
||||
{
|
||||
public const float TransitionViewPlaneDistance = 0.001f;
|
||||
|
||||
private float _gameViewPlaneDistance = 1f;
|
||||
|
||||
public bool Enabled { get; private set; }
|
||||
public float CurrentViewPlaneDistance { get; private set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>BeginTeleportAnimation</c> captures
|
||||
/// <c>SmartBox::GetOverrideFovDistance</c> once when starting from Off.
|
||||
/// For a standard perspective matrix, M22 is exactly
|
||||
/// <c>cot(verticalFov / 2)</c>, retail's view-plane-distance value.
|
||||
/// </summary>
|
||||
public void Begin(Matrix4x4 gameProjection)
|
||||
{
|
||||
float distance = gameProjection.M22;
|
||||
if (!float.IsFinite(distance) || distance <= 0f)
|
||||
distance = 1f;
|
||||
|
||||
_gameViewPlaneDistance = distance;
|
||||
CurrentViewPlaneDistance = distance;
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply the four retail fade-state branches. Their projection blend is
|
||||
/// numerically the same table-driven level as the black fade: normal to
|
||||
/// 0.001 on fade-out, and 0.001 back to normal on fade-in.
|
||||
/// </summary>
|
||||
public void Update(TeleportAnimSnapshot snapshot)
|
||||
{
|
||||
Enabled = snapshot.State is TeleportAnimState.WorldFadeOut
|
||||
or TeleportAnimState.TunnelFadeIn
|
||||
or TeleportAnimState.TunnelFadeOut
|
||||
or TeleportAnimState.WorldFadeIn;
|
||||
|
||||
CurrentViewPlaneDistance = Enabled
|
||||
? Lerp(_gameViewPlaneDistance, TransitionViewPlaneDistance, snapshot.FadeAlpha)
|
||||
: _gameViewPlaneDistance;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Enabled = false;
|
||||
CurrentViewPlaneDistance = _gameViewPlaneDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuild a perspective projection with retail's active view-plane
|
||||
/// distance while preserving the source projection's aspect and far
|
||||
/// plane. <c>Render::set_vdst</c> uses
|
||||
/// <c>FOV = 2 * atan(1 / distance)</c> and
|
||||
/// <c>znear = max(0.1, distance * 0.25)</c>.
|
||||
/// </summary>
|
||||
public Matrix4x4 Apply(Matrix4x4 baseProjection)
|
||||
{
|
||||
if (!Enabled)
|
||||
return baseProjection;
|
||||
|
||||
float aspect = baseProjection.M11 != 0f
|
||||
? baseProjection.M22 / baseProjection.M11
|
||||
: 1f;
|
||||
float far = baseProjection.M33 != -1f
|
||||
? baseProjection.M43 / (baseProjection.M33 + 1f)
|
||||
: 5000f;
|
||||
|
||||
if (!float.IsFinite(aspect) || aspect <= 0f)
|
||||
aspect = 1f;
|
||||
if (!float.IsFinite(far) || far <= 0.1f)
|
||||
far = 5000f;
|
||||
|
||||
float distance = MathF.Max(CurrentViewPlaneDistance, TransitionViewPlaneDistance);
|
||||
float fov = 2f * MathF.Atan(1f / distance);
|
||||
float near = MathF.Max(0.1f, distance * 0.25f);
|
||||
if (near >= far)
|
||||
near = MathF.Min(0.1f, far * 0.5f);
|
||||
|
||||
return Matrix4x4.CreatePerspectiveFieldOfView(fov, aspect, near, far);
|
||||
}
|
||||
|
||||
private static float Lerp(float from, float to, float amount) =>
|
||||
from + (to - from) * Math.Clamp(amount, 0f, 1f);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue