code wiki / (root) / nx_meshgen_domain_candidate_t337.nx

nx_meshgen_domain_candidate_t337.nx source

↩ module page · 191 lines · 10373 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_box(base: i64, F: *i64, origin: i64, step: i64) -> i64 { 25 if step <= 0 { return 1 } 26 // --- sample the field at every corner --- 27 var i: i64 = 0 28 while i <= MG_N { 29 var j: i64 = 0 30 while j <= MG_N { 31 var k: i64 = 0 32 while k <= MG_N { 33 F[mg_fi(i, j, k)] = sdf_eval(base, origin+i*step, origin+j*step, origin+k*step) 34 k = k + 1 35 } 36 j = j + 1 37 } 38 i = i + 1 39 } 40 return 0 41} 42// extract a mesh from a PRE-FILLED corner grid F (works for ANY field: SDF, or an image-inflation field). 43func mg_extract_box(F: *i64, cubevi: *i64, vbuf: *i64, fbuf: *i64, out: *i64, origin: i64, step: i64) -> i64 { 44 out[0]=0;out[1]=0 45 if step <= 0 { return 1 } 46 // --- pass 1: a vertex per surface-straddling cube, at the mean of its 12 edge crossings --- 47 var nv: i64 = 0 48 var i: i64 = 0 49 while i < MG_N * MG_N * MG_N { cubevi[i] = 0 - 1; i = i + 1 } 50 i = 0 51 while i < MG_N { 52 var j: i64 = 0 53 while j < MG_N { 54 var k: i64 = 0 55 while k < MG_N { 56 // 8 corner values 57 let c000: i64 = F[mg_fi(i, j, k)] 58 let c100: i64 = F[mg_fi(i + 1, j, k)] 59 let c010: i64 = F[mg_fi(i, j + 1, k)] 60 let c110: i64 = F[mg_fi(i + 1, j + 1, k)] 61 let c001: i64 = F[mg_fi(i, j, k + 1)] 62 let c101: i64 = F[mg_fi(i + 1, j, k + 1)] 63 let c011: i64 = F[mg_fi(i, j + 1, k + 1)] 64 let c111: i64 = F[mg_fi(i + 1, j + 1, k + 1)] 65 var mn: i64 = c000 66 var mx: i64 = c000 67 if c100 < mn { mn = c100 } 68 if c100 > mx { mx = c100 } 69 if c010 < mn { mn = c010 } 70 if c010 > mx { mx = c010 } 71 if c110 < mn { mn = c110 } 72 if c110 > mx { mx = c110 } 73 if c001 < mn { mn = c001 } 74 if c001 > mx { mx = c001 } 75 if c101 < mn { mn = c101 } 76 if c101 > mx { mx = c101 } 77 if c011 < mn { mn = c011 } 78 if c011 > mx { mx = c011 } 79 if c111 < mn { mn = c111 } 80 if c111 > mx { mx = c111 } 81 if mn < 0 { if mx >= 0 { 82 // this cube straddles the surface -> place a vertex at the mean of the 12 edge crossings 83 let x0: i64 = origin+i*step 84 let y0: i64 = origin+j*step 85 let z0: i64 = origin+k*step 86 var sx: i64 = 0 87 var sy: i64 = 0 88 var sz: i64 = 0 89 var nc: i64 = 0 90 // 12 edges: interpolate zero crossing t = a/(a-b) along the edge 91 // x-edges (4) 92 if (c000 < 0) != (c100 < 0) { sx = sx + x0 + c000 * step / (c000 - c100); sy = sy + y0; sz = sz + z0; nc = nc + 1 } 93 if (c010 < 0) != (c110 < 0) { sx = sx + x0 + c010 * step / (c010 - c110); sy = sy + y0 + step; sz = sz + z0; nc = nc + 1 } 94 if (c001 < 0) != (c101 < 0) { sx = sx + x0 + c001 * step / (c001 - c101); sy = sy + y0; sz = sz + z0 + step; nc = nc + 1 } 95 if (c011 < 0) != (c111 < 0) { sx = sx + x0 + c011 * step / (c011 - c111); sy = sy + y0 + step; sz = sz + z0 + step; nc = nc + 1 } 96 // y-edges (4) 97 if (c000 < 0) != (c010 < 0) { sx = sx + x0; sy = sy + y0 + c000 * step / (c000 - c010); sz = sz + z0; nc = nc + 1 } 98 if (c100 < 0) != (c110 < 0) { sx = sx + x0 + step; sy = sy + y0 + c100 * step / (c100 - c110); sz = sz + z0; nc = nc + 1 } 99 if (c001 < 0) != (c011 < 0) { sx = sx + x0; sy = sy + y0 + c001 * step / (c001 - c011); sz = sz + z0 + step; nc = nc + 1 } 100 if (c101 < 0) != (c111 < 0) { sx = sx + x0 + step; sy = sy + y0 + c101 * step / (c101 - c111); sz = sz + z0 + step; nc = nc + 1 } 101 // z-edges (4) 102 if (c000 < 0) != (c001 < 0) { sx = sx + x0; sy = sy + y0; sz = sz + z0 + c000 * step / (c000 - c001); nc = nc + 1 } 103 if (c100 < 0) != (c101 < 0) { sx = sx + x0 + step; sy = sy + y0; sz = sz + z0 + c100 * step / (c100 - c101); nc = nc + 1 } 104 if (c010 < 0) != (c011 < 0) { sx = sx + x0; sy = sy + y0 + step; sz = sz + z0 + c010 * step / (c010 - c011); nc = nc + 1 } 105 if (c110 < 0) != (c111 < 0) { sx = sx + x0 + step; sy = sy + y0 + step; sz = sz + z0 + c110 * step / (c110 - c111); nc = nc + 1 } 106 if nc < 1 { nc = 1 } 107 if nv < MG_MAXV { 108 vbuf[nv * 3] = sx / nc 109 vbuf[nv * 3 + 1] = sy / nc 110 vbuf[nv * 3 + 2] = sz / nc 111 cubevi[mg_ci(i, j, k)] = nv 112 nv = nv + 1 113 } 114 } } 115 k = k + 1 116 } 117 j = j + 1 118 } 119 i = i + 1 120 } 121 // --- pass 2: a quad per surface-crossing grid edge, linking the 4 surrounding cubes' vertices --- 122 var nf: i64 = 0 123 i = 1 124 while i < MG_N { 125 var j: i64 = 1 126 while j < MG_N { 127 var k: i64 = 1 128 while k < MG_N { 129 let f0: i64 = F[mg_fi(i, j, k)] 130 // +x edge -> quad of cubes (i, j-1..j, k-1..k) 131 if (f0 < 0) != (F[mg_fi(i + 1, j, k)] < 0) { 132 let a: i64 = cubevi[mg_ci(i, j - 1, k - 1)] 133 let b: i64 = cubevi[mg_ci(i, j, k - 1)] 134 let c: i64 = cubevi[mg_ci(i, j, k)] 135 let d: i64 = cubevi[mg_ci(i, j - 1, k)] 136 if a >= 0 { if b >= 0 { if c >= 0 { if d >= 0 { if nf + 2 <= MG_MAXF { 137 // Outward traversal follows the inside-to-outside edge; the Y-axis base quad is reversed. 138 var qb:i64=b;var qd:i64=d 139 if f0 >= 0 {qb=d;qd=b} 140 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = qb; fbuf[nf * 3 + 2] = c; nf = nf + 1 141 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = c; fbuf[nf * 3 + 2] = qd; nf = nf + 1 142 } } } } } 143 } 144 // +y edge -> quad of cubes (i-1..i, j, k-1..k) 145 if (f0 < 0) != (F[mg_fi(i, j + 1, k)] < 0) { 146 let a: i64 = cubevi[mg_ci(i - 1, j, k - 1)] 147 let b: i64 = cubevi[mg_ci(i, j, k - 1)] 148 let c: i64 = cubevi[mg_ci(i, j, k)] 149 let d: i64 = cubevi[mg_ci(i - 1, j, k)] 150 if a >= 0 { if b >= 0 { if c >= 0 { if d >= 0 { if nf + 2 <= MG_MAXF { 151 // Outward traversal follows the inside-to-outside edge; the Y-axis base quad is reversed. 152 var qb:i64=b;var qd:i64=d 153 if f0 < 0 {qb=d;qd=b} 154 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = qb; fbuf[nf * 3 + 2] = c; nf = nf + 1 155 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = c; fbuf[nf * 3 + 2] = qd; nf = nf + 1 156 } } } } } 157 } 158 // +z edge -> quad of cubes (i-1..i, j-1..j, k) 159 if (f0 < 0) != (F[mg_fi(i, j, k + 1)] < 0) { 160 let a: i64 = cubevi[mg_ci(i - 1, j - 1, k)] 161 let b: i64 = cubevi[mg_ci(i, j - 1, k)] 162 let c: i64 = cubevi[mg_ci(i, j, k)] 163 let d: i64 = cubevi[mg_ci(i - 1, j, k)] 164 if a >= 0 { if b >= 0 { if c >= 0 { if d >= 0 { if nf + 2 <= MG_MAXF { 165 // Outward traversal follows the inside-to-outside edge; the Y-axis base quad is reversed. 166 var qb:i64=b;var qd:i64=d 167 if f0 >= 0 {qb=d;qd=b} 168 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = qb; fbuf[nf * 3 + 2] = c; nf = nf + 1 169 fbuf[nf * 3] = a; fbuf[nf * 3 + 1] = c; fbuf[nf * 3 + 2] = qd; nf = nf + 1 170 } } } } } 171 } 172 k = k + 1 173 } 174 j = j + 1 175 } 176 i = i + 1 177 } 178 out[0] = nv 179 out[1] = nf 180 return 0 181} 182// convenience: sample the SDF field then extract (the original one-call path). 183func mg_build(base: i64, F: *i64, cubevi: *i64, vbuf: *i64, fbuf: *i64, out: *i64) -> i64 { 184 mg_sample_sdf(base, F) 185 mg_extract(F, cubevi, vbuf, fbuf, out) 186 return 0 187} 188 189// Legacy callers retain the exact original sampling domain. 190func mg_sample_sdf(base:i64,F:*i64)->i64{return mg_sample_sdf_box(base,F,0-MG_GR,mg_step())} 191func mg_extract(F:*i64,cubevi:*i64,vbuf:*i64,fbuf:*i64,out:*i64)->i64{return mg_extract_box(F,cubevi,vbuf,fbuf,out,0-MG_GR,mg_step())}