feat(render) Campaign FW3.2a: the walk-to-draw population layer
The piece that turns walk-visited static content into draws, with no production frame wiring (FW3.2b roots the frame): - TryClassifyBatch: ONE shared per-batch classify core (the #426 untextured gate, #188 opacity promotion, texture resolve, foliage classification, in the exact original order) extracted from ClassifyBatches; the classic and packed classifiers now call it - behavior-identical, proven by the full hermetic + InstalledDat + Core Wb suites. - ClassifyEntityForWalk / WalkClassifiedBatch: the per-entity seam yielding per-batch keys + instance data WITHOUT InstanceGroup bucketing, plus the per-part selection data (picking stays alive on the walk path - the survey's unlisted-consumer fix). - WalkStaticStreamPopulator: per-entity walk-ordered opaque appends (under depth Less, opaque order is pixel-relevant only for coplanar surfaces, which retail resolves first-drawn-wins in ITS order - never material-grouped), translucent instances to the SAME RetailAlphaQueue via SubmitWalkAlphaInstance (identical viewer distances; walk-order submission improves retail's tie fidelity), selection parts published per entity. - SubmitOrderedStream now owns _orderedDrawCullModes, retiring the FW2-recorded alpha-scope interleaving constraint; DrawIndirectRangeRhi takes an optional cull array (all existing call sites unchanged). The referee test was verified to FAIL against the old shared-scratch behavior. - WalkDrawStage.OutdoorStatic added for the landscape turn. Suites: full Release build 0 warnings; Walk lane 195/1 skip; hermetic 6,747/0 (the two failures the implementation round reported were transient - both pass in isolation and in the full run). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b10ad662b0
commit
81c6531727
9 changed files with 1264 additions and 116 deletions
|
|
@ -598,6 +598,12 @@ public sealed partial class WbDrawDispatcher : IDisposable
|
|||
private BatchData[] _batchData = new BatchData[256];
|
||||
private DrawElementsIndirectCommand[] _indirectCommands = new DrawElementsIndirectCommand[256];
|
||||
private CullMode[] _drawCullModes = new CullMode[256];
|
||||
|
||||
// Campaign FW stage FW3.2a: SubmitOrderedStream's OWN cull-mode scratch,
|
||||
// separate from _drawCullModes above. See DrawIndirectRangeRhi's doc
|
||||
// comment for why sharing the array made an ordered submission unsafe to
|
||||
// interleave with a mid-flight RetailAlphaQueue scope.
|
||||
private CullMode[] _orderedDrawCullModes = new CullMode[256];
|
||||
private BatchDataPublic[] _batchPublicScratch = new BatchDataPublic[256];
|
||||
private readonly List<IndirectGroupInput> _groupInputScratch = new(256);
|
||||
private readonly List<GroupKey> _retiredGroupKeys = new();
|
||||
|
|
@ -3312,62 +3318,25 @@ public sealed partial class WbDrawDispatcher : IDisposable
|
|||
bool allTexturesReady = true;
|
||||
for (int batchIdx = 0; batchIdx < renderData.Batches.Count; batchIdx++)
|
||||
{
|
||||
var batch = renderData.Batches[batchIdx];
|
||||
|
||||
// #426: retail's D3DPolyRender::DrawMesh skips an UNTEXTURED
|
||||
// (solid-colour) subset only on a BUILDING SHELL
|
||||
// (RenderDeviceD3D::DrawBuilding sets ObjBuildingOrBuildingPart);
|
||||
// ordinary statics/scenery/creatures/items draw it same as any
|
||||
// textured subset. ONE shared predicate with ClassifyPackedBatches
|
||||
// and AddDirectionalShadowBatches — see RetailUntexturedSubsetPolicy.
|
||||
if (!RetailUntexturedSubsetPolicy.Draws(entity.IsBuildingShell, batch.Key.IsSolid))
|
||||
continue;
|
||||
|
||||
TranslucencyKind translucency = batch.Translucency;
|
||||
|
||||
// #188: a mid-fade instance whose surface is otherwise Opaque/ClipMap
|
||||
// must route through the alpha-blend pass so mesh_modern.frag's
|
||||
// (blend-enabled) shader actually composites the reduced alpha —
|
||||
// the no-blend opaque pass would ignore it.
|
||||
if (opacityMultiplier < 1.0f && IsOpaque(translucency))
|
||||
translucency = TranslucencyKind.AlphaBlend;
|
||||
|
||||
ResolvedTexture texture = ResolveTexture(
|
||||
in entity,
|
||||
meshRef,
|
||||
batch,
|
||||
paletteIdentity,
|
||||
out bool compositePending);
|
||||
// Campaign FW stage FW3.2a: the untextured-subset gate, the #188
|
||||
// opacity promotion, texture resolution, and Campaign VM foliage
|
||||
// classification now live in the one shared core
|
||||
// (WbDrawDispatcher.WalkClassify.cs) also used by
|
||||
// ClassifyPackedBatches and the walk classifier — see
|
||||
// TryClassifyBatch's doc comment. `survives=false` still applies
|
||||
// compositePending exactly as before this extraction (a batch
|
||||
// that fails the untextured-subset gate never touched
|
||||
// ResolveTexture, so compositePending is always false there; a
|
||||
// batch with an unresolved texture slot still reports it).
|
||||
bool survives = TryClassifyBatch(
|
||||
renderData, batchIdx, in entity, meshRef, paletteIdentity,
|
||||
opacityMultiplier, entityHasCutoutSubset,
|
||||
out GroupKey key, out bool compositePending);
|
||||
if (compositePending)
|
||||
allTexturesReady = false;
|
||||
// Campaign V slice V4t: an unassigned slot is the "no texture yet"
|
||||
// case a zero handle used to signal. It is a real sentinel
|
||||
// (GpuTextureSlot.Unassigned == ACDREAM_TEXTURE_NONE), not the
|
||||
// default value, so nothing here can silently resolve to slot 0.
|
||||
if (!texture.Slot.IsAssigned) continue;
|
||||
GpuTextureSlot texSlot = texture.Slot;
|
||||
uint texLayer = texture.Layer;
|
||||
|
||||
// Campaign VM VM6 review fix round: classify BEFORE constructing
|
||||
// the key and fold the result INTO the key (rather than
|
||||
// stamping it onto whatever group the key already resolves to).
|
||||
// Classification is from the RAW (pre-#188-promotion)
|
||||
// batch.Translucency — a mid-fade trunk is still a trunk, it
|
||||
// just landed in the alpha-blend group instead of opaque. This
|
||||
// is what keeps a scenery instance and a non-scenery instance
|
||||
// of the identical mesh subset in two SEPARATE groups instead of
|
||||
// coalescing into one group whose classification depends on
|
||||
// whichever entity classified it last.
|
||||
uint foliageFlags = FoliageWindClassification.Classify(
|
||||
entity.LocalEntityId,
|
||||
FoliageWindExclusions.Contains(meshRef.GfxObjId),
|
||||
batch.Translucency,
|
||||
entityHasCutoutSubset);
|
||||
var key = new GroupKey(
|
||||
batch.FirstIndex, (int)batch.BaseVertex,
|
||||
batch.IndexCount, texSlot, texLayer, translucency,
|
||||
FoliageFlags: foliageFlags,
|
||||
CullMode: batch.CullMode);
|
||||
if (!survives)
|
||||
continue;
|
||||
GpuTextureSlot texSlot = key.TextureSlot;
|
||||
|
||||
InstanceGroup grp = GetOrCreateInstanceGroup(key);
|
||||
grp.Matrices.Add(model);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue