nx_boneheat_lib.nx
buildroot/runtime/nx_boneheat_lib.nx
about
nx_boneheat_lib.nx -- SOVEREIGN AUTO-WEIGHTS: geodesic bone-heat skin weights over the VOXELISED VOLUME of a mesh.
WHY (2026-09-05). modding MD4 and dcc DC16 both price auto-rigging, and MD4's pre-declared accept rule says the
learned rig must beat a nearest-joint heat-weight CONTROL -- an organ the estate did not have (nx_catalog:
nx_boneheat ABSENT; nx_capsearch: no voxel flood-fill and no geodesic-weight ruler anywhere in 7,414 sources).
nx_nxa_skin's autoskin is nearest-segment inverse-distance, which bleeds across air: a hand resting on a hip
takes hip weight. That is the failure Blender's Automatic Weights (bone heat, Baran and Popovic 2007) avoids and
the one Maya's geodesic voxel bind (Dionne and de Lasa 2013) avoids more robustly, because it never needs a
manifold mesh -- it needs a volume. This lib is that class, integer and deterministic, first byte up:
1. VOXELISE: rasterise every triangle into a grid sized from knowledge/boneheat.conf, flood the EXTERIOR from
the padded border through non-surface cells, and call the rest INTERIOR. The partition is printed and SUMS.
A mesh that is not sealed simply has interior=0 and the solve runs over its shell: no refusal, announced.
2. SEED: each joint owns the segment from itself to the mean of its children (a leaf owns a point); the
segment's cells are distance 0. A joint whose segment lies outside the volume is PROJECTED to the nearest
domain cell and COUNTED, never silently dropped.
3. SOLVE: per joint, Dijkstra over the 26-connected domain with chamfer weights 10/14/17 (Dial buckets, an
exact push bound of 26 per settled cell). Air is not domain, so distance cannot cross it -- that is the
whole difference from nearest-joint, and the gate proves it on two shells.
4. WEIGH: per vertex keep the four nearest joints at 2^40/(d+half)^2, normalise to the NXA sum of 4096 with the
residual folded into the largest influence (the estate's own zero-volume-loss rule). Vertices no joint can
reach fall back to the nearest segment and are COUNTED.
The NEAREST mode is the control MD4 names: one joint, weight 4096, the nearest segment by Euclidean distance.
It shares every reader and the writer, so the two modes cannot disagree about the asset.
UNITS: VERT and SKEL are 0.01 mm model units (NXA v1); the grid cell is derived from the bounding box.
license_tier: ORIGINAL
dependencies 3 imports · 6 importers
imports: nx_syscalls.nxnx_nxa.nxnx_vecmath.nx
imported by: nx_boneheat.nxnx_boneheat_gate.nxnx_curveskel_lib.nxnx_motion_gate.nxnx_motion_serve_gate.nxnx_profile_semantic_overlay_t239.nx
structs
| none |
consts
| 30 | const BH_Q12: i64 = 4096 // NXA v1: q12 weights summing 4096 (format-fixed) |
| 31 | const BH_INF_SLOTS: i64 = 4 // NXA v1: 4 influences per vertex (format-fixed) |
| 32 | const BH_JOINT_WORDS: i64 = 8 // SKEL row: parent tx ty tz qx qy qz qw |
| 33 | const BH_SKIN_WORDS: i64 = 8 // SKIN row: 4 joint ids then 4 q12 weights |
| 34 | const BH_VERT_WORDS: i64 = 3 |
| 35 | const BH_TRI_WORDS: i64 = 3 |
| 36 | const BH_HDR_BYTES: i64 = 32 // magic ver ns toc-check |
| 37 | const BH_TOC_WORDS: i64 = 4 // tag byte-offset word-len payload-check |
| 38 | const BH_TOC_BYTES: i64 = 32 |
| 39 | const BH_MAX_SECTIONS: i64 = 64 // nxa_find's own bound |
| 40 | const BH_KIND_EXTERIOR: i64 = 0 |
| 41 | const BH_KIND_SURFACE: i64 = 1 |
| 42 | const BH_KIND_INTERIOR: i64 = 2 |
| 43 | const BH_KIND_UNSEEN: i64 = 3 |
| 44 | const BH_DILATE_STEPS: i64 = 1 // bh_dilate runs ONE 6-dilation; the shell depth below is derived from it |
| 45 | const BH_WALL_DEPTH: i64 = 3 // 1 (the raster's own cell) + 2 x BH_DILATE_STEPS: the deepest six-step a REAL shell cell can sit from the exterior |
| 46 | const BG_WALLS: i64 = 21 // internal-wall cells stripped to INTERIOR by bh_flood (grid descriptor slot) |
| 47 | const BR_WALLS: i64 = 20 // the same count in the report, so the caller can print walls= |
| 48 | const BH_WALL_HIST: i64 = 10 // shell-depth census buckets d1..d9 (d9 = nine or deeper): the measurement the strip depth is DERIVED from |
| 49 | const BH_STEP: i64 = 10 // one face step = 10 so the chamfer weights stay integer |
| 50 | const BH_W_FACE: i64 = 10 // sqrt(1) x 10 |
| 51 | const BH_W_EDGE: i64 = 14 // sqrt(2) x 10, rounded |
| 52 | const BH_W_CORNER: i64 = 17 // sqrt(3) x 10, rounded |
| 53 | const BH_NBUCKET: i64 = 18 // Dial buckets = largest edge weight + 1 |
| 54 | const BH_PUSH_PER_CELL: i64 = 26 // a settled cell relaxes at most its 26 neighbours: the pool bound is EXACT |
| 55 | const BH_DIST_INF: i64 = 1152921504606846976 |
| 56 | const BH_HALF_STEP: i64 = 5 // half a face step: the smallest distance the grid resolves |
| 57 | const BH_WSCALE_SHIFT: i64 = 40 // raw weight = 2^40 / (d + half)^2 |
| 58 | const BH_PAD_CELLS: i64 = 2 // DERIVED = 1 + BH_DILATE_STEPS: bh_dilate grows the shell OUTWARD by one cell, so a one-cell pad is FILLED wherever a face touches the bounding box and the exterior flood is starved there. MEASURED 2026-09-06 on a lone 60 mm prism (no internal geometry): exterior 472 of 14,112 cells, shell-depth census RISING with depth (d1=1352 d3=2424 d5=2136) and 4,416 false walls; the sheet neg-control stopped being refused. One spare layer beyond the dilation keeps a flood seed on every side. |
| 59 | const BH_SAMPLE_DIV: i64 = 2 // triangles and segments are sampled at half a cell: no cell is skipped |
| 60 | const BH_GRID_DEFAULT: i64 = 96 // used ONLY when the conf is absent; provenance is printed |
| 61 | const BH_MODE_GEODESIC: i64 = 1 |
| 62 | const BH_MODE_NEAREST: i64 = 2 |
| 63 | const BH_Q10: i64 = 1024 // segment parameter fixed point for the nearest control |
| 64 | const BH_MODE_0644: i64 = 420 |
| 65 | const BH_NOJOINT: i64 = 0 - 1 |
| 66 | const BH_CONF_KEY: *u8 = "grid_cells_longest=" |
| 67 | const BH_CONF_PATH: *u8 = "knowledge/boneheat.conf" |
| 69 | const BG_NX: i64 = 0 |
| 70 | const BG_NY: i64 = 1 |
| 71 | const BG_NZ: i64 = 2 |
| 72 | const BG_CELL: i64 = 3 |
| 73 | const BG_OX: i64 = 4 |
| 74 | const BG_OY: i64 = 5 |
| 75 | const BG_OZ: i64 = 6 |
| 76 | const BG_N: i64 = 7 |
| 77 | const BG_KIND: i64 = 8 |
| 78 | const BG_DIST: i64 = 9 |
| 79 | const BG_SET: i64 = 10 |
| 80 | const BG_POOLC: i64 = 11 |
| 81 | const BG_POOLN: i64 = 12 |
| 82 | const BG_POOLCAP: i64 = 13 |
| 83 | const BG_HEAD: i64 = 14 |
| 84 | const BG_EXT: i64 = 15 |
| 85 | const BG_SURF: i64 = 16 |
| 86 | const BG_INT: i64 = 17 |
| 87 | const BG_DOMAIN: i64 = 18 |
| 88 | const BG_POOLUSED: i64 = 19 |
| 89 | const BG_QUEUE: i64 = 20 |
| 90 | const BG_WORDS: i64 = 24 |
| 92 | const BR_VERTS: i64 = 0 |
| 93 | const BR_TRIS: i64 = 1 |
| 94 | const BR_JOINTS: i64 = 2 |
| 95 | const BR_CELLS: i64 = 3 |
| 96 | const BR_EXT: i64 = 4 |
| 97 | const BR_SURF: i64 = 5 |
| 98 | const BR_INT: i64 = 6 |
| 99 | const BR_SEALED: i64 = 7 |
| 100 | const BR_SEEDS: i64 = 8 |
| 101 | const BR_PROJECTED: i64 = 9 |
| 102 | const BR_UNREACH_J: i64 = 10 |
| 103 | const BR_UNREACH_V: i64 = 11 |
| 104 | const BR_MIXED: i64 = 12 |
| 105 | const BR_BYTES: i64 = 13 |
| 106 | const BR_NX: i64 = 14 |
| 107 | const BR_NY: i64 = 15 |
| 108 | const BR_NZ: i64 = 16 |
| 109 | const BR_CELL: i64 = 17 |
| 110 | const BR_CONF: i64 = 18 |
| 111 | const BR_GRIDN: i64 = 19 |
| 112 | const BR_WORDS: i64 = 24 |
| 114 | const BH_EXIT_OK: i64 = 0 |
| 115 | const BH_EXIT_USAGE: i64 = 2 |
| 116 | const BH_EXIT_REFUSE: i64 = 3 |
functions
| 118 | func bh_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 119 | func bh_num(v: i64) -> i64 |
| 132 | func bh_kv(k: *u8, v: i64) -> i64 { bh_puts(k); bh_num(v); return 0 } |
| 133 | func bh_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } |
| 134 | func bh_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } called by 1: bh_grid_build |
| 135 | func bh_abs(a: i64) -> i64 { if a < 0 { return 0 - a } return a } |
| 136 | func bh_streq(a: *u8, b: *u8) -> i64 called by 1: main |
| 144 | func bh_conf_cells(path: *u8) -> i64 |
| 177 | func bh_idx(g: *i64, ix: i64, iy: i64, iz: i64) -> i64 |
| 186 | func bh_cell_of(g: *i64, x: i64, y: i64, z: i64) -> i64 |
| 190 | func bh_kind(g: *i64, c: i64) -> i64 { let k: *u8 = g[BG_KIND] as *u8; return k[c] as i64 } called by 1: bh_is_domain |
| 191 | func bh_is_domain(g: *i64, c: i64) -> i64 |
| 199 | func bh_grid_build(g: *i64, w: *i64, vwo: i64, nv: i64, cells: i64) -> i64 |
| 233 | func bh_mark_surface(g: *i64, x: i64, y: i64, z: i64) -> i64 |
| 240 | func bh_seglen(ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64) -> i64 |
| 245 | func bh_raster(g: *i64, w: *i64, vwo: i64, two: i64, nt: i64) -> i64 |
| 277 | func bh_dilate(g: *i64) -> i64 |
| 307 | func bh_flood(g: *i64) -> i64 |
| 438 | func bh_reset(g: *i64) -> i64 |
| 449 | func bh_push(g: *i64, c: i64, d: i64) -> i64 |
| 462 | func bh_seed(g: *i64, c: i64) -> i64 |
| 471 | func bh_dijkstra(g: *i64) -> i64 |
| 526 | func bh_project(g: *i64, x: i64, y: i64, z: i64) -> i64 |
| 555 | func bh_seed_segment(g: *i64, ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64, projected: *i64) -> i64 |
| 575 | func bh_joint_segments(w: *i64, swo: i64, nj: i64, seg: *i64) -> i64 |
| 605 | func bh_seg_dist2(seg: *i64, j: i64, x: i64, y: i64, z: i64) -> i64 called by 1: bh_nearest_joint |
| 620 | func bh_nearest_joint(seg: *i64, nj: i64, x: i64, y: i64, z: i64) -> i64 |
| 632 | func bh_top4_insert(tj: *i64, tw: *i64, v: i64, j: i64, wgt: i64) -> i64 called by 1: bh_run |
| 641 | func bh_nxa_write(path: *u8, ns: i64, tags: *i64, ptrs: *i64, wls: *i64) -> i64 |
| 671 | func bh_run(inpath: *u8, outpath: *u8, mode: i64, cells_conf: i64, rep: *i64) -> i64 |
| 811 | func bh_report(mode: i64, rep: *i64, inpath: *u8, outpath: *u8) -> i64 |