Skip to content

Commit 313890a

Browse files
TMHSDigitalclaude
andcommitted
fix(examples): redesign depsgraph-export as a controller cage beside its subdivided shell
The gallery review called the hero programmer art: a teal cube with a wire outline beside a wire-caged sphere, where the evaluated-vs-original story did not read. The checked object is now a game controller. Its shell is a 90-vertex quad control cage under a level-2 SUBSURF modifier; sticks, d-pad, face buttons, pills, home button and bumpers are modeled parts (no modifiers) seated on the evaluated limit surface by ray cast and parented to the shell. The still shows the shell datablock as the file stores it (orange wire, a bead per vertex, faint blue facets) beside the smooth cobalt controller the OBJ contains, both on low satin display stands. Tiny labels are gone. The check got stricter, not weaker: every mesh is measured through evaluated_get().to_mesh()/to_mesh_clear(), the evaluated shell must equal the Catmull-Clark closed form from its own cage topology (new exit 7: V=90 E=176 F=88 S=352 -> 1410), and the OBJ vertex count must equal the summed evaluated counts (3666, versus 2346 base). The render path now also runs the asset-quality floors (exit 11); asset_sheet.py gains its SELECT row. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent 1b096de commit 313890a

11 files changed

Lines changed: 958 additions & 234 deletions

File tree

‎README.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,15 +440,16 @@ semver on LTS builds (`"4.5.11 LTS"`), and that a Mesh reference dies at
440440
</tr>
441441
<tr>
442442
<td width="46%" valign="middle">
443-
<a href="examples/depsgraph-export/"><img src="examples/depsgraph-export/preview.webp" alt="Depsgraph-evaluated export: a teal base cube beside the smooth teal sphere of its subdivision-surface evaluated form - one shared material, two silhouettes - on a dark studio floor with a warm light pool behind" /></a>
443+
<a href="examples/depsgraph-export/"><img src="examples/depsgraph-export/preview.webp" alt="Depsgraph-evaluated export: the sparse control cage of a game controller drawn as orange wire and vertex beads over faint blue facets, beside the smooth subdivided cobalt controller with sticks, d-pad and colored face buttons that the OBJ export contains, on a dark studio floor with a warm light pool behind" /></a>
444444
</td>
445445
<td valign="middle">
446446

447447
### [depsgraph-export](examples/depsgraph-export/)
448448

449-
A depsgraph-evaluated export — builds a cube with `SUBSURF`, measures the evaluated mesh via
450-
`evaluated_get().to_mesh()` / `to_mesh_clear()`, and asserts `wm.obj_export` ships the
451-
modifier-applied geometry (exported vertex count == evaluated > base).
449+
A depsgraph-evaluated export — builds a game controller whose shell is a 90-vertex quad cage
450+
under `SUBSURF`, measures every mesh via `evaluated_get().to_mesh()` / `to_mesh_clear()`,
451+
asserts the evaluated shell matches the Catmull-Clark closed form (1,410 vertices), and asserts
452+
`wm.obj_export` ships the modifier-applied geometry (exported vertex count == evaluated > base).
452453

453454
</td>
454455
</tr>
54.7 KB
Loading
19.6 KB
Loading
-4.52 KB
Loading

‎docs/gallery/depsgraph-export/index.html‎

Lines changed: 467 additions & 114 deletions
Large diffs are not rendered by default.

‎docs/gallery/index.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,12 @@ <h2><a href="gn-sdf-remesh/">gn-sdf-remesh</a></h2>
376376
</article>
377377
<article class="card" data-tags="depsgraph export">
378378
<a class="card-media" href="depsgraph-export/" tabindex="-1" aria-hidden="true">
379-
<img src="assets/depsgraph-export-hero.webp" alt="A teal cube outlined by its twelve edges beside a faceted teal sphere covered in a dense pale wire grid, on a dark studio floor." loading="lazy" decoding="async" />
379+
<img src="assets/depsgraph-export-hero.webp" alt="A game controller&#x27;s sparse control cage in orange wire and vertex beads beside the smooth subdivided cobalt controller with sticks and colored buttons, on a dark studio floor." loading="lazy" decoding="async" />
380380
</a>
381381
<div class="card-body">
382382
<h2><a href="depsgraph-export/">depsgraph-export</a></h2>
383383
<p class="teaches">The depsgraph lifetime contract — evaluated_get().to_mesh() paired with to_mesh_clear() — measured against an OBJ export of the same object.</p>
384-
<p class="witnesses"><span class="tag">witnesses</span> Exports ship evaluated geometry: the exported vertex count equals the subsurf-applied count and is strictly greater than the base mesh.</p>
384+
<p class="witnesses"><span class="tag">witnesses</span> Exports ship evaluated geometry: the controller shell subdivides to exactly its Catmull-Clark closed form, and the exported vertex count equals the subsurf-applied count, strictly greater than the base mesh.</p>
385385
<a class="card-link" href="depsgraph-export/">View example<span class="sr-only"> depsgraph-export</span> <span aria-hidden="true">&rarr;</span></a>
386386
</div>
387387
</article>

‎examples/depsgraph-export/README.md‎

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,32 @@
22

33
A runnable example that proves **modifiers actually ship in exports** and demonstrates the
44
[`depsgraph-and-evaluated-data`](../../skills/depsgraph-and-evaluated-data/SKILL.md) lifetime
5-
contract. It builds a cube with a SUBSURF modifier, measures the evaluated mesh via
6-
`evaluated_get().to_mesh()` (paired with `to_mesh_clear()`), exports through `wm.obj_export`,
7-
and asserts the exported vertex count equals the **evaluated** (modifier-applied) count and is
8-
strictly greater than the base mesh.
5+
contract. It builds a game controller whose shell is a sparse quad control cage (90 vertices)
6+
under a level-2 `SUBSURF` modifier, with the sticks, d-pad, face buttons and bumpers modeled
7+
as ordinary parts parented to it. It measures every mesh via `evaluated_get().to_mesh()`
8+
(each paired with `to_mesh_clear()`), exports the scene through `wm.obj_export`, and asserts:
9+
10+
- the evaluated shell has exactly the vertex count the Catmull-Clark closed form predicts
11+
from the cage's own topology — per level `V' = V + E + F`, `E' = 2E + S`, `F' = S`
12+
(S = face corners) — which for this cage (V=90, E=176, F=88, S=352) is **1,410**;
13+
- the exported OBJ vertex count equals the summed **evaluated** counts of every mesh
14+
(3,666), not the summed base counts (2,346).
915

1016
**What it witnesses:** the `evaluated_get` → `to_mesh` → `to_mesh_clear` contract, and that
1117
`wm.obj_export` writes the depsgraph-evaluated geometry (so modifiers are baked into the
1218
export) rather than the unmodified base mesh.
1319

20+
## The render
21+
22+
Left: the shell datablock as the `.blend` stores it — its 90-vertex control cage drawn as
23+
orange wire with a bead on every vertex, over faint blue facets. Right: the same object as the
24+
depsgraph evaluates it and the OBJ contains it — the smooth subdivided cobalt controller with
25+
its controls. If the export shipped the base mesh, the right-hand piece would be the blocky
26+
cage on the left.
27+
28+
Both pieces lean toward the camera on low satin display stands (render-only, added after the
29+
check and export have run).
30+
1431
## Run
1532

1633
```bash
@@ -20,7 +37,7 @@ blender --background --python depsgraph_export.py --
2037
# Falsifier: apply_modifiers=False. Must exit non-zero (export ≠ evaluated).
2138
blender --background --python depsgraph_export.py -- --unevaluated
2239

23-
# Also render a still of base vs evaluated (EEVEE on a GPU host; cycles on GPU-less hosts):
40+
# Also render a still of cage vs evaluated (EEVEE on a GPU host; cycles on GPU-less hosts):
2441
blender --background --python depsgraph_export.py -- --output depsgraph.png
2542
blender --background --python depsgraph_export.py -- --output depsgraph.png --engine cycles
2643

@@ -31,24 +48,27 @@ blender --background --python depsgraph_export.py -- --obj exported.obj
3148
## Exit codes
3249

3350
Per-script sequential checks. `9` is a valid check code; there is no rule
34-
against it. `10` is the shared framing helper.
51+
against it. `10` and `11` are the shared framing and asset-quality helpers.
3552

3653
| Code | Meaning |
3754
| --- | --- |
3855
| 0 | Success |
3956
| 1 | Uncaught exception (FATAL wrapper) |
4057
| 2 | argparse / usage |
41-
| 3 | Evaluated mesh did not apply the modifier |
58+
| 3 | Evaluated shell did not apply the modifier (evaluated count not above the cage) |
4259
| 4 | No OBJ written |
4360
| 5 | Export vert count ≠ evaluated (`--unevaluated` lands here) |
4461
| 6 | `--output` produced no file |
62+
| 7 | Evaluated shell count ≠ Catmull-Clark closed form |
4563
| 10 | Gallery framing violation |
64+
| 11 | Asset-quality floor violation (render path only) |
4665

4766
`--obj` is a path selector, not a falsifier.
4867

4968
The `blender-smoke` workflow runs the check on Blender 5.2 LTS and 4.5 LTS
5069
(5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch).
5170
Smoke does not pass `--output`, `--obj`, or `--unevaluated`.
5271

53-
54-
The `--output` render path additionally measures framing against the Layer 1 band via `examples/gallery_framing.py` (exit 10 on violation) before writing the still.
72+
The `--output` render path additionally measures framing against the Layer 1 band via
73+
`examples/gallery_framing.py` (exit 10) and the asset-quality floors on the shipped
74+
controller via `examples/gallery_asset_quality.py` (exit 11) before writing the still.

0 commit comments

Comments
 (0)