/** * Performs the visibility culling for a {@link Renderer}: per-camera light visibility, * mesh-instance culling (request/execute) and shadow-caster culling. It holds the per-frame * culling state and operates on the renderer's shared state (lights, shadow renderers, light * atlas, stats) through a back-reference to the renderer. * * @ignore */ export class Culler { /** * @param {Renderer} renderer - The renderer that owns this culler. */ constructor(renderer: Renderer); /** * A set of visible mesh instances which need further processing before being rendered, e.g. * skinning or morphing. Extracted during culling. * * @type {Set} */ processingMeshInstances: Set; /** * The distinct cameras with mesh-instance cull requests registered for the current frame, in * registration order. Populated by {@link Culler#requestMeshInstanceCull} and drained by * {@link Culler#executeMeshInstanceCull}. Reused across frames to avoid per-frame allocation. * * @type {Camera[]} * @private */ private _cullCameras; /** * Directional (light, camera) pairs requested by shadow passes this frame. References the * existing render data to avoid allocating requests. Kept through splat culling and one-shot * consumption, then reset before the next frame graph is built. * * @type {LightRenderData[]} * @private */ private _directionalShadowCullRequests; /** * Local lights requested by shadow passes this frame. Reuses face 0's render data so * separate cube-map passes share one cull without allocating request objects. * * @type {LightRenderData[]} * @private */ private _localShadowCullRequests; /** * A list of unique directional shadow casting lights for each enabled camera. This is generated * each frame during light culling. * * @type {Map>} */ cameraDirShadowLights: Map>; /** * A mapping of a directional light to a camera, for which the shadow is currently valid. This * is cleared each frame, and updated each time a directional light shadow is rendered for a * camera, and allows us to manually schedule shadow passes when a new camera needs a shadow. * * @type {Map} */ dirLightShadows: Map; /** @type {Renderer} */ renderer: Renderer; /** * @param {Camera} camera - The camera used for culling. * @param {MeshInstance[]} drawCalls - Draw calls to cull. * @param {CulledInstances} culledInstances - Stores culled instances. */ cullMeshInstances(camera: Camera, drawCalls: MeshInstance[], culledInstances: CulledInstances): void; /** * Culls a set of lights against a camera's frustum, marking the visible ones (and updating their * max screen size and physical-units flag). Directional lights are marked visible at the start * of the frame and are skipped here, so only local (omni / spot) lights are frustum tested. In * non-clustered lighting, a shadow-casting light with no shadow map allocated yet is also marked * visible so its shadow map gets allocated. * * @param {Camera} camera - The camera whose frustum the lights are culled against. * @param {Light[]} lights - The lights to cull (typically a layer's lights). */ cullLights(camera: Camera, lights: Light[]): void; /** * Cull shadow casters for the local and directional updates requested by scheduled shadow * passes. Visible mesh instances are collected into the light's render data, and directional * shadow cameras are fitted to their cascades. * * @param {LayerComposition} comp - The layer composition. */ cullShadowmaps(comp: LayerComposition): void; /** * After the frame graph is built and shadow casters are culled, account for shadow-map updates * and consume one-shot ({@link SHADOWUPDATE_THISFRAME}) requests for lights whose shadow * update is scheduled this frame, reverting them to {@link SHADOWUPDATE_NONE}. A light without * a scheduled update keeps its request until its shadow can be rendered. Runs after the frame * graph build and all mesh and splat shadow culling, so every consumer sees the pending update * mode before it is consumed. */ consumeOneShotShadows(): void; /** * Requests directional shadow culling for a scheduled shadow pass. Multiple passes using * the same light and camera share one cull; their render passes remain independently scheduled. * * @param {Light} light - The shadow-casting light. * @param {Camera} camera - The camera the shadow is fitted to. * @param {number} cascadeMask - Bit mask of cascades the pass will render. */ requestDirectionalShadowCull(light: Light, camera: Camera, cascadeMask: number): void; /** * Requests local shadow culling for a scheduled shadow pass. Multiple face passes using * the same light share one cull. * * @param {Light} light - The shadow-casting local light. */ requestLocalShadowCull(light: Light): void; /** * Collects the set of shadow-casting directional lights for each camera into * {@link Culler#cameraDirShadowLights}, and ensures each such light has a shadow map allocated. * This is independent of mesh culling and camera frusta (it uses only the composition's cameras * and the layers' directional lights), so it can run before the frame graph is built. The * actual shadow-caster culling is done separately. * * @param {LayerComposition} comp - The layer composition. */ collectDirectionalShadowLights(comp: LayerComposition): void; /** * Per-camera light visibility culling, light-atlas allocation and directional-shadow-light * collection. This is independent of mesh culling and the frame graph, so it runs before the * frame graph is built. The mesh and shadow-caster culling that depends on it is done later in * {@link Culler#cullComposition}. * * @param {LayerComposition} comp - The layer composition. */ updateLightVisibility(comp: LayerComposition): void; /** * Registers a request to cull a layer's mesh instances for a camera in the current frame. The * culling itself is performed later, in a single batch, by * {@link Culler#executeMeshInstanceCull}. Requests are de-duplicated per (camera, layer), so * requesting the same pair more than once (e.g. for its opaque and transparent sub-layers) is * harmless. * * This lets the frame graph drive culling - each pass requests the (camera, layer) pairs it * will actually render - instead of culling every camera/layer combination in the composition. * * @param {Camera} camera - The camera to cull for. * @param {Layer} layer - The layer whose mesh instances should be culled. */ requestMeshInstanceCull(camera: Camera, layer: Layer): void; /** * Performs all mesh-instance culling requested via {@link Culler#requestMeshInstanceCull} this * frame, then clears the request list. For each requested camera the precull event is fired * (before the frustum is refreshed, so a listener may still adjust the camera), the camera * frustum is updated, each requested layer is culled, and the postcull event is fired. * * The events are passed the owning camera component for a framework camera, or null for an * internal camera (shadow / reflection / picker), matching the documented precull/postcull * contract. */ executeMeshInstanceCull(): void; /** * Visibility culling of meshInstances and shadow casters. Light visibility, the light atlas and * the directional-shadow-light collection are done earlier in * {@link Culler#updateLightVisibility}. * * @param {LayerComposition} comp - The layer composition. */ cullComposition(comp: LayerComposition): void; } import type { MeshInstance } from '../mesh-instance.js'; import type { Camera } from '../camera.js'; import type { Light } from '../light.js'; import type { Renderer } from './renderer.js'; import type { CulledInstances } from '../layer.js'; import type { LayerComposition } from '../composition/layer-composition.js'; import type { Layer } from '../layer.js';