HammeriteLightmapper

Core: lighting. Inherits RefCounted

Bakes a map's light into lightmaps on its faces and props and into its light probes, on the GPU.

var lightmapper := HammeriteLightmapper.new(map, settings)
lightmapper.yield_to = get_tree()       # optional: give the tree frames while it bakes
if await lightmapper.bake(progress) == OK:
HammeriteDataFile.write(map, path)

bake() is the whole bake. Its steps - prepare(), transfer(), write_lightmaps(), write_probes() - are there for a caller that has to do something between them, and must be taken in that order. Needs a RenderingDevice (can_bake()). docs/baking.md has the rest.

Properties

TypeNameDefault
boolenable_diagnostic_reportfalse
HammeriteLightmapBakeReportbake_reportnull
SceneTreeyield_tonull
boolcancelledfalse
HammeriteBakeSettingssettingsnull

Methods

ReturnsMethod
voidcancel()
boolcan_bake() static
intbake(progress_cb: Callable = Callable())
intquick_bake(progress_cb: Callable = Callable())
voidprepare(progress_cb: Callable = Callable())
voidtransfer(bounce_count: int = -1, progress_cb: Callable = Callable())
voidwrite_lightmaps(progress_cb: Callable = Callable())
voidwrite_probes()

Property descriptions

enable_diagnostic_report

var enable_diagnostic_report: bool = false

Write a detailed per-pass report of the bake to a text file in HammeriteLightmapperDiagnosticReport.DEFAULT_DIRECTORY, and every atlas beside it as a PNG, for debugging the lightmapper itself. Off, because a bake is not something that should leave files behind unasked.

bake_report

var bake_report: HammeriteLightmapBakeReport = null

Lean, in-memory, per-pass energy report (HammeriteLightmapBakeReport), always built and left available after the bake so tests and debugging can assert on the static+dynamic, patch+probe energy flow between passes - the thing the verbose _diagnostic_report (dynamic-only, patch-only, write-to-file) cannot show. Rebuilt at the start of each transfer(). Cheap: pure CPU aggregation over data the per-pass readback already decoded.

yield_to

var yield_to: SceneTree = null

Set, a bake that is awaited gives this tree a frame every _YIELD_MS or so - between GPU submits, and between faces - so an editor can draw its progress and take a Cancel. Unset, a bake runs straight through and need not be awaited.

cancelled

var cancelled: bool = false

Whether the bake under way, or the last one, was stopped - by cancel(), or by transfer() when this process cannot bake (see can_bake()). Cleared as a bake starts.

settings

var settings: HammeriteBakeSettings = null

How the bake is done. Shared with nothing: a lightmapper reads its own, made fresh when none is given.

Method descriptions

cancel()

func cancel() -> void

Stop the bake under way at its next chance. bake() puts back the lighting it began with; a caller running the steps itself has what it began with to put back (see HammeriteMap.snapshot_lighting()). A stopped bake cannot be continued.

can_bake()

static func can_bake() -> bool

False under the Compatibility renderer, on the web and in a --headless run: a bake dispatches compute shaders on a RenderingDevice, and those have none. A map baked elsewhere still displays there.

bake()

func bake(progress_cb: Callable = Callable()) -> int

Bake the map as settings say: new light probes, then prepare(), transfer(), write_lightmaps() and write_probes(). The lighting the map had stays on it until the new lighting is written over it, and is put back whole if the bake is cancelled. progress_cb is called as progress_cb(stage: String, current: int, total: int). Await it: with yield_to set it gives that tree frames as it goes. OK when baked; ERR_UNAVAILABLE where this process cannot bake (can_bake()); ERR_SKIP when it was cancelled.

quick_bake()

func quick_bake(progress_cb: Callable = Callable()) -> int

Lights the faces that have no lighting - the walls an edit has moved, cut or made since the last bake - by direct light alone, and leaves the rest as they are: the other walls, the props and the probes. A face a bake has already left dark is not tried again (HammeriteMap.dark_surfaces). Only the lights that can see one of the faces take part, and only the rock and brushwork around them and those lights shadows them. Each bake adds atlases of its own, which the next full bake packs together again. The bake stays as out of date as it was (see HammeriteMap.store_partial_bake()). Returns how many faces it lit; when it was cancelled, the lighting is put back as it was.

prepare()

func prepare(progress_cb: Callable = Callable()) -> void

Step 1 of a bake: finds the faces, props and lights to bake, unwraps them, and cuts them into the patches light is carried between. Clears cancelled. Awaitable; see yield_to.

transfer()

func transfer(bounce_count: int = -1, progress_cb: Callable = Callable()) -> void

Step 2 of a bake, after prepare(): the direct pass, then, when bounce_count - by default HammeriteBakeSettings.bounces - is above 0, a gather into the probes, bounce_count - 1 probe-to-probe bounces and a distribute back onto the texels. 0 is direct light only. Creates and frees its own local RenderingDevice; where there is none it reports an error and sets cancelled. Rebuilds bake_report. Awaitable; see yield_to.

write_lightmaps()

func write_lightmaps(progress_cb: Callable = Callable()) -> void

Step 3 of a bake, after transfer(): groups and packs the faces into atlases, writes the textures, and assigns them to every baked face and prop. Records the bake's warnings and baked surfaces on the map and notifies its views. Call write_probes() after it. Awaitable; see yield_to.

write_probes()

func write_probes() -> void

The last step of a bake, after write_lightmaps(): tone-maps each lit probe's radiosity and gives it the HammeriteBakedLights that reach it, then tells the map its probes are baked. Once per bake: a second call does nothing.

Hammerite 1.0 · built from a6dd634, 2026-10-10