Wooden Barrel

showcase/wooden-barrel/

A procedural wine-cask with boarded, croze-seated heads and chord-lofted hoops through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.

Rendered headless by the showcase piece itself. Select it to enlarge.

witnesses Recomputed: 7312 tris, two materials with 2584 wood and 1440 metal faces, UVs in 0..1 with zero AABB overlap, outer AABB 0.722×0.714×0.880 m, 20 grounded staves, hoop bite 0.003 m, head-croze gap 0.007 m, four boards per head with 1.5 mm seams, LOD ratios in band, convex collider 226 tris, non-empty glTF. --skip-decimate exits 9; --round-band exits 18 on the hoop-seat budget; --one-piece-head exits 17 on the head-board budget.

category Village

tags mesh export showcase

blender --background --python showcase/wooden-barrel/wooden_barrel.py --

A showcase piece, not an example. Procedural wine-cask (20 staves with seeded width jitter, heads of four boards seated in a croze below a chime, iron hoops lofted on the stave faces, a bung) then the shipped pipeline: unique-cell UVs, Cycles high-to-low normal bake, LOD chain, convex collider, Unity glTF export.

Hoops evaluate the same host_outer_r chord as the stave flats. --round-band is the falsifier: a circle of radius_at(z) instead of the chord, which is what made the old capped cylinder float off every face. Heads follow the inner stave polygon, not a circle, so they fill the croze instead of leaving triangular slots at every joint. Each head is that outline cut across into four boards with a 1.5 mm seam, so the seat is unchanged and the head no longer reads as a lid.

It asserts budget conformance of the generated result. It does not witness an API contract. "It rendered without error" is not a check.

Composes skills mesh-editing-and-bmesh, bake-high-to-low, depsgraph-and-evaluated-data, engine-export-presets, and snippets bake_normal_high_to_low.py, setup_bake_target_image.py, lod_chain.py / decimate_to_budget.py, convex_hull_collider.py, export_preset_unity.py (helpers copied, not imported as a package).

Budgets#

Declared as named constants; every gate recomputes from the mesh, materials, UVs, evaluated LOD, collider, or export file.

AxisDeclaredMeasured (4.5.11 / 5.1.2 / 5.2.1)
Base triangles6000–85007312 / 7312 / 7312
LOD1 ratio0.32–0.62 of base0.5000 / 0.5000 / 0.5000
LOD2 ratio0.10–0.35 of base0.2199 / 0.2199 / 0.2199
Materialsexactly 2 distinct; ≥400 wood, ≥200 metal faces2 slots; 2584 / 1440
UVsin 0..1, AABB overlap ≤ 1e-5in range, overlap 0
Outer AABB(0.722, 0.714, 0.880) m ± 0.015(0.7220, 0.7142, 0.8800), zmin 0
Collider tris≤ 400226
Exportwritten, size > 0555344 / 555344 / 555340 bytes (4.5.11 / 5.1.2 / 5.2.1)

Base triangles rose from 4312 to 7216 in the quality pass: 12 identical staves with 5 mm daylight and circular hoops became 20 jittered staves, 8-ring bulge, chord-seated hoops, polygonal croze heads, and a bung. Cutting each head into four boards added 96 more (7312).

DECIMATE COLLAPSE triangle counts are not identical across series — the gate is a ratio band, not an exact count. Bake pixels are stochastic; the gate is has_data plus operator FINISHED, not byte-identity. Stave-width jitter uses fixed seed 17. Export byte counts differ by 16 B on 5.2.1 (glTF serializer), not a gated axis.

Hygiene#

Recomputed from the generated mesh, not asserted about the script.

AxisDeclaredMeasured (all three)
Non-manifold edges00
Loose verts / edges0 / 00 / 0
Doubles merged at 1e-500
Zero-area faces00
N-gons00
Coplanar disjoint face pairs00
Grounded: zminwithin 1e-4 of 00.0000
Named supports: 20 staveseach zmin ≤ 0.00120, stave_z 0.00000
Body plan0.714 m dia × 0.880 m high ± 0.040.7142 × 0.8800

Joint fit and seat#

AxisDeclaredMeasured (all three)
Head-croze rim BVH gap≤ 0.010 m0.00710
Head boards4 per head; every seam 0.0008–0.003 m4 + 4; 0.00150
Hoop bite (host r − inner hoop r)0.0012–0.008 m0.00300

Falsifiers#

Each violates one named budget. All seven were run on 4.5.11, 5.1.2 and 5.2.1 and returned the same code on each.

FlagBudget violatedExit
--skip-decimateLOD1 ratio band9
--stray-vertloose vertex count is 015
--lift-zbounding box zmin is 016
--short-stavesnamed stave supports at Z=016
--float-headhead-croze gap17
--round-bandhoop bite band18
--one-piece-headhead boards: 4 per head17

Surface#

The staves were one flat tone and the hoops bright polished steel. Each stave and each head board now carries a seeded PlankTone and a GrainDir (its own long axis) as face attributes. wood_material stretches grain along that axis, so it runs up the curved staves and across the head boards. The hoops are dark rusted iron, the same recipe as shipping-crate. The temp .glb is removed once its size is measured.

Run#

blender --background --python wooden_barrel.py --
blender --background --python wooden_barrel.py -- --skip-decimate
blender --background --python wooden_barrel.py -- --stray-vert
blender --background --python wooden_barrel.py -- --lift-z
blender --background --python wooden_barrel.py -- --short-staves
blender --background --python wooden_barrel.py -- --float-head
blender --background --python wooden_barrel.py -- --round-band
blender --background --python wooden_barrel.py -- --one-piece-head
blender --background --python wooden_barrel.py -- --output barrel.png

Smoke passes no flags.

Exit codes#

File-local. 9 is a valid check code. 10 is reserved for gallery_framing.check_framing on the --output path. 15–19 are the hygiene and joint-fit family.

CodeMeaning
0Success
1Uncaught exception (FATAL wrapper)
2argparse / usage
3Mesh did not build / no UV layer
4Base triangle count outside range
5Material count ≠ 2 distinct slots, or a face-count floor missed
6UVs outside 0..1
7UV AABB overlap above tolerance
8World AABB off declared outer size
9LOD ratio band (--skip-decimate lands here)
10Framing gate (render path only)
11Collider triangle count above ceiling
12Bake did not finish or image has no data
13Export file missing or empty
14--output produced no file
15Mesh hygiene: loose, non-manifold, zero-area, doubles, n-gons, z-fight
16Not grounded: bounding box zmin off 0, or a named stave floats
17Joint fit: head-croze gap (--float-head), or head boards and seams (--one-piece-head)
18Seat: hoop bite band (--round-band)
19Body diameter or height off the stated real-world size
20Gallery asset-quality violation (render path; the floors' 11 is remapped here)

Source

showcase/wooden-barrel/wooden_barrel.py View the script on GitHub →
A wooden stave barrel bound by four iron hoops, its head made of boards.