API reference

Every public class, method, and event in @codexo/exojs. Generated from source.

C

classForwardLighting

@codexo/exojs-lighting / lighting / stable

Lighting shaded inside the sprite fragment stage, against one packed light texture. ```ts const lighting = new ForwardLighting(app, { maxLights: 16, ambient: new Color(20, 20, 24) }); scene.systems.add(lighting); ``` One draw and no extra render targets, which is what makes it the floor renderer. It is also the only one that does normal mapping, through LitMaterial - the other two multiply a finished frame, which has no surface normals left to shade against. The price is the cap: every lit fragment walks every light, so ForwardLightingOptions.maxLights bounds how many there may be, and it casts no shadows at all. It is the one system that can be built without a host, because its light data is a texture a material samples rather than anything the frame slot runs: ```ts const lighting = new ForwardLighting({ maxLights: 16 }); ``` A filter chain is a frame pass, so `post` needs the host.

11
props
11
methods
0
events
Import
import { ForwardLighting } from '@codexo/exojs-lighting'

Lighting shaded inside the sprite fragment stage, against one packed light texture.

```ts const lighting = new ForwardLighting(app, { maxLights: 16, ambient: new Color(20, 20, 24) });

scene.systems.add(lighting); ```

One draw and no extra render targets, which is what makes it the floor renderer. It is also the only one that does normal mapping, through LitMaterial - the other two multiply a finished frame, which has no surface normals left to shade against. The price is the cap: every lit fragment walks every light, so ForwardLightingOptions.maxLights bounds how many there may be, and it casts no shadows at all.

It is the one system that can be built without a host, because its light data is a texture a material samples rather than anything the frame slot runs:

```ts const lighting = new ForwardLighting({ maxLights: 16 }); ```

A filter chain is a frame pass, so `post` needs the host.

Constructors2
Methods11
add(light: T): T
Register a light and return it, so it can be created, parented and registered in one expression. Registering the same light twice shades it twice; the second registration is ignored instead.
clear(): this
Unregister every light.
clearOccluders(): this
Unregister every occluder source.
clearSurfaces(): this
Unregister every normal surface.
destroy(): void
Release the renderer's resources. Registered lights and sources are unregistered, not destroyed.
Give a drawable surface normals, and return it so it can be created, parented and registered in one expression. ts lighting.normalsFrom(crate, new NormalMap(crateNormals)); Only lightmap reads these. forward shades inside the sprite stage and takes its normals from LitMaterial instead, and radiance gathers each probe's rays into one arriving colour, which leaves no incident direction at a fragment for a normal to be measured against - under both, registering a surface is recorded and ignored, and activeSurfaceCount stays at zero. Nothing is required of a drawable that is not registered: it is lit as a plane, which is what the renderer already assumed of everything. The drawable and the source are the caller's; the system only reads them. Registering the same drawable twice replaces its source rather than describing the surface twice.
occludeFrom(source: T): T
Register something that blocks light, and return it so it can be built and registered in one expression. Only a renderer with shadows reads them - forward has no light field to darken, and skips collecting entirely. ts lighting.occludeFrom(new PhysicsOccluder(world)); The source is asked, once per frame, for the edges in the region the visible lights jointly reach. It is the caller's; the system only reads it. Registering the same source twice collects it twice, so the second registration is ignored instead.
update(): void
System update phase: publish this frame's lights, occluders and surfaces to the renderer.
Properties11
activeLightCount: number
Lights the last frame actually shaded with. Lower than lights when some are disabled, have no intensity, or fall beyond what the renderer in use can carry.
activeSurfaceCount: number
Surfaces the last frame actually took normals from. Lower than surfaces when some are hidden or carry no texture, and zero under every renderer but lightmap. See normalsFrom.
debugExposure: number
Scale applied to the shaded output, 1 by default. It moves the exposure only: the lights, the transport and the bounce history are all untouched, so raising it shows what a light field holds above 1.0 without changing what any of it computed. That is what makes it the right knob for looking at an overbright scene - turning a light down instead would change the scene being looked at. Under forward, where nothing is composited, it does nothing. It is not a tone map: values still clip, one stop further along.
hdr: boolean
Whether light accumulates with headroom above 1.0, so that overlapping lights add up instead of saturating to white and a filter over the frame has something above the clipping point to work with. false under forward, which shades straight into the frame, and under lightmap on a WebGL2 context without EXT_color_buffer_float. The picture is still correct there - it clips earlier, and a bloom keyed on a threshold near 1.0 finds little to bloom.
Registered normal surfaces, in registration order.
Source