Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commitdd348ac6c3

README.md

baking

Shared utilities for the globalIllumination package's lightmap and probe bakers — light gathering, surface-attribute gathering (albedo + emissive per instance), transform helpers, and the scene-geometry gather that feeds compute.buildBvh. The lowest layer of the package; both bakers consume the same primitives so the lighting model stays consistent across the lightmap and probe pipelines.

Exports

Constants:

  • Baking.SH_COEFFS = 9 — number of L2 SH basis functions per probe.

  • Baking.SH_FLOATS_PER_PROBE = 36 — std430-padded SH stride.

  • Baking.TRI_FLOATS = 72 — std430-padded triangle stride (matches the BVH builder).

  • Baking.BVH_NODE_FLOATS = 8 — floats per BVH node on the GPU.

  • Baking.LIGHT_FLOATS = 16 — GPU light record stride.

  • Baking.RAY_BUDGET_PER_FRAME = 1048576 — estimated ray traversals of bake work one frame carries.

  • Baking.PER_THREAD_RAY_CAP = 1024 — rays one invocation traces in one sample pass.

  • Baking.OCCUPANCY_TARGET = 16384 — invocations per dispatch the plan aims for.

  • Baking.MAX_FRAMES_IN_FLIGHT = 2 — fenced frames of bake work queued on the GPU at once.

  • Baking.LIGHTMAP_BYTES_PER_TEXEL = 144 — GPU bytes one lightmap texel holds while its receiver bakes.

Functions:

  • Baking.vec3 / add / sub / scale / dot / cross / length / normalize — vec3 helpers used everywhere downstream.
  • Baking.lightsTraced(lights) -> { direct, path } / Baking.lightmapRays(spec) / Baking.probeRays(spec) — the cost model: estimated rays per texel or probe.
  • Baking.planChunks(spec) -> { Chunk } — split a bake into dispatches that each stay inside a ray budget.
  • Baking.bakeLimits(pageSize) -> BakeLimits — the memory budget and the largest lightmap resolution this device bakes.
  • Baking.newGpuScheduler(opts) -> GpuScheduler — issue a pass's dispatches a frame's worth at a time, fenced, checking the device. A wait for one drawn frame is bounded to 30 seconds of real time (frameWaitSeconds); a renderer that draws none in that time raises naming the device's state.
  • Baking.beginGpuPass(programs) / Baking.gpuFailureCause(start) -> string — say why queued GPU work did not produce its result: a lost device, a dispatch that failed since the pass began, an error the device reported.
  • Baking.gatherLights() -> { Light } — enumerate every Light component in the scene.
  • Baking.packLights(lights) -> FloatArray — pack lights for compute upload.
  • Baking.transformPoint / transformNormal / makeMatrix / entityWorldMatrix — 4x4 matrix helpers.
  • Baking.surfaceAttributes(entityId, cache) -> { albedo, emissive } — the entity's bake-facing surface description: linear albedo (base_color factor × average base-color texture color, clamped below 1) and emissive (color × strength).
  • Baking.gatherMeshInstances(excludeIds?) -> { instances, release } — every mesh-bearing entity as a { guid, transform, attributes } record for compute.buildBvh, CPU mesh items materialised; release() drops them again.
  • Baking.getEntityTriangles(entityId) -> { Triangle } — one entity's mesh triangles in local space (used by the UV rasterizer).

Types:

  • Vec3 = { x: number, y: number, z: number }
  • ColorRGB = { r: number, g: number, b: number }
  • UV = { x: number, y: number }
  • Mat4 = { number } — 16-float row-major.
  • Light = { id, kind, position, direction, color, intensity, radius }
  • Triangle = { v0, v1, v2, n0, n1, n2, uv0, uv1, uv2 }

Usage

local Baking = require("@builtin::systems.globalIllumination.baking")

local lights = Baking.gatherLights()
local gather = Baking.gatherMeshInstances({ entityId })
local bvh = compute.buildBvh(gather.instances)
gather.release()

Notes

  • The cost model counts lightmapRays: 17 + 64 * direct + 64 (contact occlusion) rays per texel in the direct stage, then bounces * (1 + path) per chain; probeRays counts bounces * (1 + path) per sample plus path + 6 in the last pass. It is an upper bound: a path that ends early still counts.
  • A scheduler's gate waits for the pass's programs to compile (a dispatch queued behind a compile drains with every other held dispatch in one frame), issue(rays, fn) runs fn inside the frame's budget, finish waits for the last fence, check raises when the device was lost or replaced, close frees the fence buffer, and stats reports { frames, maxRaysPerFrame, maxDispatchesPerFrame, totalRays, rayBudget, oversizeChunks, fenceGiveUps }.
  • All vec3 helpers return new tables — none mutate their arguments. Safe to call in hot paths but allocates per call.
  • gatherMeshInstances walks entity.findAll and materialises each mesh-bearing entity's CPU item (ecs.Mesh guid → mesh asset → ref:load()), so the engine-side BVH build can read the geometry — triangles never enter the Luau heap. Call release() after the build; assets whose keepCpu setting holds them stay resident.
  • surfaceAttributes deduplicates the texture averaging through the cache table — pass one table per gather so entities sharing a material average its texture once. Albedo lanes are clamped to 0.96 so multi-bounce transport converges.