From 011037e70cccc21949af273af4182c7eae06fc72 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Tue, 14 Jul 2026 21:31:58 -0700 Subject: [PATCH] =?UTF-8?q?Docs:=20art-dev=20cookbook=20=E2=80=94=20locked?= =?UTF-8?q?=20lighting=20+=20posed-static=20hero=20bake?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'Light is territory' pool lighting (reads top-down; vertical god-rays don't), undulating seabed mesh, Play-mode ambiance script, and the apply-armature + visual-transform static hero-bake recipe for style-proof placement. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../art-dev/references/blender-cookbook.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.claude/skills/art-dev/references/blender-cookbook.md b/.claude/skills/art-dev/references/blender-cookbook.md index bcf954729..f6625b8ff 100644 --- a/.claude/skills/art-dev/references/blender-cookbook.md +++ b/.claude/skills/art-dev/references/blender-cookbook.md @@ -249,4 +249,21 @@ A committed dev scene set up in the **correct A0 conditions** so the operator ca - **To verify a newly-baked asset:** `import_model_file` the glb → assign the shared material (`M_Lit_Palette` statics; emissive bulbs → an HDR-emission material so bloom triggers) → `PrefabUtility.InstantiatePrefab(asset, scene)` into ArtStaging at a slot → `SaveScene` → tell the operator to open it, OR render `Camera.main` via §11. - ⚠ Opening ArtStaging `Single` closes the active scene — only do it when the editor is free / operator-authorized (a parallel agent's scene would be swapped out). Check `editor/state` first; the scene must be clean before swapping. - Beginner view steps to hand over: open the scene (double-click in Project ▸ Assets/Scenes), **orbit** = middle-mouse drag, **zoom** = scroll, **frame a selected object** = `F`, **Game tab** shows the gameplay-angle camera. + +### Underwater ambiance recipe (built into ArtStaging — the gameplay-env prototype) +The staging env IS the gameplay ambiance (build it from real systems so it transfers). Elements that made it read "underwater" (vs a bland dark disc): +- **Caustics** = a tileable cookie on an overhead **Spot** light (dappled seabed light). Generate procedurally (sum of `Sin` interference, `pow(1-abs(n), k)` for bright ridges), save PNG, importer `wrapMode=Repeat`, `light.cookie=tex`; spot ~4.5m up, angle ~85°, cool color, intensity ~40 (spots need high intensity). ⚠ a texture `SaveAndReimport` mid-render → one BLACK frame; just re-render. +- **Marine snow** = a `ParticleSystem` (real gameplay system): World sim space, ~500 particles, `startSpeed`~0.03, tiny size, cool-white low-alpha, box shape ~9×5×9, `noise` on for wander, slight negative gravity (drift up). Renderer material = `Sprites/Default` + a generated soft-dot texture. ⚠ edit-mode doesn't auto-play — `ps.Clear(); ps.Simulate(10f,true,true); ps.Pause();` **before** rendering. +- **Depth fog** teal (`ExponentialSquared`, cool color), **cool grade** (WhiteBalance temp ~-20, Vignette dark-teal), lifted cool **ambient** (Flat ~0.09,0.16,0.20), warm-key vs cold-fill contrast + a warm point "pool" (the beacon-in-murk look). +- **Seabed dressing** = scatter real meshes (my flora as bioluminescent ground-clutter = the readability-law density dial; Synty rocks as boulders). ⚠ **Synty rocks import HUGE** (DungeonRealms boulders are multi-metre) — never scatter at raw scale; **bounds-normalize**: instantiate at scale 1, measure `MeshRenderer.bounds` max dim, `scale = targetMetres / maxDim` (target ~0.35–1.0 m), then place. Strip colliders on cosmetic dressing. + +### ★ LOCKED lighting = "light is territory" (the thematic template; reads TOP-DOWN) +The direction that landed (operator-approved): **the interest lives in the LIGHTING, not geometry.** +- ⚠ **Vertical god-ray shafts DON'T read from a top-down camera** — you look straight down them. Tried, removed. For a top-down ARPG, thematic light must live in **pools ON the ground.** +- **Warm beacon pool** (a warm point light) = "our light / safe territory." **Cold bioluminescent pools** = a cold-teal point light AT each glow-flora (emissive meshes don't illuminate — add real lights). **Deep dark between** the pools (drop ambient to ~0.03,0.055,0.08, gentle key ~1.2 for form only) → chiaroscuro. This IS the "light is territory" pillar, made literal, and it reads perfectly top-down. +- **Undulating seabed mesh** (not a disc — a disc reads as a platform): procedural grid + layered `PerlinNoise` height, **damped to flat within ~2 m of the hero assets**, extended past the fog cutoff so the edge fades to murk. Flat-faceted (per-quad verts). Save as a `.asset` mesh so it persists. +- **Dynamic layer** = a Play-mode `MonoBehaviour` (`StagingAmbiance`) modulating **LIGHTS ONLY** (no material writes → nothing persists on Play exit): slow-spin the caustics spot, flicker the beacon, sine-pulse the flora pool intensities. Self-wires by `GameObject.Find`. ⚠ hitting Play in a non-menu scene runs `GameBootstrap` (spawns netcode worlds) — harmless to the visual, just background noise. + +### Posed STATIC hero bake (style-proof placement without the Rukhanka pipeline) +To drop a posed suit/creature into the staging scene as a static mesh (skinned Rukhanka bake is separate `/dots-dev` work): in Blender — **apply the `Armature` modifier** on each skinned mesh (bakes the current pose into geometry), **`visual_transform_apply` + clear constraints** on bone-parented kit (eyes/lamp Child-Of), then export a static glb (meshes only, no armature). ⚠ both `modifier_apply` and `export_scene.gltf` need the **window `temp_override`** after `open_mainfile` (context.active_object). Import via `import_model_file`, `InstantiatePrefab` at the slot — glTFast carries the embedded materials (Synty atlas + emission). ```