Protected_Protected_Protected_The clear color of the renderer.
Protected_Protected_Protected_Protected_Cached light data to avoid GC pressure.
Protected_Protected_Protected_Protected_Global quality settings.
Protected_Protected_Protected_Protected_Protected_Protected_Protected_Protected_Protected_Protected Optional_ReadonlycontextPer-instance bundle of DeviceCaps/ShaderRegistry/AssetManager -- see RendererContext.
OptionalonOptional callback triggered when the GPU context is lost.
The global post processing volume/group.
ReadonlytypeThe type of the renderer.
Gets the clear color of the renderer.
The color-target format any RenderPipeline drawing into the CURRENTLY bound target must be
built for -- i.e. whatever render()'s own view resolution (see the isOffscreen block
around _activeRenderTarget) will actually bind this frame. A custom offscreen RenderTarget
(e.g. PlanarReflectionNode.renderTarget) is always backed by a this._format texture,
regardless of postProcessing.enabled -- only the main scene pass (no active render
target) targets the "rgba16float" HDR intermediate buffer when post-processing is on.
Single source of truth for this decision: anything that needs to match the pipeline format
_renderSubgroup() will request in the current context (e.g. a shadow pass's own throwaway
dummy color attachment) must read this getter too, rather than re-deriving the same decision
from postProcessing.enabled alone and silently drifting out of sync with it whenever
something renders into a custom RenderTarget (see CascadedShadowPassGPU/SpotShadowPassGPU,
which used to do exactly that).
Read by the fragment shader's global bind group; reassigned once by
CascadedShadowPassGPU when a real cascaded shadow map first exists.
Read by the fragment shader's global bind group; reassigned once by
SpotShadowPassGPU when a real spot shadow map first exists.
Rebuilt once (not per-frame) by a shadow pass, the first time a real shadow map for that
light type exists -- see CascadedShadowPassGPU/SpotShadowPassGPU.
Satisfies RenderPass-consuming passes, which have no other way to reach this.
Satisfies Renderer interface
Satisfies RenderPass-consuming passes, which have no other way to reach this.
Satisfies Renderer interface
Gets the global quality settings of the renderer.
Reused every frame (never reallocated) -- see _updateGlobalBuffers().
Same Map instance every frame -- shadow passes .get()/.set() on it directly.
Builds this frame's HZB pyramid: mip 0 seeded from _depthTexture (this frame's
just-finished opaque depth, already written by DepthPrePassGPU earlier in _passes), then
mips 1..N max-reduced from the level below, one dispatch per level -- see
hzb_copy_depth.wgsl/hzb_downsample_max.wgsl. Recorded into the frame's shared command
encoder: unlike GPUTextureResourceCache's texture mip generation (which needs its own
throwaway encoder+submit since
callers run it mid-frame while a render pass may already be open), this runs between two
whole passes, never inside one. No-ops for offscreen render targets -- see
docs/adr/0008-hzb-occlusion-culling-webgpu-only.md's main-canvas-only scope.
Optionalscene: ScenePacks this frame's frustum-visible objects into _hzbAabbBuffer as world-space bounding
spheres, dispatches the visibility test compute shader against the pyramid
_buildHzbPyramid() just built, and copies the results into whichever staging buffer slot
isn't still waiting on a previous mapAsync().
The candidate list is derived from scene.lastFrustumVisibleObjects (isVisible && inFrustum,
same condition FrustumCuller's own fallback path uses -- see _collectHzbCandidates())
rather than reading any of FrustumCuller's output fields: this renderer only holds a
scene, not the owning SmallWorld's private culler instance. Reading scene's own
per-instance list keeps the candidate list scoped to the scene actually being rendered, without
coupling the renderer to whichever culler instance drove this frame.
Only one slot is ever in flight at a time (the two alternate every frame -- see
_hzbStagingBuffers's doc comment); if THAT slot is still pending, this frame's test is
skipped entirely rather than stalling on it. Objects simply keep last frame's
occlusionCulled value one frame longer -- never blocking, matches the same "skip and
self-correct next frame" pattern _getObjectSlotOffset()'s ring-buffer overflow clamp uses.
Protected_Protected_Protected_Returns the byte offset into the object ring buffer holding obj's ObjectUniforms for
this draw. Packs + uploads at most once per (object, material) per frame -- e.g. the same
shadow caster drawn across 4 CSM cascades (all sharing one DepthMaterial matUuid) reuses
the same slot instead of repacking. Sprites are excluded: their model matrix is billboarded
towards vMat (camera vs. light view differ per pass), so they always get a fresh slot.
OptionalvMat: Float32Array<ArrayBufferLike>Protected_Packs obj's ObjectUniforms into _scratchObjBufferData. Returns false (leaving the
scratch buffer untouched) if m.shaderId isn't registered -- caller then skips the upload,
matching the previous per-object-buffer behavior of leaving the slot's prior contents alone.
OptionalvMat: Float32Array<ArrayBufferLike>OptionalvMat: Float32Array<ArrayBufferLike>OptionalwireframeMode: "structural" | "triangles"Writes rawVp (a raw, not-yet-ZO-corrected view-projection matrix) into the per-draw view
buffer at slot and returns the byte offset to pass as setBindGroup(3, viewBindGroup, [offset]). Used by CascadedShadowPassGPU/SpotShadowPassGPU for their shadow cameras --
the main camera's slot 0 is kept up to date by _updateGlobalBuffers() instead, once per
frame, since every draw needs it regardless of pass.
OptionalprojMatrix: Float32Array<ArrayBufferLike>buffer.mapState === "mapped" on each pending slot directly, rather than reacting to
mapAsync()'s own promise resolving -- deliberately, not as a simplification. That promise
is only guaranteed to resolve eventually; nothing requires it to fire within any bounded
number of frames, and if it's ever delayed or dropped (slow GPU, a throttled/backgrounded
tab, or any other reason) a promise-driven design gets stuck: _hzbStagingSlot only ever
advances on a new successful dispatch, and dispatch itself refuses to touch a slot that's
still marked pending -- so a lost callback wedges that slot, and therefore the whole
ping-pong, forever. Reading mapState (the GPU's own ground truth for whether the buffer is
actually readable right now) sidesteps that dependency entirely: whichever slot's mapping
has genuinely completed gets consumed on the very next call, no matter what happened to its
promise.
Destroys the renderer and releases its resources.
Extracts all lights from the scene for rendering.
The scene to extract lights from.
An object containing all extracted light data.
Initializes the renderer.
Optionalattributes: Record<string, unknown>Optionalconfig: EngineOptionsTracks that obj currently depends on the textures in textures (typically
material.getRenderManifest().textures). Called once per object per frame from
the render loop. textures is diffed key-by-key against obj's last-known
snapshot rather than by container reference, since a material's manifest object
is created once and mutated in place on every getRenderManifest() call.
Sets the active render target for off-screen rendering. If null, the renderer targets the screen/post-processing buffer.
The target to render into.
OptionalactiveCubeFace: number
Optional. Which face (0-5) of the RenderTargetCube to render into.
Sets the size of the render viewport.
Modern WebGPU implementation with dynamic vertex updates and memory management.