fix #451: stabilize portal seam rendering
This commit is contained in:
parent
f6fe0f2a4f
commit
1d2f2f738f
29 changed files with 1650 additions and 239 deletions
|
|
@ -23,6 +23,7 @@ public sealed class RetailPViewPassExecutorTests
|
|||
[
|
||||
"begin",
|
||||
"assemble",
|
||||
"append-look-in-clips",
|
||||
"prepare-clip:3",
|
||||
"indoor-routing",
|
||||
"prepare-cells",
|
||||
|
|
@ -33,6 +34,7 @@ public sealed class RetailPViewPassExecutorTests
|
|||
"terrain-clip",
|
||||
"clear-routing",
|
||||
"landscape-late",
|
||||
"unattached-particles",
|
||||
"landscape-alpha",
|
||||
"indoor-routing",
|
||||
"indoor-routing",
|
||||
|
|
@ -272,6 +274,88 @@ public sealed class RetailPViewPassExecutorTests
|
|||
executor);
|
||||
|
||||
Assert.Contains("look-in-punch", executor.Operations);
|
||||
AssertAppearsInOrder(
|
||||
string.Join('|', executor.Operations),
|
||||
"landscape-early",
|
||||
"unattached-particles",
|
||||
"landscape-static-particles",
|
||||
"landscape-alpha",
|
||||
"look-in-punch",
|
||||
"landscape-late",
|
||||
"landscape-alpha",
|
||||
"interior-depth-clear");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DrawInside_repaints_the_exterior_building_shell_after_its_look_in()
|
||||
{
|
||||
var renderer = new RetailPViewRenderer();
|
||||
using var executor = new RecordingExecutor();
|
||||
LoadedCell root = InteriorWithExit(0xA9B40100u);
|
||||
root.BuildingId = 1u;
|
||||
LoadedCell[] building = NearbyTwoCellBuilding();
|
||||
WorldEntity exteriorShell = Entity(
|
||||
0x700u,
|
||||
isBuildingShell: true,
|
||||
buildingShellAnchorCellId: building[0].CellId);
|
||||
|
||||
renderer.DrawInside(
|
||||
Frame(
|
||||
root,
|
||||
[exteriorShell],
|
||||
nearbyBuildingCells: building,
|
||||
additionalCells: building),
|
||||
executor);
|
||||
|
||||
AssertAppearsInOrder(
|
||||
string.Join('|', executor.Operations),
|
||||
"landscape-early",
|
||||
"look-in-punch",
|
||||
"landscape-building-shell",
|
||||
"landscape-late");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DrawInside_pairs_each_look_in_with_only_its_own_shell_and_alpha_barrier()
|
||||
{
|
||||
var renderer = new RetailPViewRenderer();
|
||||
using var executor = new RecordingExecutor();
|
||||
LoadedCell root = InteriorWithExit(0xA9B40100u);
|
||||
root.BuildingId = 1u;
|
||||
LoadedCell[] first = NearbyTwoCellBuilding();
|
||||
LoadedCell[] second = NearbyTwoCellBuilding(
|
||||
0xA9B40172u,
|
||||
0xA9B40173u,
|
||||
buildingId: 3u);
|
||||
LoadedCell[] buildings = [.. first, .. second];
|
||||
WorldEntity[] shells =
|
||||
[
|
||||
Entity(
|
||||
0x700u,
|
||||
isBuildingShell: true,
|
||||
buildingShellAnchorCellId: first[0].CellId),
|
||||
Entity(
|
||||
0x701u,
|
||||
isBuildingShell: true,
|
||||
buildingShellAnchorCellId: second[0].CellId),
|
||||
];
|
||||
|
||||
renderer.DrawInside(
|
||||
Frame(
|
||||
root,
|
||||
shells,
|
||||
nearbyBuildingCells: buildings,
|
||||
additionalCells: buildings),
|
||||
executor);
|
||||
|
||||
AssertAppearsInOrder(
|
||||
string.Join('|', executor.Operations),
|
||||
"look-in-punch",
|
||||
"landscape-building-shell",
|
||||
"landscape-static-particles",
|
||||
"landscape-alpha",
|
||||
"look-in-punch",
|
||||
"landscape-building-shell");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -429,20 +513,21 @@ public sealed class RetailPViewPassExecutorTests
|
|||
return cell;
|
||||
}
|
||||
|
||||
private static LoadedCell[] NearbyTwoCellBuilding()
|
||||
private static LoadedCell[] NearbyTwoCellBuilding(
|
||||
uint vestibuleId = 0xA9B40170u,
|
||||
uint roomId = 0xA9B40171u,
|
||||
uint buildingId = 2u)
|
||||
{
|
||||
const uint vestibuleId = 0xA9B40170u;
|
||||
const uint roomId = 0xA9B40171u;
|
||||
var vestibule = new LoadedCell
|
||||
{
|
||||
CellId = vestibuleId,
|
||||
BuildingId = 2u,
|
||||
BuildingId = buildingId,
|
||||
WorldTransform = Matrix4x4.Identity,
|
||||
InverseWorldTransform = Matrix4x4.Identity,
|
||||
Portals =
|
||||
[
|
||||
new CellPortalInfo(0xFFFF, 0, 0, 0),
|
||||
new CellPortalInfo(0x0171, 1, 0, 0),
|
||||
new CellPortalInfo((ushort)(roomId & 0xFFFFu), 1, 0, 0),
|
||||
],
|
||||
ClipPlanes =
|
||||
[
|
||||
|
|
@ -472,10 +557,17 @@ public sealed class RetailPViewPassExecutorTests
|
|||
var room = new LoadedCell
|
||||
{
|
||||
CellId = roomId,
|
||||
BuildingId = 2u,
|
||||
BuildingId = buildingId,
|
||||
WorldTransform = Matrix4x4.Identity,
|
||||
InverseWorldTransform = Matrix4x4.Identity,
|
||||
Portals = [new CellPortalInfo(0x0170, 0, 0, 1)],
|
||||
Portals =
|
||||
[
|
||||
new CellPortalInfo(
|
||||
(ushort)(vestibuleId & 0xFFFFu),
|
||||
0,
|
||||
0,
|
||||
1),
|
||||
],
|
||||
};
|
||||
room.PortalPolygons.Add(
|
||||
[
|
||||
|
|
@ -490,7 +582,9 @@ public sealed class RetailPViewPassExecutorTests
|
|||
private static WorldEntity Entity(
|
||||
uint id,
|
||||
uint serverGuid = 0,
|
||||
uint? parentCellId = null) => new()
|
||||
uint? parentCellId = null,
|
||||
bool isBuildingShell = false,
|
||||
uint? buildingShellAnchorCellId = null) => new()
|
||||
{
|
||||
Id = id,
|
||||
ServerGuid = serverGuid,
|
||||
|
|
@ -499,6 +593,8 @@ public sealed class RetailPViewPassExecutorTests
|
|||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = [new MeshRef(1u, Matrix4x4.Identity)],
|
||||
ParentCellId = parentCellId,
|
||||
IsBuildingShell = isBuildingShell,
|
||||
BuildingShellAnchorCellId = buildingShellAnchorCellId,
|
||||
};
|
||||
|
||||
private static void AssertAppearsInOrder(string source, params string[] needles)
|
||||
|
|
@ -566,6 +662,17 @@ public sealed class RetailPViewPassExecutorTests
|
|||
return ClipFrameAssembler.Assemble(_clipFrame, portalFrame, reuseAssembly);
|
||||
}
|
||||
|
||||
public void AppendLookInClipFrames(
|
||||
IReadOnlyList<PortalVisibilityFrame> lookInFrames,
|
||||
ClipFrameAssembly assembly)
|
||||
{
|
||||
Operations.Add("append-look-in-clips");
|
||||
ClipFrameAssembler.AppendLookInFrames(
|
||||
_clipFrame,
|
||||
lookInFrames,
|
||||
assembly);
|
||||
}
|
||||
|
||||
public void PrepareClipFrame(int terrainUploadCount) =>
|
||||
Operations.Add($"prepare-clip:{terrainUploadCount}");
|
||||
|
||||
|
|
@ -574,6 +681,8 @@ public sealed class RetailPViewPassExecutorTests
|
|||
|
||||
public void ClearClipRouting() => Operations.Add("clear-routing");
|
||||
public void UseIndoorMembershipOnlyRouting() => Operations.Add("indoor-routing");
|
||||
public void UseCellPortalViewRouting(uint cellId, ClipViewSlice slice) =>
|
||||
Operations.Add($"cell-portal-routing:{cellId:X8}:{slice.Slot}");
|
||||
public void PrepareCellBatches(RetailPViewFrameInput frame, HashSet<uint> visibleCellIds) =>
|
||||
Operations.Add("prepare-cells");
|
||||
public void DrawOpaqueCellShells(HashSet<uint> cellIds) => Operations.Add("opaque-shells");
|
||||
|
|
@ -624,10 +733,37 @@ public sealed class RetailPViewPassExecutorTests
|
|||
request.TupleLandblockId);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLandscapeStaticParticles(
|
||||
RetailPViewFrameInput frame,
|
||||
RetailPViewLandscapeStaticParticleContext context) =>
|
||||
Operations.Add("landscape-static-particles");
|
||||
public void DrawLandscapeBuildingShellSlice(
|
||||
RetailPViewFrameInput frame,
|
||||
RetailPViewLandscapeBuildingShellSliceContext context)
|
||||
{
|
||||
Operations.Add("landscape-building-shell");
|
||||
if (context.EntityDraw is RenderFrameEntityDrawRequest request)
|
||||
{
|
||||
RenderFrameView view = request.View;
|
||||
DrawEntityRoute(
|
||||
frame.Camera,
|
||||
in view,
|
||||
request.Route,
|
||||
request.RouteIndex,
|
||||
request.CellId,
|
||||
request.TupleLandblockId);
|
||||
}
|
||||
}
|
||||
public void ClearInteriorDepth() => Operations.Add("interior-depth-clear");
|
||||
public void DrawExitPortalMask(RetailPViewFrameInput frame, RetailPViewCellSliceContext context) => Operations.Add("exit-mask");
|
||||
public void DrawLookInPortalPunch(RetailPViewFrameInput frame, RetailPViewCellSliceContext context) => Operations.Add("look-in-punch");
|
||||
public void DrawUnattachedSceneParticles(RetailPViewFrameInput frame) => Operations.Add("unattached-particles");
|
||||
public void DrawLookInPortalPunch(
|
||||
RetailPViewFrameInput frame,
|
||||
RetailPViewCellSliceContext context,
|
||||
int portalIndex) => Operations.Add("look-in-punch");
|
||||
public void DrawUnattachedSceneParticles(
|
||||
RetailPViewFrameInput frame,
|
||||
ClipViewSlice slice) => Operations.Add("unattached-particles");
|
||||
public void FlushLandscapeAlpha() => Operations.Add("landscape-alpha");
|
||||
public void DrawCellParticles(RetailPViewFrameInput frame, RetailPViewCellSliceContext context) => Operations.Add("cell-particles");
|
||||
public void DrawDynamicsParticles(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue