fix(render): harden portal exit handoff
Some checks failed
CI / linux-portable (push) Successful in 3m19s
CI / windows-gate (push) Failing after 6m43s
CI / release (push) Has been skipped

This commit is contained in:
Erik 2026-08-25 17:39:44 +02:00
parent ddbd7e4096
commit 82e4b4cb6d
17 changed files with 896 additions and 119 deletions

View file

@ -1,4 +1,7 @@
using System.Reflection;
using AcDream.App.Rendering;
using AcDream.App.Streaming;
using AcDream.App.Tests.Architecture;
using AcDream.App.UI;
using AcDream.Content;
using AcDream.Content.Vfx;
@ -12,6 +15,30 @@ namespace AcDream.App.Tests.Rendering;
public sealed class PortalTunnelAssetTests
{
[Fact]
public void PortalWorldHandoff_HidesTunnelBeforePublishingWorldFadeInProjection()
{
MethodInfo tick = typeof(LocalPlayerTeleportPresentation).GetMethod(
nameof(LocalPlayerTeleportPresentation.Tick),
BindingFlags.Instance | BindingFlags.Public)
?? throw new InvalidOperationException("Presentation Tick method missing.");
IReadOnlyList<CompiledCall> calls = CompiledCallGraph.Read(tick);
int hide = CompiledCallGraph.IndexOf(
calls,
typeof(PortalTunnelPresentation),
nameof(PortalTunnelPresentation.Exit));
int publish = CompiledCallGraph.IndexOf(
calls,
typeof(TeleportViewPlaneController),
nameof(TeleportViewPlaneController.Update));
Assert.True(hide >= 0, "Presentation Tick no longer retires portal space.");
Assert.True(publish >= 0, "Presentation Tick no longer publishes its view plane.");
Assert.True(
hide < publish,
"Portal space must retire before the WorldFadeIn projection is visible to rendering.");
}
/// <summary>
/// Campaign V slice V6m. The RHI arm cannot inherit a bound framebuffer, so
/// its pass re-establishes the colour the frame already cleared. That is
@ -189,7 +216,7 @@ public sealed class PortalTunnelAssetTests
TeleportViewPlaneController.TransitionViewPlaneDistance,
wideProjection.M22,
precision: 5);
Assert.Equal(0.1f, wideProjection.M43 / wideProjection.M33, precision: 5);
Assert.Equal(0.00025f, wideProjection.M43 / wideProjection.M33, precision: 7);
controller.Update(new TeleportAnimSnapshot(
TeleportAnimState.Off,
@ -201,6 +228,37 @@ public sealed class PortalTunnelAssetTests
Assert.Equal(baseProjection, controller.Apply(baseProjection));
}
[Fact]
public void TeleportViewPlane_TunnelKeepsRetailNearPlaneWhileWorldUsesCoverageNearPlane()
{
var baseProjection = System.Numerics.Matrix4x4.CreatePerspectiveFieldOfView(
MathF.PI / 3f,
16f / 9f,
0.1f,
5000f);
var controller = new TeleportViewPlaneController();
controller.Begin(baseProjection);
controller.Update(new TeleportAnimSnapshot(
TeleportAnimState.TunnelFadeOut,
ViewPlaneBlend: 1f,
ShowTunnel: true,
ShowPleaseWait: false));
System.Numerics.Matrix4x4 tunnelProjection = controller.Apply(baseProjection);
controller.Update(new TeleportAnimSnapshot(
TeleportAnimState.WorldFadeIn,
ViewPlaneBlend: 1f,
ShowTunnel: false,
ShowPleaseWait: false));
System.Numerics.Matrix4x4 worldProjection = controller.Apply(baseProjection);
Assert.Equal(0.1f, tunnelProjection.M43 / tunnelProjection.M33, precision: 5);
Assert.Equal(0.00025f, worldProjection.M43 / worldProjection.M33, precision: 7);
Assert.Equal(tunnelProjection.M11, worldProjection.M11);
Assert.Equal(tunnelProjection.M22, worldProjection.M22);
}
[Fact]
public void TeleportViewPlane_ApplyToSuppliesOverrideToEveryCameraConsumer()
{