code wiki / (root) / nx_subdiv.nx

nx_subdiv.nx source

↩ module page · 132 lines · 5357 B

1// nx_subdiv.nx -- SUBDIVISION + DISPLACEMENT DETAIL (the Elara detail architecture, rung 1 of "8K/16K down 2// to sensor level"): gland/pore-scale geometry cannot live in a base mesh -- you SUBDIVIDE the detail region 3// (each level x4 triangles, midpoint dedup keeps it watertight) and DISPLACE vertices along their normals 4// from a DETERMINISTIC DETAIL FIELD (position-hashed bump field: density/amplitude/seed = DATA -- the exact 5// mechanical form of "Montgomery glands on an areola" or skin pores). Position-hashing (not index-hashing) 6// makes shared vertices displace identically => NO CRACKS across subdivision levels or patch borders. 7// ALL INTEGER on nx_mesh3. license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_mesh3.nx" 10import "nx_vecmath.nx" 11const K_MAGIC_374761393: i64 = 374761393 12const K_MAGIC_668265263: i64 = 668265263 13const K_MAGIC_2147483647: i64 = 2147483647 14const K_MAGIC_974634599: i64 = 974634599 15const K_MAGIC_1274126177: i64 = 1274126177 16 17func sd_isqrt(v: i64) -> i64 { return vm_isqrt(v) } 18// find-or-add an exact vertex (the mesh3 dedup idiom) 19func sd_getvert(mesh: i64, x: i64, y: i64, z: i64) -> i64 { 20 let h: *i64 = m3_hdr(mesh) 21 var i: i64 = 0 22 while i < h[0] { 23 let v: *i64 = m3_vert(mesh, i) 24 if v[0] == x { if v[1] == y { if v[2] == z { return i } } } 25 i = i + 1 26 } 27 return m3_add_vert(mesh, x, y, z) 28} 29 30// one subdivision level: meshIn -> meshOut (tris x4, midpoints deduplicated => watertight) 31func sd_subdivide(meshIn: i64, meshOut: i64) -> i64 { 32 m3_init(meshOut) 33 let hin: *i64 = m3_hdr(meshIn) 34 var t: i64 = 0 35 while t < hin[1] { 36 let tr: *i64 = m3_tri(meshIn, t) 37 let a: *i64 = m3_vert(meshIn, tr[0]) 38 let b: *i64 = m3_vert(meshIn, tr[1]) 39 let c: *i64 = m3_vert(meshIn, tr[2]) 40 let ia: i64 = sd_getvert(meshOut, a[0], a[1], a[2]) 41 let ib: i64 = sd_getvert(meshOut, b[0], b[1], b[2]) 42 let ic: i64 = sd_getvert(meshOut, c[0], c[1], c[2]) 43 let iab: i64 = sd_getvert(meshOut, (a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2) 44 let ibc: i64 = sd_getvert(meshOut, (b[0] + c[0]) / 2, (b[1] + c[1]) / 2, (b[2] + c[2]) / 2) 45 let ica: i64 = sd_getvert(meshOut, (c[0] + a[0]) / 2, (c[1] + a[1]) / 2, (c[2] + a[2]) / 2) 46 m3_add_tri(meshOut, ia, iab, ica) 47 m3_add_tri(meshOut, iab, ib, ibc) 48 m3_add_tri(meshOut, ica, ibc, ic) 49 m3_add_tri(meshOut, iab, ibc, ica) 50 t = t + 1 51 } 52 return hin[1] * 4 53} 54 55// integer position hash (the detail field's randomness source; POSITION-keyed => crack-free) 56func sd_hash(x: i64, y: i64, z: i64, seed: i64) -> i64 { 57 var h: i64 = x * K_MAGIC_374761393 + y * K_MAGIC_668265263 + z * K_MAGIC_2147483647 + seed * K_MAGIC_974634599 58 h = h ^ (h >> 13) 59 h = h * K_MAGIC_1274126177 60 h = h ^ (h >> 16) 61 if h < 0 { h = 0 - h } 62 return h 63} 64 65// vertex normals: accumulate face cross products per vertex, normalize fx256 (scratch = caller arena) 66func sd_normals(mesh: i64, nrm: *i64) -> i64 { 67 let h: *i64 = m3_hdr(mesh) 68 var i: i64 = 0 69 while i < h[0] * 3 { nrm[i] = 0; i = i + 1 } 70 var t: i64 = 0 71 while t < h[1] { 72 let tr: *i64 = m3_tri(mesh, t) 73 let a: *i64 = m3_vert(mesh, tr[0]) 74 let b: *i64 = m3_vert(mesh, tr[1]) 75 let c: *i64 = m3_vert(mesh, tr[2]) 76 let ux: i64 = b[0] - a[0] 77 let uy: i64 = b[1] - a[1] 78 let uz: i64 = b[2] - a[2] 79 let vx: i64 = c[0] - a[0] 80 let vy: i64 = c[1] - a[1] 81 let vz: i64 = c[2] - a[2] 82 let nx: i64 = (uy * vz - uz * vy) / 256 83 let ny: i64 = (uz * vx - ux * vz) / 256 84 let nz: i64 = (ux * vy - uy * vx) / 256 85 var k: i64 = 0 86 while k < 3 { 87 nrm[tr[k] * 3] = nrm[tr[k] * 3] + nx 88 nrm[tr[k] * 3 + 1] = nrm[tr[k] * 3 + 1] + ny 89 nrm[tr[k] * 3 + 2] = nrm[tr[k] * 3 + 2] + nz 90 k = k + 1 91 } 92 t = t + 1 93 } 94 i = 0 95 while i < h[0] { 96 let mx: i64 = nrm[i * 3] 97 let my: i64 = nrm[i * 3 + 1] 98 let mz: i64 = nrm[i * 3 + 2] 99 let m: i64 = sd_isqrt(mx * mx + my * my + mz * mz) 100 if m > 0 { 101 nrm[i * 3] = mx * 256 / m 102 nrm[i * 3 + 1] = my * 256 / m 103 nrm[i * 3 + 2] = mz * 256 / m 104 } 105 i = i + 1 106 } 107 return 0 108} 109 110// DISPLACE from a bump DETAIL FIELD: density (0..256 fraction of verts bumped), amp (fx256 height), seed. 111// A vertex bumps iff hash(pos)%256 < density; height = amp scaled by a second hash (organic variation). 112// This IS the mechanical form of gland/pore detail-as-DATA. nrm = caller scratch (>= nverts*3 slots). 113func sd_displace(mesh: i64, density: i64, amp: i64, seed: i64, nrm: *i64) -> i64 { 114 sd_normals(mesh, nrm) 115 let h: *i64 = m3_hdr(mesh) 116 var bumped: i64 = 0 117 var i: i64 = 0 118 while i < h[0] { 119 let v: *i64 = m3_vert(mesh, i) 120 let hh: i64 = sd_hash(v[0], v[1], v[2], seed) 121 if hh % 256 < density { 122 let hv: i64 = 128 + (hh / 256) % 128 // 128..255: bump height variation 123 let d: i64 = amp * hv / 256 124 v[0] = v[0] + nrm[i * 3] * d / 256 125 v[1] = v[1] + nrm[i * 3 + 1] * d / 256 126 v[2] = v[2] + nrm[i * 3 + 2] * d / 256 127 bumped = bumped + 1 128 } 129 i = i + 1 130 } 131 return bumped 132}