Skip to content

Commit a089055

Browse files
TMHSDigitalclaude
andcommitted
fix(examples): redesign vertex-weight-limit as a painted industrial arm
The gallery review singled this hero out: a stack of orange cylinders in a mostly empty frame, and the bone influences the example is about were invisible. The arm is now a designed six-axis-style industrial robot - bolted plinth, turret, finned drive pack, clevis cheeks and servo drums, box-section arms, a gas-spring balancer, wrist fork and two-jaw gripper - in a reaching pose that fills the frame (fill 0.725x / 0.872y). The render path now paints the post-limit weights, read back from v.groups, as a BoneBlend colour attribute: rigid segments show their bone's colour and the two back cables grade across each joint, so the viewer sees where bones blend. The four-influence cap itself stays numeric-only (the pruned spill is at most 0.0027), and the README says so. Weights are now authored as a joint hand-over plus an auto-weight-style spill on the cables; all checks are unchanged and pass identically on 4.5.11, 5.1.2 and 5.2.1, each re-falsified. The render path also gains the asset-quality gate (exit 11). asset_sheet_panel.py keeps armatures so a skinned asset is sheeted in its pose rather than its rest pose. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent 16f9b65 commit a089055

11 files changed

Lines changed: 974 additions & 434 deletions

File tree

‎README.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ Neighbor of [`lod-decimate-chain`](examples/lod-decimate-chain/).
899899
</tr>
900900
<tr>
901901
<td width="46%" valign="middle">
902-
<a href="examples/vertex-weight-limit/"><img src="examples/vertex-weight-limit/preview.webp" alt="Vertex weight limit: a posed mech arm on a dark studio floor - orange armor shells, a glowing teal flex cuff around the hex-bolted elbow hinge, long plated forearm, three-finger gripper - deformed by weights pruned to the four-influence engine cap" /></a>
902+
<a href="examples/vertex-weight-limit/"><img src="examples/vertex-weight-limit/preview.webp" alt="Vertex weight limit: an orange industrial robot arm reaching down with a two-jaw gripper, painted with its own post-limit skin weights - each rigid segment glows in its bone colour and the back cables grade blue to teal to violet to magenta across the joints" /></a>
903903
</td>
904904
<td valign="middle">
905905

@@ -908,9 +908,10 @@ Neighbor of [`lod-decimate-chain`](examples/lod-decimate-chain/).
908908
The game-engine max-four-bone-influences constraint, enforced through the data
909909
API (`v.groups` + `VertexGroup.remove` + renormalize) rather than the
910910
`bpy.ops.object.vertex_group_limit_total` context path. Asserts the pre-limit
911-
boots really carry five influences, no vertex ends over the cap, weights still
911+
cables really carry five influences, no vertex ends over the cap, weights still
912912
sum to one, the pose survives pruning, and the modifier is still exact linear
913-
blend skinning read back from the mesh's own deform layer.
913+
blend skinning read back from the mesh's own deform layer. The render paints
914+
those post-limit weights onto the arm as a colour attribute.
914915

915916
</td>
916917
</tr>
64.9 KB
Loading
30.6 KB
Loading
26 KB
Loading

‎docs/gallery/index.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,11 @@ <h2><a href="lod-decimate-chain/">lod-decimate-chain</a></h2>
640640
</article>
641641
<article class="card" data-tags="armature mesh">
642642
<a class="card-media" href="vertex-weight-limit/" tabindex="-1" aria-hidden="true">
643-
<img src="assets/vertex-weight-limit-hero.webp" alt="A segmented orange robotic arm on a round base, bent at the elbow, with teal bands at the joints." loading="lazy" decoding="async" />
643+
<img src="assets/vertex-weight-limit-hero.webp" alt="An orange industrial robot arm reaching down with a two-jaw gripper, each segment glowing in its bone colour and the cables on its back grading from colour to colour across each joint." loading="lazy" decoding="async" />
644644
</a>
645645
<div class="card-body">
646646
<h2><a href="vertex-weight-limit/">vertex-weight-limit</a></h2>
647-
<p class="teaches">A rigged mech arm pruned to the game-engine cap of four bone influences per vertex, through the data API. The check proves no vertex exceeds the cap, weights still sum to one, the pose survives pruning, and the modifier is still exact linear blend skinning.</p>
647+
<p class="teaches">A rigged industrial robot arm pruned to the game-engine cap of four bone influences per vertex, through the data API. The check proves no vertex exceeds the cap, weights still sum to one, the pose survives pruning, and the modifier is still exact linear blend skinning.</p>
648648
<p class="witnesses"><span class="tag">witnesses</span> Limit-total and normalize without bpy.ops: keep the top four groups, VertexGroup.remove the rest, renormalize. LBS is verified against the weights read back from the mesh&#x27;s own deform layer, not the authoring function.</p>
649649
<a class="card-link" href="vertex-weight-limit/">View example<span class="sr-only"> vertex-weight-limit</span> <span aria-hidden="true">&rarr;</span></a>
650650
</div>

