Talos docs

Lighting

Since 0.7Changed in next

How a Talos scene is lit in the HD renderer, what each part costs, and what it cannot do yet.

Plain text

How a Talos scene is lit in the HD renderer, what each part costs, and what it cannot do yet. Four parts make up the "lighting" package:

  1. Global illumination (GI): bounced light.
  2. The sky: sun, air, clouds, fog, night.
  3. The default look: tonemap, exposure, grade.
  4. Ray tracing: ray-traced sun shadows and reflections.

All four are Beta (docs/FEATURES.md). Field-level reference for the sky and fog is docs/SKY.md; the render settings are in docs/RENDERING.md. GI, ray tracing and the cloud layer are HD only: the standard renderer ignores them (hd-only-ignored).

How to turn things on, off and tune them

Two places:

  • The scene (meta.environment, meta.render): what the world is (sky, fog, GI strength, exposure, look).
  • The project's quality request (render.quality in the project manifest, HD only): how much work the renderer does. A preset (low, medium, high, ultra, custom, auto) plus overrides for single knobs. The default is {"preset": "auto", "targetFps": 60}. Auto measures your scene on your GPU at start-up and picks the highest preset that fits the frame budget (80% of 1/targetFps), then steps down or back up as the scene changes. With no GPU timing it falls back to a guess by GPU class. This is windowed play only; a headless run or capture is fixed to High.
"render": { "profile": "hd",
  "quality": { "preset": "high", "overrides": { "rayTracing": { "reflections": false, "giProbeUpdates": 2048 } } } }

What the presets set for GI and ray tracing:

KnobLowMediumHighUltra
rayTracing.gioffoffonon
rayTracing.giProbeUpdates (256..16384)1024204840968192
rayTracing.giCascades (1..4)2334
rayTracing.shadowsoffoffonon
rayTracing.reflectionsoffoffonon
rayTracing.reflectionResolutionhalfhalfhalffull
rayTracing.reflectionMaxRoughness0.40.50.50.7
rayTracing.windDeformoffoffoffon
rayTracing.giAlwaysoffoffoffoff
rayTracing.giGatherResolutionhalfhalfhalfhalf

GI is skipped on a frame with nothing it could light: every surface unlit (a 2D game's sprites, tilemaps and unlit user shaders) and no virtual geometry, splats, particles, water, ground cover, decals or fog volumes. The frame is pixel for pixel the same (GI lights nothing there), 0.6 to 1.2 ms cheaper on an RTX 3080 at 1080p. The first frame with lit content turns GI on for the rest of the run (switching GI rebuilds pipelines, so it never goes back off). rayTracing.giAlways: true keeps GI on from the first frame.

rayTracing.giGatherResolution (half | quarter, optional, default half; every preset says half) sets the GI's final gather: one ray per 2x2 render pixels, or per 4x4 with quarter. quarter is opt-in: the gather, guided-sampling tiles, denoiser and upsample run at a quarter of the render resolution per axis (a quarter of the rays), and the upsample reconstructs render resolution. It is softer on thin geometry (blades, twigs): on llvmpipe its GI differs from half by 7 to 12% mean per pixel in the test scenes. The radiance cache is unchanged.

Every ray-traced knob needs a GPU with ray query. Without it the knob falls back to the screen-space path and the engine says quality-unsupported-on-device; if the device or build has no ray tracing at all it says render.hd.rt_unavailable and continues (docs/RUNTIME-CODES.md).

Global illumination

HD's GI is ray traced: a probe cache (radiance probes in giCascades nested levels, giProbeUpdates of them re-traced every frame), a per-pixel final gather from it, and a temporal denoiser. It lights surfaces with sky and sun light that bounces off other surfaces, and occludes sky light in corners. It is on in the High and Ultra presets on a ray-query GPU, and off in Low and Medium (which use the sky's image-based light and ambient occlusion only).

ToDo
Turn it offrender.quality.overrides.rayTracing.gi: false
Settle changes faster after a light changeraise rayTracing.giProbeUpdates (more cost)
Reach further from the cameraraise rayTracing.giCascades (1..4)
Brighten or dim all bounced lightmeta.environment.gi.indirectIntensity, 0..16, default 1 (changing it at run time does not restart the GI)
Brighten or dim it in one placea giVolume component: size, indirectIntensity 0..16, mode camera (default) or region, blend soft edge in metres (default 0.5); up to 8 volumes per mode, overlapping volumes multiply
Make one light bounce more or lessthat light's indirectIntensity

Details of the controls: RENDERING.md, "GI controls (HD)".

The sky

The HD renderer's physical sky is "kind": "atmosphere" (Rayleigh and Mie scattering, ozone, multiple scattering). The sun is wherever you put it, and the sky, the sun's colour, the image-based light and the aerial perspective all follow. Full fields in SKY.md; the short version:

  • Time of day. On an atmosphere sky the preset (clear-noon, golden-hour, overcast, dusk, night) sets the sun, a cloud layer, the air and a fog together, wherever the scene wrote nothing of its own. Anything the scene writes wins field by field.
  • Clouds. sky.clouds: preset (clear, fair, broken, overcast, storm), coverage 0..1, altitudeM, thicknessM, density, windSpeedMps, windDirectionRad. They cast shadows on the ground (see render.hd.cloud_shadow_unavailable). They drift with the simulation clock. Quality knobs: clouds.resolution, clouds.steps, clouds.shadowMapSize.
  • The air. sky.atmosphere: preset (earth-clear, hazy, polluted, stylised), haze 0..10, visibilityKm 0.1..1000 (overrides haze; 50 clear, 25 typical, 10 hazy, 1 fog), groundAlbedo 0..1 (default 0.3), and aerialScale 0..100 (default 1 is physical; larger values give a small world the layered blue depth of a big one, without changing the sky itself).
  • Fog. meta.environment.fog with a preset (light-haze, valley-mist, morning-mist, dense, aerial) or a visibilityM. aerial (20 km visibility, thin within about 250 m of height) is the depth cue for a 0.3 to 1 km scene, and the one to use under a panorama sky (see Known limits). A bare fog: {} is 0.02 per metre, which is thick.
  • Night. With the sun below about -4 degrees on an atmosphere sky, HD adds a moon light (the directional light, opposite the sun, 35 degrees up) and a dark blue dome so the image-based light and shaded sides are not black. Both fade in from -4 to -10 degrees. Auto exposure lifts a night frame at most 2 stops; pin exposure for a darker night.

Shadow tint (standard renderer)

The standard renderer lights a surface the sun cannot reach with the sky's light only, so a shadow on a dark surface (a dark road) goes near black. A directional light can lift its shadows with an optional shadowTint:

{ "type": "light", "kind": "directional", "color": "#FFF1D6", "intensity": 3,
  "shadowTint": { "color": "#5B7FA6", "strength": 0.45 } }

A fully shadowed surface then receives strength of the sun's light in color (the sun term is sun * (shadow + tint * (1 - shadow))), scaled by the surface's albedo and its angle to the sun, on top of the sky light. A surface the sun reaches is unchanged, and so is a scene without the field (the frame is byte for byte the same). strength is 0..1 and color a hex colour (light-shadow-tint-range); on a point or spot light it does nothing (light-shadow-tint-ignored). It applies to the lit shading models (pbr, toon, vertex); unlit materials, custom shaders and the HD renderer ignore it. A face turned away from the sun gets none of the sun's light, tinted or not, so the tint shows where a cast shadow falls on a surface that faces the sun, which is where the sun's shadow reads as black.

The default look

