code wiki / (root) / nx_meshtex.nx

nx_meshtex.nx source

↩ module page · 171 lines · 9319 B

1// nx_meshtex.nx -- R4: TEXTURED emitted-mesh renderer. Two fidelity moves the critic's pinned axes need: 2// (1) EXACT normals -- an SDF-derived mesh's true outward normal is the FIELD GRADIENT (central differences on 3// sdf_eval), smooth + consistent, unlike winding-dependent face normals (kills the patchy Gouraud); 4// (2) per-PIXEL procedural SKIN -- pore micro-bump (high-freq) + tone MOTTLE (low-freq), keyed on the fixed 5// MODEL position (rotation-invariant -> detail sticks to the surface). Per-pixel shading in fx256 (like 6// nx_swgpu, deterministic). Composes sdf_eval + it_sin4096; own raster loop. NOTE: SDF-gradient normals 7// need the analytic field (t2mesh objects have it); i2mesh (image-inflation) meshes would use an F-grid 8// gradient -- a later unify, disclosed. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_itrig.nx" 11import "nx_sdfrender.nx" 12const MT_MAGIC_65536: i64 = 65536 13const MT_MAGIC_1024: i64 = 1024 14const MT_MAGIC_4096: i64 = 4096 15const MT_MAGIC_92821: i64 = 92821 16const MT_MAGIC_68917: i64 = 68917 17const MT_MAGIC_40503: i64 = 40503 18 19const MT_ZFAR: i64 = 1073741824 20 21func mt_isqrt(v: i64) -> i64 { if v <= 0 { return 0 } var x: i64 = v; var y: i64 = (x + 1) / 2; while y < x { x = y; y = (x + v / x) / 2 } return x } 22func mt_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } 23func mt_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } 24 25// EXACT outward normals from the SDF gradient at each emitted vertex (fx256). SDF grows outward -> +gradient. 26func mt_sdf_normals(base: i64, vb: *i64, nv: i64, nbuf: *i64) -> i64 { 27 let e: i64 = 8 28 var i: i64 = 0 29 while i < nv { 30 let x: i64 = vb[i * 3] 31 let y: i64 = vb[i * 3 + 1] 32 let z: i64 = vb[i * 3 + 2] 33 let gx: i64 = sdf_eval(base, x + e, y, z) - sdf_eval(base, x - e, y, z) 34 let gy: i64 = sdf_eval(base, x, y + e, z) - sdf_eval(base, x, y - e, z) 35 let gz: i64 = sdf_eval(base, x, y, z + e) - sdf_eval(base, x, y, z - e) 36 let l: i64 = mt_isqrt(gx * gx + gy * gy + gz * gz) 37 if l > 0 { nbuf[i * 3] = gx * 256 / l; nbuf[i * 3 + 1] = gy * 256 / l; nbuf[i * 3 + 2] = gz * 256 / l } 38 else { nbuf[i * 3] = 0; nbuf[i * 3 + 1] = 256; nbuf[i * 3 + 2] = 0 } 39 i = i + 1 40 } 41 return 0 42} 43 44// render an indexed mesh with per-vertex fx256 normals + per-pixel procedural skin. scratch = nv*6 i64 45// [sx,sy,sz,vnx,vny,vnz]. 16 args (skin_b derived). 46func mt_render(vb: *i64, tb: *i64, nbuf: *i64, nv: i64, nf: i64, fb: *i64, zb: *i64, w: i64, h: i64, yaw: i64, camu: i64, focal: i64, skin_r: i64, skin_g: i64, scratch: *i64) -> i64 { 47 let sx: *i64 = scratch 48 let sy: *i64 = (scratch as i64 + nv * 8) as *i64 49 let sz: *i64 = (scratch as i64 + nv * 16) as *i64 50 let vnx: *i64 = (scratch as i64 + nv * 24) as *i64 51 let vny: *i64 = (scratch as i64 + nv * 32) as *i64 52 let vnz: *i64 = (scratch as i64 + nv * 40) as *i64 53 let skin_b: i64 = skin_g * 84 / 100 54 var p: i64 = 0 55 while p < w * h { 56 let yy0: i64 = p / w 57 fb[p] = (26 + yy0 * 34 / h) + (28 + yy0 * 32 / h) * 256 + (44 + yy0 * 28 / h) * MT_MAGIC_65536 58 zb[p] = MT_ZFAR 59 p = p + 1 60 } 61 let c4: i64 = it_cos4096(yaw) 62 let s4: i64 = it_sin4096(yaw) 63 let cam: i64 = camu * MT_MAGIC_1024 64 var i: i64 = 0 65 while i < nv { 66 let px: i64 = vb[i * 3] 67 let py: i64 = vb[i * 3 + 1] 68 let pz: i64 = vb[i * 3 + 2] 69 let rx: i64 = (c4 * px + s4 * pz) / MT_MAGIC_4096 70 let rz: i64 = (0 - s4 * px + c4 * pz) / MT_MAGIC_4096 71 let vz: i64 = rz + cam 72 if vz < 64 { sz[i] = 0 - 1 } else { 73 sx[i] = w / 2 + focal * rx / vz 74 sy[i] = h / 2 - focal * py / vz 75 sz[i] = vz 76 } 77 let nx0: i64 = nbuf[i * 3] 78 let nz0: i64 = nbuf[i * 3 + 2] 79 vnx[i] = (c4 * nx0 + s4 * nz0) / MT_MAGIC_4096 80 vny[i] = nbuf[i * 3 + 1] 81 vnz[i] = (0 - s4 * nx0 + c4 * nz0) / MT_MAGIC_4096 82 i = i + 1 83 } 84 let Lx: i64 = 121 85 let Ly: i64 = 191 86 let Lz: i64 = 0 - 121 87 var t: i64 = 0 88 while t < nf { 89 let a: i64 = tb[t * 3] 90 let b: i64 = tb[t * 3 + 1] 91 let c: i64 = tb[t * 3 + 2] 92 if sz[a] > 0 { if sz[b] > 0 { if sz[c] > 0 { 93 let ax: i64 = sx[a] 94 let ay: i64 = sy[a] 95 let bx: i64 = sx[b] 96 let by: i64 = sy[b] 97 let cx: i64 = sx[c] 98 let cy: i64 = sy[c] 99 var area: i64 = (bx - ax) * (cy - ay) - (cx - ax) * (by - ay) 100 var ws: i64 = 1 101 if area < 0 { area = 0 - area; ws = 0 - 1 } 102 if area > 0 { 103 let minx: i64 = mt_max(0, mt_min(ax, mt_min(bx, cx))) 104 let maxx: i64 = mt_min(w - 1, mt_max(ax, mt_max(bx, cx))) 105 let miny: i64 = mt_max(0, mt_min(ay, mt_min(by, cy))) 106 let maxy: i64 = mt_min(h - 1, mt_max(ay, mt_max(by, cy))) 107 var yy: i64 = miny 108 while yy <= maxy { 109 var xx: i64 = minx 110 while xx <= maxx { 111 let w0: i64 = ((bx - xx) * (cy - yy) - (cx - xx) * (by - yy)) * ws 112 let w1: i64 = ((cx - xx) * (ay - yy) - (ax - xx) * (cy - yy)) * ws 113 let w2: i64 = ((ax - xx) * (by - yy) - (bx - xx) * (ay - yy)) * ws 114 if w0 >= 0 { if w1 >= 0 { if w2 >= 0 { 115 let d: i64 = (w0 * sz[a] + w1 * sz[b] + w2 * sz[c]) / area 116 let idx: i64 = yy * w + xx 117 if d < zb[idx] { 118 zb[idx] = d 119 var nx: i64 = (w0 * vnx[a] + w1 * vnx[b] + w2 * vnx[c]) / area 120 var ny: i64 = (w0 * vny[a] + w1 * vny[b] + w2 * vny[c]) / area 121 var nz: i64 = (w0 * vnz[a] + w1 * vnz[b] + w2 * vnz[c]) / area 122 if nz > 0 { nx = 0 - nx; ny = 0 - ny; nz = 0 - nz } 123 // interpolated MODEL position (rotation-invariant) for the procedural skin 124 let mpx: i64 = (w0 * vb[a * 3] + w1 * vb[b * 3] + w2 * vb[c * 3]) / area 125 let mpy: i64 = (w0 * vb[a * 3 + 1] + w1 * vb[b * 3 + 1] + w2 * vb[c * 3 + 1]) / area 126 let mpz: i64 = (w0 * vb[a * 3 + 2] + w1 * vb[b * 3 + 2] + w2 * vb[c * 3 + 2]) / area 127 // pore micro-bump: perturb the normal by a fine procedural field 128 nx = nx + (it_sin4096(mpx * 43 + mpy * 27) + it_sin4096(mpz * 51 + mpx * 31)) * 22 / MT_MAGIC_4096 129 ny = ny + (it_sin4096(mpy * 43 + mpz * 27) + it_sin4096(mpx * 51 + mpy * 31)) * 22 / MT_MAGIC_4096 130 nz = nz + (it_sin4096(mpz * 43 + mpx * 27) + it_sin4096(mpy * 51 + mpz * 31)) * 22 / MT_MAGIC_4096 131 let nl: i64 = mt_isqrt(nx * nx + ny * ny + nz * nz) 132 if nl > 0 { nx = nx * 256 / nl; ny = ny * 256 / nl; nz = nz * 256 / nl } 133 var diff: i64 = (nx * Lx + ny * Ly + nz * Lz) / 256 134 if diff < 0 { diff = 0 } 135 if diff > 256 { diff = 256 } 136 let lit: i64 = 60 + diff * 178 / 256 137 // tone MOTTLE (low freq) -> chroma variation 138 let mot: i64 = it_sin4096(mpx * 3 + mpy * 5 + mpz * 2) * 13 / MT_MAGIC_4096 139 var r: i64 = (skin_r + mot) * lit / 256 140 var g: i64 = (skin_g + mot * 2 / 3) * lit / 256 141 var bcol: i64 = (skin_b + mot / 3) * lit / 256 142 let sp2: i64 = diff * diff / 256 * diff / 256 143 r = r + sp2 * 58 / 256 144 g = g + sp2 * 58 / 256 145 bcol = bcol + sp2 * 58 / 256 146 // per-PIXEL skin GRAIN (pore-scale micro-texture): a hash of the interpolated 147 // model position -> honest 1px micro-contrast (the structure axis keeps this 148 // from being pure-noise gaming: real form must ALSO be present). 149 let grain: i64 = (((mpx * MT_MAGIC_92821 + mpy * MT_MAGIC_68917 + mpz * MT_MAGIC_40503) >> 9) & 31) - 15 150 r = r + grain 151 g = g + grain 152 bcol = bcol + grain 153 if r > 255 { r = 255 } 154 if g > 255 { g = 255 } 155 if bcol > 255 { bcol = 255 } 156 if r < 0 { r = 0 } 157 if g < 0 { g = 0 } 158 if bcol < 0 { bcol = 0 } 159 fb[idx] = r + g * 256 + bcol * MT_MAGIC_65536 160 } 161 } } } 162 xx = xx + 1 163 } 164 yy = yy + 1 165 } 166 } 167 } } } 168 t = t + 1 169 } 170 return 0 171}