Skip to content

feat(kit): per-light Cycles baked GI lightmaps and L1 SH probes - #505

Merged
kitlangton merged 2 commits into
mainfrom
kit-lightmaps
Oct 23, 2026
Merged

kitlangton merged 2 commits into
mainfrom
kit-lightmaps

Conversation

@kitlangton

@kitlangton kitlangton commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What it does. Adds per-light indirect lightmaps (128×128×4 rgb9e5ufloat texture array) and a 4×2×4 3D L1 spherical-harmonics probe grid (packages/kit/gpu/gi/lightmap.ts) baked with headless Blender 5.2 Cycles (scripts/bake-room.py), plus a canopy sky-openness baker (bakeCanopyOpenness) for forests. No game turns it on by default; to see it, open the Lab world preset Baked indirect GI (Cycles) (?preset=baked-gi).

How it works.

  1. extractBakeSceneSpec exports the room's packed mesh and physical SceneLight fixtures to scripts/house-bake-scene.json with a SHA-256 input hash (00d64d3e69a5aa26..., verified by assertBakedLightmapFresh).
  2. scripts/bake-room.py imports those triangles and emitters into headless Blender 5.2.2 LTS, unwraps UV2 islands with bpy.ops.uv.lightmap_pack(PREF_BOX_DIV=64, PREF_MARGIN_DIV=0.10), and bakes 3-bounce indirect diffuse light (384 samples, use_adaptive_sampling = False, island-clamped despiking and 4-pass separable binomial smoothing) at unit reference power (energy = 4π · P for spot/point, π · P for cosine AREA panels, multiplied by ENGINE_LIGHT_GAIN = 5.0 in WGSL with zero fudge factor; 0.04% vs closed-form analyticSpotFloorBounce).
  3. At runtime, evaluateBakedLightWeights scales each light layer and probe strictly linearly by (livePower / bakedPower) * giIntensity (returning 0 immediately when a LiveBounceSource such as screenBounceSource is off). Static lightmapped surfaces sample only the UV2 lightmap array; dynamic objects (MAT.actor) sample only the trilinear L1 SH probe volume.

Risk. Kit, Lab world, scripts and docs only. bakedRoom and the :baked renderer variant in packages/kit/lab/world/world.ts are gated on giMode === "baked". Verified by hashing the compiled scene shaders of every game and every non-baked-gi Lab preset plus the Lab world's static mesh bytes against origin/main (b566ecf0):

Target origin/main (b566ecf0) kit-lightmaps Status
kit: sceneShader(true, false) (Brawl / Blackout / Getaway / Carrier) 3a519e694b51a728 3a519e694b51a728 Identical
kit: sceneShader(false, false) (Renderer baseline) 9d6b6514cf214e3c 9d6b6514cf214e3c Identical
kit: sceneShader(true, true) (Renderer motion) 89cf8b6c89a1492b 89cf8b6c89a1492b Identical
kit: makeSceneShader({}, false, false) 5a939988fe356741 5a939988fe356741 Identical
game: Outbreak town scene (shaders.scene) 0aaef9e108110742 0aaef9e108110742 Identical
game: Outbreak vignette scene (vignetteShaders.scene) bf78443910bd56de bf78443910bd56de Identical
game: BARBARA forest scene (forestHooks + treeVertex + cutoutDepth) 9a0de263cba56c04 9a0de263cba56c04 Identical
game: BARBARA batch scene (batchHooks) 7a37736025481bf2 7a37736025481bf2 Identical
game: BARBARA moonlit lake scene (forestLakeHooks) c44ddc6f1ea747f0 c44ddc6f1ea747f0 Identical
game: Lot scene (makeSceneShader(lotHooks)) 984e98afc28efce0 984e98afc28efce0 Identical
game: Nightshift scene (makeSceneShader(nightshiftHooks)) 81e9fe6d870dc599 81e9fe6d870dc599 Identical
game: Archers custom scene (archersSceneShader) 60e2061ffe1189d1 60e2061ffe1189d1 Identical
lab preset: day / night-today (Today scene shader) 3a519e694b51a728 3a519e694b51a728 Identical
lab preset: night-physical / spot-shadows / screen-bench (Physical scene shader) 46074b9e088af2b9 46074b9e088af2b9 Identical
lab preset: finished-props (Physical + finish scene shader) b5ee1abc4c3cdfc0 b5ee1abc4c3cdfc0 Identical
lab preset: finished-props (Today + finish scene shader) e831946f2283ec5f e831946f2283ec5f Identical
lab: WORLD_POST shader 319648dfaf929515 319648dfaf929515 Identical
lab: default world (day) level.chunks[0].data (541,296 B) 0299f39c500ff018 0299f39c500ff018 Identical
lab: screen-bench level.chunks[0].data (616,608 B) c7eba7a1afd1b8c7 c7eba7a1afd1b8c7 Identical
lab: finished-props level.chunks[0].data (809,280 B) f51eca92c8f718a1 f51eca92c8f718a1 Identical

