nx_skinneural.nx source
↩ module page · 156 lines · 6651 B
1// nx_skinneural.nx -- ★P4-R3: DEPLOY the trained skin-family model onto generated people. Loads the R2 artifact
2// (knowledge/skinfam_w.bin: coordinate-MLP weights + the 6 learned patch latents), derives a NOVEL in-family
3// latent from a person seed, and BAKES a seamless albedo RATIO tile (texel 128 = x1.0) for the anatstack
4// as_set_skintex hook -- so a seed-grown person gets seed-grown NEURAL skin that modulates (never replaces)
5// their seeded tone. Integer inference only; consts MUST match nx_skinfam_train_gate. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_itrig.nx"
8const SKN_MAGIC_6364136223846793005: i64 = 6364136223846793005
9const SKN_MAGIC_1442695040888963407: i64 = 1442695040888963407
10const SKN_MAGIC_2147483647: i64 = 2147483647
11const SKN_MAGIC_2654435761: i64 = 2654435761
12const SKN_MAGIC_1024: i64 = 1024
13const SKN_MAGIC_888888877: i64 = 888888877
14const SKN_MAGIC_12289: i64 = 12289
15const SKN_MAGIC_25736: i64 = 25736
16const SKN_MAGIC_4096: i64 = 4096
17const SKN_MAGIC_16384: i64 = 16384
18const SKN_MAGIC_65536: i64 = 65536
19
20const SKN_PS: i64 = 32
21const SKN_NFR: i64 = 5
22const SKN_NFF: i64 = 20
23const SKN_NL: i64 = 8
24const SKN_NIN: i64 = 28
25const SKN_NH: i64 = 56
26const SKN_NO: i64 = 3
27const SKN_NPAT: i64 = 6
28const SKN_BYTES: i64 = 14744 // (56*28 + 56 + 3*56 + 3 + 6*8) i64s * 8
29
30func skn_lcg(st: *i64) -> i64 { var h: i64=st[0]; h=h*SKN_MAGIC_6364136223846793005+SKN_MAGIC_1442695040888963407; st[0]=h; return (h>>33)&SKN_MAGIC_2147483647 }
31
32// load the trained model blob; returns 0 if missing/size-mismatch (caller must handle LOUDLY, no fallback)
33func skn_load() -> i64 {
34 let lsz: *i64 = sys_mmap(16) as *i64
35 let blob: *u8 = sys_read_file("knowledge/skinfam_w.bin" as *u8, lsz)
36 if (blob as i64) == 0 { return 0 }
37 if lsz[0] != SKN_BYTES { return 0 }
38 return blob as i64
39}
40
41// derive a NOVEL in-family latent from a person seed: a seeded 2-anchor blend of the learned latents + jitter
42func skn_latent(blob: i64, seed: i64, zout: *i64) -> i64 {
43 let Z: *i64 = (blob + (SKN_NH*SKN_NIN + SKN_NH + SKN_NO*SKN_NH + SKN_NO)*8) as *i64
44 let st: *i64 = sys_mmap(16) as *i64
45 st[0] = seed*SKN_MAGIC_2654435761 + 977
46 skn_lcg(st); skn_lcg(st)
47 let a: i64 = skn_lcg(st) % SKN_NPAT
48 var b: i64 = skn_lcg(st) % SKN_NPAT
49 if b == a { b = (b + 1) % SKN_NPAT }
50 let w: i64 = 200 + skn_lcg(st) % 625 // blend weight in [200,824]/SKN_MAGIC_1024
51 var l: i64 = 0
52 while l < SKN_NL {
53 let za: i64 = Z[a*SKN_NL+l]
54 let zb: i64 = Z[b*SKN_NL+l]
55 zout[l] = za + (zb - za)*w/SKN_MAGIC_1024 + (skn_lcg(st) % 100 - 50)
56 l = l + 1
57 }
58 return 0
59}
60
61// bake a tw x tw seamless RATIO tile (texel = r + g*256 + b*65536, 128 = x1.0) from the net at latent z.
62// ★R3 FINDING (measured): at R2 scale (~1.8k params) the latent's effect is almost purely TONAL -- and tone is
63// deliberately STRIPPED by the ratio normalization (persongen owns tone). So per-person SPATIAL variety comes
64// from a seeded PHASE ROLL + DIHEDRAL orientation of the (genuinely neural) pattern; the latent plumbing stays
65// for R5-scale models where capacity lets z drive the pattern itself.
66func skn_bake(blob: i64, z: *i64, tile: *i64, tw: i64, seed: i64) -> i64 {
67 let ost: *i64 = sys_mmap(16) as *i64
68 ost[0] = seed*SKN_MAGIC_888888877 + SKN_MAGIC_12289
69 skn_lcg(ost); skn_lcg(ost)
70 let phx: i64 = skn_lcg(ost) % tw
71 let phy: i64 = skn_lcg(ost) % tw
72 let orient: i64 = skn_lcg(ost) % 8
73 let W1: *i64 = blob as *i64
74 let B1: *i64 = (blob + SKN_NH*SKN_NIN*8) as *i64
75 let W2: *i64 = (blob + (SKN_NH*SKN_NIN + SKN_NH)*8) as *i64
76 let B2: *i64 = (blob + (SKN_NH*SKN_NIN + SKN_NH + SKN_NO*SKN_NH)*8) as *i64
77 let fr: *i64 = sys_mmap(8*8) as *i64
78 fr[0]=1; fr[1]=2; fr[2]=4; fr[3]=8; fr[4]=16
79 let fin: *i64 = sys_mmap(SKN_NIN*8) as *i64
80 let h: *i64 = sys_mmap(SKN_NH*8) as *i64
81 let raw: *i64 = sys_mmap(tw*tw*3*8) as *i64
82 var mr: i64 = 0
83 var mg: i64 = 0
84 var mb: i64 = 0
85 var ty: i64 = 0
86 while ty < tw {
87 var tx: i64 = 0
88 while tx < tw {
89 // seeded torus roll + dihedral orientation (seamless: the basis is periodic)
90 var sxc: i64 = (tx + phx) % tw
91 var syc: i64 = (ty + phy) % tw
92 if (orient & 1) != 0 { sxc = tw - 1 - sxc }
93 if (orient & 2) != 0 { syc = tw - 1 - syc }
94 if (orient & 4) != 0 { let tmp: i64 = sxc; sxc = syc; syc = tmp }
95 var k: i64 = 0
96 while k < SKN_NFR {
97 let ax: i64 = sxc * SKN_MAGIC_25736 * fr[k] / tw
98 let ay: i64 = syc * SKN_MAGIC_25736 * fr[k] / tw
99 fin[k*4] = it_sin4096(ax)
100 fin[k*4+1] = it_cos4096(ax)
101 fin[k*4+2] = it_sin4096(ay)
102 fin[k*4+3] = it_cos4096(ay)
103 k = k + 1
104 }
105 var l: i64 = 0
106 while l < SKN_NL { fin[SKN_NFF+l] = z[l]; l = l + 1 }
107 var j: i64 = 0
108 while j < SKN_NH {
109 var acc: i64 = B1[j]
110 var i2: i64 = 0
111 while i2 < SKN_NIN { acc = acc + W1[j*SKN_NIN+i2]*fin[i2]/SKN_MAGIC_4096; i2 = i2 + 1 }
112 if acc < 0 { acc = 0 }
113 if acc > SKN_MAGIC_16384 { acc = SKN_MAGIC_16384 }
114 h[j] = acc
115 j = j + 1
116 }
117 let ti: i64 = (ty*tw+tx)*3
118 var c: i64 = 0
119 while c < SKN_NO {
120 var acc: i64 = B2[c]
121 j = 0
122 while j < SKN_NH { acc = acc + W2[c*SKN_NH+j]*h[j]/SKN_MAGIC_4096; j = j + 1 }
123 var v: i64 = acc*255/SKN_MAGIC_4096
124 if v < 1 { v = 1 }
125 if v > 255 { v = 255 }
126 raw[ti+c] = v
127 if c == 0 { mr = mr + v }
128 if c == 1 { mg = mg + v }
129 if c == 2 { mb = mb + v }
130 c = c + 1
131 }
132 tx = tx + 1
133 }
134 ty = ty + 1
135 }
136 mr = mr/(tw*tw); mg = mg/(tw*tw); mb = mb/(tw*tw)
137 if mr < 1 { mr = 1 }
138 if mg < 1 { mg = 1 }
139 if mb < 1 { mb = 1 }
140 // ratio-to-mean, clamped gently: texture variation without tone shift
141 var i3: i64 = 0
142 while i3 < tw*tw {
143 var rr: i64 = raw[i3*3]*128/mr
144 var rg: i64 = raw[i3*3+1]*128/mg
145 var rb: i64 = raw[i3*3+2]*128/mb
146 if rr < 84 { rr = 84 }
147 if rr > 176 { rr = 176 }
148 if rg < 84 { rg = 84 }
149 if rg > 176 { rg = 176 }
150 if rb < 84 { rb = 84 }
151 if rb > 176 { rb = 176 }
152 tile[i3] = rr + rg*256 + rb*SKN_MAGIC_65536
153 i3 = i3 + 1
154 }
155 return 0
156}