code wiki / (root) / nx_softtissue.nx

nx_softtissue.nx

buildroot/runtime/nx_softtissue.nx

78002 B1590 linesdepth 5pulls 7 transitivereach 17 importersview sourcekind librarytopic softtissue
docsdependenciesstructsconstsfunctions

about

nx_softtissue.nx -- SOVEREIGN soft-tissue solver: XPBD over a tetrahedral physics cage with per-layer compliance. THE tier our body physics did not have. WHY THIS EXISTS (measured, 2026-07-30): the rigmesh viewer drives breasts with a 2-mass EMA spring (a damped oscillator with a calibrated gain). An oscillator has no VOLUME, no LAYERS and no relationship to gravity DIRECTION -- so it physically cannot reproduce the one behavior a human notices instantly: when a woman lies down, soft heavy tissue FLATTENS and spreads toward the chest wall, and firm tissue does so much less. Our own ecosystem already MEASURES that behavior -- nx_breast_drape_pose.nx bands LAYING_BACK at aspect 716..921 / centroid 410..614 against STANDING_FACING 1024..1331 / 614..768 -- so a ruler existed for a simulator that did not. This organ is the simulator; that validator is its oracle (see nx_softtissue_gate.nx). Same solver serves buttocks, thigh and abdomen: the tissue differs only by PROFILE ROWS, never by code (rule 11, rule 25). METHOD (XPBD, Macklin et al. -- position-based, so it cannot blow up like a force solver): per substep: predict -> solve constraints N times -> derive velocity -> damp constraints: distance (edges) | volume (Neo-Hookean incompressibility, C = 6V - 6V0) | contact (sphere/capsule = a finger or a surgical instrument) | attachment (chest-wall particles pinned, inverse mass 0) compliance: alpha_tilde = alpha / dt^2, per LAYER, from data rows. alpha 0 = rigid (muscle, Cooper's ligament), alpha large = soft (adipose). WHY IT CANNOT INVERT: the volume constraint's correction magnitude scales as 1/(6V) as the element collapses, so resistance rises without bound as det F -> 0. Tissue gets HARDER the harder it is pressed -- the same qualitative guarantee the Neo-Hookean strain-energy barrier gives, which is why a deep press dimples instead of exploding. Proven by tooth, not asserted: the gate presses a capsule 60% into the cage and asserts every 6V stays > 0. UNITS: positions in cmm (0.01 mm) -- the NXA VERT unit, so cage and mesh share a frame. H=171530 cmm = 1.7153 m. Scalars q12 (4096=1.0), compliance q20 (1048576=1.0). Velocity cmm/s. dt in microseconds. Frame: +x lateral, +y cranial, +z anterior. Gravity is a UNIT VECTOR in that body frame -- standing (0,-1,0), supine (0,0,-1). That single input is what makes lying-down flattening emergent, not scripted. QUANTIZATION (honest): positions are integer cmm, so one substep's displacement carries ~1 cmm of rounding. st_div_r rounds to NEAREST (not toward zero) so the error does not bias into fake damping -- a truncating divide would silently drain energy and read as viscosity we did not model. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 3 imports · 14 importers

nx_syscalls.nx nx_proportion_guard.nx nx_vecmath.nx nx_softtissue.nx nx_contactforce_gate.nx nx_contactfriction_gate.nx nx_dyna_bind_skin.nx nx_engorge_gate.nx nx_gm_cloth_lib.nx nx_gm_cloth_lib_t138.nx nx_gm_xpbd_drape_t138.nx nx_gm_xpbd_gate.nx nx_proportion_guard_gate.nx nx_selfcontact_gate.nx

diagram shows first 10 each side; +0 more imports, +4 more importers in the complete lists below.

imports: nx_syscalls.nxnx_proportion_guard.nxnx_vecmath.nx

imported by: nx_contactforce_gate.nxnx_contactfriction_gate.nxnx_dyna_bind_skin.nxnx_engorge_gate.nxnx_gm_cloth_lib.nxnx_gm_cloth_lib_t138.nxnx_gm_xpbd_drape_t138.nxnx_gm_xpbd_gate.nxnx_proportion_guard_gate.nxnx_selfcontact_gate.nxnx_softtissue_diss_gate.nxnx_softtissue_gate.nxnx_softtissue_rot_gate.nxnx_tissuematerial_gate.nx

structs

none

consts

42const ST_MAGIC_1229: i64 = 1229
43const ST_MAGIC_12288: i64 = 12288
44const ST_MAGIC_20972: i64 = 20972
45const ST_MAGIC_1434: i64 = 1434
46const ST_MAGIC_2654435761: i64 = 2654435761
47const ST_MAGIC_1013904223: i64 = 1013904223
48const ST_MAGIC_1442695040888963407: i64 = 1442695040888963407
49const ST_MAGIC_2246822519: i64 = 2246822519
50const ST_MAGIC_288230376151711743: i64 = 288230376151711743
51const ST_MAGIC_1050: i64 = 1050
52const ST_MAGIC_9216: i64 = 9216
53const ST_MAGIC_1024: i64 = 1024
54const ST_MAGIC_4096: i64 = 4096
55const ST_MAGIC_22528: i64 = 22528
56const ST_MAGIC_2048: i64 = 2048
57const ST_MAGIC_8192: i64 = 8192
58const ST_MAGIC_24576: i64 = 24576
59const ST_MAGIC_20480: i64 = 20480
60const ST_MAGIC_1000000: i64 = 1000000
61const ST_MAGIC_999999999: i64 = 999999999
62const ST_MAGIC_999999999999999: i64 = 999999999999999
65const ST_MAXP: i64 = 8192
66const ST_MAXT: i64 = 16384
67const ST_MAXE: i64 = 49152
70const ST_LAY_MUSCLE: i64 = 0
71const ST_LAY_GLAND: i64 = 1
72const ST_LAY_ADIPOSE: i64 = 2
73const ST_LAY_SKIN: i64 = 3
74const ST_LAY_LIGAMENT: i64 = 4
75const ST_LAY_N: i64 = 5
78const ST_W_NP: i64 = 0
79const ST_W_NT: i64 = 1
80const ST_W_NE: i64 = 2
81const ST_W_PX: i64 = 3
82const ST_W_PY: i64 = 4
83const ST_W_PZ: i64 = 5
84const ST_W_QX: i64 = 6
85const ST_W_QY: i64 = 7
86const ST_W_QZ: i64 = 8
87const ST_W_VX: i64 = 9
88const ST_W_VY: i64 = 10
89const ST_W_VZ: i64 = 11
90const ST_W_IW: i64 = 12
91const ST_W_LAY: i64 = 13
92const ST_W_TET: i64 = 14
93const ST_W_TRV: i64 = 15
94const ST_W_TLA: i64 = 16
95const ST_W_TLM: i64 = 17
96const ST_W_EDG: i64 = 18
97const ST_W_ERL: i64 = 19
98const ST_W_ELA: i64 = 20
99const ST_W_ELM: i64 = 21
100const ST_W_SRF: i64 = 22
101const ST_W_TON: i64 = 23
102const ST_W_TCX: i64 = 24
103const ST_W_TCY: i64 = 25
104const ST_W_TCZ: i64 = 26
105const ST_W_TR: i64 = 27
106const ST_W_PROF:i64 = 28
117const ST_W_CDEP: i64 = 29 // sum of push-out distance over the substep, cmm
118const ST_W_CN: i64 = 30 // particles the probe engaged on the last iteration
129const ST_W_MU: i64 = 31
130const ST_MU_UNSET: i64 = 0 - 1
136const ST_W_TDX: i64 = 32
137const ST_W_TDY: i64 = 33
138const ST_W_TDZ: i64 = 34
143const ST_W_SCN: i64 = 35
144const ST_W_SCT: i64 = 36
150const ST_W_SCP: i64 = 37
155const ST_W_ERL0: i64 = 38
156const ST_W_TRV0: i64 = 39
157const ST_W_SLOTS: i64 = 44
160const ST_PF_A_MM: i64 = 0
161const ST_PF_B_MM: i64 = 1
162const ST_PF_C_MM: i64 = 2
163const ST_PF_GLAND_PCT: i64 = 3
164const ST_PF_LIG_ALPHA: i64 = 4
165const ST_PF_FAT_ALPHA: i64 = 5
166const ST_PF_FAT_DAMP: i64 = 6
167const ST_PF_RIB_R_MM: i64 = 7
176const ST_PF_SKIN_ALPHA: i64 = 8
177const ST_PF_N: i64 = 9
179const ST_PROF_LARGE_SOFT: i64 = 0
180const ST_PROF_SMALL_FIRM: i64 = 1
181const ST_PROF_GLUTE: i64 = 2
184const ST_PROF_SOFT_TAUT: i64 = 3
191const ST_PROF_SEED_BASE: i64 = 1000
193const ST_Q12: i64 = 4096
194const ST_Q20: i64 = 1048576
195const ST_GRAV_CMM: i64 = 981000
201const ST_GRAD_SHIFT: i64 = 1
205const ST_DT_REF_US: i64 = 4167
249const ST_GA_RATIO_PERMIL: i64 = 2106 // median of the four cited within-study MRE ratios
250const ST_ALPHA_ADIPOSE: i64 = 12288 // THE ANCHOR: unchanged, for the measured reason above
1100const ST_M_ASPECT: i64 = 0
1101const ST_M_CENTROID: i64 = 1
1102const ST_M_MINVOL: i64 = 2
1103const ST_M_SUMVOL: i64 = 3
1104const ST_M_KIN: i64 = 4
1105const ST_M_NSURF: i64 = 5
1106const ST_M_PROJ: i64 = 6
1107const ST_M_N: i64 = 8

functions

208func st_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
209func st_min(a: i64, b: i64) -> i64 { if a < b { return a } return b }
called by 2: st_measuremain
210func st_max(a: i64, b: i64) -> i64 { if a > b { return a } return b }
called by 2: st_measuremain
214func st_div_r(a: i64, b: i64) -> i64
220func st_isqrt(n: i64) -> i64 { return vm_isqrt(n) }
252func st_alpha_gland() -> i64 { return ST_ALPHA_ADIPOSE * 1000 / ST_GA_RATIO_PERMIL }
called by 1: st_layer_alpha_dist
254func st_layer_alpha_dist(l: i64) -> i64
273func st_layer_alpha_vol(l: i64) -> i64
called by 1: st_new
283func st_layer_damp(l: i64) -> i64
called by 1: st_eff_damp
301func st_hash(seed: i64, salt: i64) -> i64
311func st_span(seed: i64, salt: i64, lo: i64, hi: i64) -> i64
called by 1: st_profile_seeded calls 1: st_hash
324func st_profile_seeded(seed: i64, field: i64) -> i64
called by 1: st_profile calls 3: st_hashpg_samplest_span
350func st_profile(prof: i64, field: i64) -> i64
397func st_wall_drop(xm: i64, rib_r: i64) -> i64
called by 1: st_new calls 2: st_absst_isqrt
406func st_eff_alpha_dist(W: *i64, layer: i64) -> i64
413func st_eff_damp(W: *i64, layer: i64) -> i64
called by 1: st_substep calls 2: st_profilest_layer_damp
426func st_alpha_tilde(alpha_q12: i64, dsum: i64, dt_us: i64) -> i64
438func st_inside(xm: i64, ym: i64, zm: i64, a: i64, b: i64, c: i64) -> i64
called by 1: st_new
446func st_six_vol(W: *i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64
called by 2: st_newst_measure calls 1: st_div_r
463func st_six_vol_q(W: *i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64
calls 1: st_div_r
479func st_add_edge(W: *i64, htab: *i64, hidx: *i64, hmask: i64,
called by 1: st_new calls 2: st_isqrtst_layer_alpha_dist
526func st_new(prof: i64, h_mm: i64) -> *i64
791func st_reset_state(W: *i64) -> i64
800func st_set_touch(W: *i64, on: i64, cx: i64, cy: i64, cz: i64, r: i64) -> i64
819func st_substep(W: *i64, gx: i64, gy: i64, gz: i64, dt_us: i64, iters: i64) -> i64
1093func st_run(W: *i64, gx: i64, gy: i64, gz: i64, steps: i64, dt_us: i64, iters: i64) -> i64
1153func st_surface_spacing(W: *i64) -> i64
called by 1: main calls 1: st_isqrt
1197func st_sc_bounds(W: *i64, pad: i64, out: *i64) -> i64
1241func st_self_contact(WA: *i64, WB: *i64, dist: i64, iters: i64, dt_us: i64) -> i64
called by 1: main calls 3: sys_mmapst_sc_boundsst_isqrt
1387func st_sc_hits(W: *i64) -> i64 { return W[ST_W_SCN] }
called by 1: main
1390func st_sc_peak(W: *i64) -> i64 { return W[ST_W_SCP] }
called by 1: main
1392func st_sc_tested(W: *i64) -> i64 { return W[ST_W_SCT] }
called by 1: main
1397func st_sc_min_sep(WA: *i64, WB: *i64) -> i64
called by 2: sc_placemain calls 1: st_isqrt
1449func st_inflate_rest_volume(W: *i64, layer: i64, linear_permil: i64) -> i64
called by 1: main calls 1: sys_mmap
1498func st_inflated(W: *i64) -> i64
1508func st_set_friction(W: *i64, mu256: i64) -> i64 { W[ST_W_MU] = mu256; return 0 }
called by 2: cfr_dragmain
1509func st_friction(W: *i64) -> i64 { return W[ST_W_MU] }
called by 1: main
1511func st_contact_depth(W: *i64) -> i64 { return W[ST_W_CDEP] }
called by 1: cf_press
1514func st_contact_n(W: *i64) -> i64 { return W[ST_W_CN] }
called by 2: cf_pressmain
1516func st_contact_impulse(W: *i64, dt_us: i64) -> i64
1526func st_contact_force(W: *i64, dt_us: i64) -> i64
called by 2: cf_pressmain calls 1: st_contact_impulse
1531func st_measure(W: *i64, out: *i64) -> i64