Advanced lighting

Usage guide of the render.raytrace kit: declare an advanced lighting mode (global illumination, ray tracing) once for every engine, its profile, the raster changes while it is active, the history resets, the hook and the raster fallback.

Source: module-kits:kits/render_raytrace/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs render-raytraceMCP tool: gripforge_docs { "topic": "render-raytrace" }

Advanced lighting in your game (render.raytrace) #

You declare the lighting mode of your game once; each engine applies it with its own tool. Readable offline: gripforge docs render-raytrace, or the MCP tool gripforge_docs (topic render-raytrace).

What it is for #

The kit decides whether the advanced lighting path (global illumination by ray tracing) is used, and publishes the answer; the engine applies it through its adapter: solari in the Bevy player, sdfgi in Godot, hdrp-rt in Unity, lumen in Unreal. The engine only reports facts (what it loaded, what the GPU supports); it never decides. The default is the raster rendering: a game that does not ask for anything draws as before. Where the advanced path cannot run (the web players have no ray tracing, an adapter is missing, the GPU is too old) the raster rendering takes over with a reason; the game never gets an error for it.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "render.raytrace" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "render.raytrace",
                              config: { "mode": "auto" } }

It requires game.engine. mode is off (default), auto (advanced where the engine reports it can) or on (asked for; the raster rendering still takes over, with the reason, where the engine cannot).

First example #

<!-- test: kits/game_engine/host/tests/render_raytrace.rs::raster_is_the_default_and_the_decision_follows_the_report --> With { "mode": "on" } and an engine that reported { engine: "bevy", target: "native", loaded: true, supported: true }, state() answers active: true, path: "raytraced", adapter: "solari", reason: "requested". If the same engine reports target: "webgpu", active is false and reason is "web-no-ray-tracing".

Configuration #

KeyDefaultMeaning
modeoffoff, auto or on
profile.restirtruereuse light samples between pixels and frames
profile.denoisetruedenoise the lighting
profile.spatialPasses2spatial reuse passes, 1 to 3
profile.maxHistory32frames of history a sample may be reused for, 1 to 64
profile.taatruetemporal anti-aliasing
profile.sharpening0.6sharpening strength, 0 to 1 (0 = none)
profile.mipBias0texture mip bias while active
profile.gidynamickind of global illumination where the engine has the choice: dynamic, volume or baked
profile.cascades4cascades of the dynamic global illumination, 1 to 8
profile.cellSize0.2size in metres of a cell of the first cascade
profile.occlusionfalseocclusion of the indirect light by the scene (against leaks through thin walls)
profile.bounce0.5share of the indirect light bounced again, 0 to 1.99
raster.msaa1multisampling while active: 1, 2 or 4
raster.ssaofalsekeep the screen-space occlusion while active
raster.sunShadowMapsfalsekeep the sun shadow maps while active
raster.hdrtruehigh dynamic range rendering while active
raster.probesfalsekeep the raster radiance probes while active
resetOnengine.scene.entered, camera.cut, lighting.cuttopics that restart the temporal history

raster is what the engine changes of its own raster rendering while the advanced path is active; when it is not, the engine keeps its own settings and state().raster is empty. With the Godot adapter (sdfgi) state().raster only carries msaa and ssao: its global illumination lights the indirect light only, so the sun keeps its shadow maps and Godot keeps its probes and HDR. Every key is moddable.

The decision #

In this order: mode off gives raster (off); no report from the engine gives raster (engine-unreported); a web target gives raster (web-no-ray-tracing); an adapter that is not loaded gives raster (adapter-not-implemented for Unity and Unreal, adapter-missing otherwise); a GPU or a renderer that does not support it gives raster (gpu-unsupported, the engine's detail says why); auto on a GPU that emulates ray tracing (the report's hardware: false: Apple M1, M2) gives raster (gpu-software-ray-tracing; on and a tap of the hook still turn it on); otherwise the advanced path is active (requested for on, auto-capable for auto).

History resets #

The advanced path accumulates light over frames. After a camera cut, a sudden change of light or a new scene that history must restart, otherwise the image ghosts. The kit listens to the topics of resetOn, raises the history generation and emits raytrace.history.reset { generation, reason } (the reason is the topic). camera.cut and lighting.cut are generic topics: a camera kit, a lighting kit, your game or a mod emits them at the right moment. resetHistory(reason) does the same by hand.

Hook, mods, service #

WhatNameDetail
Hookrender.raytrace.decidemutable active, profile, raster; cancellable (raster, reason hook); applied after the base decision
Moddable configmode, profile, raster, resetOna mod changes them like the game does
Eventraytrace.changed { epoch }the decision, the profile or the history changed; engines read state() again
Eventraytrace.history.reset { generation, reason }the temporal history restarts

A tap of the hook can never make active an engine that reported it cannot (not loaded, not supported, web).

Service render.raytrace: state(), setMode(mode), setProfile(partial | null), resetHistory(reason), reportEngine(report), engineReport().

state() answers { epoch, mode, active, path, adapter, reason, detail, profile, raster, history, adapters, engine }. path is raster or raytraced; adapters lists the adapter of each engine and whether it is implemented; engine is the last report or null.

Engines #

EngineAdapterStatus
Bevy (native)solariimplemented
Godot (Forward+)sdfgiimplemented: SDFGI, or VoxelGI / LightmapGI by profile.gi
Godot (Compatibility, Mobile, web export)sdfgino SDFGI there: raster, reason gpu-unsupported (web-no-ray-tracing on the web)
Unityhdrp-rtnot implemented yet: raster, reason adapter-not-implemented
Unreallumennot implemented yet: raster, reason adapter-not-implemented
Web players (WebGPU, WebGL2)noneraster, reason web-no-ray-tracing

Godot #

The Godot adapter applies the decision with Godot's own global illumination, on the Forward+ renderer:

  • profile.gi: "dynamic" (default): Environment.sdfgi_enabled with cascades, cellSize (sdfgi_min_cell_size), occlusion and bounce (sdfgi_bounce_feedback). Good for open and large scenes that change.
  • "volume": a VoxelGI over the bounds of the scene, baked when it turns on (and again on a history reset). Good for small closed scenes.
  • "baked": the LightmapGI nodes your game baked in the Godot editor are shown. Good for static scenes; nothing is baked at run time.
  • raster.ssao: false turns SSAO and SSIL off, raster.msaa sets the viewport's 3D multisampling, profile.taa its TAA. When the module turns the advanced path off, every value the adapter changed is given back.
  • History reset (history.generation): SDFGI is switched off for one frame so Godot rebuilds its cascades; a VoxelGI is baked again. Never guessed from the camera.

On the Compatibility or Mobile renderer (and in a web export) the adapter reports supported: false with the renderer in detail: the module answers raster. The decision, the report and the adapter's counters (technique, renderer, historyResets, voxelBakes) are in the debug snapshot under render.extra.raytrace.

When it does not do what you expect #

SymptomCause and fix
The image stays rasterread state().reason and state().detail: the mode is off, the engine has not reported, or it cannot
The light ghosts after a cutemit camera.cut or lighting.cut, or call resetHistory
Godot stays rasterthe project runs the Compatibility or Mobile renderer: choose Forward+ (rendering/renderer/rendering_method)
Godot light leaks through wallsprofile.occlusion: true, a smaller profile.cellSize, or profile.gi: "volume" for a closed scene
Everything is too soft or too noisylower profile.maxHistory, raise profile.sharpening or profile.spatialPasses

<!-- kit-services:begin -->

Services this kit uses (and that you can provide) #

This kit consumes no service from another kit. <!-- kit-services:end -->