Docs: art-dev cookbook — Unity render-harness + staging-scene recipes

Adds the in-engine verification recipe (URP SubmitRenderRequest render
harness, layer sign-bit gotcha, game-camera check) and the persistent
ArtStaging scene recipe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-14 14:56:52 -07:00
parent 4ee73e3872
commit 81f7db0cfa
@@ -223,4 +223,30 @@ bpy.ops.export_scene.gltf(filepath=SRC + r"\SM_<Name>.glb", export_format='GLB',
use_selection=True, export_apply=True, export_yup=True)
```
Skinned/animation export → the per-action FBX recipe in [[blender-mcp-and-unity-mcp-v10]] (`bake_anim_use_all_bones`, `bake_anim_force_startend_keying`, `apply_scale_options='FBX_SCALE_UNITS'`, `add_leaf_bones=False`; Unity import `CreateFromThisModel`). **Never export into `Assets/` while a Unity session may be live** — write to `ArtSource/`, bake in later.
## 11. In-engine verification (Unity URP render harness) — the REAL A0 check
Blender previews are a proxy; the gate is the asset in **URP** under murk + bloom + the game camera. Import + render via UnityMCP (only when the editor is free / operator granted it — else stay read-only):
1. **Import** the glb: `import_model_file(source_path=<ArtSource glb>, output_folder="Assets/_Project/Art/Models", name=...)` — needs the leading `Assets/`; glTFast handles glb + scale.
2. **Confirm the shared material samples the atlas** — the palette ShaderGraphs expose it as **`_BaseColorMap`** (NOT `_BaseMap`/`mainTexture`, so `mat.mainTexture` reads null — that's fine): `ShaderUtil` enumerate or `mat.GetTexture("_BaseColorMap")`.
3. **Render harness** (`execute_code`, C#): load the `Mesh` from the imported glb, spawn a temp GO (mesh + shared material) on an **isolated layer**, warm-key + cold-fill directional lights (`cullingMask` = that layer), murk ambient (save+restore `RenderSettings.ambientMode/ambientLight`), a temp `Camera` (SolidColor murk bg, `cullingMask` = that layer, **FOV 55**) positioned at the **game angle** and framed by `MeshRenderer.bounds`, then **`RenderPipeline.SubmitRenderRequest(cam, new StandardRequest{destination=rt})`** (URP — `Camera.Render()` is unreliable) → `ReadPixels``EncodeToPNG` to OS temp → `Read` the PNG. `DestroyImmediate` all temp objects; never save the open scene.
-**Layer sign-bit:** `1<<31` is NEGATIVE → a broken culling mask that renders NOTHING (all-black). Use **layer ≤ 30**.
- ⚠ Set `cam.cullingMask` to ONLY the temp layer so the open scene's geometry doesn't leak into the shot (`~0` renders the whole scene).
- Game-cam offset from target: `(horiz*cos(pitch) + up*sin(pitch))*dist`, `horiz=(sin(yaw),0,-cos(yaw))`, pitch 45°, then `cam.transform.LookAt(center)`.
```csharp
// core render call (URP)
var rt=new UnityEngine.RenderTexture(1000,1000,24); rt.Create();
var req=new UnityEngine.Rendering.RenderPipeline.StandardRequest(); req.destination=rt;
UnityEngine.Rendering.RenderPipeline.SubmitRenderRequest(cam, req);
UnityEngine.RenderTexture.active=rt; var tex=new UnityEngine.Texture2D(1000,1000,UnityEngine.TextureFormat.RGBA32,false);
tex.ReadPixels(new UnityEngine.Rect(0,0,1000,1000),0,0); tex.Apply();
System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex));
```
**Findings from the first bake (crate):** the palette single-material pipeline works in URP; a pure-murk render reads *dark* (in-game URP bloom + scene fill lift it); grey under a warm key reads brownish (expected, not a bug). Skinned assets (suit/creatures) need the Rukhanka path + `Skinned-Palette` — hand to `/dots-dev`.
## 12. The persistent staging scene (`Assets/Scenes/ArtStaging.unity`) — the operator's in-engine view
A committed dev scene set up in the **correct A0 conditions** so the operator can OPEN it and inspect assets live (Scene-view orbit) at the gameplay angle: murk env (cold flat ambient + `ExponentialSquared` fog, no skybox), **warm-key + cold-gloam directional lights + a warm point pool**, a **Main Camera at the game angle** (pitch ~4245°, FOV 55, `UniversalAdditionalCameraData.renderPostProcessing=true`), and a **global Volume** (profile `Assets/_Project/Art/Materials/Staging/StagingVolume.asset`: **Bloom** thr~0.85/int~1.1 — makes Emissive-Gloam glow — + **Tonemapping ACES** + **ColorAdjustments** postExposure/saturation = the capture grade), on a dark faceted pedestal. Contains labeled `SLOT_*` empties for pending assets.
- **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.
```