nx_softdyn.nx
buildroot/runtime/nx_softdyn.nx
about
nx_softdyn.nx -- LIB: SOVEREIGN SECONDARY DYNAMICS ("jiggle physics"), the general solver every animated
thing inherits. A driven ANCHOR (a bone from the rig, a weapon mount, a hair root) pulls a mass point through
a spring-damper; the mass LAGS under acceleration, OVERSHOOTS when the anchor stops, oscillates, and damps to
rest. The SAME solver serves: soft-tissue inertia on a moving body, firearm RECOIL (impulse), cloth and hair
sway, vehicle suspension. 100% integer + deterministic -> the same motion replays bit-identically.
State stride 6 per point: [px,py,pz, vx,vy,vz] all Q8 (model-units * 256).
Semi-implicit Euler: a = K*(anchor-p)/1024 - C*v/1024 ; v += a ; p += v
K = stiffness per-1024 (how hard tissue is bound to bone), C = damping per-1024 (how fast wobble dies).
Underdamped (C < 2*sqrt(K)) => visible jiggle. Critically/over-damped => rigid, no wobble.
A hard displacement CLAMP makes divergence impossible BY CONSTRUCTION (tissue can never fly off the body).
license_tier: ORIGINAL
dependencies 2 imports · 8 importers
imports: nx_syscalls.nxnx_vecmath.nx
imported by: nx_fascia.nxnx_fascia_tissue.nxnx_hairbake_probe.nxnx_hairdyn_lib.nxnx_hairdyn_pose_candidate_t263.nxnx_softbind.nxnx_softdyn_gate.nxnx_tissue.nx
structs
| none |
consts
| 16 | const SD_Q8: i64 = 256 |
| 17 | const SD_G: i64 = 1024 |
| 18 | const SD_STRIDE: i64 = 6 |
| 21 | const SD_CAPC: i64 = 1000 |
| 22 | const SD_CAPK: i64 = 3600 |
functions
| 24 | func sd_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } |
| 25 | func sd_isqrt(v: i64) -> i64 { return vm_isqrt(v) } called by 9: hd_ticks_per_sgr_scalp_rootgr_child_atgr_seglen_atsb_branch_permilsb_c_for_zeta+3 calls 1: vm_isqrt |
| 30 | func sd_clampk(K: i64) -> i64 { var k: i64 = K; if k > SD_CAPK { k = SD_CAPK } if k < 0 { k = 0 } return k } called by 1: sd_step_axq |
| 31 | func sd_clampc(C: i64) -> i64 { var c: i64 = C; if c > SD_CAPC { c = SD_CAPC } if c < 0 { c = 0 } return c } called by 1: sd_step_axq |
| 34 | func sd_alloc(n: i64) -> *i64 { return sys_mmap(n*SD_STRIDE*8) as *i64 } |
| 37 | func sd_seat(st: *i64, i: i64, ax: i64, ay: i64, az: i64) -> i64 |
| 45 | func sd_impulse(st: *i64, i: i64, ix: i64, iy: i64, iz: i64) -> i64 |
| 63 | func sd_deadsnap(st: *i64, b: i64, axis: i64, q: i64, kk: i64, cc: i64) -> i64 |
| 73 | func sd_step(st: *i64, i: i64, ax: i64, ay: i64, az: i64, K: i64, C: i64, maxd: i64) -> i64 |
| 87 | func sd_step_ax(st: *i64, i: i64, ax: i64, ay: i64, az: i64, |
| 106 | func sd_step_axq(st: *i64, i: i64, qx: i64, qy: i64, qz: i64, called by 4: hd_tickhd_tick_collidehd_tick_posed_collidesd_step_ax calls 4: sd_clampksd_clampcsd_isqrtsd_deadsnap |
| 146 | func sd_disp(st: *i64, i: i64, ax: i64, ay: i64, az: i64) -> i64 |
| 152 | func sd_disp_y(st: *i64, i: i64, ay: i64) -> i64 { return (st[i*SD_STRIDE+1] - ay*SD_Q8)/SD_Q8 } |
| 155 | func sd_disp_y_q8(st: *i64, i: i64, ay: i64) -> i64 { return st[i*SD_STRIDE+1] - ay*SD_Q8 } |
| 156 | func sd_disp_q8(st: *i64, i: i64, ax: i64, ay: i64, az: i64) -> i64 |
| 162 | func sd_energy(st: *i64, i: i64) -> i64 |