Skip to main content

Class: LocalShadowScheduler

The L3 tier: decides which clustered lights earn a shadow slot (with eviction hysteresis so orbiting the camera does not thrash the atlas), owns the cached-static / dynamic-overlay face state machine per slot, and renders the faces the ShadowFrameLedger grants each frame.

A frame with zero shadow slots costs one integer compare in update and an early return in render.

Constructors

constructor

new LocalShadowScheduler(registry, options): LocalShadowScheduler

Parameters

NameType
registryLightSourceRegistry
optionsObject
options.maxShadowedLightsnumber
options.shadowAtlasSizenumber
options.shadowEvictionHysteresisObject
options.shadowEvictionHysteresis.framesnumber
options.shadowEvictionHysteresis.rationumber
options.shadowSlotSizenumber

Returns

LocalShadowScheduler

Properties

atlas

Readonly atlas: LocalShadowAtlas


getIsOpaqueAt

getIsOpaqueAt: (vx: number, vy: number, vz: number) => boolean = null

getIsOpaqueAt hook, wired by the world; null skips mount awareness.

Type declaration

▸ (vx, vy, vz): boolean

Parameters
NameType
vxnumber
vynumber
vznumber
Returns

boolean


getStaticCasterRoots

getStaticCasterRoots: (x: number, y: number, z: number, radius: number, out: Object3D<Object3DEventMap>[]) => void = null

Static caster collection hook, wired by the world: append every world root (chunk group) whose geometry can occlude a light at (x, y, z) with range radius to out. Null falls back to rendering the whole scene per face, which stays correct but pays full-graph traversal.

Type declaration

▸ (x, y, z, radius, out): void

Parameters
NameType
xnumber
ynumber
znumber
radiusnumber
outObject3D<Object3DEventMap>[]
Returns

void


invalidationLog

Readonly invalidationLog: ShadowInvalidationEntry[] = []

Ring buffer of the most recent invalidations, for the debug HUD.


onShadowDataChanged

onShadowDataChanged: () => void = null

Called whenever packed shadow texels must be rewritten.

Type declaration

▸ (): void

Returns

void

Accessors

activeSlotCount

get activeSlotCount(): number

Returns

number


slotCapacity

get slotCapacity(): number

Returns

number

Methods

dispose

dispose(): void

Returns

void


estimateDynamicDemand

estimateDynamicDemand(entities?): number

Estimated dynamic face units this frame wants, for the ledger reservation taken before CSM renders its cascades. Mirrors exactly what render will draw through the dynamic tier — a moving light's pending world refreshes plus every slot's entity overlay faces — so an idle held light with no casters nearby reserves nothing and never squeezes the CSM far cascades or the static FIFO.

Parameters

NameType
entities?Object3D<Object3DEventMap>[]

Returns

number


invalidateAll

invalidateAll(cause): void

Parameters

NameType
causeShadowInvalidationCause

Returns

void


invalidateRegion

invalidateRegion(region): void

Public API: invalidate every cached map intersecting a world region.

Parameters

NameType
regionObject
region.max[number, number, number]
region.min[number, number, number]

Returns

void


notifyBlockEdit

notifyBlockEdit(vx, vy, vz): void

A voxel changed. Cached static maps of every slot whose range sphere intersects the edited voxel re-render through the FIFO; edits outside every range cost one AABB test per active slot.

Parameters

NameType
vxnumber
vynumber
vznumber

Returns

void


notifyChunkMeshed

notifyChunkMeshed(area): void

A chunk's mesh (re-)built. Cached maps that reach into the chunk baked whatever geometry existed at render time; streaming in late meshes must refresh them or lights shine through terrain that "wasn't there yet".

Parameters

NameType
areaObject
area.maxHeightnumber
area.maxXnumber
area.maxZnumber
area.minXnumber
area.minZnumber

Returns

void


onContextRestored

onContextRestored(): void

GPU context restored: atlas contents are gone; re-render lazily.

Returns

void


recordForIndex

recordForIndex(index): ShadowTexelRecord

Texel provider for the clustered packer.

Parameters

NameType
indexnumber

Returns

ShadowTexelRecord


render

render(renderer, scene, ledger, entities, instancePools, skipShadowObjects, stats, poolBounds?): void

Render the faces the ledger grants. Order inside the local tier: moving-light refreshes and entity overlays (dynamic units, reserved) first, then the invalidated-static FIFO (free units only).

Parameters

NameType
rendererWebGLRenderer
sceneScene<Object3DEventMap>
ledgerShadowFrameLedger
entitiesObject3D<Object3DEventMap>[]
instancePoolsGroup<Object3DEventMap>[]
skipShadowObjectsreadonly Object3D<Object3DEventMap>[]
statsLocalLightStats
poolBounds?readonly Box3[]

Returns

void


resetCacheCounters

resetCacheCounters(): void

Restart the cache-hit measurement window (benchmark harnesses).

Returns

void


setTierCaps

setTierCaps(maxShadowedLights, atlasSize, slotSize): void

Quality-tier change: new caps and atlas geometry. Every cached map is dropped (the atlas may have been reallocated at a new size).

Parameters

NameType
maxShadowedLightsnumber
atlasSizenumber
slotSizenumber

Returns

void


update

update(selectedIndices, selectedCount, cameraX, cameraY, cameraZ, stats): void

Reconcile shadow slots against the clustered selection. Runs every frame; the scoring loop is O(clustered ≤ 255) and the whole pass is a no-op micro-loop when nothing shadow-requesting is selected.

Parameters

NameType
selectedIndicesUint32Array<ArrayBufferLike>
selectedCountnumber
cameraXnumber
cameraYnumber
cameraZnumber
statsLocalLightStats

Returns

void