nx_bvhfk.nx
buildroot/runtime/nx_bvhfk.nx
about
nx_bvhfk.nx -- BVH FORWARD KINEMATICS: joint tree + channel rotations -> WORLD-SPACE positions.
WHY THIS IS THE RUNG THAT MATTERS: parsing a BVH gets you a hierarchy; PLAYING it is what
DanceXR does. Our exceed is not playback -- it is that nx_pose_retarget already inverts our
sovereign FK (joint POSITIONS -> our rig's FK angles), and nx_pose_coach / nx_pose_naturalness
already SCORE a pose track. The one missing link was world-space positions out of a BVH. This
organ is that link, so third-party mocap can drive OUR rig -- including VRM, which appears
nowhere in DanceXR's format set.
THE FK CORE (fk_eval + the integer matrix substrate) LIVES IN nx_bvhfk_lib.nx since 2026-08-13
-- extracted on the second consumer (nx_clipcheck's bvh self-clearance control). The KAT below
is the extraction's value-identity proof: bone-length isometry on real third-party data.
*THE HARDEST TOOTH IS BONE-LENGTH INVARIANCE. A rotation is an isometry: |child - parent| MUST
equal |offset|, at every frame, for every joint. A rest-pose test passes even if the rotation
path is a no-op; a length test fails the moment a matrix is mis-scaled, mis-composed, or drifts
in fixed point. It is the implied hidden quantity that physics demands, and it is checked here
against REAL third-party data, not only a fixture.
UNITS: positions in file units x B_SCALE (1000) -- BVH does not state its unit; the convention
is centimetres, so we do not claim mm. Angles arrive as millidegrees and are converted to the
it_* integer-trig circle (25736 units) -- never to floats.
usage: nx_bvhfk pos <file.bvh> <frame> world x y z per joint
nx_bvhfk lens <file.bvh> <frame> measured bone length vs declared |offset| per joint
nx_bvhfk --kat selftest: 6 teeth, 3 of them anti-vacuity
license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
dependencies 4 imports · 0 importers
imports: nx_gate_verdict.nxnx_bvh_lib.nxnx_itrig.nxnx_bvhfk_lib.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
| 32 | const FK_MAGIC_8388607: i64 = 8388607 |
| 33 | const FK_MAGIC_4096: i64 = 4096 |
| 34 | const FK_MAGIC_5000: i64 = 5000 |
| 35 | const FK_MAGIC_4900: i64 = 4900 |
| 36 | const FK_MAGIC_5100: i64 = 5100 |
| 37 | const FK_MAGIC_4000: i64 = 4000 |
| 38 | const FK_MAGIC_1500: i64 = 1500 |
| 39 | const FK_MAGIC_7500: i64 = 7500 |
| 40 | const FK_MAGIC_3500: i64 = 3500 |
| 42 | const FK_KATBUF: i64 = 4096 |
| 43 | const FK_LENTOL: i64 = 40 // permitted |measured-declared| in file-units x1000 (fixed-point) |
| 60 | const FK_MM_DIV: i64 = 100 |
| 61 | const FK_BONE_R: i64 = 14 // bone half-width in mm |
| 62 | const FK_TRI_REC: i64 = 84 |
| 63 | const FK_HDR: i64 = 16 |
| 64 | const FK_COL_R: i64 = 900 // per-mille colour, per the heatmap convention |
| 65 | const FK_COL_G: i64 = 620 |
| 66 | const FK_COL_B: i64 = 300 |
functions
| 69 | func fk_f32bits(v: i64) -> i64 called by 1: fk_tri |
| 85 | func fk_w32(b: *u8, o: i64, v: i64) -> i64 |
| 94 | func fk_tri(b: *u8, t: i64, p: *i64, nx: i64, ny: i64, nz: i64) -> i64 |
| 117 | func fk_bone_box(b: *u8, t0: i64, ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64) -> i64 |
| 172 | func fk_emit_mesh(H: *i64, parent: *i64, pos: *i64, outp: *u8) -> i64 |
| 203 | func fk_cat(b: *u8, o: i64, s: *u8) -> i64 called by 1: fk_fixture |
| 210 | func fk_fixture(b: *u8, row: *u8) -> i64 |
| 225 | func fk_kat() -> i64 |
| 335 | func fk_load(path: *u8, H: *i64, names: *u8, parent: *i64, nchan: *i64, chan0: *i64, |
| 348 | func main(argc: i64, argv: *i64) -> i64 |