code wiki / _hdl_build / nx_articulate_gate.nx

nx_articulate_gate.nx source

↩ module page · 132 lines · 8014 B

1// nx_articulate_gate.nx -- ★R9: ARTICULATED (rigged) assets. A 2-bone-per-leg skeleton with forward kinematics, 2// proven by the defining articulation property + a walk animation: 3// T1 ★HIERARCHY (FK): rotating the HIP (thigh) moves the whole leg (knee AND foot); rotating the KNEE (shin) 4// moves ONLY the lower bone (the foot moves, the knee joint does NOT) -- parent drives subtree, child doesn't 5// T2 POSE CONTROL: the same creature in a bent pose renders visibly different from standing 6// T3 ★WALK CYCLE: animating the joints produces distinct, PERIODIC frames (a gait -- skeletal animation) 7// T4 determinism + a walk-cycle strip knowledge/nx_articulate.png (6 frames of a walking creature) 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_itrig.nx" 11import "nx_png.nx" 12import "nx_creaturegen.nx" 13 14func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 15func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 16func d3(a: *i64, ai: i64, b: *i64, bi: i64) -> i64 { let dx: i64=a[ai]-b[bi]; let dy: i64=a[ai+1]-b[bi+1]; let dz: i64=a[ai+2]-b[bi+2]; var s: i64=dx*dx+dy*dy+dz*dz; if s<=0 {return 0} var r: i64=s; var q: i64=(r+1)/2; while q<r {r=q; q=(r+s/r)/2} return r } 17func L1i(a: *i64, b: *i64, n: i64) -> i64 { var s: i64=0; var i: i64=0; while i<n { var d: i64=(a[i]&255)-(b[i]&255); if d<0{d=0-d} s=s+d; i=i+1 } return s } 18 19const YAW: i64 = 6434 // ~90deg side view: leg swing (fore/aft in Z) is visible 20const THA: i64 = 1500 // thigh swing amplitude (it4096) 21const SHA: i64 = 1100 // shin bend amplitude 22 23func main() -> i64 { 24 hw("=== nx_articulate_gate -- R9: skeletal rig + forward kinematics + walk cycle ===\n" as *u8) 25 var fails: i64 = 0 26 27 // ---- T1 FK hierarchy ---- 28 let fk0: *i64 = sys_mmap(8*8) as *i64 29 let fkT: *i64 = sys_mmap(8*8) as *i64 30 let fkS: *i64 = sys_mmap(8*8) as *i64 31 cg_fk_leg(0, 800, 0, 0, 0, 132, 120, fk0) // rest 32 cg_fk_leg(0, 800, 0, 2000, 0, 132, 120, fkT) // thigh only 33 cg_fk_leg(0, 800, 0, 0, 2000, 132, 120, fkS) // shin only 34 let knee_moves_shin: i64 = d3(fkS, 0, fk0, 0) // should be 0 (shin doesn't move the knee joint) 35 let foot_moves_shin: i64 = d3(fkS, 3, fk0, 3) // should be > 0 (shin moves the foot) 36 let knee_moves_thigh: i64 = d3(fkT, 0, fk0, 0) // should be > 0 (thigh moves the knee) 37 let foot_moves_thigh: i64 = d3(fkT, 3, fk0, 3) // should be > 0 38 hw(" FK: shin->knee-disp="); pn(knee_moves_shin); hw(" shin->foot-disp="); pn(foot_moves_shin); hw(" thigh->knee-disp="); pn(knee_moves_thigh); hw("\n" as *u8) 39 var t1: i64 = 0 40 if knee_moves_shin == 0 { if foot_moves_shin > 40 { if knee_moves_thigh > 40 { if foot_moves_thigh > 40 { t1 = 1 } } } } 41 if t1 == 1 { hw("T1 PASS HIERARCHY: hip rotates the whole leg; knee rotates only the lower bone (real FK)\n" as *u8) } 42 else { fails=fails+1; hw("T1 FAIL FK hierarchy\n" as *u8) } 43 44 // ---- render setup ---- 45 let W: i64 = as_w(); let H: i64 = as_h(); let npx: i64 = W*H 46 let AP: *i64 = sys_mmap(96*AS_STRIDE*8) as *i64 47 let pose: *i64 = sys_mmap(8*8) as *i64 48 let stand: *i64 = sys_mmap(npx*8) as *i64 49 let bent: *i64 = sys_mmap(npx*8) as *i64 50 51 // T2 standing vs bent 52 var k: i64 = 0 53 while k < 8 { pose[k]=0; k=k+1 } 54 let ns: i64 = creaturegen_build_posed(AP, 4, pose) 55 anatstack_render(AP, ns, YAW, 3, 1, 45, 150, 116, 84, stand) 56 // a dramatic crouch: front legs fold forward-under, back legs splay back + deep knee bend 57 pose[0]=2600; pose[1]=0-3200; pose[2]=0-2600; pose[3]=0-3200; pose[4]=2800; pose[5]=0-3400; pose[6]=0-2800; pose[7]=0-3400 58 let nb: i64 = creaturegen_build_posed(AP, 4, pose) 59 anatstack_render(AP, nb, YAW, 3, 1, 45, 150, 116, 84, bent) 60 let dpose: i64 = L1i(stand, bent, npx) 61 hw(" pose: parts="); pn(ns); hw(" stand-vs-crouch L1="); pn(dpose); hw("\n" as *u8) 62 var t2: i64 = 0 63 if dpose > 120000 { t2 = 1 } 64 if t2 == 1 { hw("T2 PASS POSE CONTROL: the rig reposes the same creature (standing != bent)\n" as *u8) } 65 else { fails=fails+1; hw("T2 FAIL pose\n" as *u8) } 66 67 // ---- T3 walk cycle: 6 frames + a 7th at full-period (== frame 0) ---- 68 let NF: i64 = 6 69 let frames: *i64 = sys_mmap(NF*npx*8) as *i64 70 var f: i64 = 0 71 while f < NF { 72 let ph: i64 = f*25736/NF // 0..2pi over the cycle 73 let phd: i64 = ph + 12868 // diagonal pair = half-cycle offset 74 // FL,BR in phase ; FR,BL opposite 75 pose[0]=THA*it_sin4096(ph)/4096; pose[1]=SHA*it_sin4096(ph+6434)/4096 76 pose[2]=THA*it_sin4096(phd)/4096; pose[3]=SHA*it_sin4096(phd+6434)/4096 77 pose[4]=THA*it_sin4096(phd)/4096; pose[5]=SHA*it_sin4096(phd+6434)/4096 78 pose[6]=THA*it_sin4096(ph)/4096; pose[7]=SHA*it_sin4096(ph+6434)/4096 79 let nf: i64 = creaturegen_build_posed(AP, 4, pose) 80 anatstack_render(AP, nf, YAW, 3, 1, 45, 150, 116, 84, (frames as i64 + f*npx*8) as *i64) 81 f = f + 1 82 } 83 // full-period frame (phase 2pi) -> should match frame 0 84 var k2: i64 = 0 85 while k2 < 8 { pose[k2] = 0; k2 = k2 + 1 } 86 pose[0]=THA*it_sin4096(25736)/4096; pose[1]=SHA*it_sin4096(25736+6434)/4096 87 pose[2]=THA*it_sin4096(25736+12868)/4096; pose[3]=SHA*it_sin4096(25736+12868+6434)/4096 88 pose[4]=pose[2]; pose[5]=pose[3]; pose[6]=pose[0]; pose[7]=pose[1] 89 let nfw: i64 = creaturegen_build_posed(AP, 4, pose) 90 let wrap: *i64 = sys_mmap(npx*8) as *i64 91 anatstack_render(AP, nfw, YAW, 3, 1, 45, 150, 116, 84, wrap) 92 // adjacent-frame motion (min over pairs) + periodicity (frame0 vs wrap) 93 var minadj: i64 = 2000000000 94 var ff: i64 = 0 95 while ff < NF-1 { 96 let d: i64 = L1i((frames as i64 + ff*npx*8) as *i64, (frames as i64 + (ff+1)*npx*8) as *i64, npx) 97 if d < minadj { minadj = d } 98 ff = ff + 1 99 } 100 let perr: i64 = L1i(frames, wrap, npx) 101 hw(" walk: min adjacent-frame L1="); pn(minadj); hw(" periodicity err(frame0 vs 2pi)="); pn(perr); hw("\n" as *u8) 102 var t3: i64 = 0 103 if minadj > 40000 { if perr < 20000 { t3 = 1 } } // frames move, and the cycle closes (periodic gait) 104 if t3 == 1 { hw("T3 PASS WALK CYCLE: joints animate into distinct, periodic frames (skeletal animation)\n" as *u8) } 105 else { fails=fails+1; hw("T3 FAIL walk\n" as *u8) } 106 107 // ---- T4 determinism + strip ---- 108 let chk: *i64 = sys_mmap(npx*8) as *i64 109 var k3: i64 = 0 110 while k3 < 8 { pose[k3]=0; k3=k3+1 } 111 let ncd: i64 = creaturegen_build_posed(AP, 4, pose) 112 anatstack_render(AP, ncd, YAW, 3, 1, 45, 150, 116, 84, chk) 113 var ddet: i64 = 0 114 var i2: i64 = 0 115 while i2 < npx { if chk[i2] != stand[i2] { ddet = ddet + 1 } i2 = i2 + 1 } 116 var t4: i64 = 0 117 if ddet == 0 { t4 = 1 } 118 if t4 == 1 { hw("T4 PASS deterministic\n" as *u8) } 119 else { fails=fails+1; hw("T4 FAIL nondeterministic ddet="); pn(ddet); hw("\n" as *u8) } 120 121 let GW: i64 = W*NF 122 let gal: *i64 = sys_mmap(GW*H*8) as *i64 123 var y: i64 = 0 124 while y < H { var x: i64=0; while x<W { var c: i64=0; while c<NF { gal[y*GW+c*W+x] = frames[c*npx + y*W+x]; c=c+1 } x=x+1 } y=y+1 } 125 write_png(gal, GW, H, "knowledge/nx_articulate.png" as *u8) 126 hw("T5 strip -> knowledge/nx_articulate.png (6-frame walk cycle)\n" as *u8) 127 128 if fails == 0 { hw("ARTICULATE-GATE GREEN -- R9: a skeletal rig with forward kinematics (hierarchy-correct) + pose control + a periodic walk cycle = articulated, animatable assets, sovereign. Residual vs their sim-ready: joint limits + physics/URDF export.\n" as *u8); sys_exit(0); return 0 } 129 hw("ARTICULATE-GATE RED fails="); pn(fails); hw("\n" as *u8) 130 sys_exit(1) 131 return 1 132}