checkpoint(render): preserve pre-overhaul investigation state
This commit is contained in:
parent
e880860291
commit
b3b7d922f1
45 changed files with 3168 additions and 619 deletions
|
|
@ -189,11 +189,11 @@ public sealed class LightManager
|
|||
/// (2) frame-FLOOD scoping `c500912b` (gaze-dependent: the under-room portal
|
||||
/// purples entered/left the pool as the camera turned — the seam-floor
|
||||
/// blink; probe: [seam-blk]/[seam-snap]). Current model: all registered
|
||||
/// (=resident) lit lights optionally FILTERED by last frame's rendered
|
||||
/// visible-cell set (A7.L1, 2026-07-09 — <see cref="BuildPointLightSnapshot"/>'s
|
||||
/// <c>visibleCells</c> param; fixes Town Network starvation without
|
||||
/// reproducing c500912b — see that method's doc), then dynamics-first nearest-
|
||||
/// player, capped here. 128 is wider than retail's 40+7 — a documented backstop
|
||||
/// (=resident) lit lights, then dynamics-first nearest-player, capped here.
|
||||
/// A later last-frame drawable-cell filter was removed after the Facility Hub
|
||||
/// zoom trace proved it recreated the same camera-root coupling: the pool
|
||||
/// collapsed from five lights to one without the player moving. 128 is wider
|
||||
/// than retail's 40+7 — a documented backstop
|
||||
/// that in a properly cell-scoped room only ever evicts far-out-of-range
|
||||
/// statics; adopting retail's exact dual-pool caps + degrade levels is A7-arc
|
||||
/// work. The 1024 uncap remains refuted (striped-floor artifact + the unported
|
||||
|
|
@ -248,39 +248,16 @@ public sealed class LightManager
|
|||
/// set from <c>player->m_position</c>, SmartBox 0x00453d3a, with the
|
||||
/// viewer-cell fallback 0x00455ab6). The distance SORT is therefore a function
|
||||
/// of PLAYER position and light registration ONLY — camera rotation/position
|
||||
/// cannot change it (both prior camera-ANCHORED pools — nearest-camera cap;
|
||||
/// <c>c500912b</c>'s camera-seeded re-flood — produced the #176 seam-floor
|
||||
/// purple blink by making the SORT itself camera-dependent). The optional
|
||||
/// <paramref name="visibleCells"/> candidacy FILTER (A7.L1) does not change
|
||||
/// this: it narrows the input set before the player-anchored sort runs, using
|
||||
/// a value the caller captured from last frame's already-rendered draw list,
|
||||
/// not a fresh camera-seeded computation performed here. Call once per frame
|
||||
/// before per-object selection.
|
||||
/// cannot change it. Both camera-anchored pools and last-frame drawable-cell
|
||||
/// scoping produced gaze/zoom-dependent membership changes, so neither is an
|
||||
/// input to this retail resident-cell collection. Call once per frame before
|
||||
/// per-object selection.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="playerWorldPos">The player's world position (render position;
|
||||
/// callers pass the camera position only when no player exists — retail's
|
||||
/// player/viewer branch).</param>
|
||||
/// <param name="visibleCells">
|
||||
/// A7.L1 (2026-07-09) — optional visible-cell scoping. When non-null, a light
|
||||
/// is a candidate only if it is cell-less (<c>CellId == 0</c> — the viewer fill,
|
||||
/// always in scope) or its <c>CellId</c> is in this set. Fixes the Town Network
|
||||
/// starvation case (463 registered fixtures): the player-nearest cap sorts by
|
||||
/// raw Euclidean distance, which is not a reliable proxy for "same room" in a
|
||||
/// dense, maze-like hub — a fixture on the other side of a wall can be
|
||||
/// geometrically closer than the player's own room's torches and win the cap,
|
||||
/// leaving the visible room dark. Scoping candidacy to the frame's actual
|
||||
/// visible cells (the render already computes this — callers pass last frame's
|
||||
/// retail-walk visited-cell set, one frame of latency, to avoid re-threading
|
||||
/// a mid-render callback) removes
|
||||
/// non-visible cells from contention before the
|
||||
/// cap ever applies. The distance-sort anchor stays the PLAYER either way — this
|
||||
/// parameter only narrows candidacy, it does not change the sort (the #176
|
||||
/// correction: CAMERA anchoring, not cell scoping itself, caused the earlier
|
||||
/// seam-floor flicker regression, c500912b). Null (the default) preserves the
|
||||
/// legacy unscoped behavior — outdoor / no-clipRoot callers pass null.
|
||||
/// </param>
|
||||
public void BuildPointLightSnapshot(Vector3 playerWorldPos, IReadOnlySet<uint>? visibleCells = null)
|
||||
public void BuildPointLightSnapshot(Vector3 playerWorldPos)
|
||||
{
|
||||
_pointSnapshot.Clear();
|
||||
_pointSelectionHeap.Clear();
|
||||
|
|
@ -291,8 +268,6 @@ public sealed class LightManager
|
|||
foreach (var light in _all)
|
||||
{
|
||||
if (!light.IsLit || light.Kind == LightKind.Directional) continue;
|
||||
if (visibleCells is not null && light.CellId != 0 && !visibleCells.Contains(light.CellId)) continue;
|
||||
|
||||
var ranked = new RankedLight(
|
||||
light,
|
||||
qualifyingOrdinal++,
|
||||
|
|
|
|||
|
|
@ -1002,11 +1002,6 @@ public static class CellTransit
|
|||
/// docs/research/2026-08-07-ap159-pseudocode.md for the derivation.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="worldParts">Per-part world-placed authored boxes — the
|
||||
/// outdoor extent walk's input.</param>
|
||||
/// <param name="worldPartSpheres">Per-part world-placed BSP root spheres —
|
||||
/// the indoor residual's and the building bridge's input. Same parts, same
|
||||
/// order, from the same <see cref="ShadowPartGeometry"/> values.</param>
|
||||
public static IReadOnlyList<uint> BuildShadowCellSetFromParts(
|
||||
PhysicsDataCache cache,
|
||||
uint seedCellId,
|
||||
|
|
@ -1107,27 +1102,17 @@ public static class CellTransit
|
|||
}
|
||||
}
|
||||
|
||||
// Static prune (do_not_load_cells, 0x0052b66e) — indoor-seeded ONLY.
|
||||
// The outdoor rectangle is deliberately unpruned: pruning it would
|
||||
// re-create #334 in a new form.
|
||||
if (isStatic && seedLow >= 0x0100u)
|
||||
{
|
||||
var seedCell = cache.GetCellStruct(seedCellId);
|
||||
if (seedCell is not null)
|
||||
{
|
||||
var keep = new List<uint>(candidates.Count);
|
||||
foreach (uint id in candidates.OrderedIds)
|
||||
{
|
||||
if (id == seedCellId || seedCell.VisibleCellIds.Contains(id))
|
||||
keep.Add(id);
|
||||
}
|
||||
if (keep.Count != candidates.Count)
|
||||
{
|
||||
candidates.Clear();
|
||||
foreach (uint id in keep) candidates.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do NOT apply CObjCell::find_cell_list's do_not_load_cells prune
|
||||
// (0x0052b66e) here. That code belongs to the sphere/cylsphere entry
|
||||
// point at 0x0052b4e0. The part-array route used here is retail
|
||||
// CPhysicsObj::find_bbox_cell_list @0x00510fc0: it walks the growing
|
||||
// CELLARRAY through CPartArray::calc_cross_cells_static and returns
|
||||
// it directly. calc_cross_cells_static does set do_not_load_cells=1,
|
||||
// but the box transit consumes that only as a no-load policy while
|
||||
// resolving neighbouring cells; it does not delete the already-added
|
||||
// exterior cells. Pruning here removed a static Setup's legitimate
|
||||
// outdoor shadow membership after an exit portal crossing (the
|
||||
// cathedral ramp 0x020009A2: collision remained, render vanished).
|
||||
|
||||
return candidates.OrderedIds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -360,6 +360,39 @@ public sealed class ShadowObjectRegistry
|
|||
private PhysicsDataCache? _fallback;
|
||||
private PhysicsDataCache FloodCache => DataCache ?? _fallbackCache;
|
||||
|
||||
/// <summary>
|
||||
/// Computes retail's static PartArray render-cell membership without
|
||||
/// publishing collision rows. Static visual parts and collision shapes
|
||||
/// share the same <c>find_bbox_cell_list</c> portal walk, but retail keeps
|
||||
/// them in separate cell lists (<c>shadow_part_list</c> versus
|
||||
/// <c>shadow_object_list</c>). Decorative meshes therefore need this path
|
||||
/// even when <see cref="GetOwnerCells"/> is empty.
|
||||
/// </summary>
|
||||
public IReadOnlyList<uint> ComputeStaticRenderCells(
|
||||
uint seedCellId,
|
||||
Vector3 entityWorldPosition,
|
||||
Quaternion entityWorldRotation,
|
||||
IReadOnlyList<ShadowShape> visualParts)
|
||||
{
|
||||
if (seedCellId == 0u || visualParts.Count == 0)
|
||||
return Array.Empty<uint>();
|
||||
|
||||
List<ShadowPartBox> boxes = BuildFloodPartBoxes(
|
||||
entityWorldPosition,
|
||||
entityWorldRotation,
|
||||
visualParts);
|
||||
List<DatReaderWriter.Types.Sphere> spheres = BuildBspPartSpheres(
|
||||
entityWorldPosition,
|
||||
entityWorldRotation,
|
||||
visualParts);
|
||||
return CellTransit.BuildShadowCellSetFromParts(
|
||||
FloodCache,
|
||||
seedCellId,
|
||||
boxes,
|
||||
spheres,
|
||||
isStatic: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a single-shape entity. <paramref name="seedCellId"/> is the
|
||||
/// entity's <c>m_position.objcell_id</c> — the flood seed. Pass 0 to
|
||||
|
|
|
|||
|
|
@ -342,6 +342,93 @@ public static class ShadowShapeBuilder
|
|||
return shapes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves every visual part of a static object into the paired sphere +
|
||||
/// vertex-box geometry used by retail's render-shadow cell registration.
|
||||
/// Unlike <see cref="FromLandblockBspParts"/>, this deliberately includes
|
||||
/// decorative GfxObjs with no physics BSP: <c>CEnvCell::init_static_objects</c>
|
||||
/// creates a real <c>CPhysicsObj</c> for every static and
|
||||
/// <c>CPartArray::AddPartsShadow</c> registers every visual part in each
|
||||
/// crossed cell even when that part cannot collide.
|
||||
///
|
||||
/// <para>The returned values are geometry carriers only. Callers must not
|
||||
/// publish them to the collision registry.</para>
|
||||
/// </summary>
|
||||
public static List<ShadowShape> FromStaticRenderParts(
|
||||
IReadOnlyList<MeshRef> meshRefs,
|
||||
Func<uint, GfxObjPhysics?> getGfxObj,
|
||||
Func<uint, GfxObjVisualBounds?> getVisualBounds,
|
||||
out bool hasPhysicsBsp)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(meshRefs);
|
||||
ArgumentNullException.ThrowIfNull(getGfxObj);
|
||||
ArgumentNullException.ThrowIfNull(getVisualBounds);
|
||||
|
||||
hasPhysicsBsp = false;
|
||||
var parts = new List<ShadowShape>(meshRefs.Count);
|
||||
foreach (MeshRef meshRef in meshRefs)
|
||||
{
|
||||
GfxObjPhysics? physics = getGfxObj(meshRef.GfxObjId);
|
||||
bool partHasPhysicsBsp = physics?.FlatPhysicsBsp is { RootIndex: >= 0 }
|
||||
|| physics?.BSP?.Root is not null;
|
||||
hasPhysicsBsp |= partHasPhysicsBsp;
|
||||
|
||||
FlatGfxObjVisualBounds? flatBounds = physics?.VisualBounds;
|
||||
if (flatBounds is null && getVisualBounds(meshRef.GfxObjId) is { } visual)
|
||||
{
|
||||
flatBounds = new FlatGfxObjVisualBounds(
|
||||
visual.Min,
|
||||
visual.Max,
|
||||
visual.Center,
|
||||
visual.Radius,
|
||||
visual.HalfExtents);
|
||||
}
|
||||
if (flatBounds is not { } bounds)
|
||||
continue;
|
||||
|
||||
if (!Matrix4x4.Decompose(
|
||||
meshRef.PartTransform,
|
||||
out Vector3 partScaleVector,
|
||||
out Quaternion partRotation,
|
||||
out Vector3 partPosition))
|
||||
{
|
||||
partScaleVector = Vector3.One;
|
||||
partRotation = Quaternion.Identity;
|
||||
partPosition = meshRef.PartTransform.Translation;
|
||||
}
|
||||
|
||||
float partScale = partScaleVector.X > 0f ? partScaleVector.X : 1f;
|
||||
FlatCollisionSphere sphere;
|
||||
if (partHasPhysicsBsp)
|
||||
{
|
||||
FlatPhysicsBsp? flat = physics!.FlatPhysicsBsp;
|
||||
sphere = flat is { RootIndex: >= 0 }
|
||||
? flat.Nodes[flat.RootIndex].BoundingSphere
|
||||
: new FlatCollisionSphere(
|
||||
physics.BoundingSphere?.Origin ?? bounds.Center,
|
||||
physics.BoundingSphere?.Radius ?? bounds.Radius);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Retail falls back from physics_sphere to the GfxObj drawing
|
||||
// sphere. The prepared collision catalog retains the exact
|
||||
// visual AABB, not that drawing sphere; its circumsphere is a
|
||||
// conservative cheap reject while the exact box below remains
|
||||
// the admitting test.
|
||||
sphere = new FlatCollisionSphere(bounds.Center, bounds.Radius);
|
||||
}
|
||||
|
||||
parts.Add(ShadowShape.Bsp(
|
||||
meshRef.GfxObjId,
|
||||
partPosition,
|
||||
partRotation,
|
||||
partScale,
|
||||
ShadowPartGeometry.Create(sphere, bounds)));
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collision identity of part <paramref name="index"/>: the installed
|
||||
/// <c>AnimPartChanged</c> replacement when one was supplied, else the
|
||||
|
|
|
|||
|
|
@ -99,6 +99,106 @@ public static class RenderingDiagnostics
|
|||
public static bool ProbeVisibilityEnabled { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_VIS") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Temporary Facility Hub staircase discriminator. The frame walk emits
|
||||
/// camera/root/flood facts and the leaf classifier emits change-only
|
||||
/// decisions for the authored stair GfxObj (0x010000DE) and local-player
|
||||
/// setup parts in cells 0x8A02015E/015F/01C1. Output-only; it must never
|
||||
/// influence admission. Initial state from
|
||||
/// <c>ACDREAM_PROBE_FACILITY_STAIRS=1</c>.
|
||||
/// </summary>
|
||||
public static bool ProbeFacilityStairsEnabled { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_FACILITY_STAIRS") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Temporary cathedral discriminator: suppresses only the far-Z portal
|
||||
/// punch for the authored building whose look-in owns cell 0xF4180112.
|
||||
/// This is a binary visual experiment for the moving transparent seam at
|
||||
/// the 0xF4180107/0112 floating stairs, never a production admission rule.
|
||||
/// </summary>
|
||||
public static bool ProbeCathedralSkipStairBuildingPunch { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_CATHEDRAL_SKIP_PUNCH") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Temporary cathedral discriminator: suppresses only the true-depth exit
|
||||
/// seals authored by the two cells that meet at the floating-stair seam.
|
||||
/// Both portal polygons lie on world Y ~= 24 and span the reported moving
|
||||
/// triangle. This is a binary visual experiment only; normal production
|
||||
/// behavior is unchanged while the flag is unset.
|
||||
/// </summary>
|
||||
public static bool ProbeCathedralSkipFloatingStairSeals { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_CATHEDRAL_SKIP_SEALS") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Temporary cathedral carrier discriminator: suppresses only the visible
|
||||
/// EnvCell shells for cells 0xF4180107 and 0xF4180112. This deliberately
|
||||
/// removes their authored walls so a visual A/B can prove whether the
|
||||
/// moving wall-textured triangles at the floating stairs come from either
|
||||
/// cell shell. It is never a production visibility rule.
|
||||
/// </summary>
|
||||
public static bool ProbeCathedralSkipFloatingStairCellShells { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_CATHEDRAL_SKIP_CELL_SHELLS") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Temporary cathedral carrier discriminator: suppresses the visible
|
||||
/// EnvCell shells for 0xF4180112/0113/0114 only while they are reached by
|
||||
/// a building look-in. Their ordinary interior-root repaint remains
|
||||
/// untouched. This separates a pre-clear look-in cell shell from the
|
||||
/// south building's own exterior shell; it is never a production rule.
|
||||
/// </summary>
|
||||
public static bool ProbeCathedralSkipSouthLookInCellShells { get; set; } =
|
||||
Environment.GetEnvironmentVariable(
|
||||
"ACDREAM_PROBE_CATHEDRAL_SKIP_SOUTH_LOOKIN_SHELLS") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Narrow form of <see cref="ProbeCathedralSkipSouthLookInCellShells"/>:
|
||||
/// suppresses one exact EnvCell shell only during a building look-in.
|
||||
/// Accepts a full hexadecimal cell id, with or without a <c>0x</c>
|
||||
/// prefix, through <c>ACDREAM_PROBE_CATHEDRAL_SKIP_LOOKIN_SHELL</c>.
|
||||
/// Zero means disabled. Behavior-changing diagnostic only.
|
||||
/// </summary>
|
||||
public static uint ProbeCathedralSkipLookInShellCellId { get; set; } =
|
||||
ParseHexCellId(
|
||||
Environment.GetEnvironmentVariable(
|
||||
"ACDREAM_PROBE_CATHEDRAL_SKIP_LOOKIN_SHELL"));
|
||||
|
||||
/// <summary>
|
||||
/// Temporary cathedral carrier discriminator: suppresses only the own
|
||||
/// exterior shell of the south cathedral building (authored anchor cell
|
||||
/// 0xF4180112). Its portal walk, look-in cells, and particles remain live.
|
||||
/// This is a binary visual experiment, never a production rule.
|
||||
/// </summary>
|
||||
public static bool ProbeCathedralSkipSouthBuildingShell { get; set; } =
|
||||
Environment.GetEnvironmentVariable(
|
||||
"ACDREAM_PROBE_CATHEDRAL_SKIP_SOUTH_BUILDING_SHELL") == "1";
|
||||
|
||||
/// <summary>
|
||||
/// Output-only cathedral floating-stair trace. Samples the ONE frame
|
||||
/// walk's recorded clear/seal/punch/shell replay order and reports the
|
||||
/// render-stamp-deduplicated whole-shell turns for cells 0xF4180104/0106/0107
|
||||
/// and 0xF4180112/0113/0114. It never changes admission, depth state, or
|
||||
/// draw order. Initial state from
|
||||
/// <c>ACDREAM_PROBE_CATHEDRAL_SHELL_ORDER=1</c>.
|
||||
/// </summary>
|
||||
public static bool ProbeCathedralShellOrderEnabled { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_CATHEDRAL_SHELL_ORDER") == "1";
|
||||
|
||||
private static uint ParseHexCellId(string? raw)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw))
|
||||
return 0;
|
||||
ReadOnlySpan<char> value = raw.AsSpan().Trim();
|
||||
if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
value = value[2..];
|
||||
return uint.TryParse(
|
||||
value,
|
||||
NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture,
|
||||
out uint cellId)
|
||||
? cellId
|
||||
: 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase U.4c (2026-05-31) flap-convergence probe. When true, the portal
|
||||
/// visibility pass emits, EVERY frame the camera root is an indoor cell, a
|
||||
|
|
@ -186,15 +286,11 @@ public static class RenderingDiagnostics
|
|||
/// collection capped nearest-the-PLAYER — the earlier gaze-coupled scoping
|
||||
/// (rebuilding the pool from a freshly re-flooded CAMERA-seeded set,
|
||||
/// <c>c500912b</c>) was the #176 flicker mechanism and was deleted.
|
||||
/// A7.L1 (2026-07-09): visible-cell scoping is BACK, but sourced differently —
|
||||
/// <c>LightManager.BuildPointLightSnapshot</c> now takes an optional
|
||||
/// <c>visibleCells</c> filter that <c>GameWindow</c> feeds from LAST FRAME's
|
||||
/// already-rendered <c>RetailPViewFrameResult.DrawableCells</c> (one frame of
|
||||
/// latency, no independent re-flood, no callback threaded into DrawInside) —
|
||||
/// fixes the Town Network starvation case (463 fixtures, a wall-adjacent
|
||||
/// corridor's fixtures out-ranking the player's own room in raw Euclidean
|
||||
/// distance) without reproducing the #176 mechanism. <c>byCell</c> shows which
|
||||
/// cells' lights are pooled; <c>cellLess==pool</c> in a fixture-rich room still
|
||||
/// A7.L1 later added last-frame drawable-cell scoping, but the Facility Hub
|
||||
/// zoom trace proved that it also couples pool membership to the camera root
|
||||
/// (five lights became one while the player stood still), so it was removed.
|
||||
/// <c>byCell</c> now describes the resident pool; <c>cellLess==pool</c> in a
|
||||
/// fixture-rich room still
|
||||
/// means cell tagging FAILED (ParentCellId not flowing).
|
||||
/// Output-only, inert when off. Initial state from <c>ACDREAM_PROBE_INDOOR_LIGHT=1</c>.
|
||||
/// </summary>
|
||||
|
|
@ -403,14 +499,14 @@ public static class RenderingDiagnostics
|
|||
/// point-light pool: the SET COMPOSITION the <c>[light]</c> counts can't show.
|
||||
/// Cheap no-op when <see cref="ProbeIndoorLightEnabled"/> is false; otherwise
|
||||
/// fires at most once per second. Called from
|
||||
/// <c>LightManager.BuildPointLightSnapshot</c> — <paramref name="scopedSnapshot"/>
|
||||
/// already reflects any last-frame visible-cell scoping (A7.L1, 2026-07-09).
|
||||
/// <c>LightManager.BuildPointLightSnapshot</c> after resident collection and
|
||||
/// the bounded player-nearest selection.
|
||||
/// </summary>
|
||||
/// <param name="allRegistered">Every registered light (<c>LightManager._all</c>).</param>
|
||||
/// <param name="scopedSnapshot">The point-light pool just built.</param>
|
||||
/// <param name="pointSnapshot">The point-light pool just built.</param>
|
||||
public static void EmitIndoorLight(
|
||||
IReadOnlyList<AcDream.Core.Lighting.LightSource> allRegistered,
|
||||
IReadOnlyList<AcDream.Core.Lighting.LightSource> scopedSnapshot)
|
||||
IReadOnlyList<AcDream.Core.Lighting.LightSource> pointSnapshot)
|
||||
{
|
||||
if (!ProbeIndoorLightEnabled) return;
|
||||
|
||||
|
|
@ -423,10 +519,10 @@ public static class RenderingDiagnostics
|
|||
foreach (var l in allRegistered)
|
||||
if (l.IsLit && l.Kind != AcDream.Core.Lighting.LightKind.Directional) registeredLitPoints++;
|
||||
|
||||
int pool = scopedSnapshot.Count;
|
||||
int pool = pointSnapshot.Count;
|
||||
int cellLess = 0;
|
||||
var hist = new Dictionary<uint, int>();
|
||||
foreach (var l in scopedSnapshot)
|
||||
foreach (var l in pointSnapshot)
|
||||
{
|
||||
if (l.CellId == 0) cellLess++;
|
||||
hist.TryGetValue(l.CellId, out var c);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue