nx_phys3d.nx
buildroot/runtime/nx_phys3d.nx
about
nx_phys3d.nx -- the UNIFIED sovereign 3D rigid-body physics core (the 07-01 census's named gap; operator
2026-07-03: "real 3d s class exceed physics"). ONE engine for games + sim + CAD-motion: semi-implicit Euler,
sphere/AABB contacts, sequential impulse solver (restitution + Coulomb friction + positional correction),
sleeping. ALL INTEGER (deterministic law: fixed-point pos=1/256 m, vel=1/65536 m-per-tick; 60Hz implied) --
byte-identical replays by construction, no float, no libm. Base-relative so the same code runs native AND
in-wasm (mineworld pattern). Broadphase is O(n^2) pairs at this rung (BVH = ladder R4); shapes = sphere +
axis-aligned box (GJK convex = R5; rotation/orientation = R6 with joints -- stated, not hidden).
license_tier: ORIGINAL
dependencies 2 imports · 3 importers
imports: nx_syscalls.nxnx_vecmath.nx
imported by: nx_phys3d_gate.nxnx_phys3d_toi_gate.nxnx_wasm_physlab.nx
structs
| none |
consts
| 16 | const PH_MAXB: i64 = 64 |
| 17 | const PH_G: i64 = 178 // ~9.8 m/s^2 at 60Hz in vel-units (0.00272 m/tick * 65536) |
| 18 | const PH_SLOP: i64 = 4 // penetration allowance (fx256) |
| 19 | const PH_POSPCT: i64 = 128 // positional correction percent (fx256 of penetration beyond slop) |
| 20 | const PH_RESTV: i64 = 400 // |vn| below this -> restitution treated as 0 (rest, standard trick) |
| 21 | const PH_SLEEPV: i64 = 80 // per-axis |v| threshold for stillness |
| 22 | const PH_SLEEPN: i64 = 30 // still frames before sleep |
| 23 | const PH_ITERS: i64 = 6 // solver iterations per tick |
| 239 | const PH_TOI_Q: i64 = 256 // one tick in Q8 |
| 240 | const PH_TOI_ITERS: i64 = 16 |
| 241 | const PH_TOI_EPS: i64 = 2 // the gap at which advancement stops (fx256), inside PH_SLOP so the solver sees a touch |
| 242 | const PH_TOI_FAR: i64 = 1000000000 |
functions
| 25 | func ph_hdr(base: i64) -> *i64 { return base as *i64 } // [0]=nbodies [1]=tick [2..7]=spare |
| 26 | func ph_body(base: i64, id: i64) -> *i64 { return (base + 64 + id * 128) as *i64 } |
| 31 | func ph_acc(base: i64) -> *i64 { return (base + 64 + PH_MAXB * 128) as *i64 } |
| 32 | func ph_warm(base: i64) -> *i64 { return (base + 64 + PH_MAXB * 128 + PH_MAXB * PH_MAXB * 8) as *i64 } |
| 37 | func ph_tgt(base: i64) -> *i64 { return (base + 64 + PH_MAXB * 128 + PH_MAXB * PH_MAXB * 16) as *i64 } |
| 38 | func ph_bytes() -> i64 { return 64 + PH_MAXB * 128 + PH_MAXB * PH_MAXB * 24 } |
| 40 | func ph_init(base: i64) -> i64 |
| 52 | func ph_add(base: i64, shape: i64, x: i64, y: i64, z: i64, hx: i64, hy: i64, hz: i64, invm: i64, rest: i64, fric: i64) -> i64 |
| 71 | func ph_set_vel(base: i64, id: i64, vx: i64, vy: i64, vz: i64) -> i64 |
| 79 | func ph_iabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } |
| 80 | func ph_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } |
| 82 | func ph_isqrt(v: i64) -> i64 { return vm_isqrt(v) } |
| 89 | func ph_contact(base: i64, ia: i64, ib: i64, nx: i64, ny: i64, nz: i64, pen: i64, docorr: i64) -> i64 |
| 179 | func ph_pair(base: i64, ia: i64, ib: i64, docorr: i64) -> i64 |
| 227 | func ph_imax(a: i64, b: i64) -> i64 { if a > b { return a } return b } |
| 244 | func ph_ccd_off(v: i64) -> i64 { PH_CCD_OFF = v; return 0 } called by 1: main |
| 245 | func ph_bound_r(b: *i64) -> i64 |
| 252 | func ph_fast(dx: i64, dy: i64, dz: i64, r: i64) -> i64 |
| 260 | func ph_surf_dist(base: i64, j: i64, px: i64, py: i64, pz: i64) -> i64 |
| 275 | func ph_gap_at(base: i64, id: i64, j: i64, dx: i64, dy: i64, dz: i64, t: i64, r: i64) -> i64 |
| 280 | func ph_toi(base: i64, id: i64, dx: i64, dy: i64, dz: i64) -> i64 |
| 316 | func ph_max_overlap(base: i64, id: i64) -> i64 |
| 333 | func ph_step(base: i64) -> i64 |