Proof. All stills captured at the reframed BAKED_GI_CAMERA (target: [-4.72, 1.42, -11.15], yaw: -0.52, pitch: -0.01, dist: 4.35, 960×600) with fixed exposure (grade = [1.0, 0, 0, 1.45], shadowLift = 0, lensBloom = 0.25, skyLight = 0.015, giIntensity = 1.0, giProbes = 1.0). Paired GPU cost: 1.989 ms Today vs 2.015 ms Baked GI (+0.026 ms, budget ≤ 0.30 ms; 257.5 KiB GPU memory).

  1. Lamp ON — Today (left) vs Cycles Baked GI (right), v2 reframed camera & 384-sample blotch-free ceiling:
03-lamp-on-paired-v2
  1. Lamp OFF — Today (left) vs Cycles Baked GI (right), zero residual bounce:
06-lamp-off-paired
  1. CRT Colour Change — Cyan (left) vs Warm Red (right), live runtime re-tint via screenBounceSource:
11-crt-colour-paired
Condition & Region (960×600 crop) Today Before (R, G, B) Today Luma (/255) Baked GI After (R, G, B) Baked GI Luma (/255) Delta Luma
Lamp ON — Ceiling above lamp (420..740, 12..95) (2.20, 2.40, 2.91) 2.39 (99.66, 43.59, 24.07) 54.10 +51.71
Lamp ON — Back wall near lamp (360..530, 150..275) (2.83, 3.14, 3.93) 3.13 (62.91, 23.73, 13.60) 31.33 +28.20
Lamp ON — Dark left corner (15..140, 20..130) (2.51, 2.76, 3.42) 2.76 (35.75, 12.07, 7.54) 16.78 +14.02 (0.31× ceiling)
Lamp ON — Bookcase & dynamic actor (40..320, 240..485) (10.13, 9.98, 12.32) 10.18 (23.04, 12.65, 13.19) 14.90 +4.72 (+12.91 R)
Lamp ON — Rug pool under lamp (560..840, 480..588) (213.21, 194.54, 171.74) 196.86 (214.65, 195.28, 172.25) 197.74 +0.88
Lamp OFF — Full frame (0..960, 0..600) (5.65, 5.42, 6.21) 5.53 (5.65, 5.42, 6.21) 5.53 0.00
Lamp OFF — Ceiling above lamp (420..740, 12..95) (2.20, 2.40, 2.91) 2.39 (2.20, 2.40, 2.91) 2.39 0.00
CRT Cyan — Back wall (360..530, 150..275) (2.83, 3.14, 3.93) 3.13 (8.48, 23.88, 28.71) 20.96 +17.83 (B: +24.78)
CRT Red — Back wall (360..530, 150..275) (2.83, 3.14, 3.93) 3.13 (43.80, 9.99, 7.10) 16.97 +13.84 (R: +40.97)
  • bun test packages/kit/gpu/gi/lightmap.test.ts packages/kit/lab/world/world.test.ts packages/kit/architecture-map.test.ts (HiveMind mini): 30 pass
  • bun run --cwd packages/kit typecheck && bun run --cwd games/lab typecheck && bun run check:scripts (HiveMind mini): clean
  • hivemind run --kind browser --browser-approval "Kit requested baked-gi v2 framing & ceiling rebake proof" --worker mini -- bun run verify:smoke --game lab: build + smoke ok (5.0s)
  • LIGHTMAP_PROOF_DIR=/Users/kit/code/home/artifacts/kit-lightmaps-2026-10-23 deno run --unstable-webgpu --sloppy-imports --allow-env --allow-read --allow-write scripts/lightmap-gpu-proof.ts: 0 WebGPU errors, todayBaselineMaxByteDiff = 0, all assertions pass

@kitlangton
kitlangton merged commit 0738e53 into main Oct 23, 2026
15 checks passed
@kitlangton
kitlangton deleted the kit-lightmaps branch October 23, 2026 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant