You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a scene transitions from LOD_1 (single-AB LOD) to LOD_0 (the ISS-descriptor-driven, per-asset reconstruction), there's a visible window where both representations are rendered on top of each other:
LOD_1 is already in the scene.
LOD_0 starts arriving asset-by-asset via the descriptor — each ISSDescriptorAsset is parented + positioned + SetActive(true) as its per-asset AB resolves.
During the (potentially long) interval between the first descriptor entry resolving and the last one finishing, the player sees LOD_0 pieces overlapping the still-present LOD_1 mesh.
Only once LOD_0 is fully populated does the system release LOD_1.
The result is z-fighting + double-shaded geometry for a noticeable window, which is especially obvious for large scenes whose descriptor entries trickle in over multiple seconds.
Introduced by PR #8870 (chore: new lods through ISS descriptor).
Where this happens today
Explorer/Assets/DCL/LOD/Systems/ResolveISSLODSystem.cs — PositionAsset (line 161) calls asset.Root.SetActive(true) and parents the asset under InitialSceneStateLOD.ParentContaineras each per-asset bundle resolves, immediately visible.
Explorer/Assets/DCL/LOD/Components/InitialSceneStateLOD.cs — AllAssetsInstantiated() (line 91) returns true only when every descriptor entry has finished (Assets.Count == TotalAssetsToInstantiate).
Suggested approaches (cheapest → most polished) (Beware, they were AI written. Although they make sense, thet are just guidelines)
Atomic swap via deferred activation (recommended first attempt).
In ResolveISSLODSystem.PositionAsset, parent + position each asset but leave it SetActive(false).
When InitialSceneStateLOD.AllAssetsInstantiated() becomes true, walk the children of ParentContainer and SetActive(true) in a single frame, then trigger the LOD_1 unload in the same frame.
Tradeoff: ~one extra frame of "empty" scene if the unload-LOD_1 step happens after the activation. Mitigate by activating LOD_0 in the same tick that schedules LOD_1's release, or activate LOD_0 first and unload LOD_1 next tick (one frame of intentional overlap, much shorter than today).
Activate the parent, not the children.
Same idea as Test #1 but operating on InitialSceneStateLOD.ParentContainer itself (SetActive(false) until ready). Slightly less per-asset work; just one SetActive call at the end. Requires EnsureParentContainer to start inactive and AddResolvedAsset to not toggle it.
Hard gate on LOD_1 unload — keep LOD_1, build LOD_0 invisibly, swap.
Hybrid of Test #1: keep LOD_1 visible the entire time LOD_0 is assembling (no "empty frame" risk), only deactivate LOD_1 the same tick LOD_0 is activated. Memory overhead is both LODs co-resident during assembly, but the descriptor mode means LOD_0 ABs are streamed one at a time so peak overlap is bounded.
This is probably the cleanest UX: the player never sees a hole and never sees overlap — they see LOD_1, then in one frame they see LOD_0.
Per-asset staging container with same-frame swap.
Spawn into a hidden "staging" GameObject parent. Once full, reparent the entire subtree under the active container and disable LOD_1, all in the same frame. ]
Repro
Easiest in Genesis Plaza: spawn / teleport out to roughly 20,20 so the central plaza is in LOD_1, then walk straight back toward 0,0. As you cross the LOD threshold the system switches into descriptor mode for LOD_0, and the overlap window is plainly visible head-on at the boundary.
Same effect is reproducible in the world test from #8892 (cozyhouse.dcl.eth on .zone) once LODs actually fire for worlds, but Genesis Plaza is the easier reproduction today since #8892 still blocks LODs in worlds.
Problem
When a scene transitions from
LOD_1(single-AB LOD) toLOD_0(the ISS-descriptor-driven, per-asset reconstruction), there's a visible window where both representations are rendered on top of each other:LOD_1is already in the scene.LOD_0starts arriving asset-by-asset via the descriptor — eachISSDescriptorAssetis parented + positioned +SetActive(true)as its per-asset AB resolves.The result is z-fighting + double-shaded geometry for a noticeable window, which is especially obvious for large scenes whose descriptor entries trickle in over multiple seconds.
Introduced by PR #8870 (
chore: new lods through ISS descriptor).Where this happens today
Explorer/Assets/DCL/LOD/Systems/ResolveISSLODSystem.cs—PositionAsset(line 161) callsasset.Root.SetActive(true)and parents the asset underInitialSceneStateLOD.ParentContaineras each per-asset bundle resolves, immediately visible.Explorer/Assets/DCL/LOD/Components/InitialSceneStateLOD.cs—AllAssetsInstantiated()(line 91) returns true only when every descriptor entry has finished (Assets.Count == TotalAssetsToInstantiate).Suggested approaches (cheapest → most polished) (Beware, they were AI written. Although they make sense, thet are just guidelines)
Atomic swap via deferred activation (recommended first attempt).
ResolveISSLODSystem.PositionAsset, parent + position each asset but leave itSetActive(false).InitialSceneStateLOD.AllAssetsInstantiated()becomes true, walk the children ofParentContainerandSetActive(true)in a single frame, then trigger the LOD_1 unload in the same frame.Activate the parent, not the children.
InitialSceneStateLOD.ParentContaineritself (SetActive(false)until ready). Slightly less per-asset work; just oneSetActivecall at the end. RequiresEnsureParentContainerto start inactive andAddResolvedAssetto not toggle it.Hard gate on LOD_1 unload — keep LOD_1, build LOD_0 invisibly, swap.
Per-asset staging container with same-frame swap.
Repro
Easiest in Genesis Plaza: spawn / teleport out to roughly
20,20so the central plaza is inLOD_1, then walk straight back toward0,0. As you cross the LOD threshold the system switches into descriptor mode for LOD_0, and the overlap window is plainly visible head-on at the boundary.Same effect is reproducible in the world test from #8892 (
cozyhouse.dcl.ethon .zone) once LODs actually fire for worlds, but Genesis Plaza is the easier reproduction today since #8892 still blocks LODs in worlds.Related