nx_i2mesh.nx source
↩ module page · 138 lines · 5925 B
1// nx_i2mesh.nx -- sovereign IMAGE-to-MESH v0 (generator-path R3, operator: "z image be able to be ingested
2// like an i2mesh"). NOT neural (TripoSR/LRM); the honest v0 = SILHOUETTE INFLATION: an image -> foreground
3// MASK -> 2D chamfer distance transform (interior + exterior) -> a 3D field that balloons the silhouette
4// (thickest at the medial axis, pinched to 0 at the edge) -> nx_meshgen surface-nets -> emitted mesh. Ingests
5// ANY image the SAME way -- synthetic masks OR our own Z-Image/render foreground. Honest ceiling: single-view
6// inflation (front-back symmetric, no hidden geometry) vs neural multi-view; a real spine to grow. ORIGINAL
7import "nx_syscalls.nx"
8import "nx_meshgen.nx"
9
10const I2_MW: i64 = 96
11const I2_MH: i64 = 96
12const I2_LARGE: i64 = 1000000
13
14func i2m_px(m: *u8, x: i64, y: i64) -> i64 { return m[y * I2_MW + x] as i64 }
15func i2m_set(m: *u8, x: i64, y: i64, v: i64) -> i64 { m[y * I2_MW + x] = v as u8; return 0 }
16
17// --- mask generators (fill an I2_MW x I2_MH byte mask; 1=foreground) ---
18func i2m_mask_circle(m: *u8) -> i64 {
19 let cx: i64 = I2_MW / 2; let cy: i64 = I2_MH / 2; let r: i64 = I2_MW * 34 / 100
20 var y: i64 = 0
21 while y < I2_MH { var x: i64 = 0; while x < I2_MW { let dx: i64 = x - cx; let dy: i64 = y - cy; if dx * dx + dy * dy <= r * r { i2m_set(m, x, y, 1) } else { i2m_set(m, x, y, 0) } x = x + 1 } y = y + 1 }
22 return 0
23}
24func i2m_mask_square(m: *u8) -> i64 {
25 let cx: i64 = I2_MW / 2; let cy: i64 = I2_MH / 2; let w: i64 = I2_MW * 30 / 100
26 var y: i64 = 0
27 while y < I2_MH { var x: i64 = 0; while x < I2_MW { var ax: i64 = x - cx; if ax < 0 { ax = 0 - ax } var ay: i64 = y - cy; if ay < 0 { ay = 0 - ay } if ax < w { if ay < w { i2m_set(m, x, y, 1) } else { i2m_set(m, x, y, 0) } } else { i2m_set(m, x, y, 0) } x = x + 1 } y = y + 1 }
28 return 0
29}
30func i2m_mask_cross(m: *u8) -> i64 {
31 let cx: i64 = I2_MW / 2; let cy: i64 = I2_MH / 2; let a: i64 = I2_MW * 34 / 100; let b: i64 = I2_MW * 12 / 100
32 var y: i64 = 0
33 while y < I2_MH {
34 var x: i64 = 0
35 while x < I2_MW {
36 var ax: i64 = x - cx; if ax < 0 { ax = 0 - ax }
37 var ay: i64 = y - cy; if ay < 0 { ay = 0 - ay }
38 var f: i64 = 0
39 if ax < b { if ay < a { f = 1 } }
40 if ay < b { if ax < a { f = 1 } }
41 i2m_set(m, x, y, f)
42 x = x + 1
43 }
44 y = y + 1
45 }
46 return 0
47}
48// ingest OUR OWN image: a rendered framebuffer's foreground (skin = r>=b) -> mask (this is how Z-Image plugs in)
49func i2m_mask_from_fb(m: *u8, fb: *i64, w: i64, h: i64) -> i64 {
50 var my: i64 = 0
51 while my < I2_MH {
52 var mx: i64 = 0
53 while mx < I2_MW {
54 let sx: i64 = mx * w / I2_MW
55 let sy: i64 = my * h / I2_MH
56 let c: i64 = fb[sy * w + sx]
57 let r: i64 = c & 255; let b: i64 = (c >> 16) & 255
58 if r >= b { i2m_set(m, mx, my, 1) } else { i2m_set(m, mx, my, 0) }
59 mx = mx + 1
60 }
61 my = my + 1
62 }
63 return 0
64}
65
66// chamfer (3-4) distance transform: d = distance from each pixel of class (mask==fg) to the nearest pixel of
67// the OTHER class. fg=1 -> interior distance; fg=0 -> exterior distance. Units ~ 3x pixels.
68func i2m_dt(mask: *u8, d: *i64, fg: i64) -> i64 {
69 var p: i64 = 0
70 while p < I2_MW * I2_MH { if (mask[p] as i64) == fg { d[p] = I2_LARGE } else { d[p] = 0 } p = p + 1 }
71 var y: i64 = 0
72 while y < I2_MH {
73 var x: i64 = 0
74 while x < I2_MW {
75 let idx: i64 = y * I2_MW + x
76 var v: i64 = d[idx]
77 if x > 0 { if d[idx - 1] + 3 < v { v = d[idx - 1] + 3 } }
78 if y > 0 { if d[idx - I2_MW] + 3 < v { v = d[idx - I2_MW] + 3 } }
79 if x > 0 { if y > 0 { if d[idx - I2_MW - 1] + 4 < v { v = d[idx - I2_MW - 1] + 4 } } }
80 if x < I2_MW - 1 { if y > 0 { if d[idx - I2_MW + 1] + 4 < v { v = d[idx - I2_MW + 1] + 4 } } }
81 d[idx] = v
82 x = x + 1
83 }
84 y = y + 1
85 }
86 y = I2_MH - 1
87 while y >= 0 {
88 var x: i64 = I2_MW - 1
89 while x >= 0 {
90 let idx: i64 = y * I2_MW + x
91 var v: i64 = d[idx]
92 if x < I2_MW - 1 { if d[idx + 1] + 3 < v { v = d[idx + 1] + 3 } }
93 if y < I2_MH - 1 { if d[idx + I2_MW] + 3 < v { v = d[idx + I2_MW] + 3 } }
94 if x < I2_MW - 1 { if y < I2_MH - 1 { if d[idx + I2_MW + 1] + 4 < v { v = d[idx + I2_MW + 1] + 4 } } }
95 if x > 0 { if y < I2_MH - 1 { if d[idx + I2_MW - 1] + 4 < v { v = d[idx + I2_MW - 1] + 4 } } }
96 d[idx] = v
97 x = x - 1
98 }
99 y = y - 1
100 }
101 return 0
102}
103
104// fill the surface-nets corner grid F with the silhouette-inflation SDF (world units fx1024).
105func i2m_fill_field(F: *i64, mask: *u8, din: *i64, dout: *i64) -> i64 {
106 let R: i64 = MG_GR
107 var i: i64 = 0
108 while i <= MG_N {
109 var j: i64 = 0
110 while j <= MG_N {
111 let wx: i64 = mg_wc(i)
112 let wy: i64 = mg_wc(j)
113 var ix: i64 = (wx + R) * I2_MW / (2 * R)
114 var iy: i64 = (R - wy) * I2_MH / (2 * R)
115 if ix < 0 { ix = 0 }
116 if ix >= I2_MW { ix = I2_MW - 1 }
117 if iy < 0 { iy = 0 }
118 if iy >= I2_MH { iy = I2_MH - 1 }
119 let mp: i64 = iy * I2_MW + ix
120 var sdf2d: i64 = 0
121 if (mask[mp] as i64) == 1 { sdf2d = 0 - din[mp] * (2 * R) / (I2_MW * 3) } else { sdf2d = dout[mp] * (2 * R) / (I2_MW * 3) }
122 let thick: i64 = din[mp] * (2 * R) / (I2_MW * 3)
123 var k: i64 = 0
124 while k <= MG_N {
125 var az: i64 = mg_wc(k)
126 if az < 0 { az = 0 - az }
127 var v: i64 = sdf2d
128 let zc: i64 = az - thick
129 if zc > v { v = zc }
130 F[mg_fi(i, j, k)] = v
131 k = k + 1
132 }
133 j = j + 1
134 }
135 i = i + 1
136 }
137 return 0
138}