nx_meshrig.nx
buildroot/runtime/nx_meshrig.nx
about
nx_meshrig.nx -- THE BINDER: a GENERATED mesh + a GENERATED skeleton -> a first-class rigged NXA.
WHY THIS EXISTS (measured 2026-08-23, capsearch over 1,284 tools): the ONLY organ that filled
SKEL+SKIN was nx_nxa_skin, and it requires a BINARY FBX. So every GENERATED body was unriggable --
it could not enter a world, could not be scored on the asset floor's rig axes, and could not
receive the soft-tissue or skeletal-animation work that shipped the same day; all of that reached
IMPORTED donors only. It is also why the one rigged character in the corpus was the corpus
MINIMUM (14,164 verts) while the donors ran to 423,919.
nx_meshrig <mesh.nxmesh> <skel.txt> <out.nxa>
INPUT A -- NXMSH2 triangle soup: byte0=N, byte5=2, u32 at 8 = nlayers, u32 at 12 = ntris,
header = 16 + nlayers*24, then ntris records of 84 bytes whose first 9 f32 are the triangle's
three xyz corners in MILLIMETRES.
INPUT B -- nx_skelgen's emitted rest skeleton: J rows (J idx parent side x y z) in world
MILLIMETRES. Its B rows are bone lengths and joint limits and are skipped here.
OUTPUT -- NXANIM01 carrying VERT + TRIS + SKEL + SKIN per knowledge/nxa_format_spec.md:
VERT and SKEL translations are 0.01 mm; SKIN is 8 words per vertex, [j0 j1 j2 j3][w0..w3 q12],
the four weights summing to EXACTLY 4096; every section carries the spec's rolling
order-sensitive checksum, and the TOC carries one over its own words.
THE WEIGHTING METHOD, AND WHY -- the one real design choice, stated rather than buried:
Shepard normalised INVERSE DISTANCE (exponent 1) over the k nearest BONE SEGMENTS, where a
bone is a (joint,parent) pair -- the canon's OWN structure, never an invented body-part map.
k = 4 is STRUCTURAL, not a cap: the NXA SKIN record holds exactly four joint/weight lanes, so
the FORMAT fixes it and no author picked it.
Exponent 1 is used because it is the only exponent that requires no justification: every other
value is a sharpness knob, and a knob with no derivation is the magic number this estate bans.
Distance is to the SEGMENT (clamped projection), not to the joint -- a joint-distance bind
pulls mid-limb vertices toward the wrong end and is the classic candy-wrapper cause.
HONEST CEILING, NAMED NOT SILENTLY APPROXIMATED: bone-heat and bounded-biharmonic weights are
the higher-quality methods because they respect mesh CONNECTIVITY, so a weight cannot leak
across a gap the way a pure distance metric can (the inner thigh and the armpit are where this
shows). Both require a sparse Laplacian solve over the mesh, which in integer-only NishiLang is
an iterative solver needing its own convergence proof. That is the named next rung.
UP-AXIS IS DERIVED FROM BOTH INPUTS, NEVER ASSUMED: the stature axis of each is its own LARGEST
EXTENT -- the estate's proven method, the same one that caught FBX Y-up against NXA Z-up on the
donors and confirmed axis 2 on the shipped character. A mismatch is corrected by a PROPER
rotation (determinant +1, never a mirror); an unhandled pairing REFUSES BY NAME rather than
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 50 | const MR_MODE: i64 = 420 |
| 51 | const MR_Q12: i64 = 4096 |
| 52 | const MR_INF: i64 = 4 |
| 53 | const MR_BIG: i64 = 4611686018427387903 |
| 54 | const MR_M23: i64 = 8388607 |
| 55 | const MR_M24: i64 = 8388608 |
| 56 | const MR_MMQ: i64 = 100 |
| 57 | const MR_TRIB: i64 = 84 |
| 58 | const MR_HDR0: i64 = 16 |
| 59 | const MR_LAYB: i64 = 24 |
| 60 | const MR_RECIP: i64 = 1073741824 |
| 61 | const MR_CHK: i64 = 1000003 |
| 62 | const MR_NSECT: i64 = 4 |
| 63 | const MR_SP: i64 = 32 |
| 64 | const MR_NL: i64 = 10 |
| 65 | const MR_JCH: i64 = 74 |
| 66 | const MR_MINUS: i64 = 45 |
| 67 | const MR_D0: i64 = 48 |
| 68 | const MR_D9: i64 = 57 |
functions
| 70 | func mr_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 71 | func mr_num(v: i64) -> i64 |
| 83 | func mr_kv(k: *u8, v: i64) -> i64 { mr_puts(k); mr_num(v); mr_puts("\n" as *u8); return 0 } |
| 84 | func mr_refuse(reason: *u8) -> i64 { mr_puts("MESHRIG REFUSED: " as *u8); mr_puts(reason); mr_puts("\n" as *u8); return 0 } |
| 86 | func mr_u32(b: *u8, o: i64) -> i64 |
| 90 | func mr_f32q(w: i64) -> i64 called by 1: mr_load_mesh |
| 106 | func mr_isqrt(n: i64) -> i64 called by 1: mr_dseg |
| 113 | func mr_dseg(px: i64, py: i64, pz: i64, ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64) -> i64 |
| 137 | func mr_check(w: *i64, n: i64) -> i64 called by 1: main |
| 143 | func mr_tag(a: i64, b: i64, c: i64, d: i64) -> i64 { return a + (b << 8) + (c << 16) + (d << 24) } called by 1: main |
| 147 | func mr_scan_int(b: *u8, n: i64, pos: *i64) -> i64 called by 1: mr_load_skel |
| 174 | func mr_load_mesh(path: *u8, vxp: *i64) -> i64 |
| 201 | func mr_load_skel(path: *u8, jp: *i64, jx: *i64, jy: *i64, jz: *i64, maxj: i64) -> i64 |
| 253 | func mr_up_axis(c: *i64, n: i64, stride: i64, base: i64, ext_out: *i64) -> i64 called by 1: main |
| 286 | func main(argc: i64, argv: *i64) -> i64 |