code wiki / (root) / nx_anatstack.nx

nx_anatstack.nx source

↩ module page · 412 lines · 26341 B

1// nx_anatstack.nx -- ★LAYERED ANATOMICAL MODEL (operator 2026-07-08: "stop building circles on circles -- you 2// need the skeleton and muscles and all that so that as you get to the top layer it's anatomically PERFECT for the 3// final layer brush through"). The RIGHT inside-out architecture: don't eyeball skin ellipsoids -- build the real 4// stack and let the skin EMERGE from it: 5// LAYER 0 SKELETON -- the skull's bony forms (cranium, temporals, zygomatics, maxilla, mandible, nasal, brow) 6// LAYER 1 MUSCLE -- the facial muscles as CAPSULES (temporalis, masseter, zygomaticus, orbicularis, ...) 7// LAYER 2 FAT/SOFT -- the fat pads (malar, buccal, periorbital, labial, submental) 8// -> SKIN = the smooth-union ENVELOPE over all layers + a dermal offset = anatomically DERIVED, not sculpted. 9// Self-contained (own SDF + integer ray-march) so it doesn't destabilize the sdf_render pipeline. Capsules are a 10// real muscle shape (beyond ellipsoids). Every position is anatomically reasoned in the faceanat landmark frame 11// (y up: chin -676, mouth -390, subnasale -150, eye +178, brow +322, crown +760; -z = front/toward camera). 12// license_tier: ORIGINAL 13import "nx_syscalls.nx" 14import "nx_itrig.nx" 15import "nx_vecmath.nx" 16const AS_MAGIC_1024: i64 = 1024 17const AS_MAGIC_374761393: i64 = 374761393 18const AS_MAGIC_668265263: i64 = 668265263 19const AS_MAGIC_1274126177: i64 = 1274126177 20const AS_MAGIC_2654435761: i64 = 2654435761 21const AS_MAGIC_1013904223: i64 = 1013904223 22const AS_MAGIC_4096: i64 = 4096 23const AS_MAGIC_1048576: i64 = 1048576 24const AS_MAGIC_65536: i64 = 65536 25const AS_MAGIC_1000000: i64 = 1000000 26const AS_MAGIC_1000000000: i64 = 1000000000 27const AS_MAGIC_1400: i64 = 1400 28const AS_MAGIC_16777215: i64 = 16777215 29 30const AS_STRIDE: i64 = 12 // per-part: layer,type, p1(3), r(3), p2(3), _ 31const AS_BONE: i64 = 0 32const AS_MUSCLE: i64 = 1 33const AS_FAT: i64 = 2 34const AS_ELLIP: i64 = 0 35const AS_CAPS: i64 = 1 36const AS_W: i64 = 512 37const AS_H: i64 = 512 38const AS_FOCAL: i64 = 640 39const AS_K: i64 = 46 // smooth-union blend radius (units) 40 41// RETIRED ONTO THE SHARED OWNER 2026-08-24 (was a private Newton floor-sqrt; vm_isqrt is gate-proven exact). 42func as_isqrt(v: i64) -> i64 { return vm_isqrt(v) } 43func as_iabs(v: i64) -> i64 { if v < 0 { return 0-v } return v } 44func as_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } 45func as_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v } 46 47func as_ellip(P: *i64, i: i64, cx: i64, cy: i64, cz: i64, rx: i64, ry: i64, rz: i64, layer: i64) -> i64 { 48 P[i]=layer; P[i+1]=AS_ELLIP; P[i+2]=cx; P[i+3]=cy; P[i+4]=cz; P[i+5]=rx; P[i+6]=ry; P[i+7]=rz; P[i+8]=0; P[i+9]=0; P[i+10]=0; P[i+11]=0 49 return i + AS_STRIDE 50} 51func as_caps(P: *i64, i: i64, ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64, r: i64, layer: i64) -> i64 { 52 P[i]=layer; P[i+1]=AS_CAPS; P[i+2]=ax; P[i+3]=ay; P[i+4]=az; P[i+5]=r; P[i+6]=0; P[i+7]=0; P[i+8]=bx; P[i+9]=by; P[i+10]=bz; P[i+11]=0 53 return i + AS_STRIDE 54} 55 56// ★PHASE-1 GEOMETRY: per-part COLOUR + flag BITS in the spare slot (11). Backwards-compatible: 0 (the default) 57// keeps today's behaviour exactly. 58// bits 0..23 rgb -> part colour (0 = inherit the base skin colour) 59// bit 24 AS_FEAT -> FEATURE part (eye/lip/nose/ear): CRISP union (plain min, no smooth-mush) + 60// inflate/4, so small features stay sharp instead of ballooning under the dermal 61// offset; rgb 0 + flag = a crisp feature in the skin colour (e.g. a nose). 62// bit 25 AS_FUZZ -> FUZZY part (fur/fleece): the surface is DISPLACED by integer 3D value-noise -> 63// detail lives in the GEOMETRY (silhouette + shading), not just colour. The noise 64// is only evaluated near the part's surface (pd < 26) so far parts cost nothing. 65const AS_FEAT: i64 = 16777216 66const AS_FUZZ: i64 = 33554432 67const AS_FUZZAMP: i64 = 7 // displacement amplitude (units) 68const AS_FUZZCELL: i64 = 13 // noise lattice cell (units) 69// ★P2 MATERIALS: bits 26-28 of slot 11 = material class (0 default SKIN). Add the const to the rgb when colouring. 70// SKIN (0) soft broad sheen + light-wrap + terminator subsurface warmth 71// GLOSS (AS_GLOSS) tight bright specular (eyes, hooves, nose leather, lips) -- the life-giving glint 72// MATTE (AS_MATTE) cloth/wool: no specular, tight diffuse wrap (FUZZY parts read matte automatically) 73// HAIRM (AS_HAIRM) medium anisotropic-ish sheen 74const AS_GLOSS: i64 = 67108864 75const AS_MATTE: i64 = 134217728 76const AS_HAIRM: i64 = 201326592 77 78// ★P4-R3 NEURAL SKIN hook: an optional albedo RATIO tile (baked from the trained skin-family net) modulates 79// base-colour surfaces (prgb==0) MULTIPLICATIVELY -- adds the trained texture variation while PRESERVING the 80// seeded skin tone (a texel of 128 = x1.0). 0 = off (default, byte-identical behaviour). 81static AS_SKINTEX: i64 // tile ptr (tw*tw i64, each = ratio_r + ratio_g*256 + ratio_b*65536) 82static AS_SKINTEXW: i64 // tile width (texels) 83static AS_SKINTEXS: i64 // world units per texel 84func as_set_skintex(ptr: i64, w: i64, scale: i64) -> i64 { AS_SKINTEX = ptr; AS_SKINTEXW = w; AS_SKINTEXS = scale; return 0 } 85func as_color_last(P: *i64, i_after: i64, rgb: i64) -> i64 { P[i_after - AS_STRIDE + 11] = rgb; return i_after } 86func as_feature_last(P: *i64, i_after: i64, rgb: i64) -> i64 { P[i_after - AS_STRIDE + 11] = rgb + AS_FEAT; return i_after } 87func as_fuzz_last(P: *i64, i_after: i64) -> i64 { P[i_after - AS_STRIDE + 11] = P[i_after - AS_STRIDE + 11] + AS_FUZZ; return i_after } 88 89// ★FACE EXPRESSIONS (R-face): muscle-driven morphs on the soft-tissue parts. The facial muscles are already modelled 90// (zygomaticus, frontalis, orbicularis) so an expression = contracting one and letting the overlying fat/skin follow -- 91// anatomically DERIVED, not a surface hack. Set anat_set_expr(kind, intensity) BEFORE anatstack_build. Deterministic. 92static AS_EXPR: i64 // 0 neutral, 1 smile, 2 surprise, 3 frown 93static AS_EXPRI: i64 // intensity 0..1024 94func anat_set_expr(e: i64, inten: i64) -> i64 { AS_EXPR = e; AS_EXPRI = inten; return 0 } 95func as_shifty(P: *i64, idx: i64, dy: i64) -> i64 { let b: i64 = idx*AS_STRIDE; P[b+3]=P[b+3]+dy; if P[b+1]==AS_CAPS { P[b+9]=P[b+9]+dy } return 0 } 96func as_shiftz(P: *i64, idx: i64, dz: i64) -> i64 { let b: i64 = idx*AS_STRIDE; P[b+4]=P[b+4]+dz; if P[b+1]==AS_CAPS { P[b+10]=P[b+10]+dz } return 0 } 97func as_growx(P: *i64, idx: i64, dx: i64) -> i64 { P[idx*AS_STRIDE+5]=P[idx*AS_STRIDE+5]+dx; return 0 } 98func as_growy(P: *i64, idx: i64, dy: i64) -> i64 { P[idx*AS_STRIDE+6]=P[idx*AS_STRIDE+6]+dy; return 0 } 99// part indices in anatstack_build order: brow ridge=8, mandible body=9, L/R ramus=10/11, chin=12, frontalis=22, 100// L/R malar fat=25/26, L/R periorbital fat=29/30, upper lip=31, lower lip=32. 101func as_apply_expr(P: *i64) -> i64 { 102 let e: i64 = AS_EXPR 103 let t: i64 = AS_EXPRI 104 if e == 0 { return 0 } 105 if t == 0 { return 0 } 106 if e == 1 { // SMILE: zygomaticus lifts malar fat up+back, mouth widens+rises 107 as_shifty(P,25, 55*t/AS_MAGIC_1024); as_shiftz(P,25, 12*t/AS_MAGIC_1024) 108 as_shifty(P,26, 55*t/AS_MAGIC_1024); as_shiftz(P,26, 12*t/AS_MAGIC_1024) 109 as_growx(P,31, 40*t/AS_MAGIC_1024); as_shifty(P,31, 16*t/AS_MAGIC_1024) 110 as_growx(P,32, 36*t/AS_MAGIC_1024); as_shifty(P,32, 10*t/AS_MAGIC_1024) 111 } 112 if e == 2 { // SURPRISE: jaw drops (mouth opens), brow+frontalis raise, eyes widen 113 as_shifty(P,9, 0-90*t/AS_MAGIC_1024); as_shifty(P,10, 0-90*t/AS_MAGIC_1024); as_shifty(P,11, 0-90*t/AS_MAGIC_1024); as_shifty(P,12, 0-90*t/AS_MAGIC_1024) 114 as_shifty(P,32, 0-120*t/AS_MAGIC_1024) 115 as_shifty(P,8, 45*t/AS_MAGIC_1024); as_shifty(P,22, 40*t/AS_MAGIC_1024) 116 as_growy(P,29, 15*t/AS_MAGIC_1024); as_growy(P,30, 15*t/AS_MAGIC_1024) 117 } 118 if e == 3 { // FROWN: corrugator draws the brow down, depressors pull mouth corners down 119 as_shifty(P,8, 0-32*t/AS_MAGIC_1024); as_shifty(P,22, 0-20*t/AS_MAGIC_1024) 120 as_shifty(P,31, 0-22*t/AS_MAGIC_1024); as_shifty(P,32, 0-28*t/AS_MAGIC_1024) 121 } 122 return 0 123} 124 125// integer 3D value noise (trilinear over a hashed lattice) -> 0..AS_FUZZAMP. Deterministic. 126func as_h3(ix: i64, iy: i64, iz: i64) -> i64 { 127 var h: i64 = ix*AS_MAGIC_374761393 + iy*AS_MAGIC_668265263 + iz*AS_MAGIC_1274126177 128 h = h*AS_MAGIC_2654435761 + AS_MAGIC_1013904223 129 if h < 0 { h = 0 - h } 130 return h % AS_MAGIC_4096 131} 132func as_noise3(x: i64, y: i64, z: i64) -> i64 { 133 let xx: i64 = x + AS_MAGIC_1048576 // keep the lattice positive (divide truncates toward 0) 134 let yy: i64 = y + AS_MAGIC_1048576 135 let zz: i64 = z + AS_MAGIC_1048576 136 let ix: i64 = xx / AS_FUZZCELL 137 let iy: i64 = yy / AS_FUZZCELL 138 let iz: i64 = zz / AS_FUZZCELL 139 let fx: i64 = (xx - ix*AS_FUZZCELL) * AS_MAGIC_1024 / AS_FUZZCELL 140 let fy: i64 = (yy - iy*AS_FUZZCELL) * AS_MAGIC_1024 / AS_FUZZCELL 141 let fz: i64 = (zz - iz*AS_FUZZCELL) * AS_MAGIC_1024 / AS_FUZZCELL 142 let c00: i64 = as_h3(ix,iy,iz) + (as_h3(ix+1,iy,iz) - as_h3(ix,iy,iz)) * fx / AS_MAGIC_1024 143 let c10: i64 = as_h3(ix,iy+1,iz) + (as_h3(ix+1,iy+1,iz) - as_h3(ix,iy+1,iz)) * fx / AS_MAGIC_1024 144 let c01: i64 = as_h3(ix,iy,iz+1) + (as_h3(ix+1,iy,iz+1) - as_h3(ix,iy,iz+1)) * fx / AS_MAGIC_1024 145 let c11: i64 = as_h3(ix,iy+1,iz+1) + (as_h3(ix+1,iy+1,iz+1) - as_h3(ix,iy+1,iz+1)) * fx / AS_MAGIC_1024 146 let c0: i64 = c00 + (c10 - c00) * fy / AS_MAGIC_1024 147 let c1: i64 = c01 + (c11 - c01) * fy / AS_MAGIC_1024 148 let v: i64 = c0 + (c1 - c0) * fz / AS_MAGIC_1024 149 return v * AS_FUZZAMP / AS_MAGIC_4096 150} 151 152// ANATOMICAL HEAD. Returns the number of parts. (adult female proportions, faceanat frame) 153func anatstack_build(P: *i64) -> i64 { 154 var i: i64 = 0 155 // ---- LAYER 0: SKELETON ---- 156 i = as_ellip(P, i, 0, 175, 30, 445, 620, 545, AS_BONE) // cranial vault (Q6: canon facial thirds -- the golem cranium was too small) 157 i = as_ellip(P, i, 0, 150, 330, 360, 380, 300, AS_BONE) // occiput (back) 158 i = as_ellip(P, i, 0-430, 130, 110, 140, 300, 300, AS_BONE) // L temporal bone 159 i = as_ellip(P, i, 430, 130, 110, 140, 300, 300, AS_BONE) // R temporal bone 160 i = as_ellip(P, i, 0-300, 30, 0-360, 150, 120, 150, AS_BONE) // L zygomatic (cheekbone) 161 i = as_ellip(P, i, 300, 30, 0-360, 150, 120, 150, AS_BONE) // R zygomatic 162 i = as_ellip(P, i, 0, 0-170, 0-350, 300, 210, 240, AS_BONE) // maxilla (midface / upper jaw) 163 i = as_ellip(P, i, 0, 60, 0-540, 70, 175, 120, AS_BONE) // nasal bone (bridge) 164 i = as_ellip(P, i, 0, 322, 0-470, 300, 55, 120, AS_BONE) // brow ridge (supraorbital) 165 i = as_caps(P, i, 0-300, 0-400, 0-110, 300, 0-400, 0-110, 92, AS_BONE) // mandible body (jaw arch) 166 i = as_caps(P, i, 0-320, 0-400, 0-60, 0-345, 0-90, 90, 72, AS_BONE) // L mandible ramus 167 i = as_caps(P, i, 320, 0-400, 0-60, 345, 0-90, 90, 72, AS_BONE) // R mandible ramus 168 i = as_ellip(P, i, 0, 0-560, 0-370, 175, 150, 215, AS_BONE) // chin (mental eminence) 169 // ---- LAYER 1: MUSCLE (capsules = real elongated muscle bellies) ---- 170 i = as_caps(P, i, 0-380, 355, 40, 0-360, 70, 0-170, 88, AS_MUSCLE) // L temporalis (fan on temple) 171 i = as_caps(P, i, 380, 355, 40, 360, 70, 0-170, 88, AS_MUSCLE) // R temporalis 172 i = as_caps(P, i, 0-330, 0-360, 0-130, 0-300, 0-40, 0-250, 86, AS_MUSCLE) // L masseter (ramus->zygomatic) 173 i = as_caps(P, i, 330, 0-360, 0-130, 300, 0-40, 0-250, 86, AS_MUSCLE) // R masseter 174 i = as_caps(P, i, 0-300, 20, 0-400, 0-130, 0-350, 0-520, 44, AS_MUSCLE) // L zygomaticus major 175 i = as_caps(P, i, 300, 20, 0-400, 130, 0-350, 0-520, 44, AS_MUSCLE) // R zygomaticus major 176 i = as_ellip(P, i, 0, 0-385, 0-555, 205, 125, 95, AS_MUSCLE) // orbicularis oris (mouth ring) 177 i = as_ellip(P, i, 0-258, 180, 0-500, 195, 155, 72, AS_MUSCLE) // L orbicularis oculi (eye ring) 178 i = as_ellip(P, i, 258, 180, 0-500, 195, 155, 72, AS_MUSCLE) // R orbicularis oculi 179 i = as_ellip(P, i, 0, 430, 0-455, 380, 175, 90, AS_MUSCLE) // frontalis (forehead sheet) 180 i = as_caps(P, i, 0-240, 0-250, 0-360, 0-120, 0-300, 0-470, 66, AS_MUSCLE) // L buccinator (cheek) 181 i = as_caps(P, i, 240, 0-250, 0-360, 120, 0-300, 0-470, 66, AS_MUSCLE) // R buccinator 182 // ---- LAYER 2: FAT / SOFT TISSUE ---- 183 i = as_ellip(P, i, 0-262, 0-120, 0-475, 175, 175, 135, AS_FAT) // L malar (cheek) fat pad 184 i = as_ellip(P, i, 262, 0-120, 0-475, 175, 175, 135, AS_FAT) // R malar fat pad 185 i = as_ellip(P, i, 0-232, 0-300, 0-420, 128, 140, 120, AS_FAT) // L buccal fat 186 i = as_ellip(P, i, 232, 0-300, 0-420, 128, 140, 120, AS_FAT) // R buccal fat 187 i = as_ellip(P, i, 0-258, 118, 0-500, 185, 115, 82, AS_FAT) // L periorbital fat 188 i = as_ellip(P, i, 258, 118, 0-500, 185, 115, 82, AS_FAT) // R periorbital fat 189 i = as_ellip(P, i, 0, 0-330, 0-600, 158, 72, 92, AS_FAT) // upper lip 190 i = as_ellip(P, i, 0, 0-442, 0-585, 140, 92, 92, AS_FAT) // lower lip 191 i = as_ellip(P, i, 0, 0-600, 0-360, 205, 120, 150, AS_FAT) // submental (under chin) 192 i = as_ellip(P, i, 0, 0-120, 0-620, 86, 105, 130, AS_FAT) // nasal tip (soft, projects) 193 // ---- ★Q6 FACE SCULPT (2026-07-12): EYES (sclera+iris+pupil, crisp+gloss, proud of the socket) + LIP SEAM ---- 194 i = as_ellip(P, i, 0-258, 178, 0-560, 64, 64, 62, AS_FAT) // L eyeball (sclera) 195 i = as_feature_last(P, i, 246 + 244*256 + 238*AS_MAGIC_65536 + AS_GLOSS) 196 i = as_ellip(P, i, 258, 178, 0-560, 64, 64, 62, AS_FAT) // R eyeball 197 i = as_feature_last(P, i, 246 + 244*256 + 238*AS_MAGIC_65536 + AS_GLOSS) 198 i = as_ellip(P, i, 0-258, 178, 0-628, 30, 30, 16, AS_FAT) // L iris 199 i = as_feature_last(P, i, 96 + 118*256 + 74*AS_MAGIC_65536 + AS_GLOSS) 200 i = as_ellip(P, i, 258, 178, 0-628, 30, 30, 16, AS_FAT) // R iris 201 i = as_feature_last(P, i, 96 + 118*256 + 74*AS_MAGIC_65536 + AS_GLOSS) 202 i = as_ellip(P, i, 0-258, 178, 0-643, 13, 13, 8, AS_FAT) // L pupil 203 i = as_feature_last(P, i, 22 + 18*256 + 20*AS_MAGIC_65536 + AS_GLOSS) 204 i = as_ellip(P, i, 258, 178, 0-643, 13, 13, 8, AS_FAT) // R pupil 205 i = as_feature_last(P, i, 22 + 18*256 + 20*AS_MAGIC_65536 + AS_GLOSS) 206 i = as_ellip(P, i, 0, 0-386, 0-668, 150, 13, 46, AS_FAT) // lip seam (the mouth line) 207 i = as_feature_last(P, i, 128 + 62*256 + 58*AS_MAGIC_65536) 208 as_apply_expr(P) // ★muscle-driven expression morph (neutral = no-op) 209 return i / AS_STRIDE 210} 211 212// signed distance of one part 213func as_part_sdf(P: *i64, k: i64, x: i64, y: i64, z: i64) -> i64 { 214 let i: i64 = k * AS_STRIDE 215 if P[i+1] == AS_ELLIP { 216 let dx: i64 = x - P[i+2]; let dy: i64 = y - P[i+3]; let dz: i64 = z - P[i+4] 217 let rx: i64 = P[i+5]; let ry: i64 = P[i+6]; let rz: i64 = P[i+7] 218 let sd: i64 = as_isqrt((dx*AS_MAGIC_1024/rx)*(dx*AS_MAGIC_1024/rx) + (dy*AS_MAGIC_1024/ry)*(dy*AS_MAGIC_1024/ry) + (dz*AS_MAGIC_1024/rz)*(dz*AS_MAGIC_1024/rz)) 219 let rmin: i64 = as_min(as_min(rx, ry), rz) 220 return (sd - AS_MAGIC_1024) * rmin / AS_MAGIC_1024 221 } 222 // capsule: distance to segment p1-p2 minus radius 223 let ax: i64 = P[i+2]; let ay: i64 = P[i+3]; let az: i64 = P[i+4]; let r: i64 = P[i+5] 224 let bx: i64 = P[i+8]; let by: i64 = P[i+9]; let bz: i64 = P[i+10] 225 let pax: i64 = x-ax; let pay: i64 = y-ay; let paz: i64 = z-az 226 let bax: i64 = bx-ax; let bay: i64 = by-ay; let baz: i64 = bz-az 227 let bb: i64 = bax*bax + bay*bay + baz*baz 228 var h: i64 = 0 229 if bb > 0 { h = as_clamp((pax*bax + pay*bay + paz*baz)*AS_MAGIC_1024/bb, 0, AS_MAGIC_1024) } 230 let cx: i64 = pax - bax*h/AS_MAGIC_1024; let cy: i64 = pay - bay*h/AS_MAGIC_1024; let cz: i64 = paz - baz*h/AS_MAGIC_1024 231 return as_isqrt(cx*cx + cy*cy + cz*cz) - r 232} 233 234func as_smin(a: i64, b: i64, k: i64) -> i64 { 235 var hh: i64 = k - as_iabs(a-b) 236 if hh < 0 { hh = 0 } 237 return as_min(a, b) - hh*hh/(4*k) 238} 239 240// SDF of the model up to `maxlayer`, inflated by `inflate` (the dermal offset for the skin envelope). 241// FEATURE parts (AS_FEAT) join CRISP (plain min) with inflate/4 -- sharp eyes/lips/ears, not dermal balloons. 242// FUZZY parts (AS_FUZZ) get 3D-noise surface displacement near their surface -- fur detail in the geometry. 243func anatstack_sdf(P: *i64, np: i64, x: i64, y: i64, z: i64, maxlayer: i64, inflate: i64) -> i64 { 244 var d: i64 = AS_MAGIC_1000000 245 var k: i64 = 0 246 while k < np { 247 if P[k*AS_STRIDE] <= maxlayer { 248 let fl: i64 = P[k*AS_STRIDE+11] 249 if (fl & AS_FEAT) != 0 { 250 let pd: i64 = as_part_sdf(P, k, x, y, z) - inflate/4 251 d = as_min(d, pd) 252 } else { 253 var pd: i64 = as_part_sdf(P, k, x, y, z) - inflate 254 if (fl & AS_FUZZ) != 0 { if pd < 26 { pd = pd - as_noise3(x, y, z) } } 255 d = as_smin(d, pd, AS_K) 256 } 257 } 258 k = k + 1 259 } 260 return d 261} 262 263// FULL slot-11 word (rgb + flags + material bits) of the NEAREST part at a point (argmin of the per-part 264// inflated sdf). rgb 0 = inherit the base skin colour. 265func anatstack_nearest_fl(P: *i64, np: i64, x: i64, y: i64, z: i64, maxlayer: i64, inflate: i64) -> i64 { 266 var best: i64 = AS_MAGIC_1000000000 267 var out: i64 = 0 268 var k: i64 = 0 269 while k < np { 270 if P[k*AS_STRIDE] <= maxlayer { 271 let fl: i64 = P[k*AS_STRIDE+11] 272 var inf2: i64 = inflate 273 if (fl & AS_FEAT) != 0 { inf2 = inflate/4 } 274 let pd: i64 = as_part_sdf(P, k, x, y, z) - inf2 275 if pd < best { best = pd; out = fl } 276 } 277 k = k + 1 278 } 279 return out 280} 281 282// integer sphere-trace renderer. colour by a passed base rgb + Lambert + subsurface rim. Writes fb (AS_W*AS_H). 283func anatstack_render(P: *i64, np: i64, yaw: i64, camz: i64, maxlayer: i64, inflate: i64, cr: i64, cg: i64, cb: i64, fb: *i64) -> i64 { 284 let sy4: i64 = it_sin4096(yaw) 285 let cy4: i64 = it_cos4096(yaw) 286 let R: i64 = camz * AS_MAGIC_1024 287 let ox: i64 = 0 - sy4*R/AS_MAGIC_4096 288 let oz: i64 = 0 - cy4*R/AS_MAGIC_4096 289 // light dir (upper-front-left), fx1024 unit-ish 290 let lx: i64 = 360; let ly: i64 = 560; let lz: i64 = 0-740 // upper-RIGHT-front = matches the worldgen sun (scene-coherent shadows) 291 let ll: i64 = as_isqrt(lx*lx+ly*ly+lz*lz) 292 var py: i64 = 0 293 while py < AS_H { 294 var px: i64 = 0 295 while px < AS_W { 296 let ndcx: i64 = px - AS_W/2 297 let ndcy: i64 = AS_H/2 - py 298 // ray dir = forward*FOCAL + right*ndcx + up*ndcy ; forward=(sy4,0,cy4)/4096, right=(cy4,0,-sy4)/4096 299 var dx: i64 = sy4*AS_FOCAL/AS_MAGIC_4096 + cy4*ndcx/AS_MAGIC_4096 300 var dy: i64 = ndcy 301 var dz: i64 = cy4*AS_FOCAL/AS_MAGIC_4096 - sy4*ndcx/AS_MAGIC_4096 302 let dl: i64 = as_isqrt(dx*dx+dy*dy+dz*dz) 303 if dl > 0 { dx = dx*AS_MAGIC_1024/dl; dy = dy*AS_MAGIC_1024/dl; dz = dz*AS_MAGIC_1024/dl } 304 var t: i64 = R - AS_MAGIC_1400 305 if t < 0 { t = 0 } 306 var hit: i64 = 0 307 var step: i64 = 0 308 while step < 96 { 309 let sx: i64 = ox + dx*t/AS_MAGIC_1024 310 let sy: i64 = dy*t/AS_MAGIC_1024 311 let sz: i64 = oz + dz*t/AS_MAGIC_1024 312 let d: i64 = anatstack_sdf(P, np, sx, sy, sz, maxlayer, inflate) 313 if d < 2 { hit = 1; step = 999 } 314 else { t = t + d*7/10; if t > R + AS_MAGIC_1400 { step = 999 } } 315 if step != 999 { step = step + 1 } 316 } 317 var col: i64 = 26 + 28*256 + 44*AS_MAGIC_65536 // bg 318 if hit == 1 { 319 let hx: i64 = ox + dx*t/AS_MAGIC_1024 320 let hy: i64 = dy*t/AS_MAGIC_1024 321 let hz: i64 = oz + dz*t/AS_MAGIC_1024 322 let e: i64 = 4 323 let gx: i64 = anatstack_sdf(P,np,hx+e,hy,hz,maxlayer,inflate) - anatstack_sdf(P,np,hx-e,hy,hz,maxlayer,inflate) 324 let gy: i64 = anatstack_sdf(P,np,hx,hy+e,hz,maxlayer,inflate) - anatstack_sdf(P,np,hx,hy-e,hz,maxlayer,inflate) 325 let gz: i64 = anatstack_sdf(P,np,hx,hy,hz+e,maxlayer,inflate) - anatstack_sdf(P,np,hx,hy,hz-e,maxlayer,inflate) 326 let gl: i64 = as_isqrt(gx*gx+gy*gy+gz*gz) 327 var nnx: i64 = 0; var nny: i64 = AS_MAGIC_1024; var nnz: i64 = 0 // unit normal (fx1024) 328 if gl > 0 { nnx=gx*AS_MAGIC_1024/gl; nny=gy*AS_MAGIC_1024/gl; nnz=gz*AS_MAGIC_1024/gl } 329 var kd: i64 = (nnx*lx + nny*ly + nnz*lz)/ll // key light (Lambert), ~[-AS_MAGIC_1024,AS_MAGIC_1024] 330 if kd < 0 { kd = 0 } 331 var fd: i64 = (nnx*300 + nny*520 + nnz*640)/862 // soft fill (upper-back) 332 if fd < 0 { fd = 0 } 333 // SDF ambient occlusion: geometry near the surface along the normal -> crevices darken (real form) 334 let s1: i64 = anatstack_sdf(P,np, hx+nnx*30/AS_MAGIC_1024, hy+nny*30/AS_MAGIC_1024, hz+nnz*30/AS_MAGIC_1024, maxlayer, inflate) 335 let s2: i64 = anatstack_sdf(P,np, hx+nnx*72/AS_MAGIC_1024, hy+nny*72/AS_MAGIC_1024, hz+nnz*72/AS_MAGIC_1024, maxlayer, inflate) 336 var o1: i64 = s1*AS_MAGIC_1024/30; if o1<0{o1=0} if o1>AS_MAGIC_1024{o1=AS_MAGIC_1024} 337 var o2: i64 = s2*AS_MAGIC_1024/72; if o2<0{o2=0} if o2>AS_MAGIC_1024{o2=AS_MAGIC_1024} 338 let ao: i64 = (o1+o2)/2 339 // rim / fresnel edge sheen 340 var nv: i64 = (nnx*(0-dx) + nny*(0-dy) + nnz*(0-dz))/AS_MAGIC_1024; if nv<0{nv=0} 341 var rim: i64 = AS_MAGIC_1024-nv; rim = rim*rim/AS_MAGIC_1024 342 // ---- ★P2 MATERIALS: per-part albedo + material class ---- 343 let pfl: i64 = anatstack_nearest_fl(P, np, hx, hy, hz, maxlayer, inflate) 344 let prgb: i64 = pfl & AS_MAGIC_16777215 345 var pmat: i64 = (pfl >> 26) & 7 346 if (pfl & AS_FUZZ) != 0 { pmat = 2 } // fur reads MATTE (wool) 347 var ucr: i64 = cr 348 var ucg: i64 = cg 349 var ucb: i64 = cb 350 if prgb != 0 { ucr = prgb & 255; ucg = (prgb >> 8) & 255; ucb = (prgb >> 16) & 255 } 351 if prgb == 0 { if AS_SKINTEX != 0 { 352 // neural albedo tile: planar (x,y) sample, ratio around 128 = x1.0 (tone-preserving) 353 let tp: *i64 = AS_SKINTEX as *i64 354 let tu: i64 = ((hx + AS_MAGIC_1048576) / AS_SKINTEXS) % AS_SKINTEXW 355 let tv: i64 = ((hy + AS_MAGIC_1048576) / AS_SKINTEXS) % AS_SKINTEXW 356 let tx: i64 = tp[tv*AS_SKINTEXW + tu] 357 ucr = ucr * (tx & 255) / 128 358 ucg = ucg * ((tx >> 8) & 255) / 128 359 ucb = ucb * ((tx >> 16) & 255) / 128 360 if ucr > 255 { ucr = 255 } 361 if ucg > 255 { ucg = 255 } 362 if ucb > 255 { ucb = 255 } 363 } } 364 // diffuse LIGHT-WRAP by material (skin wraps most = the soft subsurface falloff) 365 var wrap: i64 = 300 366 if pmat == 1 { wrap = 120 } 367 if pmat == 2 { wrap = 90 } 368 if pmat == 3 { wrap = 170 } 369 var kdw: i64 = (kd + wrap)*AS_MAGIC_1024/(AS_MAGIC_1024 + wrap) 370 if kdw < 0 { kdw = 0 } 371 var lit: i64 = 24*ao/AS_MAGIC_1024 + kdw*76/AS_MAGIC_1024 + fd*20/AS_MAGIC_1024 // ambient*AO + wrapped key + fill 372 if lit < 12 { lit = 12 } 373 if lit > 135 { lit = 135 } 374 // SPECULAR: R = 2(N.L)N - L ; spec = (R.V)^n * strength, n + strength by material 375 var spec: i64 = 0 376 if kd > 0 { 377 let lux: i64 = lx*AS_MAGIC_1024/ll 378 let luy: i64 = ly*AS_MAGIC_1024/ll 379 let luz: i64 = lz*AS_MAGIC_1024/ll 380 let rx2: i64 = 2*kd*nnx/AS_MAGIC_1024 - lux 381 let ry2: i64 = 2*kd*nny/AS_MAGIC_1024 - luy 382 let rz2: i64 = 2*kd*nnz/AS_MAGIC_1024 - luz 383 var rv: i64 = (rx2*(0-dx) + ry2*(0-dy) + rz2*(0-dz))/AS_MAGIC_1024 384 if rv < 0 { rv = 0 } 385 if rv > AS_MAGIC_1024 { rv = AS_MAGIC_1024 } 386 var s: i64 = rv*rv/AS_MAGIC_1024 387 s = s*s/AS_MAGIC_1024 // ^4 = skin's soft sheen 388 var sstr: i64 = 26 389 if pmat == 1 { s = s*s/AS_MAGIC_1024; sstr = 100 } // gloss: ^8 glint (integer 390 if pmat == 2 { sstr = 5 } // normals speckle at ^16) 391 if pmat == 3 { s = s*s/AS_MAGIC_1024; sstr = 60 } // hair: ^8 sheen 392 spec = s*sstr/AS_MAGIC_1024 393 } 394 // skin SUBSURFACE: red bleeds at the light terminator (peaks where light grazes out) 395 var sssr: i64 = 0 396 if pmat == 0 { sssr = (AS_MAGIC_1024 - as_iabs(kd*2 - AS_MAGIC_1024))*16/AS_MAGIC_1024 } 397 var r: i64 = ucr*lit/100 + rim*30/AS_MAGIC_1024 + spec + sssr + kd*6/AS_MAGIC_1024 398 var g: i64 = ucg*lit/100 + rim*28/AS_MAGIC_1024 + spec*88/100 399 var b: i64 = ucb*lit/100 + rim*28/AS_MAGIC_1024 + spec*82/100 - kd*4/AS_MAGIC_1024 400 if r<0{r=0} if g<0{g=0} if b<0{b=0} 401 if r>255{r=255} if g>255{g=255} if b>255{b=255} 402 col = r + g*256 + b*AS_MAGIC_65536 403 } 404 fb[py*AS_W+px] = col 405 px = px + 1 406 } 407 py = py + 1 408 } 409 return 0 410} 411func as_w() -> i64 { return AS_W } 412func as_h() -> i64 { return AS_H }