‎docs/gallery/vertex-weight-limit/index.html‎

Lines changed: 468 additions & 209 deletions
Large diffs are not rendered by default.

‎examples/gallery.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,8 @@
366366
{
367367
"name": "vertex-weight-limit",
368368
"dir": "examples/vertex-weight-limit",
369-
"teaches": "A rigged mech arm pruned to the game-engine cap of four bone influences per vertex, through the data API. The check proves no vertex exceeds the cap, weights still sum to one, the pose survives pruning, and the modifier is still exact linear blend skinning.",
370-
"alt": "A segmented orange robotic arm on a round base, bent at the elbow, with teal bands at the joints.",
369+
"teaches": "A rigged industrial robot arm pruned to the game-engine cap of four bone influences per vertex, through the data API. The check proves no vertex exceeds the cap, weights still sum to one, the pose survives pruning, and the modifier is still exact linear blend skinning.",
370+
"alt": "An orange industrial robot arm reaching down with a two-jaw gripper, each segment glowing in its bone colour and the cables on its back grading from colour to colour across each joint.",
371371
"witnessesFix": "Limit-total and normalize without bpy.ops: keep the top four groups, VertexGroup.remove the rest, renormalize. LBS is verified against the weights read back from the mesh's own deform layer, not the authoring function.",
372372
"hero": "docs/gallery/assets/vertex-weight-limit-hero.webp",
373373
"preview": "examples/vertex-weight-limit/preview.webp",

‎examples/vertex-weight-limit/README.md‎

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
# Vertex Weight Limit
22

3-
A runnable example that rigs a mech arm — flanged bolted pedestal and
4-
shoulder fairing, a panel-seamed upper arm ending in clevis cheeks, the
5-
elbow hinge pin and knuckle barrel capped with hex bolts through a ribbed
6-
flex cuff, a long seam-grooved forearm, wrist cuff and collar, and a
7-
three-finger gripper — with deliberately rich five-bone weight bumps in
8-
the cuffs, then enforces the game-engine
9-
**maximum of four bone influences per vertex** through the data API, following
10-
[`mesh-editing-and-bmesh`](../../skills/mesh-editing-and-bmesh/SKILL.md) and
11-
building on the linear-blend-skinning precedent of
3+
A runnable example that rigs a six-axis-style industrial robot arm — bolted
4+
floor plinth and turret drum with a finned rear drive pack, clevis cheeks
5+
and servo drums at the shoulder and elbow, a tapered box-section upper arm
6+
and forearm, a gas-spring balancer across the shoulder, a wrist fork and a
7+
two-jaw gripper — as **one skinned mesh**, then enforces the game-engine
8+
**maximum of four bone influences per vertex** through the data API,
9+
following [`mesh-editing-and-bmesh`](../../skills/mesh-editing-and-bmesh/SKILL.md)
10+
and building on the linear-blend-skinning precedent of
1211
[`armature-bend`](../armature-bend/).
1312

13+
Every rigid part (armor, motors, cheeks, piston, gripper) is weighted 1.0 to
14+
one bone. The two cable runs along the arm's back are the flex parts: they
15+
hand over smoothly from bone to bone across each joint and carry the tail an
16+
auto-weighting pass leaves behind — a small, distance-ranked spill onto all
17+
five bones. That tail is the five-influence authoring the limit prunes.
18+
1419
**Pipeline arc:** modeling/LOD in [`lod-decimate-chain`](../lod-decimate-chain/),
1520
weighting here, export in [`gltf-export-roundtrip`](../gltf-export-roundtrip/).
1621

@@ -20,28 +25,43 @@ AI-generated rigging code most often violates silently.
2025
- **The limit is a data-API operation, not a context operator.** Instead of
2126
`bpy.ops.object.vertex_group_limit_total`, the example reads each vertex's
2227
groups, keeps the top four by weight, `VertexGroup.remove`s the rest, and
23-
renormalizes the survivors. Dropping without renormalizing leaves sums at
24-
0.984 — a mesh that shrinks toward the origin under load (the check's
25-
measured failure, 1.616e-02 off unit sum).
28+
renormalizes the survivors. Dropping without renormalizing leaves sums
29+
short of one — a mesh that shrinks toward the origin under load (the
30+
check's measured failure, 2.647e-03 off unit sum).
2631
- **The armature modifier is still exactly linear blend skinning** after the
2732
limit: every depsgraph-evaluated vertex equals
2833
`Σ wᵢ · (pose.matrix @ bone.matrix_local.inverted()) @ rest`, with the
2934
weights **read back from the mesh's own deform layer** (`v.groups`) — the
3035
weights on the mesh are the contract, not the weights you meant to write.
31-
Measured `lbs_err = 2.7e-07`.
36+
Measured `lbs_err = 1.2e-06`.
3237
- **Pruning must not damage the pose.** Evaluated positions before and after
33-
the limit are held within 0.05 (measured 2.8e-03), the pedestal mount stays
34-
exactly pinned (Root is unposed), and the pre-limit authoring really carries
35-
five influences in the cuffs — otherwise the witness would be vacuous.
38+
the limit are held within 0.05 (measured 4.2e-03 over 3108 limited
39+
vertices), the plinth stays exactly pinned (Root is unposed), and the
40+
pre-limit authoring really carries five influences on the cables —
41+
otherwise the witness would be vacuous.
3642

3743
The vertex-group API (`v.groups`, `VertexGroup.add`/`remove`) is stable between
38-
Blender 4.5 LTS and 5.1 — the example runs identically on both, which is itself
39-
the version witness (measured values match to the digit).
44+
Blender 4.5 LTS and 5.2 — the example runs identically on 4.5, 5.1 and 5.2,
45+
which is itself the version witness (measured values match to the digit).
46+
47+
## What the render shows
48+
49+
The render path paints the **post-limit weights** onto the arm as a
50+
`BoneBlend` colour attribute — `Σ wᵢ · colourᵢ` per vertex, read back from
51+
`v.groups` after the prune — and the cables, side hatches and trim bands
52+
display it through a matte Attribute-node material. Each rigid segment
53+
therefore shows its bone's flat colour (blue turret, teal upper arm, violet
54+
forearm, magenta wrist, lime gripper), and the cables grade from colour to
55+
colour exactly where the skin weights blend across each joint, while the
56+
posed arm shows those weights deforming it.
4057

41-
The render shows the pruned arm mid-pose: the flex cuffs carry the teal
42-
accent — the five-influence zones the limit prunes glow at the elbow hinge
43-
and wrist, sealed by the bright hoop on the elbow cuff — proof that the
44-
limited weights still deform as authored.
58+
**Numeric-only contract** (docs/VISUAL-STYLE.md § The render is the proof):
59+
the four-influence cap itself has no visual signature. The pruned fifth
60+
weight is the small spill (at most 0.0027 on any vertex), so a five-influence
61+
arm deforms and paints indistinguishably — the prune preserves the pose by
62+
design, and that is what check 3 asserts. The render depicts the subject and
63+
where its weights blend; the cap is witnessed by the numbers above and by the
64+
`--skip-limit` falsifier.
4565

4666
## Run
4767

@@ -61,7 +81,7 @@ blender --background --python vertex_weight_limit.py -- --output arm.png --engin
6181

6282
Per-script sequential checks. `9` is a valid check code; there is no rule
6383
against it. `10` is the shared framing helper; it is also the missing-render
64-
code.
84+
code. `11` is the shared asset-quality helper.
6585

6686
| Code | Meaning |
6787
| --- | --- |
@@ -76,6 +96,7 @@ code.
7696
| 8 | Evaluated mesh off LBS over limited weights |
7797
| 9 | Root-weighted mount moved |
7898
| 10 | Gallery framing violation; also `--output` produced no file |
99+
| 11 | Asset-quality floor violation (`--output` only) |
79100

80101
The `blender-smoke` workflow runs the check on Blender 5.2 LTS and 4.5 LTS
81102
(5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch).
29 KB
Loading

0 commit comments

Comments
 (0)