code wiki / (root) / nx_meshtex.nx

nx_meshtex.nx source

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