code wiki / (root) / nx_meshgen.nx

nx_meshgen.nx source

↩ module page · 176 lines · 9304 B

1// nx_meshgen.nx -- sovereign SURFACE NETS: turn ANY signed-distance FIELD into a watertight triangle MESH 2// (generator-path R1, operator 2026-07-04: the ecosystem must EMIT geometry, not hand-craft). This is the 3// BRIDGE: the pioneer SDF (sdf_body/sdf_head) -- or a t2mesh/i2mesh-generated field -- becomes real emitted 4// verts+faces. Dual method (naive surface nets): (1) each grid CUBE straddling the 0-surface gets ONE vertex 5// at the mean of its edge zero-crossings; (2) each grid EDGE that crosses the surface emits a QUAD (2 tris) 6// linking the 4 cubes around it. Integer fx1024; deterministic. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_sdfrender.nx" 9 10const MG_N: i64 = 56 // grid resolution (cells per axis) 11const MG_GR: i64 = 1500 // world half-range fx1024 (body fits [-1500,1500]) 12const MG_MAXV: i64 = 200000 13const MG_MAXF: i64 = 400000 14 15func mg_step() -> i64 { return 2 * MG_GR / MG_N } 16// field sample index over the (N+1)^3 corner grid 17func mg_fi(i: i64, j: i64, k: i64) -> i64 { return (i * (MG_N + 1) + j) * (MG_N + 1) + k } 18func mg_ci(i: i64, j: i64, k: i64) -> i64 { return (i * MG_N + j) * MG_N + k } 19func mg_wc(idx: i64) -> i64 { return 0 - MG_GR + idx * mg_step() } // grid idx -> world coord fx1024 20 21// build the mesh from base's SDF field. verts (x,y,z fx1024) into vbuf, tri indices into fbuf. 22// out[0]=nverts out[1]=ntris. returns 0. 23// sample the SDF field (from base's parts) into the corner grid F. 24func mg_sample_sdf(base: i64, F: *i64) -> i64 { 25 // --- sample the field at every corner --- 26 var i: i64 = 0 27 while i <= MG_N { 28 var j: i64 = 0 29 while j <= MG_N { 30 var k: i64 = 0 31 while k <= MG_N { 32 F[mg_fi(i, j, k)] = sdf_eval(base, mg_wc(i), mg_wc(j), mg_wc(k)) 33 k = k + 1 34 } 35 j = j + 1 36 } 37 i = i + 1 38 } 39 return 0 40} 41// extract a mesh from a PRE-FILLED corner grid F (works for ANY field: SDF, or an image-inflation field). 42func mg_extract(F: *i64, cubevi: *i64, vbuf: *i64, fbuf: *i64, out: *i64) -> i64 { 43 let step: i64 = mg_step() 44 // --- pass 1: a vertex per surface-straddling cube, at the mean of its 12 edge crossings --- 45 var nv: i64 = 0 46 var i: i64 = 0 47 while i < MG_N * MG_N * MG_N { cubevi[i] = 0 - 1; i = i + 1 } 48 i = 0 49 while i < MG_N { 50 var j: i64 = 0 51 while j < MG_N { 52 var k: i64 = 0 53 while k < MG_N { 54 // 8 corner values 55 let c000: i64 = F[mg_fi(i, j, k)] 56 let c100: i64 = F[mg_fi(i + 1, j, k)] 57 let c010: i64 = F[mg_fi(i, j + 1, k)] 58 let c110: i64 = F[mg_fi(i + 1, j + 1, k)] 59 let c001: i64 = F[mg_fi(i, j, k + 1)] 60 let c101: i64 = F[mg_fi(i + 1, j, k + 1)] 61 let c011: i64 = F[mg_fi(i, j + 1, k + 1)] 62 let c111: i64 = F[mg_fi(i + 1, j + 1, k + 1)] 63 var mn: i64 = c000 64 var mx: i64 = c000 65 if c100 < mn { mn = c100 } 66 if c100 > mx { mx = c100 } 67 if c010 < mn { mn = c010 } 68 if c010 > mx { mx = c010 } 69 if c110 < mn { mn = c110 } 70 if c110 > mx { mx = c110 } 71 if c001 < mn { mn = c001 } 72 if c001 > mx { mx = c001 } 73 if c101 < mn { mn = c101 } 74 if c101 > mx { mx = c101 } 75 if c011 < mn { mn = c011 } 76 if c011 > mx { mx = c011 } 77 if c111 < mn { mn = c111 } 78 if c111 > mx { mx = c111 } 79 if mn < 0 { if mx >= 0 { 80 // this cube straddles the surface -> place a vertex at the mean of the 12 edge crossings 81 let x0: i64 = mg_wc(i) 82 let y0: i64 = mg_wc(j) 83 let z0: i64 = mg_wc(k) 84 var sx: i64 = 0 85 var sy: i64 = 0 86 var sz: i64 = 0 87 var nc: i64 = 0 88 // 12 edges: interpolate zero crossing t = a/(a-b) along the edge 89 // x-edges (4) 90 if (c000 < 0) != (c100 < 0) { sx = sx + x0 + c000 * step / (c000 - c100); sy = sy + y0; sz = sz + z0; nc = nc + 1 } 91 if (c010 < 0) != (c110 < 0) { sx = sx + x0 + c010 * step / (c010 - c110); sy = sy + y0 + step; sz = sz + z0; nc = nc + 1 } 92 if (c001 < 0) != (c101 < 0) { sx = sx + x0 + c001 * step / (c001 - c101); sy = sy + y0; sz = sz + z0 + step; nc = nc + 1 } 93 if (c011 < 0) != (c111 < 0) { sx = sx + x0 + c011 * step / (c011 - c111); sy = sy + y0 + step; sz = sz + z0 + step; nc = nc + 1 } 94 // y-edges (4) 95 if (c000 < 0) != (c010 < 0) { sx = sx + x0; sy = sy + y0 + c000 * step / (c000 - c010); sz = sz + z0; nc = nc + 1 } 96 if (c100 < 0) != (c110 < 0) { sx = sx + x0 + step; sy = sy + y0 + c100 * step / (c100 - c110); sz = sz + z0; nc = nc + 1 } 97 if (c001 < 0) != (c011 < 0) { sx = sx + x0; sy = sy + y0 + c001 * step / (c001 - c011); sz = sz + z0 + step; nc = nc + 1 } 98 if (c101 < 0) != (c111 < 0) { sx = sx + x0 + step; sy = sy + y0 + c101 * step / (c101 - c111); sz = sz + z0 + step; nc = nc + 1 } 99 // z-edges (4) 100 if (c000 < 0) != (c001 < 0) { sx = sx + x0; sy = sy + y0; sz = sz + z0 + c000 * step / (c000 - c001); nc = nc + 1 } 101 if (c100 < 0) != (c101 < 0) { sx = sx + x0 + step; sy = sy + y0; sz = sz + z0 + c100 * step / (c100 - c101); nc = nc + 1 } 102 if (c010 < 0) != (c011 < 0) { sx = sx + x0; sy = sy + y0 + step; sz = sz + z0 + c010 * step / (c010 - c011); nc = nc + 1 } 103 if (c110 < 0) != (c111 < 0) { sx = sx + x0 + step; sy = sy + y0 + step; sz = sz + z0 + c110 * step / (c110 - c111); nc = nc + 1 } 104 if nc < 1 { nc = 1 } 105 if nv < MG_MAXV { 106 vbuf[nv * 3] = sx / nc 107 vbuf[nv * 3 + 1] = sy / nc 108 vbuf[nv * 3 + 2] = sz / nc 109 cubevi[mg_ci(i, j, k)] = nv 110 nv = nv + 1 111 } 112 } } 113 k = k + 1 114 } 115 j = j + 1 116 } 117 i = i + 1 118 } 119 // --- pass 2: a quad per surface-crossing grid edge, linking the 4 surrounding cubes' vertices --- 120 var nf: i64 = 0 121 i = 1 122 while i < MG_N { 123 var j: i64 = 1 124 while j < MG_N { 125 var k: i64 = 1 126 while k < MG_N { 127 let f0: i64 = F[mg_fi(i, j, k)] 128 // +x edge -> quad of cubes (i, j-1..j, k-1..k) 129 if (f0 < 0) != (F[mg_fi(i + 1, j, k)] < 0) { 130 let a: i64 = cubevi[mg_ci(i, j - 1, k - 1)] 131 let b: i64 = cubevi[mg_ci(i, j, k - 1)] 132 let c: i64 = cubevi[mg_ci(i, j, k)] 133 let d: i64 = cubevi[mg_ci(i, j - 1, k)] 134 if a >= 0 { if b >= 0 { if c >= 0 { if d >= 0 { if nf + 2 <= MG_MAXF { 135 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = b; fbuf[nf * 3 + 2] = c; nf = nf + 1 136 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = c; fbuf[nf * 3 + 2] = d; nf = nf + 1 137 } } } } } 138 } 139 // +y edge -> quad of cubes (i-1..i, j, k-1..k) 140 if (f0 < 0) != (F[mg_fi(i, j + 1, k)] < 0) { 141 let a: i64 = cubevi[mg_ci(i - 1, j, k - 1)] 142 let b: i64 = cubevi[mg_ci(i, j, k - 1)] 143 let c: i64 = cubevi[mg_ci(i, j, k)] 144 let d: i64 = cubevi[mg_ci(i - 1, j, k)] 145 if a >= 0 { if b >= 0 { if c >= 0 { if d >= 0 { if nf + 2 <= MG_MAXF { 146 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = b; fbuf[nf * 3 + 2] = c; nf = nf + 1 147 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = c; fbuf[nf * 3 + 2] = d; nf = nf + 1 148 } } } } } 149 } 150 // +z edge -> quad of cubes (i-1..i, j-1..j, k) 151 if (f0 < 0) != (F[mg_fi(i, j, k + 1)] < 0) { 152 let a: i64 = cubevi[mg_ci(i - 1, j - 1, k)] 153 let b: i64 = cubevi[mg_ci(i, j - 1, k)] 154 let c: i64 = cubevi[mg_ci(i, j, k)] 155 let d: i64 = cubevi[mg_ci(i - 1, j, k)] 156 if a >= 0 { if b >= 0 { if c >= 0 { if d >= 0 { if nf + 2 <= MG_MAXF { 157 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = b; fbuf[nf * 3 + 2] = c; nf = nf + 1 158 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = c; fbuf[nf * 3 + 2] = d; nf = nf + 1 159 } } } } } 160 } 161 k = k + 1 162 } 163 j = j + 1 164 } 165 i = i + 1 166 } 167 out[0] = nv 168 out[1] = nf 169 return 0 170} 171// convenience: sample the SDF field then extract (the original one-call path). 172func mg_build(base: i64, F: *i64, cubevi: *i64, vbuf: *i64, fbuf: *i64, out: *i64) -> i64 { 173 mg_sample_sdf(base, F) 174 mg_extract(F, cubevi, vbuf, fbuf, out) 175 return 0 176}