A scene that writes nothing gets:

  • Tonemap agx-punchy in both renderers (meta.render.tonemap; others: agx, aces, neutral, none, HD's unreal-filmic).
  • Auto exposure in HD (exposureMode: "auto", metered every frame), unless the scene sets exposure or the retro style. exposure then shifts the metered result by log2(exposure) stops. For a fixed exposure write "exposureMode": "manual" (with exposure, default 1).
  • No grade. meta.render.look absent draws no grade, the same as { "preset": "natural" }.

To grade, name a look and tune it:

"render": { "look": { "preset": "cinematic", "contrast": 1.1, "temperatureK": 6000, "shadowsLift": -0.3 } }

Presets natural, cinematic, bright-day, overcast, night, stylised; overrides contrast 0.5..2, saturation 0..2, temperatureK 2000..15000, tint -1..1, shadowsLift -1..1, vignette 0..0.9 (HD). See RENDERING.md, "Scene look".

Ray tracing

Ray-traced sun shadows replace the shadow cascades, and ray-traced reflections replace the screen-space ones. Both need a GPU with ray query. The same ray-tracing core is what GI traces against, so a mesh that is not in it casts and receives neither.

  • On or off: rayTracing.shadows and rayTracing.reflections (table above). Both are on in High and Ultra on a ray-query GPU and off in Low and Medium. To keep them off in a project that runs High, override them to false.
  • Size floor. The HD setting rt_min_radius_m leaves instances smaller than that bounding radius (ferns, weeds, debris) out of ray tracing. The default is 0 (off: everything is traced). It is an engine setting, not a scene or project field yet; the capture tool sets it from its manifest.
  • Wind deformation. rayTracing.windDeform (Ultra only by default) makes swaying foliage trace the exact deformed shape, about 0.7 ms in a dense forest (from the knob's own description).

What it costs

RTX 5080, 1920x1080, High (all ray-traced effects on), median GPU time per frame spent in the GI and RT passes, measured 16 Oct 2026 on the gate's reference scenes (raw numbers: the per-pass budgets in scripts/gate/perf/gpu-cells.json, added with the gate's advisory per-pass check). Provisional: the gate does not enforce these yet, and they will move as GI changes.

SceneGI (probe select, trace, blend, gather, denoise)RT shadows and reflectionsTotal
Open water, UI gallery0.14 ms0.04 msabout 0.18 ms
Driving course0.37 ms0.05 msabout 0.42 ms
Alpine terrain0.32 ms0.11 msabout 0.43 ms
Dense forest (one camera)0.53 ms0.18 msabout 0.71 ms
  • Low and Medium run no GI and no RT, so these passes cost nothing there. Ultra has more probe updates, a fourth cascade and full-resolution reflections and has not been measured per pass.
  • gi-probe-blend is a fixed 0.07 ms in every scene. Everything else scales with foliage and what the camera sees.
  • RTX 3080: roughly 1.7 times these numbers (an estimate, not yet measured per pass), and more in leaf-heavy frames (a gather over a frame full of leaf cards read 1.9 ms on the 3080 against 0.25 ms for opaque terrain; docs/status/hd-gi-gather-leaf2.md).
  • After a camera cut in a leaf view the GI re-converges at 1.4 to 2.2 ms for a short while (llvmpipe and 5080 lane measurements; not gated).
  • Idle cost of having the ray-tracing core built at all: about 0.05 ms and 300 to 420 MiB of GPU memory (docs/status/hd-quality.md).

Known limits

  • GI over thin foliage is dark. Leaves are handled approximately (the gather sees the front hemisphere only), so forest floors, undergrowth and crowns read darker than they should and lack a translucent glow.
  • Probe spacing is coarse, 0.5 m, so thin walls and small gaps can leak or darken a little, and a dim room lit by a small lamp is noisy.
  • Far-terrain patches. GI rays hit a coarse terrain proxy that can sit above the true surface in hollows, which gives soft darker patches (about 10%) on distant hills.
  • Noise and settling. After a camera cut or a fast light change the GI takes a couple of seconds to settle, and small-source interiors stay blotchy longer.
  • Meshes over the ray-tracing binding limit (very large scanned meshes, millions of triangles) are drawn but not traced: no ray-traced shadow, reflection or GI from them, and the log says render.hd.rt_mesh_too_large once per mesh. An automatic simplified copy for such meshes is in progress. Until then use a decimated mesh.
  • Small plants under rt_min_radius_m cast no ray-traced sun shadow when the floor is set, because with ray-traced shadows on the cascades are off. Leave the floor at 0 if small plants must shadow.
  • Captures (splat or probe captures) are not seen by ambient occlusion or GI.
  • No stars and no moon disc in the night sky: night has a moon light and a dark dome only.
  • No aerial perspective under a panorama (hdr) sky. It runs only with "kind": "atmosphere". Under a panorama use the fog preset aerial as the depth cue.
  • The terrain horizon map is off by default. Set horizon: true on the terrain component for terrain shadows past the cascades and valleys that darken when the sun sets behind a ridge (RENDERING.md).
  • Foliage and rough ray-traced reflections: thin foliage pixels skip the reflection ray for cost, so reflections of leaves are not ray traced.

Troubleshooting

Shade looks too dark

  • Ambient occlusion stacks on GI under plants and in shadow. Check ambientOcclusion.enabled in the quality overrides; lower the AO knobs or accept the known foliage limit above.
  • Raise meta.environment.gi.indirectIntensity (or place a giVolume) to lift bounced light.
  • Auto exposure meters a bright sky and leaves shadows low. Shift it with exposure (stops = log2(exposure)), or set exposureMode: "manual".
  • Low and Medium have no GI, so shadowed ground gets only the sky's flat light.
  • A closed mesh around the camera (a backdrop sphere, a room) blocks ray-traced sun shadows and traps GI inside; in a recording or capture the log says render.hd.black_frame. Give the mesh a material file with "castShadows": false.

Looks milky or washed out

  • Fog too thick: a bare fog: {} is 0.02 per metre. Write a preset or a visibilityM.
  • A time-of-day preset brings its own fog (golden-hour and overcast light-haze, dusk valley-mist). Write "fog": { "density": 0 } to remove it.
  • Air too hazy: raise atmosphere.visibilityKm, lower haze, and check aerialScale is not set above 1 for a large world.
  • A tonemap of none or a look with low contrast also flattens the image.

Banding in the sky or on distant slopes. This is not a colour-precision problem. Measured on the 5080: output dithering is on, the sky lookup is clean, and the same view with clouds off is a smooth gradient. The bands are the cloud layer's own structure: the deck has a sharp flat base, and its shadows lie flat on far slopes, most visible in a low-sun glow. clouds.steps does not help (32, 64 and 128 steps give the same image). Change clouds.preset or coverage, or set "clouds": { "preset": "clear" } to remove the layer. A softer cloud base is a planned look change.

Codes to look for (docs/RUNTIME-CODES.md, docs/RULE-CODES.md):

CodeMeans
render.hd.rt_unavailableno ray tracing on this device or build; the screen-space fallbacks are used
quality-unsupported-on-devicea ray-tracing knob fell back because the GPU cannot do it
render.hd.rt_mesh_too_largea mesh is not traced: no RT shadow, reflection or GI from it
render.hd.black_framea frame came out black, often a closed mesh around the camera
render.hd.horizon_map_unavailabledevice too limited for the terrain horizon map
render.hd.cloud_shadow_unavailableclouds draw but cast no shadow on this device
render.hd.rt-deform-over-budgetswaying instances trace their undeformed shape
render-clouds-without-atmospheresky.clouds is set but the sky is not atmosphere
hd-only-ignoreda GI, cloud or exposure field was set on the standard renderer