"""For each finger bone, report how much geometry it actually OWNS (verts where it is the dominant influence) and where that geometry sits. On a two-finger hand rig the five-finger bone set is present but several chains own nothing, or several chains share one fused mass. usage: hand_bone_ownership.py body.glb [side l|r] """ import json, struct, sys, math from pathlib import Path from collections import defaultdict FING = ("thumb", "index", "middle", "ring", "pinky") side = sys.argv[2] if len(sys.argv) > 2 else None def read_glb(p): d = Path(p).read_bytes() length = struct.unpack_from(" best[0]: best = (w, jname[j]) if best[1] and any(t in best[1].lower() for t in FING): if side and not best[1].lower().endswith("_" + side): continue own[best[1]].append(p) print(f"{Path(sys.argv[1]).name} dominant-owner geometry per finger bone" f"{' (side ' + side + ')' if side else ''}\n") print(f" {'bone':20s} {'verts':>7s} {'z-centre':>9s} {'z-span':>8s} {'x-centre':>9s}") for fam in FING: rows = [(n, v) for n, v in own.items() if fam in n.lower()] if not rows: print(f" {fam:20s} {'0':>7s} -- owns no geometry --") continue for n in sorted(r[0] for r in rows): ps = own[n] zc = sum(p[2] for p in ps) / len(ps) * 100 zs = (max(p[2] for p in ps) - min(p[2] for p in ps)) * 100 xc = sum(p[0] for p in ps) / len(ps) * 100 print(f" {n:20s} {len(ps):7d} {zc:8.1f}cm {zs:7.1f}cm {xc:8.1f}cm") print() tot = sum(len(v) for v in own.values()) print(f" total finger-owned verts: {tot}")