fix(world): remove non-retail portal exit fade
This commit is contained in:
parent
842bd89c16
commit
dded9e6b17
21 changed files with 919 additions and 347 deletions
|
|
@ -8,14 +8,16 @@ namespace AcDream.App.Rendering;
|
|||
/// (<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.
|
||||
/// FOV and adjusts the near plane. At the exit edge retail swaps directly
|
||||
/// from portal space to the destination world at the transition projection;
|
||||
/// there is no black-alpha compositor between them.
|
||||
/// </summary>
|
||||
public sealed class TeleportViewPlaneController
|
||||
{
|
||||
public const float TransitionViewPlaneDistance = 0.001f;
|
||||
|
||||
private float _gameViewPlaneDistance = 1f;
|
||||
private readonly ProjectionOverrideCamera _projectionCamera = new();
|
||||
|
||||
public bool Enabled { get; private set; }
|
||||
public float CurrentViewPlaneDistance { get; private set; } = 1f;
|
||||
|
|
@ -38,20 +40,42 @@ public sealed class TeleportViewPlaneController
|
|||
}
|
||||
|
||||
/// <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.
|
||||
/// Apply retail's view-plane state machine. Here "fade" is retail's state
|
||||
/// name for a projection transition: normal to 0.001 on fade-out, and
|
||||
/// 0.001 back to normal on fade-in. A logout transition retains the
|
||||
/// captured override during stable Tunnel; <c>EndTeleportAnimation</c>
|
||||
/// (<c>0x004D65D5</c>) releases it when entering TunnelContinue.
|
||||
/// </summary>
|
||||
public void Update(TeleportAnimSnapshot snapshot)
|
||||
{
|
||||
Enabled = snapshot.State is TeleportAnimState.WorldFadeOut
|
||||
or TeleportAnimState.TunnelFadeIn
|
||||
or TeleportAnimState.TunnelFadeOut
|
||||
or TeleportAnimState.WorldFadeIn;
|
||||
switch (snapshot.State)
|
||||
{
|
||||
case TeleportAnimState.WorldFadeOut:
|
||||
case TeleportAnimState.TunnelFadeIn:
|
||||
case TeleportAnimState.TunnelFadeOut:
|
||||
case TeleportAnimState.WorldFadeIn:
|
||||
Enabled = true;
|
||||
CurrentViewPlaneDistance = Lerp(
|
||||
_gameViewPlaneDistance,
|
||||
TransitionViewPlaneDistance,
|
||||
snapshot.ViewPlaneBlend);
|
||||
break;
|
||||
|
||||
CurrentViewPlaneDistance = Enabled
|
||||
? Lerp(_gameViewPlaneDistance, TransitionViewPlaneDistance, snapshot.FadeAlpha)
|
||||
: _gameViewPlaneDistance;
|
||||
case TeleportAnimState.Tunnel:
|
||||
// Retail preserves the captured FOV override through the
|
||||
// logout path's stable tunnel. A normal portal begins in
|
||||
// Tunnel with no override, so its disabled state is retained.
|
||||
if (Enabled)
|
||||
CurrentViewPlaneDistance = _gameViewPlaneDistance;
|
||||
break;
|
||||
|
||||
case TeleportAnimState.TunnelContinue:
|
||||
case TeleportAnimState.Off:
|
||||
default:
|
||||
Enabled = false;
|
||||
CurrentViewPlaneDistance = _gameViewPlaneDistance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
|
@ -93,6 +117,39 @@ public sealed class TeleportViewPlaneController
|
|||
return Matrix4x4.CreatePerspectiveFieldOfView(fov, aspect, near, far);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decorate the active camera with the same projection returned by
|
||||
/// <see cref="Apply(Matrix4x4)"/>. Retail's <c>Render::set_vdst</c> is
|
||||
/// global to every 3-D draw; callers must pass this returned camera to
|
||||
/// terrain, meshes, particles, sky, weather, and portal-cell rendering so
|
||||
/// rasterization and frustum culling cannot use different projections.
|
||||
/// </summary>
|
||||
public ICamera ApplyTo(ICamera baseCamera)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(baseCamera);
|
||||
_projectionCamera.Update(baseCamera, Apply(baseCamera.Projection));
|
||||
return _projectionCamera;
|
||||
}
|
||||
|
||||
private static float Lerp(float from, float to, float amount) =>
|
||||
from + (to - from) * Math.Clamp(amount, 0f, 1f);
|
||||
|
||||
private sealed class ProjectionOverrideCamera : ICamera
|
||||
{
|
||||
private ICamera _source = null!;
|
||||
|
||||
public Matrix4x4 View => _source.View;
|
||||
public Matrix4x4 Projection { get; private set; } = Matrix4x4.Identity;
|
||||
public float Aspect
|
||||
{
|
||||
get => _source.Aspect;
|
||||
set => _source.Aspect = value;
|
||||
}
|
||||
|
||||
public void Update(ICamera source, Matrix4x4 projection)
|
||||
{
|
||||
_source = source;
|
||||
Projection = projection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue