feat(render): implement Campaign AR and terrain fidelity
This commit is contained in:
parent
99cf26e00c
commit
7a5f96ede5
368 changed files with 50611 additions and 950 deletions
|
|
@ -2,6 +2,7 @@ using System.Numerics;
|
|||
using System.Reflection;
|
||||
using AcDream.App.Composition;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Rendering.Packs;
|
||||
using AcDream.App.Rendering.Selection;
|
||||
using AcDream.App.Rendering.Vfx;
|
||||
using AcDream.App.Streaming;
|
||||
|
|
@ -15,6 +16,94 @@ namespace AcDream.App.Tests.Rendering;
|
|||
|
||||
public sealed class WorldSceneRendererTests
|
||||
{
|
||||
[Fact]
|
||||
public void EnhancedPreparation_BuildsCanonicalWorldOnceBeforeExecution()
|
||||
{
|
||||
var rig = new Rig(portalVisible: false, waitingForLogin: false, clipRoot: null);
|
||||
|
||||
PreparedWorldSceneFrame prepared = rig.Renderer.PrepareEnhanced(default);
|
||||
WorldRenderFrameOutcome result = rig.Renderer.RenderPreparedEnhanced(
|
||||
default,
|
||||
in prepared);
|
||||
|
||||
Assert.True(result.NormalWorldDrawn);
|
||||
Assert.True(prepared.ShouldRender);
|
||||
Assert.Equal(1, rig.Calls.Count(value => value == "frame:build"));
|
||||
Assert.True(rig.Calls.IndexOf("frame:build") < rig.Calls.IndexOf("selection:begin"));
|
||||
Assert.Equal(prepared.World.Camera.Frustum, rig.Selection.PreparedViewFrustum);
|
||||
Assert.Equal(rig.Entities.ResidentWindow, prepared.World.ResidentStreamingWindow);
|
||||
Assert.Equal((0, 0), rig.Entities.LastResidentWindowCenter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnhancedPreparation_AttachesTheSelectedAuthoredCelestialSource()
|
||||
{
|
||||
var rig = new Rig(portalVisible: false, waitingForLogin: false, clipRoot: null);
|
||||
rig.DayGroup.SkyObjects =
|
||||
[
|
||||
new SkyObjectData
|
||||
{
|
||||
GfxObjId = AuthoredCelestialShadowSourceResolver.SunGfxObjId,
|
||||
AuthoredSortCenter = Vector3.UnitX,
|
||||
BeginTime = 0f,
|
||||
EndTime = 0f,
|
||||
BeginAngle = 90f,
|
||||
EndAngle = 90f,
|
||||
},
|
||||
];
|
||||
|
||||
PreparedWorldSceneFrame prepared = rig.Renderer.PrepareEnhanced(default);
|
||||
|
||||
Assert.True(prepared.ShouldRender);
|
||||
Assert.Equal(
|
||||
AuthoredCelestialShadowSourceKind.Sun,
|
||||
prepared.World.CelestialShadowSource.Kind);
|
||||
Assert.Equal(0, prepared.World.CelestialShadowSource.ObjectIndex);
|
||||
Assert.Equal(
|
||||
AuthoredCelestialShadowSourceResolver.SunGfxObjId,
|
||||
prepared.World.CelestialShadowSource.GfxObjId);
|
||||
Assert.InRange(
|
||||
Vector3.Distance(
|
||||
Vector3.UnitZ,
|
||||
prepared.World.CelestialShadowSource.SurfaceToLightDirection),
|
||||
0f,
|
||||
1e-5f);
|
||||
|
||||
rig.Renderer.CancelPreparedEnhanced(in prepared);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnhancedPreparation_SkippedWorldStillPublishesEmptySelectionFrame()
|
||||
{
|
||||
var rig = new Rig(portalVisible: true, waitingForLogin: false, clipRoot: null);
|
||||
|
||||
PreparedWorldSceneFrame prepared = rig.Renderer.PrepareEnhanced(default);
|
||||
WorldRenderFrameOutcome result = rig.Renderer.RenderPreparedEnhanced(
|
||||
default,
|
||||
in prepared);
|
||||
|
||||
Assert.False(prepared.ShouldRender);
|
||||
Assert.Equal(default, result);
|
||||
Assert.Equal(["selection:begin", "selection:complete"], rig.Calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CancelledEnhancedPrepass_DoesNotPoisonTheNextFrame()
|
||||
{
|
||||
var rig = new Rig(portalVisible: false, waitingForLogin: false, clipRoot: null);
|
||||
PreparedWorldSceneFrame failed = rig.Renderer.PrepareEnhanced(default);
|
||||
|
||||
// Models an exception in the shadow prepass before a world pass opens.
|
||||
rig.Renderer.CancelPreparedEnhanced(in failed);
|
||||
PreparedWorldSceneFrame recovered = rig.Renderer.PrepareEnhanced(default);
|
||||
WorldRenderFrameOutcome result = rig.Renderer.RenderPreparedEnhanced(
|
||||
default,
|
||||
in recovered);
|
||||
|
||||
Assert.True(result.NormalWorldDrawn);
|
||||
Assert.Equal(2, rig.Calls.Count(value => value == "frame:build"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PortalViewport_PublishesEmptySelectionFrameAndSkipsWorldOwners()
|
||||
{
|
||||
|
|
@ -445,20 +534,21 @@ public sealed class WorldSceneRendererTests
|
|||
clipRoot,
|
||||
playerSeenOutside ?? clipRoot is not null);
|
||||
Frames = new FrameBuilder(Calls, frame);
|
||||
var selection = new SelectionFrame(Calls);
|
||||
Selection = new SelectionFrame(Calls);
|
||||
var alpha = new AlphaFrame(Calls);
|
||||
var visibility = new ParticleVisibility(Calls);
|
||||
PView = new PViewRenderer(Calls);
|
||||
Passes = new PassExecutor(Calls);
|
||||
var diagnostics = new Diagnostics(Calls);
|
||||
Entities = new EntitySource();
|
||||
|
||||
Renderer = new WorldSceneRenderer(
|
||||
foundation,
|
||||
login,
|
||||
sky,
|
||||
Frames,
|
||||
new EntitySource(),
|
||||
selection,
|
||||
Entities,
|
||||
Selection,
|
||||
alpha,
|
||||
visibility,
|
||||
PView,
|
||||
|
|
@ -479,6 +569,10 @@ public sealed class WorldSceneRendererTests
|
|||
|
||||
public FrameBuilder Frames { get; }
|
||||
|
||||
public EntitySource Entities { get; }
|
||||
|
||||
public SelectionFrame Selection { get; }
|
||||
|
||||
public PViewRenderer PView { get; }
|
||||
|
||||
public PassExecutor Passes { get; }
|
||||
|
|
@ -535,6 +629,16 @@ public sealed class WorldSceneRendererTests
|
|||
|
||||
private sealed class EntitySource : IWorldSceneEntitySource
|
||||
{
|
||||
public ResidentStreamingWindowFact ResidentWindow { get; } = new(
|
||||
Revision: 77,
|
||||
CenterX: 0,
|
||||
CenterY: 0,
|
||||
CompleteRadiusLandblocks: 2,
|
||||
PublishedLandblockCount: 25,
|
||||
HasPublishedCenter: true);
|
||||
|
||||
public (int X, int Y)? LastResidentWindowCenter { get; private set; }
|
||||
|
||||
public IReadOnlyList<(uint LandblockId, Vector3 AabbMin, Vector3 AabbMax,
|
||||
IReadOnlyList<WorldEntity> Entities,
|
||||
IReadOnlyDictionary<uint, WorldEntity>? AnimatedById)> LandblockEntries =>
|
||||
|
|
@ -543,11 +647,25 @@ public sealed class WorldSceneRendererTests
|
|||
|
||||
public IReadOnlyList<(uint LandblockId, Vector3 AabbMin, Vector3 AabbMax)> LandblockBounds =>
|
||||
Array.Empty<(uint, Vector3, Vector3)>();
|
||||
|
||||
public ResidentStreamingWindowFact CaptureResidentStreamingWindow(
|
||||
int centerX,
|
||||
int centerY)
|
||||
{
|
||||
LastResidentWindowCenter = (centerX, centerY);
|
||||
return ResidentWindow;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SelectionFrame(List<string> calls) : IWorldSceneSelectionFrame
|
||||
{
|
||||
public void BeginFrame() => calls.Add("selection:begin");
|
||||
public FrustumPlanes? PreparedViewFrustum { get; private set; }
|
||||
|
||||
public void BeginFrame(FrustumPlanes? preparedViewFrustum = null)
|
||||
{
|
||||
PreparedViewFrustum = preparedViewFrustum;
|
||||
calls.Add("selection:begin");
|
||||
}
|
||||
|
||||
public void CompleteFrame() => calls.Add("selection:complete");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue