Skip to content

Commit 26396cd

Browse files
authored
feat: add gltf-export-roundtrip example witnessing glTF interchange contracts (#75)
The game-engine interchange path is where AI-generated Blender code drifts silently: the +Y-up convention, modifier application at export, UV V-flips. This example pins them: a supply crate exported GLTF_SEPARATE and re-imported, checked against the depsgraph-evaluated mesh (positions, normals, UVs, per-triangle material bindings), with the on-disk JSON/buffer parsed directly for the axis-conversion and V-flip witnesses. Probed during authoring on 4.5.11 and 5.1.2: exporter/importer RNA is byte-identical, so the example guards the kwarg set explicitly instead of papering over a divergence that does not exist. Mesh.calc_normals() being removed on 5.x surfaced as a real authoring hazard and is pinned in code. Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
1 parent a483d26 commit 26396cd

12 files changed

Lines changed: 1582 additions & 2 deletions

File tree

‎.cursor-plugin/plugin.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"examples/damped-track-aim",
6868
"examples/depsgraph-export",
6969
"examples/driver-wave",
70+
"examples/gltf-export-roundtrip",
7071
"examples/gn-instance-grid",
7172
"examples/gn-sdf-remesh",
7273
"examples/grease-pencil-rosette",

‎.github/workflows/blender-smoke.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,16 @@ jobs:
369369
xvfb-run -a "$BLENDER" --background \
370370
--python examples/vse-cut-list/vse_cut_list.py -- \
371371
--check-pixels --engine cycles
372+
373+
- name: Shipped example - glTF export round-trip (+Y-up, applied modifiers, UVs)
374+
run: |
375+
set -euo pipefail
376+
# Check only (no render): a 35-part supply crate exported GLTF_SEPARATE
377+
# and re-imported; asserts the exporter/importer kwarg set still exists
378+
# (RNA guard), the on-disk +Y-up conversion ((x,y,z)->(x,z,-y) baked
379+
# into POSITION bounds, no node rotation), disk vertex count ==
380+
# evaluated loop count (export_apply), V-flipped TEXCOORD_0, and the
381+
# full round-trip of positions/normals/UVs/per-triangle material
382+
# bindings within float tolerances. Exits non-zero on failure.
383+
xvfb-run -a "$BLENDER" --background \
384+
--python examples/gltf-export-roundtrip/gltf_export_roundtrip.py --

‎README.md‎

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</p>
1919

2020
<p align="center">
21-
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>23 examples</strong>
21+
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>24 examples</strong>
2222
</p>
2323

2424
<p align="center">
@@ -36,7 +36,7 @@
3636

3737
## Overview
3838

39-
This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 22 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.
39+
This repository ships **12 skills, 6 rules, 2 templates, 17 snippets, and 24 runnable examples** for Blender Python development targeting Blender 5.1 (current stable) with Blender 4.5 LTS fallback support.
4040

4141
The content is consumed by AI coding agents (Cursor, Claude Code, any MCP-capable client) when working on Blender add-ons, geometry nodes scripts, batch pipelines, or animation tooling. There is no build step. Edit the markdown and Python files directly.
4242

@@ -465,6 +465,32 @@ round-trips through the raw `POINT` buffer.
465465

466466
</details>
467467

468+
<details>
469+
<summary><strong>Game asset pipeline</strong> — 1 example</summary>
470+
471+
<table>
472+
<tr>
473+
<td width="46%" valign="middle">
474+
<a href="examples/gltf-export-roundtrip/"><img src="examples/gltf-export-roundtrip/preview.webp" alt="glTF export round-trip: two identical olive-drab sci-fi supply crates on a dark studio floor - authored beside re-imported - with teal status strips, riveted panels, and corner armor, proving the export/import round-trip preserves the asset" /></a>
475+
</td>
476+
<td valign="middle">
477+
478+
### [gltf-export-roundtrip](examples/gltf-export-roundtrip/)
479+
480+
A game-prop supply crate round-tripped through `bpy.ops.export_scene.gltf` and
481+
the importer — the check reads the `.gltf` JSON and `.bin` buffer directly.
482+
Witnesses the +Y-up convention baked into vertex data with no node rotation,
483+
`export_apply` shipping the evaluated mesh (one disk vertex per evaluated
484+
loop), V-flipped UVs, and per-triangle material bindings — all against the
485+
depsgraph-evaluated mesh. The exporter/importer RNA signatures are probed
486+
byte-identical on 4.5.11 and 5.1.2 and guarded against future renames.
487+
488+
</td>
489+
</tr>
490+
</table>
491+
492+
</details>
493+
468494
## How content is organized
469495

470496
```

‎ROADMAP.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
103103
- Attribute domain witness: writing a POINT-domain color attribute and reading it as if it were CORNER (or vice versa) silently shears colors across shared verts — companion to `color-attribute-wheel`
104104
- Light-linking collection witness: object light linking / receiver collections so a key illuminates only the hero (common AI miss when staging multi-light studios)
105105
- ~~VSE sequences-to-strips witness~~ **SHIPPED** as `examples/vse-cut-list/` — `.sequences` removed on 5.x (4.5 bridges to `.strips`), `new_effect` end kwarg `frame_end=` (4.5) vs `length=` (5.x), `frame_final_*` deprecated in favor of `left_handle`/`right_handle`/`duration`, TRANSFORM effect type removed, GAMMA_CROSS clamps to the source overlap, effect strips consume inputs only when stacked above them, same-scene scene strips render transparent; save/reload round-trip + tiny-render pixel witness
106+
- ~~glTF export round-trip witness~~ **SHIPPED** as `examples/gltf-export-roundtrip/` — `export_yup` bakes `(x,y,z)→(x,z,−y)` into vertex data with no node rotation (probed identical on 4.5.11 and 5.1.2), `export_apply` ships the evaluated mesh (one disk vertex per evaluated loop), TEXCOORD_0 is V-flipped on disk, per-triangle material bindings survive; exporter/importer RNA signatures byte-identical between 4.5.11 and 5.1.2 (guarded against future renames); `Mesh.calc_normals()` removal on 5.x surfaced during authoring
106107
- GAMMA_CROSS blend-curve witness: the cross blend is not the naive linear mix (mid-cross measured (0.341, 0.349, 0.463) from crimson (0.85, 0.10, 0.22) and teal (0.06, 0.75, 0.80)) — derive and assert the gamma-space closed form per frame; follow-up to `vse-cut-list`
107108
- Falsy `bpy_prop_collection` trap snippet: an empty collection is falsy, so `editor.strips or editor.sequences` silently falls through to the legacy accessor on an empty timeline — always branch on `hasattr`; likely generalizes across the API (found authoring `vse-cut-list`)
108109

12.4 KB
Loading
37.1 KB
Loading

0 commit comments

Comments
 (0)