code wiki / (root) / nx_assetvariant.nx

nx_assetvariant.nx source

↩ module page · 135 lines · 6663 B

1// nx_assetvariant.nx -- SWAP-AS-DATA v0 (swap+motion census SCOPE A, the DnD/game ask): reuse ONE synthetic 2// base asset (person / wolf / goblin) and produce MANY variants by SWAPPING slots -- head (plain/horns/snout), 3// ears (none/pointy), tail (none/tail), build (slim/normal/bulk radius scale). A VARIANT IS DATA: the tuple 4// {species, head, ears, tail, build} fully determines the SDF part list, so a bestiary row = a tuple, and 5// diversity = enumerating tuples -- no hand-crafted one-offs. Fills the nx_sdfrender base (parts/npart/kblend) 6// exactly like sdf_body/t2mesh, so every variant renders on the SAME photoreal-path shader and can feed 7// nx_meshgen -> STL for game assets. Neural face/clothes swap on IMAGES = the S5 rung; this is the parametric 8// spine (like t2mesh before Shap-E). license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_sdfrender.nx" 11const AV_MAGIC_1250: i64 = 1250 12const AV_MAGIC_1060: i64 = 1060 13const AV_MAGIC_1190: i64 = 1190 14 15// species ids 16const AV_HUMAN: i64 = 0 17const AV_WOLF: i64 = 1 18const AV_GOBLIN: i64 = 2 19 20func av_p(base: i64, ip: *i64, cx: i64, cy: i64, cz: i64, rx: i64, ry: i64, rz: i64) -> i64 { 21 let p: *i64 = (base + O_PARTS) as *i64 22 let i: i64 = ip[0] 23 p[i * 6] = cx; p[i * 6 + 1] = cy; p[i * 6 + 2] = cz 24 p[i * 6 + 3] = rx; p[i * 6 + 4] = ry; p[i * 6 + 5] = rz 25 ip[0] = i + 1 26 return 0 27} 28 29// --- species bases (part recipes; grounded near the same world scale as sdf_body, camera camz=5) --------- 30func av_base_human(base: i64, ip: *i64) -> i64 { 31 // compact humanoid (reuses sdf_body proportions, fewer parts so slots read clearly) 32 av_p(base, ip, 0, AV_MAGIC_1250, 0, 225, 285, 235) // head 33 av_p(base, ip, 0, 1010, 0, 115, 160, 115) // neck 34 av_p(base, ip, 0, 770, 0, 330, 300, 235) // chest 35 av_p(base, ip, 0, 500, 0, 250, 250, 200) // waist 36 av_p(base, ip, 0, 80, 0, 410, 280, 270) // hips 37 av_p(base, ip, 0-470, 650, 0, 145, 340, 145) // arm L up 38 av_p(base, ip, 0-620, 280, 0, 115, 330, 118) // arm L lo 39 av_p(base, ip, 470, 650, 0, 145, 340, 145) // arm R up 40 av_p(base, ip, 620, 280, 0, 115, 330, 118) // arm R lo 41 av_p(base, ip, 0-195, 0-520, 0, 205, 640, 205) // leg L 42 av_p(base, ip, 195, 0-520, 0, 205, 640, 205) // leg R 43 return AV_MAGIC_1250 // head center Y (slot anchor) 44} 45func av_base_wolf(base: i64, ip: *i64) -> i64 { 46 // quadruped: long horizontal barrel + chest + head w/ snout-anchor forward + 4 legs 47 av_p(base, ip, 0, 0-100, 0, 780, 300, 280) // body barrel (long in x) 48 av_p(base, ip, 0-560, 20, 0, 330, 330, 300) // chest/shoulders 49 av_p(base, ip, 0-940, 320, 0, 230, 220, 210) // head 50 av_p(base, ip, 560, 0-40, 0, 300, 270, 260) // haunches 51 av_p(base, ip, 0-560, 0-640, 90, 95, 420, 95) // front leg L(z+) 52 av_p(base, ip, 0-560, 0-640, 0-90, 95, 420, 95) // front leg R 53 av_p(base, ip, 560, 0-640, 90, 100, 420, 100) // hind leg L 54 av_p(base, ip, 560, 0-640, 0-90, 100, 420, 100) // hind leg R 55 return 320 // head center Y 56} 57func av_base_goblin(base: i64, ip: *i64) -> i64 { 58 // short humanoid: big head, squat torso, short legs 59 av_p(base, ip, 0, 820, 0, 300, 330, 300) // BIG head 60 av_p(base, ip, 0, 500, 0, 105, 130, 105) // neck 61 av_p(base, ip, 0, 280, 0, 330, 280, 240) // torso 62 av_p(base, ip, 0, 0-30, 0, 340, 240, 250) // belly/hips 63 av_p(base, ip, 0-420, 260, 0, 120, 300, 120) // arm L 64 av_p(base, ip, 420, 260, 0, 120, 300, 120) // arm R 65 av_p(base, ip, 0-170, 0-480, 0, 150, 430, 150) // leg L 66 av_p(base, ip, 170, 0-480, 0, 150, 430, 150) // leg R 67 return 820 // head center Y 68} 69 70// --- swap slots (each writes parts relative to the species head anchor / body) --------------------------- 71func av_slot_head(base: i64, ip: *i64, sp: i64, hv: i64, heady: i64) -> i64 { 72 var hx: i64 = 0 73 if sp == AV_WOLF { hx = 0 - 940 } 74 if hv == 1 { // HORNS: two cones-ish above the head 75 av_p(base, ip, hx - 130, heady + 300, 0, 60, 220, 60) 76 av_p(base, ip, hx + 130, heady + 300, 0, 60, 220, 60) 77 } 78 if hv == 2 { // SNOUT: forward muzzle (z+ for bipeds, x- for wolf) 79 if sp == AV_WOLF { av_p(base, ip, hx - 260, heady - 40, 0, 190, 120, 130) } 80 else { av_p(base, ip, hx, heady - 40, 240, 130, 110, 190) } 81 } 82 return 0 83} 84func av_slot_ears(base: i64, ip: *i64, sp: i64, ev: i64, heady: i64) -> i64 { 85 if ev == 0 { return 0 } 86 var hx: i64 = 0 87 if sp == AV_WOLF { hx = 0 - 940 } 88 var ry: i64 = 220 89 if sp == AV_GOBLIN { ry = 300 } // goblin ears BIG 90 av_p(base, ip, hx - 210, heady + 210, 0, 70, ry, 55) 91 av_p(base, ip, hx + 210, heady + 210, 0, 70, ry, 55) 92 return 0 93} 94func av_slot_tail(base: i64, ip: *i64, sp: i64, tv: i64) -> i64 { 95 if tv == 0 { return 0 } 96 if sp == AV_WOLF { 97 av_p(base, ip, 900, 200, 0, 90, 90, 90) 98 av_p(base, ip, AV_MAGIC_1060, 360, 0, 80, 80, 80) 99 av_p(base, ip, AV_MAGIC_1190, 540, 0, 70, 70, 70) 100 } else { 101 av_p(base, ip, 0, 0-60, 0-320, 80, 80, 80) 102 av_p(base, ip, 0, 0-180, 0-470, 70, 70, 70) 103 av_p(base, ip, 0, 0-340, 0-560, 60, 60, 60) 104 } 105 return 0 106} 107 108// build a full variant into base: tuple {species, head, ears, tail, buildpct}. Returns part count. 109func av_build(base: i64, sp: i64, hv: i64, ev: i64, tv: i64, buildpct: i64) -> i64 { 110 let ip: *i64 = sys_mmap(8) as *i64 111 ip[0] = 0 112 var heady: i64 = 0 113 if sp == AV_HUMAN { heady = av_base_human(base, ip) } 114 if sp == AV_WOLF { heady = av_base_wolf(base, ip) } 115 if sp == AV_GOBLIN { heady = av_base_goblin(base, ip) } 116 av_slot_head(base, ip, sp, hv, heady) 117 av_slot_ears(base, ip, sp, ev, heady) 118 av_slot_tail(base, ip, sp, tv) 119 let n: i64 = ip[0] 120 // BUILD slot: scale every radius (slim 80 / normal 100 / bulk 125) 121 if buildpct != 100 { 122 let p: *i64 = (base + O_PARTS) as *i64 123 var i: i64 = 0 124 while i < n { 125 p[i * 6 + 3] = p[i * 6 + 3] * buildpct / 100 126 p[i * 6 + 4] = p[i * 6 + 4] * buildpct / 100 127 p[i * 6 + 5] = p[i * 6 + 5] * buildpct / 100 128 i = i + 1 129 } 130 } 131 let np: *i64 = (base + O_NPART) as *i64; np[0] = n 132 let kb: *i64 = (base + O_KBLEND) as *i64; kb[0] = 130 133 sdf_clear_ops(base, n) 134 return n 135}