① One-shot authoring
model claude-fable-5 · 121 tool calls · 50m19s · cost $20.197310000000005
•STEP #1
I'll start by reading `Room.md` and `Room.py` in full, then study the stitched references.
📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /home/zelda/zh340/.claude/projects/-scra🔧 ToolSearch select:mcp__cap__render,mcp__cap__fetch_📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen🎨 fetch_material blue office carpet tiles low pile🎨 fetch_material white painted brick wall🎨 fetch_material office suspended ceiling tile
✏️EDIT #2
The carpet match was flagged weak — let me inspect the recoloured diffuse before wiring it.
📄 Read /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash🖼 render room📄 Read /home/zelda/zh340/.claude/projects/-scra⌘ Bash⌘ Bash⌘ Bash
•STEP #3
The room rebuilt cleanly with the harness layer. Now the per-wall verification — reading each compare (ortho render | rectified stitch).
📄 Read /tmp/psi_ref/Wall0_compare.png📄 Read /tmp/psi_ref/Wall1_compare.png
✏️EDIT #4
The comparisons are too small to judge silhouettes — let me crop and enlarge each half.
⌘ Bash⌘ Bash📄 Read /tmp/psi_ref/big/Wall0_render.png📄 Read /tmp/psi_ref/big/Wall0_real.png📄 Read /tmp/psi_ref/big/Wall1_render.png📄 Read /tmp/psi_ref/big/Wall1_real.png📄 Read /tmp/psi_ref/big/Wall2_render.png📄 Read /tmp/psi_ref/big/Wall2_real.png📄 Read /tmp/psi_ref/big/Wall3_render.png📄 Read /tmp/psi_ref/big/Wall3_real.png📄 Read /tmp/psi_ref/big/Ceiling0_render.png📄 Read /tmp/psi_ref/big/Ceiling0_real.png📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /tmp/psi_ref/Floor0_compare.png🎨 fetch_material white painted brick wall✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen
✏️EDIT #5
Now the ceiling T-bar grid (the room is an exact parallelogram, so an affine a/b grid covers it):
✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash⌘ Bash📄 Read /tmp/psi_ref2/big/Wall2_render.png📄 Read /tmp/psi_ref2/big/Wall3_render.png📄 Read /tmp/psi_ref2/big/Wall1_render.png📄 Read /tmp/psi_ref2/big/Ceiling0_render.png
✏️EDIT #6
All four walls now match. Let me spot-check perspective frames for floating/clipping artifacts, then run the critic.
📄 Read /tmp/psi_ref2/Wall1_frame_00004.png📄 Read /tmp/psi_ref2/Wall3_frame_00016.png📄 Read /tmp/psi_ref2/Wall0_frame_00087.png⚖️ critic✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash⌘ Bash📄 Read /tmp/psi_ref3/big/Wall1_render.png📄 Read /tmp/psi_ref3/big/Wall0_render.png⚖️ critic
✏️EDIT #7
Checking frame 27 before adjusting blinds — I need to see which windows the critic says should be open.
📄 Read /tmp/psi_ref3/Wall1_frame_00027.png📄 Read /tmp/psi_ref3/Wall1_frame_00004.png🎨 fetch_material white painted brick wall✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref4/big/Wall1_render.png📄 Read /tmp/psi_ref4/big/Wall0_render.png📄 Read /tmp/psi_ref4/big/Wall3_render.png⌘ Bash📄 Read /tmp/psi_ref4/big/W5_zoom.png✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref5/big/Wall1_render.png📄 Read /tmp/psi_ref5/Wall1_frame_00027.png✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref6/W5_zoom.png⚖️ critic📄 Read /tmp/psi_ref5/Wall0_frame_00082.png📄 Read /tmp/psi_ref5/Wall3_frame_00014.png✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref7/Wall0_frame_00082.png📄 Read /tmp/psi_ref7/Wall3_frame_00014.png📄 Read /tmp/psi_ref7/Wall0_frame_00087.png✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref8/Wall0_frame_00082.png📄 Read /tmp/psi_ref8/big/Wall0_render.png
✏️EDIT #8
Much better — the partition reads as clear glass with scattered notices. Final critic gate.
⚖️ critic✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref9/big/Wall0_render.png📄 Read /tmp/psi_ref9/Wall0_frame_00082.png📄 Read /tmp/psi_ref9/big/Wall1_render.png📄 Read /tmp/psi_ref9/big/Wall2_render.png
✏️EDIT #9
All fixes landed. Final critic check.
⚖️ critic✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /tmp/psi_ref10/big/Wall0_render.png📄 Read /tmp/psi_ref10/big/Wall3_render.png📄 Read /tmp/psi_ref10/Wall0_frame_00082.png📄 Read /tmp/psi_ref10/Wall3_frame_00016.png✏️ Write /home/zelda/zh340/.claude/projects/-scra⌘ Bash
•STEP #10
Done — `Room.py` now carries the full harness layer (structure fixes, materials, ceiling, and ~30 grouped multi-part fixtures), compiles, and rebuilds
Authoring — model summary
Done — `Room.py` now carries the full harness layer (structure fixes, materials, ceiling, and ~30 grouped multi-part fixtures), compiles, and rebuilds cleanly; every wall was render-verified against the stitches and capture frames over 10 iterations, with fixes applied after each look.
**Shell structure corrections (evidence-based, in `SHELL`):** both internal windows on the door wall were badly under-sized by the scan — the real room has wide glazed corridor partitions on either side of the double door. `Window0` → offset 1.25 / width 1.55 / sill 1.0 / height 1.4, `Window1` → offset 4.95 / width 1.9 / sill 1.0 / height 1.4 (confirmed by frames 82/14/87). No furniture boxes were touched.
**Materials:** blue carpet tiles (Poly Haven, recoloured; matches the real checkered blue carpet), faint whitewashed brick on Wall1 (pattern flattened to 0.22 — the wall is painted brick), cream paint on Walls 0/2/3, and a real ceiling: tile-textured prism + suspended T-bar grid + `CeilingLights0` (6 troffers, frame + emissive lens). A `_fix_dark_glass()` pass lightens the recon windows' near-black glass so they read as daylit.
**Fixtures per wall** (each a named hide-as-a-unit group via `group_fixture`, every part wall-prefixed):
- **Wall0 (door wall)** — `Trunking0` (channel+lid, broken at the door), `Socket0`/`Socket1` (faceplate + 2 raised outlets each), `WindowSill0` (board+lip under the partition), `ExitSign0` (2 drop rods + green emissive box above the door), `NoticeBoard0` (cork patch behind glass + 13 A4 sheets taped on the room side — behind-glass papers were invisible through the frosted GLB glass), `Skirting0` (board+lip, breaks at door). Verified frames 82/87 + ortho.
- **Wall1 (brick window wall)** — `Trunking1`, `Socket2-4`, `WindowSill1-4`, `VBlind0-3` (headrail + slat loops: W4 closed @yaw 12°, W3 open stack, W2 ~35% drawn @45°, W5 open stack at end), `Radiator0` (back panel + 14-fin loop + top grille + end caps + 2 valves with pipe stubs), `Pipe0` (full-height boxed pipe + 3 clips), `PipeRun0` (twin flow/return pipes + brackets), `Skirting1`. Verified frames 4/27 + ortho. Note: Window5's GLB has a closed blind baked into the asset — matches the raw stitch, left as-is.
- **Wall2** — `Whiteboard0` (back + gloss face + 4 aluminium bars + tray+lip; re-seated to u 3.42 after the rectified compare showed the raw stitch was mirrored), `Thermostat0` (plate + LCD + button at u 0.5), `Trunking2`, `Socket5-7`, `Skirting2`. Verified frames 7/39 + ortho.
- **Wall3
✓ [3/6] one-shot authoring · 50m20s
⊘ [4/6] per-object refinement — skipped (SKIP_REFINE=1)
⊘ [5/6] per-wall fixture refinement — skipped (REFINE_WALLS=0)
▶ [6/6] export three.js viewer (0 stages left)
=== RoomScene.build (blank) ===
shell <- SHELL(compact): 4 walls, 7 openings, 18 objects(无 usdz)
thickened 4 walls outward to ~0.1 m
cut 7/7 openings {'Door0': 'Wall0', 'Window0': 'Wall0', 'Window1': 'Wall0', 'Window2': 'Wall1', 'Window3': 'Wall1', 'Window4': 'Wall1', 'Window5': 'Wall1'}
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cube.002
14:17:51 | INFO: Blender create Mesh node Cube.007
14:17:51 | INFO: Blender create Mesh node Cube.012
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cube.007
14:17:51 | INFO: Blender create Mesh node Cube.013
14:17:51 | INFO: Blender create Mesh node Cube.006
14:17:51 | INFO: glTF import finished in 0.00s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cylinder
14:17:51 | INFO: Blender create Mesh node Cylinder.001
14:17:51 | INFO: Blender create Mesh node Cube.005
14:17:51 | INFO: Blender create Mesh node Cube.009
14:17:51 | INFO: Blender create Mesh node Cube.012
14:17:51 | INFO: Blender create Mesh node Cylinder.002
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cube.004
14:17:51 | INFO: glTF import finished in 0.00s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cube.017
14:17:51 | INFO: Blender create Mesh node Cube.005
14:17:51 | INFO: Blender create Mesh node Cube.013
14:17:51 | INFO: Blender create Mesh node Cube.014
14:17:51 | INFO: Blender create Mesh node Cube.015
14:17:51 | INFO: Blender create Mesh node Cube.016
14:17:51 | INFO: Blender create Mesh node Cube.004
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cube.008
14:17:51 | INFO: Blender create Mesh node Cube.009
14:17:51 | INFO: Blender create Mesh node Cube.017
14:17:51 | INFO: Blender create Mesh node Cube.007
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cylinder
14:17:51 | INFO: Blender create Mesh node Cube.006
14:17:51 | INFO: Blender create Mesh node Cube.007
14:17:51 | INFO: Blender create Mesh node Cube.005
14:17:51 | INFO: Blender create Mesh node Cube.012
14:17:51 | INFO: Blender create Mesh node Cube.004
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node Cube
14:17:51 | INFO: Blender create Mesh node Cube.011
14:17:51 | INFO: Blender create Mesh node Cube.012
14:17:51 | INFO: Blender create Mesh node Cube.026
14:17:51 | INFO: Blender create Mesh node Cube.010
14:17:51 | INFO: Blender create Mesh node Cube.005
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
14:17:51 | INFO: Data are loaded, start creating Blender stuff
14:17:51 | INFO: Blender create Mesh node geometry_0
14:17:51 | INFO: glTF import finished in 0.01s
placed 25 asset instances
built 0 capture cameras
indexed 30 objects, 0 cameras
floor-grounded 0 visible piece(s)
harness layer: materials + ceiling + fixtures built
=== ROOM SCENE (blank) ===
blind : VBlind0, VBlind1, VBlind2, VBlind3
ceiling : Ceiling0
ceiling_grid: CeilingGrid0
chair : Chair0, Chair1, Chair10, Chair11, Chair12, Chair13, Chair14, Chair15, Chair2, Chair3, Chair4, Chair5, Chair6, Chair7, Chair8, Chair9
door : Door0
floor : Floor0
light : CeilingLights0
noticeboard: NoticeBoard0
pipe : Pipe0, PipeRun0
radiator : Radiator0
rail : Rail0
sign : ExitSign0
sill : WindowSill0, WindowSill1, WindowSill2, WindowSill3, WindowSill4
skirting : Skirting0, Skirting1, Skirting2, Skirting3
socket : Socket0, Socket1, Socket2, Socket3, Socket4, Socket5, Socket6, Socket7, Socket8, Socket9
table : Table0, Table1
television: TV0
thermostat: Thermostat0
trunking : Trunking0, Trunking1, Trunking2, Trunking3
wall : Wall0, Wall1, Wall2, Wall3
whiteboard: Whiteboard0, Whiteboard1
window : Window0, Window1, Window2, Window3, Window4, Window5
placeable surfaces (top z):
Table0 z=-0.631 center=[2.3025, -0.3011, -1.0016]
Table1 z=-0.632 center=[-0.906, 1.2525, -1.002]
cameras: none
INFO Draco mesh compression is available, use library at /scratch2/zh340/blender-4.5.1-linux-x64/4.5/scripts/addons_core/io_scene_gltf2/libextern_draco.so
14:17:51 | INFO: Starting glTF 2.0 export
14:17:51 | INFO: Extracting primitive: Floor0
14:17:51 | INFO: Primitives created: 1
14:17:51 | INFO: Extracting primitive: Wall0
14:17:51 | INFO: Primitives created: 1
14:17:51 | INFO: Extracting primitive: Wall1
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: Wall2
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: Wall3
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: Ceiling0
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: Cube
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 3
14:17:52 | INFO: Extracting primitive: Cube.001
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 2
14:17:52 | INFO: Extracting primitive: Cube.002
14:17:52 | INFO: Primitives created: 3
14:17:52 | INFO: Extracting primitive: Cube.007
14:17:52 | INFO: Primitives created: 3
14:17:52 | INFO: Extracting primitive: Cube.012
14:17:52 | INFO: Primitives created: 3
14:17:52 | INFO: Extracting primitive: geometry_0
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: geometry_0.001
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: geometry_0.002
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: geometry_0.003
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: geometry_0.004
14:17:52 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:52 | INFO: Primitives created: 1
14:17:52 | INFO: Extracting primitive: geometry_0.005
14:17:53 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:53 | INFO: Primitives created: 1
14:17:53 | INFO: Extracting primitive: geometry_0.006
14:17:53 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:53 | INFO: Primitives created: 1
14:17:53 | INFO: Extracting primitive: geometry_0.007
14:17:53 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:53 | INFO: Primitives created: 1
14:17:53 | INFO: Extracting primitive: geometry_0.008
14:17:53 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:53 | INFO: Primitives created: 1
14:17:53 | INFO: Extracting primitive: geometry_0.009
14:17:53 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:53 | INFO: Primitives created: 1
14:17:53 | INFO: Extracting primitive: geometry_0.010
14:17:54 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:54 | INFO: Primitives created: 1
14:17:54 | INFO: Extracting primitive: geometry_0.011
14:17:54 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:54 | INFO: Primitives created: 1
14:17:54 | INFO: Extracting primitive: geometry_0.012
14:17:54 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:54 | INFO: Primitives created: 1
14:17:54 | INFO: Extracting primitive: geometry_0.013
14:17:54 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:54 | INFO: Primitives created: 1
14:17:54 | INFO: Extracting primitive: geometry_0.014
14:17:54 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:54 | INFO: Primitives created: 1
14:17:54 | INFO: Extracting primitive: geometry_0.015
14:17:55 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.003
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.004
14:17:55 | INFO: Primitives created: 3
14:17:55 | INFO: Extracting primitive: Cube.013
14:17:55 | INFO: Primitives created: 3
14:17:55 | INFO: Extracting primitive: Cube.006
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Plane
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.005
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cylinder
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cylinder.001
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.008
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.009
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.010
14:17:55 | INFO: Primitives created: 3
14:17:55 | INFO: Extracting primitive: Cylinder.002
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Plane.001
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.011
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.014
14:17:55 | INFO: Primitives created: 3
14:17:55 | INFO: Extracting primitive: Plane.002
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.015
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.017
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.016
14:17:55 | INFO: Primitives created: 2
14:17:55 | INFO: Extracting primitive: Cube.018
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.019
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.020
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.021
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.022
14:17:55 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Plane.003
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.023
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.024
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.025
14:17:55 | INFO: Primitives created: 2
14:17:55 | INFO: Extracting primitive: Cube.026
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.027
14:17:55 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Plane.004
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.028
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cylinder.003
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.029
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.030
14:17:55 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.031
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.032
14:17:55 | INFO: Primitives created: 3
14:17:55 | INFO: Extracting primitive: Cube.033
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Plane.005
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.034
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.035
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.036
14:17:55 | WARNING: More than one shader node tex image used for a texture. The resulting glTF sampler will behave like the first shader node tex image.
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.037
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.038
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Cube.039
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA6
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridA7
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB6
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB7
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB8
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_gridB9
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Trunking0_ch0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Trunking0_ch1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Trunking0_lid0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Trunking0_lid1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out30
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_out31
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket0_pl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out30
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_out31
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Socket1_pl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Sill0_board
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Sill0_lip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Exit0_box
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Exit0_rod0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Exit0_rod1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_cork
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg12
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg6
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg7
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg8
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Notice0_pg9
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Skirting0_bd0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Skirting0_bd1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Skirting0_lip0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall0_Skirting0_lip1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Trunking1_ch0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Trunking1_lid0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket2_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket3_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out30
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_out31
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Socket4_pl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill1_board
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill1_lip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill2_board
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill2_lip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill3_board
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill3_lip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill4_board
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_WindowSill4_lip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_rail
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl12
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl13
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl14
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl6
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl7
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl8
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind0_sl9
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_rail
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_sl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_sl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_sl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_sl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_sl4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind1_sl5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind2_rail
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind2_sl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind2_sl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind2_sl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind2_sl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind2_sl4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_rail
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_sl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_sl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_sl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_sl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_sl4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_VBlind3_sl5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_cap0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_cap1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin12
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin13
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin4
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin5
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin6
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin7
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin8
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_fin9
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_panel
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_pipe0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_pipe1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_top
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_valve0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Rad0_valve1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Pipe0_clip0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Pipe0_clip1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Pipe0_clip2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Pipe0_run
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_br0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_br1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_br2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_p00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_p01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_p10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_PipeRun0_p11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Skirting1_bd0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall1_Skirting1_lip0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_back
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_face
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_fB
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_fL
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_fR
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_fT
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_tray
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Whiteboard0_traylip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Thermo_btn
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Thermo_lcd
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Thermo_plate
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Trunking2_ch0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Trunking2_lid0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket5_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out30
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_out31
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket6_pl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Socket7_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Skirting2_bd0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall2_Skirting2_lip0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_back
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_face
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_fB
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_fL
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_fR
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_fT
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_tray
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Whiteboard1_traylip
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_base
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_bzB
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_bzL
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_bzR
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_bzT
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_cable
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_pole
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_TV0_screen
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Rail0_bar
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Rail0_br0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Rail0_br1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Rail0_br2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Rail0_br3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Trunking3_ch0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Trunking3_lid0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out30
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_out31
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket8_pl3
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_out00
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_out01
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_out10
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_out11
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_out20
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_out21
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_pl0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_pl1
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Socket9_pl2
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Skirting3_bd0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Wall3_Skirting3_lip0
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt00_fr
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt00_lens
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt01_fr
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt01_lens
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt10_fr
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt10_lens
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt11_fr
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt11_lens
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt20_fr
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt20_lens
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt21_fr
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Extracting primitive: Ceil_Lt21_lens
14:17:55 | INFO: Primitives created: 1
14:17:55 | INFO: Finished glTF 2.0 export in 3.7441282272338867 s
EXPORTED -> /scratch2/code/LiteReality_to_share/agentic_litereality/output/Psi_2_seminar-Zhening/scene_stage/_oneshot/room_preview/Room.glb (20868 KB)
LAYOUT -> /scratch2/code/LiteReality_to_share/agentic_litereality/output/Psi_2_seminar-Zhening/scene_stage/_oneshot/room_preview/room_layout.json (70 objects, 0 cameras)
Info: Saved as "Room.blend"
BLEND -> /scratch2/code/LiteReality_to_share/agentic_litereality/output/Psi_2_seminar-Zhening/scene_stage/_oneshot/room_preview/Room.blend (69844 KB)
COPIED -> /scratch2/code/LiteReality_to_share/agentic_litereality/output/Psi_2_seminar-Zhening/scene_stage/_oneshot/room_preview/build_room.py
DONE
Blender 4.5.1 LTS (hash b0a72b245dcf built 2025-07-29 06:24:35)
Blender quit
=== 物化 11 个物体 ===
tex Table0: 重建 4 张贴图
regen Table0 (object.py)
tex Table1: 重建 3 张贴图
regen Table1 (object.py)
regen Wall0_Door_0 (object.py)
regen Wall0_Window_0 (object.py)
regen Wall0_Window_1 (object.py)
tex Wall1_Window_2: 重建 4 张贴图
regen Wall1_Window_2 (object.py)
tex Wall1_Window_3: 重建 4 张贴图
regen Wall1_Window_3 (object.py)
tex Wall1_Window_4: 重建 1 张贴图
regen Wall1_Window_4 (object.py)
tex Wall1_Window_5: 重建 1 张贴图
regen Wall1_Window_5 (object.py)
wrap ChairCluster0 (object.py)
wrap ChairCluster1 (object.py)
room materials: 重建 9 张贴图 -> /scratch2/code/LiteReality_to_share/agentic_litereality/final_results/Psi_2_seminar-Zhening/scene_stage/_oneshot/room/materials
=== 装配(无 frames(仅几何),外壳来自 Room.py 的 SHELL)-> Room.glb + Room.blend ===
物化 11/11 个物体
Room_preview -> /scratch2/code/LiteReality_to_share/agentic_litereality/output/Psi_2_seminar-Zhening/scene_stage/_oneshot/room_preview
viewer → /scratch2/code/LiteReality_to_share/agentic_litereality/final_results/Psi_2_seminar-Zhening/Psi_2_seminar-Zhening.html (12.9 MB, self-contained)
final_results → /scratch2/code/LiteReality_to_share/agentic_litereality/final_results/Psi_2_seminar-Zhening
✓ [6/6] export three.js viewer · 17s
╭────────── Psi_2_seminar-Zhening ──────────╮
✓ init (skipped) 0s
✓ stitches (skipped) 0s
✓ one-shot authoring 50m20s
✓ obj refine (skipped) 0s
✓ wall refine (skipped) 0s
✓ export three.js viewer 17s
total 50m37s
viewer /scratch2/code/LiteReality_to_share/agentic_litereality/final_results/Psi_2_seminar-Zhening/Psi_2_seminar-Zhening.html
room /scratch2/code/LiteReality_to_share/agentic_litereality/output/Psi_2_seminar-Zhening/scene_stage/_oneshot/room/Room.py
╰────────────────────────────────────────────────╯
② Code changes
Room.py diffseed (blank shell) → authored
+514 −8 lines · seed → authored Room.py
@@ -1159,8 +1159,514 @@
# ============================================================================
+# HARNESS LAYER — Psi_2_seminar: ceiling + materials + multi-part wall fixtures
+# Authored against the head-on stitches (surface_ref/*_stitched.jpg). Every
+# fixture is a named, hide-as-a-unit group (empty handle + own collection).
+# ============================================================================
+MAT_DIR = os.path.join(HERE, "materials")
+
+
+def _flat(name, srgb, rough=0.6, metal=0.0):
+ mat = bpy.data.materials.get(name)
+ if mat is not None:
+ return mat
+ mat = bpy.data.materials.new(name)
+ mat.use_nodes = True
+ nt = mat.node_tree
+ nt.nodes.clear()
+ out = nt.nodes.new("ShaderNodeOutputMaterial")
+ b = nt.nodes.new("ShaderNodeBsdfPrincipled")
+ nt.links.new(b.outputs["BSDF"], out.inputs["Surface"])
+ b.inputs["Base Color"].default_value = (*srgb_to_linear(srgb), 1.0)
+ b.inputs["Roughness"].default_value = rough
+ if "Metallic" in b.inputs:
+ b.inputs["Metallic"].default_value = metal
+ return mat
+
+
+def _emis(name, srgb, strength):
+ mat = bpy.data.materials.get(name)
+ if mat is not None:
+ return mat
+ mat = bpy.data.materials.new(name)
+ mat.use_nodes = True
+ nt = mat.node_tree
+ nt.nodes.clear()
+ e = nt.nodes.new("ShaderNodeEmission")
+ e.inputs["Color"].default_value = (*srgb_to_linear(srgb), 1.0)
+ e.inputs["Strength"].default_value = strength
+ out = nt.nodes.new("ShaderNodeOutputMaterial")
+ nt.links.new(e.outputs["Emission"], out.inputs["Surface"])
+ return mat
+
+
+def _pbr(name, slug, scale=1.0, force_rough=None, nstr=0.6):
+ """Poly Haven set materials/<slug>_{diff,rough,normal}.jpg, BOX-projected on
+ Object coords (shell + part meshes carry metric coords -> scale = repeats/m)."""
+ mat = bpy.data.materials.get(name)
+ if mat is not None:
+ return mat
+ mat = bpy.data.materials.new(name)
+ mat.use_nodes = True
+ nt = mat.node_tree
+ nt.nodes.clear()
+ out = nt.nodes.new("ShaderNodeOutputMaterial")
+ b = nt.nodes.new("ShaderNodeBsdfPrincipled")
+ nt.links.new(b.outputs["BSDF"], out.inputs["Surface"])
+ co = nt.nodes.new("ShaderNodeTexCoord")
+ mp = nt.nodes.new("ShaderNodeMapping")
+ mp.inputs["Scale"].default_value = (scale, scale, scale)
+ nt.links.new(co.outputs["Object"], mp.inputs["Vector"])
+
+ def img(suffix, non_color):
+ p = os.path.join(MAT_DIR, f"{slug}_{suffix}.jpg")
+ if not os.path.exists(p):
+ return None
+ t = nt.nodes.new("ShaderNodeTexImage")
+ t.image = bpy.data.images.load(p, check_existing=True)
+ t.projection = "BOX"
+ t.projection_blend = 0.2
+ if non_color:
+ t.image.colorspace_settings.name = "Non-Color"
+ nt.links.new(mp.outputs["Vector"], t.inputs["Vector"])
+ return t
+
+ d = img("diff", False)
+ if d:
+ nt.links.new(d.outputs["Color"], b.inputs["Base Color"])
+ if force_rough is not None:
+ b.inputs["Roughness"].default_value = force_rough
+ else:
+ r = img("rough", True)
+ if r:
+ nt.links.new(r.outputs["Color"], b.inputs["Roughness"])
+ nrm = img("normal", True)
+ if nrm:
+ nm = nt.nodes.new("ShaderNodeNormalMap")
+ nm.inputs["Strength"].default_value = nstr
+ nt.links.new(nrm.outputs["Color"], nm.inputs["Color"])
+ nt.links.new(nm.outputs["Normal"], b.inputs["Normal"])
+ return mat
+
+
+def _mats():
+ return {
+ "paint": _flat("Paint_Cream", (0.96, 0.94, 0.89), rough=0.85),
+ "pvc": _flat("White_PVC", (0.94, 0.94, 0.92), rough=0.35),
+ "metal_white": _flat("Metal_White", (0.92, 0.92, 0.91), rough=0.5),
+ "alum": _flat("Aluminium", (0.72, 0.73, 0.75), rough=0.35, metal=0.9),
+ "wb_face": _flat("Whiteboard_Face", (0.97, 0.97, 0.96), rough=0.12),
+ "blind": _flat("Blind_Fabric", (0.27, 0.29, 0.34), rough=0.95),
+ "tv_screen": _flat("TV_Screen", (0.02, 0.02, 0.025), rough=0.2),
+ "tv_dark": _flat("TV_Dark", (0.09, 0.09, 0.10), rough=0.6, metal=0.2),
+ "sign_green": _emis("Sign_Green", (0.10, 0.75, 0.30), 1.2),
+ "lens": _emis("Light_Lens", (1.0, 1.0, 1.0), 5.0),
+ "lcd": _flat("LCD_Grey", (0.62, 0.68, 0.62), rough=0.3),
+ "carpet": _pbr("Floor_Carpet", "floor_carpet", scale=0.33, force_rough=0.92),
+ "brick": _pbr("Wall1_Brick", "wall1_brick", scale=0.5, nstr=0.35),
+ "ceil": _pbr("Ceiling_Tile", "ceiling_tile", scale=0.42),
+ }
+
+
+def _wf(wall):
+ """(start, along-dir, inward-normal, length) of a SHELL wall on the floor plane."""
+ ws = SHELL["walls"]
+ c = Vector((0.0, 0.0, 0.0))
+ for w in ws.values():
+ c += Vector((w["start"][0], w["start"][1], 0.0))
+ c /= max(len(ws), 1)
+ w = ws[wall]
+ s = Vector((w["start"][0], w["start"][1], 0.0))
+ e = Vector((w["end"][0], w["end"][1], 0.0))
+ d = e - s
+ L = d.length
+ d.normalize()
+ n = Vector((-d.y, d.x, 0.0))
+ if n.dot(c - (s + e) / 2) < 0:
+ n = -n
+ return s, d, n, L
+
+
+def _frame_M(center, xdir, ydir):
+ x = Vector((xdir.x, xdir.y, 0.0)).normalized()
+ y = Vector((ydir.x, ydir.y, 0.0)).normalized()
+ if (x.x * y.y - x.y * y.x) < 0: # keep right-handed (boxes are xy-symmetric)
+ x = -x
+ return Matrix(
+ (
+ (x.x, y.x, 0.0, center[0]),
+ (x.y, y.y, 0.0, center[1]),
+ (0.0, 0.0, 1.0, center[2]),
+ (0.0, 0.0, 0.0, 1.0),
+ )
+ )
+
+
+def _mkbox(name, dims, mat, M):
+ """Metric-vertex box (local = metres, so BOX projection maps 1:1), placed by a
+ rotation+translation matrix."""
+ me = _unit_cube_mesh(name)
+ for v in me.vertices:
+ v.co.x *= dims[0]
+ v.co.y *= dims[1]
+ v.co.z *= dims[2]
+ me.update()
+ ob = bpy.data.objects.new(name, me)
+ ob.matrix_world = M
+ if mat is not None:
+ ob.data.materials.append(mat)
+ bpy.context.scene.collection.objects.link(ob)
+ return ob
+
+
+def _wall_box(wall, name, mat, u, z, ln, h, dp, out=0.0, yaw=0.0):
+ """A box flush on a wall's interior face. u = centre along wall from its start,
+ z = centre above floor, ln/h = size along wall / vertical, dp = depth into the
+ room, out = gap between wall face and box back, yaw = spin about vertical
+ (for blind slats). Part names carry the wall prefix so the per-wall ortho
+ montage keeps corner fixtures with their own wall."""
+ s, d, n, _L = _wf(wall)
+ c = s + d * u + n * (out + dp / 2.0)
+ r = math.radians(yaw)
+ dr = d * math.cos(r) + n * math.sin(r)
+ nr = Vector((-dr.y, dr.x, 0.0))
+ return _mkbox(
+ f"{wall}_{name}", (ln, dp, h), mat,
+ _frame_M((c.x, c.y, SHELL["floor_z"] + z), dr, nr),
+ )
+
+
+def group_fixture(name, category, parts):
+ """Bundle a fixture's parts into ONE named, hide-as-a-unit group: an empty
+ handle with room_id/category props, every part parented to it, all moved
+ into a collection named after the fixture (selects/hides like Table0)."""
+ parts = [p for p in parts if p is not None]
+ handle = bpy.data.objects.new(name, None)
+ handle.empty_display_size = 0.1
+ handle["room_id"] = name
+ handle["category"] = category
+ coll = get_or_make_collection(name)
+ coll.objects.link(handle)
+ c = Vector((0.0, 0.0, 0.0))
+ for p in parts:
+ c += p.matrix_world.translation
+ c /= max(len(parts), 1)
+ handle.matrix_world = Matrix.Translation(c)
+ inv = Matrix.Translation(c).inverted()
+ for p in parts:
+ p.parent = handle
+ p.matrix_parent_inverse = inv
+ move_to_collection(p, coll)
+ return handle
+
+
+# ---------------------------------------------------------------- shared builders
+def _trunk(wall, name, spans, z, M):
+ """Dado cable trunking: channel base + proud lid per free span."""
+ parts = []
+ for i, (a, b) in enumerate(spans):
+ ln, u = b - a, (a + b) / 2.0
+ parts.append(_wall_box(wall, f"{name}_ch{i}", M["pvc"], u, z, ln, 0.09, 0.038))
+ parts.append(_wall_box(wall, f"{name}_lid{i}", M["pvc"], u, z, ln, 0.055, 0.018, out=0.038))
+ return parts
+
+
+def _sockets(wall, name, us, z, M, out=0.056):
+ """A bank of double sockets on the trunking: faceplate + two raised outlets."""
+ parts = []
+ for i, u in enumerate(us):
+ parts.append(_wall_box(wall, f"{name}_pl{i}", M["pvc"], u, z, 0.146, 0.086, 0.010, out=out))
+ for j, du in enumerate((-0.034, 0.034)):
+ parts.append(
+ _wall_box(wall, f"{name}_out{i}{j}", M["pvc"], u + du, z, 0.048, 0.040, 0.008,
+ out=out + 0.010)
+ )
+ return parts
+
+
+def _skirt(wall, name, spans, M):
+ """Skirting board + slightly proud top lip, broken at door openings."""
+ parts = []
+ for i, (a, b) in enumerate(spans):
+ ln, u = b - a, (a + b) / 2.0
+ parts.append(_wall_box(wall, f"{name}_bd{i}", M["pvc"], u, 0.0475, ln, 0.095, 0.012))
+ parts.append(_wall_box(wall, f"{name}_lip{i}", M["pvc"], u, 0.099, ln, 0.018, 0.018))
+ return parts
+
+
+def _whiteboard(M, wall, name, u, w, z0, z1):
+ """Backing board + recessed gloss face + 4 aluminium frame bars + pen tray."""
+ zc, h = (z0 + z1) / 2.0, z1 - z0
+ tw = min(w, 0.6 * w + 0.4)
+ parts = [
+ _wall_box(wall, name + "_back", M["pvc"], u, zc, w, h, 0.014),
+ _wall_box(wall, name + "_face", M["wb_face"], u, zc, w - 0.07, h - 0.07, 0.004, out=0.014),
+ _wall_box(wall, name + "_fT", M["alum"], u, z1 - 0.016, w, 0.032, 0.020, out=0.006),
+ _wall_box(wall, name + "_fB", M["alum"], u, z0 + 0.016, w, 0.032, 0.020, out=0.006),
+ _wall_box(wall, name + "_fL", M["alum"], u - w / 2 + 0.016, zc, 0.032, h, 0.020, out=0.006),
+ _wall_box(wall, name + "_fR", M["alum"], u + w / 2 - 0.016, zc, 0.032, h, 0.020, out=0.006),
+ _wall_box(wall, name + "_tray", M["alum"], u, z0 - 0.030, tw, 0.014, 0.070),
+ _wall_box(wall, name + "_traylip", M["alum"], u, z0 - 0.012, tw, 0.030, 0.010, out=0.060),
+ ]
+ group_fixture(name, "whiteboard", parts)
+
+
+def _vblind(M, name, u, w, mode):
+ """Vertical blind over a Wall1 window: headrail + a loop of yawed slats.
+ mode: closed = full run of slats, half = end-side half covered, open = slats
+ stacked edge-on at the start-side edge."""
+ wb = w + 0.12
+ parts = [_wall_box("Wall1", name + "_rail", M["pvc"], u, 2.79, wb, 0.05, 0.06, out=0.05)]
+ top, bot = 2.755, 1.12
+ zc, h = (top + bot) / 2.0, top - bot
+ if mode == "closed":
+ nsl = max(6, int(wb / 0.082))
+ for i in range(nsl):
+ ui = u - wb / 2 + 0.05 + i * (wb - 0.10) / max(nsl - 1, 1)
+ parts.append(_wall_box("Wall1", f"{name}_sl{i}", M["blind"], ui, zc, 0.089, h, 0.012,
+ out=0.068, yaw=12))
+ elif mode == "half": # ~35% drawn from the end side, vanes well spaced
+ nsl = max(4, int(wb * 0.35 / 0.09))
+ for i in range(nsl):
+ ui = u + wb / 2 - 0.06 - i * 0.095
+ parts.append(_wall_box("Wall1", f"{name}_sl{i}", M["blind"], ui, zc, 0.089, h, 0.012,
+ out=0.068, yaw=45))
+ else: # open / open_end — slats gathered edge-on at one side of the window
+ sgn = 1.0 if mode == "open_end" else -1.0
+ for i in range(6):
+ ui = u + sgn * (wb / 2 - 0.05 - i * 0.020)
+ parts.append(_wall_box("Wall1", f"{name}_sl{i}", M["blind"], ui, zc, 0.089, h, 0.012,
+ out=0.068, yaw=72))
+ group_fixture(name, "blind", parts)
+
+
+# ---------------------------------------------------------------- per-wall fixtures
+def _wall0_fixtures(M):
+ """Door wall: trunking broken at the double door, socket banks, sill shelf under
+ the notice-board window (Window1), hanging exit box + wall exit sign, skirting."""
+ z = 0.87 # trunking centre — top stays below Window0's 0.9365 sill
+ group_fixture("Trunking0", "trunking",
+ _trunk("Wall0", "Trunking0", [(0.05, 2.17), (3.96, 6.28)], z, M))
+ group_fixture("Socket0", "socket", _sockets("Wall0", "Socket0", (4.15, 4.35, 4.55, 4.75), z, M))
+ group_fixture("Socket1", "socket", _sockets("Wall0", "Socket1", (0.50, 0.67, 0.84, 1.01), z, M))
+ group_fixture("WindowSill0", "sill", [
+ _wall_box("Wall0", "Sill0_board", M["pvc"], 4.95, 0.975, 2.00, 0.03, 0.16),
+ _wall_box("Wall0", "Sill0_lip", M["pvc"], 4.95, 0.940, 2.00, 0.04, 0.015, out=0.13),
+ ])
+ parts = [_wall_box("Wall0", f"Exit0_rod{i}", M["pvc"], 3.05 + du, 2.87, 0.02, 0.30, 0.02, out=0.11)
+ for i, du in enumerate((-0.14, 0.14))]
+ parts.append(_wall_box("Wall0", "Exit0_box", M["sign_green"], 3.05, 2.63, 0.38, 0.18, 0.04, out=0.10))
+ group_fixture("ExitSign0", "sign", parts)
+ # a few notices seen THROUGH Window1's glazed partition (corridor side):
+ # small cork patch + scattered A4 sheets just behind the wall plane —
+ # most of the glass stays clear
+ parts = [
+ _wall_box("Wall0", "Notice0_cork", _flat("Cork", (0.76, 0.62, 0.44), rough=0.9),
+ 4.35, 1.55, 0.55, 0.65, 0.012, out=-0.050),
+ ]
+ for i, (du, dz) in enumerate(
+ ((-0.55, 0.45), (-0.30, 0.10), (-0.08, 0.42), (-0.05, -0.02), (0.18, 0.18),
+ (0.42, 0.48), (0.55, 0.02), (0.80, 0.35), (0.95, -0.12), (1.20, 0.22),
+ (-0.35, -0.35), (0.30, -0.40), (0.90, -0.45))
+ ):
+ parts.append(_wall_box("Wall0", f"Notice0_pg{i}", M["wb_face"], 4.35 + du, 1.55 + dz,
+ 0.20, 0.27, 0.004, out=0.09)) # taped on the room-side glass
+ group_fixture("NoticeBoard0", "noticeboard", parts)
+ group_fixture("Skirting0", "skirting",
+ _skirt("Wall0", "Skirting0", [(0.03, 2.17), (3.96, 6.30)], M))
+
+
+def _wall1_fixtures(M):
+ """Window wall (painted brick): trunking + 3 socket banks, sills, vertical
+ blinds, finned radiator under Window2, vertical pipe, pipe run, skirting."""
+ group_fixture("Trunking1", "trunking", _trunk("Wall1", "Trunking1", [(0.05, 6.28)], 1.00, M))
+ group_fixture("Socket2", "socket", _sockets("Wall1", "Socket2", (0.80, 1.00, 1.20), 1.00, M))
+ group_fixture("Socket3", "socket", _sockets("Wall1", "Socket3", (2.25, 2.45, 2.65), 1.00, M))
+ group_fixture("Socket4", "socket", _sockets("Wall1", "Socket4", (3.62, 3.80, 3.98, 4.16), 1.00, M))
+ for nm, u, w, sill in (
+ ("WindowSill1", 0.7915, 1.159, 1.1911),
+ ("WindowSill2", 2.2755, 1.0176, 1.1345),
+ ("WindowSill3", 3.9999, 1.2438, 1.1345),
+ ("WindowSill4", 5.4415, 1.1872, 1.177),
+ ):
+ group_fixture(nm, "sill", [
+ _wall_box("Wall1", nm + "_board", M["pvc"], u, sill - 0.015, w + 0.10, 0.03, 0.12),
+ _wall_box("Wall1", nm + "_lip", M["pvc"], u, sill - 0.05, w + 0.10, 0.04, 0.014, out=0.09),
+ ])
+ _vblind(M, "VBlind0", 0.7915, 1.159, "closed")
+ _vblind(M, "VBlind1", 2.2755, 1.0176, "open")
+ _vblind(M, "VBlind2", 3.9999, 1.2438, "half")
+ _vblind(M, "VBlind3", 5.4415, 1.1872, "open_end")
+ # radiator under Window2: back panel + fin loop + top grille + caps + valves
+ parts = [_wall_box("Wall1", "Rad0_panel", M["metal_white"], 4.05, 0.41, 1.25, 0.58, 0.022, out=0.025)]
+ for i in range(14):
+ ui = 4.05 - 0.58 + i * 1.16 / 13.0
+ parts.append(_wall_box("Wall1", f"Rad0_fin{i}", M["metal_white"], ui, 0.40, 0.046, 0.50, 0.052,
+ out=0.047))
+ parts.append(_wall_box("Wall1", "Rad0_top", M["metal_white"], 4.05, 0.705, 1.25, 0.015, 0.10, out=0.02))
+ for j, ue in enumerate((3.445, 4.655)):
+ parts.append(_wall_box("Wall1", f"Rad0_cap{j}", M["metal_white"], ue, 0.41, 0.04, 0.60, 0.10, out=0.02))
+ for j, uv in enumerate((3.39, 4.71)):
+ parts.append(_wall_box("Wall1", f"Rad0_valve{j}", M["metal_white"], uv, 0.115, 0.05, 0.07, 0.05, out=0.03))
+ parts.append(_wall_box("Wall1", f"Rad0_pipe{j}", M["metal_white"], uv, 0.04, 0.028, 0.08, 0.028, out=0.04))
+ group_fixture("Radiator0", "radiator", parts)
+ # full-height boxed pipe between Window3 and Window2
+ parts = [_wall_box("Wall1", "Pipe0_run", M["pvc"], 3.08, 1.515, 0.10, 3.03, 0.085)]
+ for i, zb in enumerate((0.35, 1.55, 2.75)):
+ parts.append(_wall_box("Wall1", f"Pipe0_clip{i}", M["pvc"], 3.08, zb, 0.13, 0.035, 0.10))
+ group_fixture("Pipe0", "pipe", parts)
+ # horizontal flow/return pipes: vertical pipe -> radiator -> right corner
+ parts = []
+ for i, (a, b) in enumerate(((3.14, 3.32), (4.68, 6.28))):
+ for j, zp in enumerate((0.44, 0.53)):
+ parts.append(_wall_box("Wall1", f"PipeRun0_p{i}{j}", M["metal_white"], (a + b) / 2, zp,
+ b - a, 0.035, 0.035, out=0.015))
+ for i, ub in enumerate((4.9, 5.5, 6.1)):
+ parts.append(_wall_box("Wall1", f"PipeRun0_br{i}", M["metal_white"], ub, 0.485, 0.03, 0.15, 0.06))
+ group_fixture("PipeRun0", "pipe", parts)
+ group_fixture("Skirting1", "skirting", _skirt("Wall1", "Skirting1", [(0.03, 6.30)], M))
+
+
+def _wall2_fixtures(M):
+ """Small whiteboard, thermostat, trunking + 3 socket banks, skirting."""
+ _whiteboard(M, "Wall2", "Whiteboard0", 3.42, 1.50, 1.08, 2.44)
+ group_fixture("Thermostat0", "thermostat", [
+ _wall_box("Wall2", "Thermo_plate", M["pvc"], 0.50, 1.60, 0.095, 0.13, 0.022),
+ _wall_box("Wall2", "Thermo_lcd", M["lcd"], 0.50, 1.625, 0.06, 0.035, 0.004, out=0.022),
+ _wall_box("Wall2", "Thermo_btn", M["pvc"], 0.50, 1.555, 0.04, 0.018, 0.005, out=0.022),
+ ])
+ group_fixture("Trunking2", "trunking", _trunk("Wall2", "Trunking2", [(0.05, 5.26)], 1.00, M))
+ group_fixture("Socket5", "socket", _sockets("Wall2", "Socket5", (0.70, 1.00, 1.30), 1.00, M))
+ group_fixture("Socket6", "socket", _sockets("Wall2", "Socket6", (1.80, 2.10, 2.40, 2.70), 1.00, M))
+ group_fixture("Socket7", "socket", _sockets("Wall2", "Socket7", (3.60, 3.80, 4.00), 1.00, M))
+ group_fixture("Skirting2", "skirting", _skirt("Wall2", "Skirting2", [(0.03, 5.28)], M))
+
+
+def _wall3_fixtures(M):
+ """Large whiteboard, TV on floor-stand trolley in the window corner, top rail,
+ trunking + 2 socket banks, skirting."""
+ _whiteboard(M, "Wall3", "Whiteboard1", 3.00, 3.40, 1.10, 2.50)
+ u, zc, w, h = 0.85, 1.68, 1.45, 0.85
+ group_fixture("TV0", "television", [
+ _wall_box("Wall3", "TV0_screen", M["tv_screen"], u, zc, w - 0.05, h - 0.05, 0.02, out=0.16),
+ _wall_box("Wall3", "TV0_bzT", M["tv_dark"], u, zc + h / 2 - 0.017, w, 0.035, 0.030, out=0.155),
+ _wall_box("Wall3", "TV0_bzB", M["tv_dark"], u, zc - h / 2 + 0.017, w, 0.035, 0.030, out=0.155),
+ _wall_box("Wall3", "TV0_bzL", M["tv_dark"], u - w / 2 + 0.017, zc, 0.035, h, 0.030, out=0.155),
+ _wall_box("Wall3", "TV0_bzR", M["tv_dark"], u + w / 2 - 0.017, zc, 0.035, h, 0.030, out=0.155),
+ _wall_box("Wall3", "TV0_pole", M["tv_dark"], u, 0.80, 0.075, 1.60, 0.055, out=0.10),
+ _wall_box("Wall3", "TV0_base", M["tv_dark"], u, 0.03, 0.65, 0.06, 0.48),
+ _wall_box("Wall3", "TV0_cable", M["tv_dark"], u + 0.12, 0.60, 0.020, 1.20, 0.015, out=0.13),
+ ])
+ parts = [_wall_box("Wall3", "Rail0_bar", M["pvc"], 3.27, 2.58, 3.95, 0.040, 0.022, out=0.008)]
+ for i, ub in enumerate((1.5, 2.5, 3.5, 4.5)):
+ parts.append(_wall_box("Wall3", f"Rail0_br{i}", M["pvc"], ub, 2.58, 0.03, 0.055, 0.030))
+ group_fixture("Rail0", "rail", parts)
+ group_fixture("Trunking3", "trunking", _trunk("Wall3", "Trunking3", [(0.05, 5.26)], 1.00, M))
+ group_fixture("Socket8", "socket", _sockets("Wall3", "Socket8", (1.95, 2.15, 2.35, 2.55), 1.00, M))
+ group_fixture("Socket9", "socket", _sockets("Wall3", "Socket9", (3.55, 3.75, 3.95), 1.00, M))
+ group_fixture("Skirting3", "skirting", _skirt("Wall3", "Skirting3", [(0.03, 5.28)], M))
+
+
+def _build_ceiling(M):
+ """Suspended-tile ceiling: a thin prism over the wall-corner loop (both faces
+ shaded), tile texture BOX-projected."""
+ cz = SHELL["ceiling_z"]
+ loop = [SHELL["walls"][w]["start"] for w in ("Wall3", "Wall1", "Wall2", "Wall0")] # CCW
+ verts = [(x, y, cz) for x, y in loop] + [(x, y, cz + 0.03) for x, y in loop]
+ faces = [(3, 2, 1, 0), (4, 5, 6, 7), (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (3, 0, 4, 7)]
+ me = bpy.data.meshes.new("Ceiling0")
+ me.from_pydata(verts, [], faces)
+ me.update()
+ ob = bpy.data.objects.new("Ceiling0", me)
+ bpy.context.scene.collection.objects.link(ob)
+ ob.data.materials.append(M["ceil"])
+ move_to_collection(ob, get_or_make_collection(COLL_SHELL))
+ # suspended T-bar grid (0.6 m): the room is an exact parallelogram, so an
+ # affine (a,b) grid in the Wall1 frame covers it edge to edge
+ s1, d1, _n, L1 = _wf("Wall1")
+ w2 = SHELL["walls"]["Wall2"]
+ e2 = Vector((w2["start"][0], w2["start"][1], 0.0)) - s1
+ L2 = e2.length
+ e2.normalize()
+ parts = []
+ zg = cz - 0.008
+ for i in range(1, int(L2 / 0.6)): # bars running along Wall1
+ c = s1 + d1 * (L1 / 2) + e2 * (i * 0.6)
+ parts.append(_mkbox(f"Ceil_gridA{i}", (L1, 0.024, 0.016), M["pvc"],
+ _frame_M((c.x, c.y, zg), d1, e2)))
+ for i in range(1, int(L1 / 0.6)): # bars running along Wall2
+ c = s1 + d1 * (i * 0.6) + e2 * (L2 / 2)
+ parts.append(_mkbox(f"Ceil_gridB{i}", (L2, 0.024, 0.016), M["pvc"],
+ _frame_M((c.x, c.y, zg), e2, d1)))
+ group_fixture("CeilingGrid0", "ceiling_grid", parts)
+ return ob
+
+
+def _ceiling_lights(M):
+ """Six recessed troffers (frame + emissive lens) on the ceiling grid."""
+ s, d, n, _L = _wf("Wall1")
+ cz = SHELL["ceiling_z"]
+ parts = []
+ for i, a in enumerate((1.10, 3.17, 5.23)):
+ for j, b in enumerate((1.40, 3.60)):
+ c = s + d * a + n * b
+ parts.append(_mkbox(f"Ceil_Lt{i}{j}_fr", (0.64, 0.64, 0.03), M["pvc"],
+ _frame_M((c.x, c.y, cz - 0.015), d, n)))
+ parts.append(_mkbox(f"Ceil_Lt{i}{j}_lens", (0.55, 0.55, 0.012), M["lens"],
+ _frame_M((c.x, c.y, cz - 0.033), d, n)))
+ group_fixture("CeilingLights0", "light", parts)
+
+
+def _fix_dark_glass():
+ """The recon window GLBs ship near-black tinted glass that reads as a closed
+ blind. Lighten any near-black principled material on the window assets so
+ the daylight card behind shows through as a lit pane."""
+ for i in range(6):
+ h = bpy.data.objects.get(f"Window{i}")
+ if h is None:
+ continue
+ for o in h.children_recursive:
+ if o.type != "MESH":
+ continue
+ for slot in o.material_slots:
+ m = slot.material
+ if not m or not m.use_nodes:
+ continue
+ for node in m.node_tree.nodes:
+ if node.type == "BSDF_PRINCIPLED":
+ c = node.inputs["Base Color"].default_value
+ if (c[0] + c[1] + c[2]) / 3 < 0.35:
+ node.inputs["Base Color"].default_value = (0.72, 0.78, 0.85, 1.0)
+ node.inputs["Roughness"].default_value = 0.15
+ if "Transmission Weight" in node.inputs:
+ node.inputs["Transmission Weight"].default_value = 0.0
+
+
+def harness_stage(scene):
+ """Materials on every surface + ceiling + all grouped wall fixtures."""
+ M = _mats()
+ _fix_dark_glass()
+ for wn, key in (("Wall0", "paint"), ("Wall1", "brick"), ("Wall2", "paint"),
+ ("Wall3", "paint"), ("Floor0", "carpet")):
+ ob = bpy.data.objects.get(wn)
+ if ob is not None:
+ ob.data.materials.clear()
+ ob.data.materials.append(M[key])
+ _build_ceiling(M)
+ _wall0_fixtures(M)
+ _wall1_fixtures(M)
+ _wall2_fixtures(M)
+ _wall3_fixtures(M)
+ _ceiling_lights(M)
+ bpy.context.view_layer.update()
+ print(" harness layer: materials + ceiling + fixtures built")
+
+
+# ============================================================================
# main
# ============================================================================
def main():
scene = RoomScene().build()
+ harness_stage(scene)
+ scene.index()
scene.summary()
scene.export_glb()
@@ -1237,16 +1743,16 @@
"wall": "Wall0",
"type": "window",
- "offset": 1.6254,
- "width": 0.848,
- "height": 1.1742,
- "sill": 0.9365
+ "offset": 1.25,
+ "width": 1.55,
+ "height": 1.4,
+ "sill": 1.0
},
"Window1": {
"wall": "Wall0",
"type": "window",
- "offset": 4.5794,
- "width": 1.0459,
- "height": 1.0469,
- "sill": 1.0638
+ "offset": 4.95,
+ "width": 1.9,
+ "height": 1.4,
+ "sill": 1.0
},
"Window2": {
③ QC pass(es)
qc · qc_20260720_075525.log
👁INSPECT #1
I'll start by reading the room files and the ground-truth stitches.
⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen⌘ Bash🔧 ToolSearch select:mcp__cap__render,mcp__cap__fetch_⌘ Bash⌘ Bash⌘ Bash⌘ Bash⌘ Bash⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen🖼 render room
•STEP #2
You're out of usage credits. Run /usage-credits to keep using Fable 5 or /model to switch models.
directed · qc_directed_20260720_115314.log
•STEP #1
I'll start by reading the room definition and understanding the scene structure.
⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen⌘ Bash📄 Read /home/zelda/zh340/.claude/projects/-scra📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #2
Now let me look at the window objects and their references. Let me check for window reference images and read the current window builds.
⌘ Bash
•STEP #3
Only tables have refs. Windows must be judged from the wall stitches. Let me read the window object.py files and the SHELL in Room.py.
📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #4
This is a major QC task. Let me set up tracking and gather ground truth. Let me look at the raw frames and the SHELL/window placement in Room.py.
⌘ Bash· Grep📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #5
The conf_ files are depth/confidence maps. Let me find the RGB frames.
⌘ Bash⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #6
Frame 27 shows the real windows well. Let me look at a few more window-facing frames to nail the design.
📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #7
Let me compare the window object.py files to see how much they differ, and check how windows are fit to openings.
⌘ Bash
•STEP #8
The 4 Wall1 windows are authored as 4 *different* designs — exactly the inconsistency flagged. I need one unified real design. Let me get a clearer lo
⌘ Bash📄 Read /tmp/f27_up.png📄 Read /tmp/w1_right.png
•STEP #9
Now I can see the real window: a cream-framed grid, **2 columns × 3 rows** with a central mullion and two transoms, vertical louvre blinds on the room
📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #10
Now I understand the architecture: vertical blinds are separate room fixtures (`_vblind` → VBlind0-3) placed over the windows — so the window GLBs sho
📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #11
Confirmed: GLBs are scaled to fit each opening box, so one canonical design works for all four. Vertical blinds are room fixtures (not part of window
⌘ Bash
👁INSPECT #12
Now I have the full picture. Let me load the render tool and render the current Wall0 and Wall1 to establish a baseline before editing.
🔧 ToolSearch select:mcp__cap__render🖼 render Wall1
•STEP #13
The MCP render needs an explicit scan. Per my notes I should use the engine CLI with `scan=`. Let me locate the render engine.
⌘ Bash⌘ Bash⌘ Bash
•STEP #14
`render_wall_reference` gives head-on wall renders paired with the reference. Let me render Wall0 and Wall1 to compare with stitches.
⌘ Bash📄 Read /tmp/qc_render/Wall1_compare.png⌘ Bash📄 Read /tmp/Wall1_compare_R.png
•STEP #15
Window3 (2nd window) is already the correct real design — 2-column × 3-row cream grid, transparent glass, operable sash, no baked blinds. The other th
📄 Read /tmp/Wall0_compare_R.png
•STEP #16
The render shows NoticeBoard0 (scattered sheets) behind the **right** panel (Window1), but the stitch shows notices on the left. I need to resolve the
📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #17
The stitch is mirrored (per my project notes), and the render is built from true geometry — so notices genuinely belong on Window1 (right). The user's
📄 Read /scratch2/code/LiteReality_to_share/agen
✏️EDIT #18
Window3 is the correct canonical design — only its dark sill needs to be paler (real sills are painted pale). Let me fix W3's sill, then copy it to W2
✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen
•STEP #19
Now copy the corrected Window3 design to Window2, 4, 5 (unifying all four), fixing the filename references in each.
⌘ Bash
✏️EDIT #20
All four Wall1 windows are now unified to the correct 2×3-grid design. Now remove the unreal rolled-up roller blind from Wall0 Window0 (not present in
✏️ Edit /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen
•STEP #21
Now the main NoticeBoard0 rebuild. Let me check `_wall_box` and `_add_daylight_card` signatures first.
⌘ Bash
✏️EDIT #22
The daylight card sits 0.06 m behind the wall, so a board on the room side will read clearly and helpfully occludes the fake-daylight glow. Let me reb
✏️ Edit /scratch2/code/LiteReality_to_share/agen
•STEP #23
Let me check the vertical-blind fixture material color (the render showed near-black blinds vs pale-grey real ones), and the `M` material dict.
⌘ Bash
•STEP #24
The blinds are `(0.27,0.29,0.34)` — dark navy-grey vs the pale-grey real blinds; I'll judge that after rebuild. First, let me check whether the `final
⌘ Bash
•STEP #25
Room.py is hardlinked between copies. Let me verify the object.py files are too, then rebuild with object regeneration.
⌘ Bash
•STEP #26
Both hardlinked. Let me rebuild with `--regenerate` so the changed object.py files materialize into new GLBs.
⌘ Bash
•STEP #27
Build succeeded (11/11). Now render Wall1 and Wall0 to verify the fixes.
⌘ Bash📄 Read /tmp/Wall1_compare2_R.png
•STEP #28
The Wall1 windows are now unified (mostly hidden behind the VBlind fixtures, which is why the render looks similar — only Window3 shows fully and it w
📄 Read /tmp/Wall0_compare2_R.png
•STEP #29
The notice board now fills Window1's panel properly (vs scattered sheets). Let me zoom in to confirm the paper grid reads.
⌘ Bash📄 Read /tmp/nb_zoom.png
•STEP #30
The ortho compare render is hazy/low-contrast. Let me render an actual perspective frame of Wall0 to judge the notice board properly.
⌘ Bash📄 Read /tmp/qc_f/wall_frame_00082.png
✏️EDIT #31
The board reads as a featureless grey panel — the white papers aren't contrasting against the light backing. Let me darken the backing and make the pa
✏️ Edit /scratch2/code/LiteReality_to_share/agen
✏️EDIT #32
Now lighten the near-black vertical-blind material to the pale-grey of the real blinds (a match-at-a-glance fix; the render showed them far darker tha
✏️ Edit /scratch2/code/LiteReality_to_share/agen
•STEP #33
Rebuild (Room.py-only changes, so no `--regenerate` needed — cached object GLBs are reused), then re-render Wall0 and Wall1.
⌘ Bash⌘ Bash📄 Read /tmp/qc_f2/wall_frame_00082.png📄 Read /tmp/Wall1_3R.png
•STEP #34
Both fixes verified:
⌘ Bash📄 Read /tmp/win3_zoom.png
✏️EDIT #35
Window3 now shows the correct real design: cream frame, central mullion (2 columns), two transoms (3 rows), transparent glazing, operable sash with ha
📄 Read /home/zelda/zh340/.claude/projects/-scra✏️ Edit /home/zelda/zh340/.claude/projects/-scra
•STEP #36
All fixes are complete and render-verified. Here's the per-surface summary of what I changed:
All fixes are complete and render-verified. Here's the per-surface summary of what I changed:
## Summary of QC changes
**Wall1 — the four exterior windows (MANDATORY FIX #1)**
The four window objects (`Wall1_Window_2/3/4/5`) had **four different hallucinated designs** (asymmetric casement with baked-in blinds, a clean grid, a fabric-blind variant, a mullion-only variant). The real windows — read off the de-rotated raw frame 27 and the Wall1 stitch — are all **one identical type**: a cream-framed **2-column × 3-row grid** (central mullion + two transoms), transparent glazing, one operable side-hung sash.
- `Wall1_Window_3` was already this correct design, so I made it canonical (paled its dark wood sill to a painted off-white) and **copied it to Window2/4/5**, unifying all four.
- Removed the windows' **baked-in blinds** — the vertical louvre blinds are separate room fixtures (`_vblind`→VBlind0-3) that sit over each window, so a correct window GLB must carry none (the baked blinds were the visible bug on W2/W4).
- Glazing is transparent (transmission 0.94) and the sash articulates (revolute), unchanged.
**Wall0 — NoticeBoard0 (MANDATORY FIX #2)**
It was a cork patch plus ~13 **scattered A4 sheets floating on the glass**, off-centre toward the door. Rebuilt as **one proper notice board** filling Window1's glazed panel: a dark-felt backing (1.52×1.12, centred in the panel) with an aluminium surround, papered with a tidy 6×4 grid of bright A4 sheets (a few tinted). The dark backing was needed so the white papers read (a light board rendered as a featureless grey panel). Kept on Window1 — that's where the notices sit in true geometry; the Wall0 surface stitch is mirrored.
**Wall0 — Window0**
Removed the unreal rolled-up roller blind (the real borrowed-light corridor partition has none).
**Wall1 — blind material**
Lightened `M["blind"]` from near-black `(0.27,0.29,0.34)` to a mid-grey `(0.50,0.51,0.54)` to match the real pale-grey vertical blinds (they were rendering almost black).
I left everything else (furniture, ceiling, other fixtures, door, materials) untouched. Rebuilt with `build_from_room --regenerate` and render-verified Wall1 (Window3 fully visible = correct grid + transparent glass) and Wall0 (frame 82: board now reads as a papered notice board).
opus · qc_opus_20260720_083725.log
•STEP #1
I'll start by reading the Room.md and Room.py in full to understand what's already authored.
⌘ Bash⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #2
Let me read the existing memory for this scene and the full Room.py.
📄 Read /home/zelda/zh340/.claude/projects/-scra📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #3
Let me read the rest of the file.
📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #4
I've read Room.md and Room.py in full. Now let me look at the ground-truth images and set up the render tool to check current state.
🔧 ToolSearch select:mcp__cap__render,mcp__cap__fetch_📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
👁INSPECT #5
Both tables are beech-top flip tables on silver T-legs with casters — Table1 is a wider double. Now let me render the current room and view the wall s
🖼 render room📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #6
The MCP render can't infer the scan from this `_qc` dir. Let me check the render-engine recipe memories.
📄 Read /home/zelda/zh340/.claude/projects/-scra📄 Read /home/zelda/zh340/.claude/projects/-scra
•STEP #7
Now I understand the render recipe. Let me check the render engine CLI and the Objects directory structure.
⌘ Bash⌘ Bash
•STEP #8
Let me examine the window and door object.py (the GLB source) to understand the glass and articulation.
📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #9
The window GLB already uses transparent glass (transmission 0.92) and an articulated casement sash — good. Let me render to see actual state. I'll use
⌘ Bash⌘ Bash📄 Read /tmp/qc_ref/Wall1_compare.png📄 Read /tmp/qc_ref/Wall0_compare.png
•STEP #10
Renders are low-res. Let me read the articulation-recipe memory and inspect the perspective frames + door at higher detail.
📄 Read /home/zelda/zh340/.claude/projects/-scra📄 Read /tmp/qc_ref/Wall1_frame_00004.png
•STEP #11
Let me read the articulation recipe context and check the remaining walls, the door object, and a scene frame.
📄 Read /tmp/qc_ref/Wall2_compare.png📄 Read /tmp/qc_ref/Wall3_compare.png📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #12
The door is well-built (two articulated glazed leaves, frosted translucent glass 0.62, metal handle/hinges/kick). Walls 2/3 look good. Let me zoom int
⌘ Bash📄 Read /tmp/qc_ref/Wall1_render_zoom.png
•STEP #13
Windows read correctly — open windows show transparent lit glass, closed/half ones show blinds, matching the real scene. Door is translucent frosted,
⌘ Bash📄 Read /tmp/qc_t0/Table0_frame_00016.png
✏️EDIT #14
Table0 matches the reference well (beech flip-table, TV stand, whiteboard all align). Table1 (the wide double beech table) is visible and correct in t
📄 Read /scratch2/code/LiteReality_to_share/agen✏️ Edit /scratch2/code/LiteReality_to_share/agen
✏️EDIT #15
Now add `frame_set(0)` at the end of `harness_stage` so the exported rest pose is the authored state:
✏️ Edit /scratch2/code/LiteReality_to_share/agen
•STEP #16
Now let me re-render Wall1 to confirm it still compiles and the static rest pose is unchanged:
⌘ Bash
•STEP #17
It compiles. Let me confirm the static blind pose is unchanged (frame 1 = authored rest):
⌘ Bash📄 Read /tmp/qc_ref2/Wall1_render_zoom.png
•STEP #18
The static rest pose is byte-for-byte identical to before my edit — same blind states per window (closed / open-lit / half / closed), confirming `fram
⌘ Bash
•STEP #19
The `room_preview/Room.glb` is likely stale (built before my edit). Let me check timestamps and rebuild it properly:
⌘ Bash
•STEP #20
Stale glb (08:17 < my edit 08:45). Let me rebuild the preview and re-check:
⌘ Bash⌘ Bash⌘ Bash⌘ Bash
✏️EDIT #21
The rebuild now exports **39 animations: 32 vane-tilt clips (blinds) + 7 door/window swing clips** — the blind articulation landed correctly, and the
✏️ Edit /home/zelda/zh340/.claude/projects/-scra
•STEP #22
QC pass complete. Here's what I found and changed, per surface:
QC pass complete. Here's what I found and changed, per surface:
## Summary
I read `Room.md` + `Room.py` in full and verified every checklist item against the head-on stitches and object references via ortho + perspective renders. The scene was already in good shape — **only one genuine defect** needed fixing.
**Wall1 (window/brick wall) — the one fix.** The four vertical blinds (`_vblind`) were static geometry. Blinds must articulate. I added `_anim_vane_tilt(vanes)`: it keyframes each vane's rotation about its own vertical centreline (a real vertical-blind vane tilt), open→closed→open. Frame 1 is the authored rest pose and `harness_stage` now ends with `frame_set(0)`, so the **static look is byte-for-byte identical** (confirmed by before/after render) — the change is purely additive motion. `_vblind` now animates the vanes *after* `group_fixture` so parenting is settled. Rebuild confirms the GLB now carries **32 vane-tilt clips**.
**Wall1 windows themselves — already correct, no edit.** GLBs use transparent glass (Principled Transmission 0.92) with an articulated casement sash (revolute); daylight cards behind read as lit panes. Open windows show transparent lit glass, closed/half show blinds — matching the real scene. `_fix_dark_glass` doesn't fire (glass is bright, not near-black). The 4 windows are genuinely different widths (1.02–1.24 m), each matching its own reference, so I did **not** force-unify them.
**Wall0 (door wall) — already correct, no edit.** Door GLB has two glazed leaves with frosted translucent glass (0.62, not opaque), brushed-metal handle/hinges/kick, and both leaves articulate (revolute). Openings are true cuts. Trunking/sockets/skirting break at the door and sit below the window sills — no fixture over any opening. I did not add a hydraulic closer (not clearly present in the Wall0 stitch).
**Wall2 & Wall3 — already correct, no edit.** Whiteboards, thermostat, TV-on-stand, rails, trunking/sockets all match the stitches; glass N/A.
**Ceiling — already materialed** (PBR tile + T-bar grid + 6 emissive troffers; troffers are the only added emitters and are real).
**Objects — match references.** Table0 (beech flip-table on silver T-legs) aligns tightly with the real frame; Table1 (wide double beech table) matches too. No changes (and furniture was off-limits anyway).
Edits were confined to `Room.py` (`_vblind` + new `_anim_vane_tilt` + one `frame_set(0)` line); the file re-executes in Blender cleanly and the preview rebuilds 11/11 objects.
opus · qc_opus_20260720_113531.log
•STEP #1
I'll start by reading the Room.md and Room.py files in full to understand what I'm working with.
⌘ Bash⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #2
Now let me read the full Room.py.
📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen
•STEP #3
Let me examine the object structure and look at the reference images and stitches.
⌘ Bash📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /scratch2/code/LiteReality_to_share/agen📄 Read /home/zelda/zh340/.claude/projects/-scra🔧 ToolSearch select:mcp__cap__render
•STEP #4
This is very helpful — a prior QC pass was already completed in this exact directory today. Let me verify the current state with render checks rather
⌘ Bash⌘ Bash⌘ Bash⌘ Bash
👁INSPECT #5
Build succeeded. Now let me render the room and the key walls to verify the current state.
🖼 render room
•STEP #6
The MCP render needs a scan hint it can't infer. Let me use the render engine directly with explicit scan.
⌘ Bash⌘ Bash⌘ Bash
•STEP #7
`render_surface` gives head-on wall views with refs — ideal for verification. Let me render all walls.
⌘ Bash
•STEP #8
Let me view the wall comparison renders (render on left/right vs ref).
📄 Read /tmp/qc_surf/Wall1_compare.png📄 Read /tmp/qc_surf/Wall0_compare.png
•STEP #9
Let me view larger single-frame perspective renders to check door glass, window glass, and blinds.
📄 Read /tmp/qc_surf/Wall0_frame_00082.png📄 Read /tmp/qc_surf/Wall1_frame_00018.png
•STEP #10
Both walls match the references well. Let me verify the actual glass materials programmatically (the "do first" correctness item) to confirm door/wind
⌘ Bash⌘ Bash⌘ Bash⌘ Bash
•STEP #11
Glass confirmed transmissive (windows 0.92–0.94 transmission, low roughness; door frosted 0.62), and `_fix_dark_glass` won't fire since all bases are
📄 Read /tmp/qc_surf/Wall2_compare.png📄 Read /tmp/qc_surf/Wall3_compare.png📄 Read /tmp/qc_surf/Ceiling0_compare.png
•STEP #12
All surfaces verified. The scene in this directory already reflects a completed QC pass (done earlier today per project memory), and my independent re
All surfaces verified. The scene in this directory already reflects a completed QC pass (done earlier today per project memory), and my independent re-verification confirms every "Done when" criterion is already satisfied. I made **no edits** — the existing authoring is correct, and the prompt explicitly warns against overwriting good work.
Here's what I checked and found per surface:
**Openings & glass (verified from the actual GLB materials, not just renders):**
- **Windows (Window0–5):** `Glass` material has `transmission 0.92–0.94`, roughness 0.03–0.05, bright base — genuine transparent glass, frames/sashes opaque. ✓
- **Door (Wall0_Door_0):** vision panels are `Frosted_Glass` transmission 0.62 (translucent privacy glazing), opaque `Frame_White`/`Brushed_Metal` handle. Both leaves carry revolute clips (2 animations). ✓
- **`_fix_dark_glass()` is a confirmed no-op** — it only fires on near-black glass (<0.35 avg); every window base is 0.90+, so the transmissive glass is never overwritten to opaque. ✓
- Openings are true boolean cuts with the leaf/pane sitting in the hole; horizontal runs (trunking/skirting) break at openings via `_wall_free_spans`. ✓
**Wall0 (door wall):** double door + glazed corridor partitions with notices taped room-side; exit sign; render matches the mirrored stitch. ✓
**Wall1 (window wall):** 4 windows with vertical vane blinds (closed / open / half / open-stack), radiator, sills — matches stitch. Blinds **articulate**: `_anim_vane_tilt` keyframes each vane's revolute tilt (frame 1 = authored rest, so the static look is unchanged). 5/6 window GLBs carry sash clips; Window5 has a closed blind baked into the asset (matches the raw stitch) with the articulated VBlind3 fixture over it — accepted by the prior pass. ✓
**Wall2:** centre-right whiteboard + thermostat + sockets/skirting — matches. ✓
**Wall3:** near-wall-spanning whiteboard + floor-stand TV in the window corner — matches. ✓
**Ceiling0:** materialed with tile PBR + T-bar grid + 6 recessed troffers — matches. ✓
**Objects:** Table0 (single beech folding table) and Table1 (long triple-leg beech table) match their `reference_1024.png` at a glance. ✓
I rebuilt `room_preview/Room.glb` from the current `Room.py` to make sure renders reflected the live source (that's the only artifact touched). No `Room.py` or `object.py` changes were needed or made.
④ Reference images used
Object references (object refs)real crop → reference · 2




Object references (opening refs)real crop → reference · 7














Final — render | photo













