@developerz.ai/ts23d 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/CLAUDE.md +1 -1
- package/README.md +10 -5
- package/dist/{chunk-a8fxakcj.js → chunk-6b05mnmx.js} +2 -2
- package/dist/{chunk-kgvbpqqw.js → chunk-7rtfjh9f.js} +6 -5
- package/dist/chunk-7rtfjh9f.js.map +10 -0
- package/dist/{chunk-1ypfs7ga.js → chunk-8j4c28jt.js} +790 -276
- package/dist/chunk-8j4c28jt.js.map +46 -0
- package/dist/{chunk-wtqhq529.js → chunk-d1fv6hrm.js} +6 -6
- package/dist/{chunk-wtqhq529.js.map → chunk-d1fv6hrm.js.map} +1 -1
- package/dist/{chunk-gcyp9b4d.js → chunk-dbq4qf52.js} +362 -215
- package/dist/chunk-dbq4qf52.js.map +25 -0
- package/dist/{chunk-xnt2sdhf.js → chunk-drna2rny.js} +2 -2
- package/dist/{chunk-ravbb06q.js → chunk-dxvypr7y.js} +2 -2
- package/dist/{chunk-11v28977.js → chunk-f6yme003.js} +85 -71
- package/dist/{chunk-11v28977.js.map → chunk-f6yme003.js.map} +6 -6
- package/dist/{chunk-4ddzsqtc.js → chunk-hg7pf34j.js} +4 -3
- package/dist/{chunk-4ddzsqtc.js.map → chunk-hg7pf34j.js.map} +5 -5
- package/dist/{chunk-w1zyhj40.js → chunk-jq4e17tj.js} +2 -2
- package/dist/{chunk-kvcep7ft.js → chunk-y63c6zcv.js} +967 -218
- package/dist/chunk-y63c6zcv.js.map +53 -0
- package/dist/cli/args.d.ts +7 -1
- package/dist/cli/bin.js +66 -25
- package/dist/cli/bin.js.map +6 -5
- package/dist/cli/manifest.d.ts +5 -1
- package/dist/cli/texture-cache.d.ts +4 -0
- package/dist/core/definition.d.ts +7 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/export/credits.d.ts +4 -0
- package/dist/export/glb-options.d.ts +48 -0
- package/dist/export/glb.d.ts +5 -35
- package/dist/export/hierarchy.d.ts +23 -0
- package/dist/export/index.d.ts +2 -1
- package/dist/export/index.js +21 -7
- package/dist/export/index.js.map +1 -1
- package/dist/export/lod-coverage.d.ts +12 -0
- package/dist/export/metadata.d.ts +2 -0
- package/dist/export/version.d.ts +2 -2
- package/dist/grammar/index.js +2 -2
- package/dist/index.js +63 -17
- package/dist/index.js.map +1 -1
- package/dist/kinds/head-armour.d.ts +3 -7
- package/dist/kinds/head-bust.d.ts +3 -2
- package/dist/kinds/head-face.d.ts +3 -1
- package/dist/kinds/head-garb.d.ts +4 -0
- package/dist/kinds/head-mesh.d.ts +4 -0
- package/dist/kinds/head-mouth.d.ts +4 -0
- package/dist/kinds/head-params.d.ts +9 -1
- package/dist/kinds/head-tone.d.ts +10 -0
- package/dist/kinds/head-torso.d.ts +35 -0
- package/dist/kinds/index.js +6 -6
- package/dist/material/cc0.d.ts +4 -0
- package/dist/material/define.d.ts +34 -0
- package/dist/material/generator.d.ts +1 -1
- package/dist/material/index.d.ts +8 -3
- package/dist/material/index.js +39 -7
- package/dist/material/index.js.map +1 -1
- package/dist/material/library.d.ts +7 -0
- package/dist/material/material-def.d.ts +30 -0
- package/dist/material/paint/canvas.d.ts +7 -0
- package/dist/material/paint/default-sheet.d.ts +3 -1
- package/dist/material/paint/fabric.d.ts +4 -0
- package/dist/material/paint/image-strip.d.ts +4 -0
- package/dist/material/paint/kit.d.ts +5 -0
- package/dist/material/paint/metal.d.ts +3 -0
- package/dist/material/paint/orm.d.ts +1 -1
- package/dist/material/paint/strip.d.ts +1 -1
- package/dist/material/paint/types.d.ts +32 -2
- package/dist/material/palette.d.ts +2 -0
- package/dist/material/slots.d.ts +5 -0
- package/dist/material/texture-source.d.ts +34 -0
- package/dist/material/trim-sheet.d.ts +20 -4
- package/dist/neural/index.js +2 -2
- package/dist/passes/index.js +2 -2
- package/dist/primitives/index.js +3 -3
- package/dist/qa/index.js +2 -2
- package/dist/render/beauty.d.ts +1 -1
- package/dist/render/index.js +3 -3
- package/dist/render/lighting.d.ts +7 -0
- package/dist/render/shade.d.ts +1 -1
- package/dist/testing/index.js +5 -5
- package/docs/README.md +4 -0
- package/docs/architecture/gltf-capabilities.md +38 -1
- package/docs/architecture/materials.md +151 -0
- package/docs/idea/10-sculpting.md +166 -0
- package/docs/idea/11-materials-authoring.md +132 -0
- package/docs/idea/12-blender-bridge.md +136 -0
- package/docs/idea/13-asset-pipeline-research.md +89 -0
- package/docs/plans/roadmap.md +12 -0
- package/package.json +2 -1
- package/recipes/boxcar/README.md +7 -0
- package/recipes/boxcar/boxcar.ts +118 -34
- package/recipes/goblin_head/README.md +27 -14
- package/recipes/goblin_head/goblin_head.ts +11 -9
- package/recipes/human_head/README.md +8 -4
- package/recipes/human_head/human_head.ts +4 -3
- package/recipes/material_swatches/material_swatches.ts +11 -5
- package/recipes/orc_head/README.md +32 -20
- package/recipes/orc_head/orc_head.ts +9 -7
- package/src/cli/args.ts +16 -3
- package/src/cli/manifest.ts +6 -0
- package/src/cli/run.ts +33 -9
- package/src/cli/texture-cache.ts +24 -0
- package/src/core/asset.ts +1 -0
- package/src/core/definition.ts +7 -0
- package/src/core/errors.ts +6 -1
- package/src/export/credits.ts +25 -0
- package/src/export/glb-options.ts +53 -0
- package/src/export/glb.ts +100 -113
- package/src/export/hierarchy.ts +122 -0
- package/src/export/index.ts +17 -1
- package/src/export/lod-coverage.ts +71 -0
- package/src/export/metadata.ts +3 -0
- package/src/export/version.ts +1 -1
- package/src/kinds/head-armour.ts +103 -73
- package/src/kinds/head-bust.ts +49 -86
- package/src/kinds/head-face.ts +94 -74
- package/src/kinds/head-garb.ts +181 -0
- package/src/kinds/head-hair.ts +74 -33
- package/src/kinds/head-mesh.ts +43 -5
- package/src/kinds/head-mouth.ts +111 -0
- package/src/kinds/head-params.ts +11 -2
- package/src/kinds/head-presets.ts +30 -27
- package/src/kinds/head-tone.ts +52 -0
- package/src/kinds/head-torso.ts +230 -0
- package/src/kinds/head.ts +8 -3
- package/src/material/cc0.ts +41 -0
- package/src/material/define.ts +130 -0
- package/src/material/generator.ts +15 -8
- package/src/material/index.ts +34 -3
- package/src/material/library.ts +196 -0
- package/src/material/material-def.ts +84 -0
- package/src/material/paint/canvas.ts +11 -1
- package/src/material/paint/compose.ts +1 -1
- package/src/material/paint/decode-png.ts +19 -13
- package/src/material/paint/default-sheet.ts +40 -28
- package/src/material/paint/fabric.ts +63 -0
- package/src/material/paint/image-strip.ts +88 -0
- package/src/material/paint/kit.ts +37 -0
- package/src/material/paint/masks.ts +3 -1
- package/src/material/paint/metal.ts +109 -0
- package/src/material/paint/orm.ts +14 -1
- package/src/material/paint/planks.ts +49 -4
- package/src/material/paint/strip.ts +35 -29
- package/src/material/paint/types.ts +45 -2
- package/src/material/paint/validate.ts +19 -3
- package/src/material/palette.ts +3 -0
- package/src/material/slots.ts +18 -0
- package/src/material/texture-source.ts +86 -0
- package/src/material/trim-sheet.ts +79 -13
- package/src/render/beauty.ts +2 -2
- package/src/render/lighting.ts +26 -0
- package/src/render/shade.ts +10 -5
- package/dist/chunk-1ypfs7ga.js.map +0 -42
- package/dist/chunk-gcyp9b4d.js.map +0 -22
- package/dist/chunk-kgvbpqqw.js.map +0 -10
- package/dist/chunk-kvcep7ft.js.map +0 -43
- /package/dist/{chunk-a8fxakcj.js.map → chunk-6b05mnmx.js.map} +0 -0
- /package/dist/{chunk-xnt2sdhf.js.map → chunk-drna2rny.js.map} +0 -0
- /package/dist/{chunk-ravbb06q.js.map → chunk-dxvypr7y.js.map} +0 -0
- /package/dist/{chunk-w1zyhj40.js.map → chunk-jq4e17tj.js.map} +0 -0
|
@@ -13,16 +13,16 @@ import {
|
|
|
13
13
|
dot2,
|
|
14
14
|
cross2,
|
|
15
15
|
normalize2
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-hg7pf34j.js";
|
|
17
17
|
import {
|
|
18
18
|
split2,
|
|
19
19
|
parseWhyte2
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-dxvypr7y.js";
|
|
21
21
|
import {
|
|
22
|
-
|
|
22
|
+
hex2,
|
|
23
23
|
DEFAULT_SHEET2,
|
|
24
|
-
|
|
25
|
-
} from "./chunk-
|
|
24
|
+
stripRect2
|
|
25
|
+
} from "./chunk-y63c6zcv.js";
|
|
26
26
|
import {
|
|
27
27
|
box2,
|
|
28
28
|
lathe2,
|
|
@@ -38,10 +38,10 @@ import {
|
|
|
38
38
|
arcLengths2,
|
|
39
39
|
transportFrames2,
|
|
40
40
|
sweep2
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-d1fv6hrm.js";
|
|
42
42
|
import {
|
|
43
43
|
bakeAo2
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-drna2rny.js";
|
|
45
45
|
|
|
46
46
|
// src/kinds/faces.ts
|
|
47
47
|
var EPS = 0.000000001;
|
|
@@ -531,17 +531,189 @@ function beardEdits(p, l) {
|
|
|
531
531
|
return out;
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
// src/kinds/head-torso.ts
|
|
535
|
+
var sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
536
|
+
var mid = (a, b) => [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2];
|
|
537
|
+
var dist = (a, b) => Math.hypot(...sub(a, b));
|
|
538
|
+
var PLINTH = 0.17;
|
|
539
|
+
function frameOf(p, l) {
|
|
540
|
+
const m = p.bust.mass ?? 0.5;
|
|
541
|
+
const b = l.base + 0.06 + 0.1 * m;
|
|
542
|
+
const nz = b + 0.6;
|
|
543
|
+
return {
|
|
544
|
+
cx: l.cranium.at[0] + p.jaw.muzzle * 0.3,
|
|
545
|
+
s: p.bust.shoulders,
|
|
546
|
+
b,
|
|
547
|
+
floor: l.base,
|
|
548
|
+
nz,
|
|
549
|
+
m,
|
|
550
|
+
n: p.neck.radius,
|
|
551
|
+
trapZ: nz + 0.12 + (l.hinge[1] - 0.2 - nz - 0.12) * m,
|
|
552
|
+
cutZ: l.base + PLINTH + 0.06 + 0.1 * m
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function torsoForms(f, g = 0) {
|
|
556
|
+
const { cx, s, b, m, n } = f;
|
|
557
|
+
const grow = (r) => [r[0] + g, r[1] + g, r[2] + g];
|
|
558
|
+
const top = [cx - 0.12, n * 0.5, f.trapZ];
|
|
559
|
+
const acromion = [cx - 0.05, s * 0.78, b + 0.62 + 0.05 * m];
|
|
560
|
+
return [
|
|
561
|
+
{
|
|
562
|
+
shape: "ellipsoid",
|
|
563
|
+
at: [cx - 0.05, 0, b + 0.36],
|
|
564
|
+
size: grow([0.25 + 0.07 * m, s * 0.66, 0.38])
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
shape: "ellipsoid",
|
|
568
|
+
at: [cx + 0.1 + 0.05 * m, s * 0.27, b + 0.46 + 0.02 * m],
|
|
569
|
+
size: grow([0.09 + 0.06 * m, s * 0.27, 0.11 + 0.03 * m]),
|
|
570
|
+
rotate: [-12, 0, 16],
|
|
571
|
+
blend: 0.05
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
shape: "ellipsoid",
|
|
575
|
+
at: [cx - 0.03, s * 0.8, b + 0.5 + 0.03 * m],
|
|
576
|
+
size: grow([0.13 + 0.06 * m, 0.11 + 0.05 * m, 0.16 + 0.05 * m]),
|
|
577
|
+
rotate: [-18, 0, 0],
|
|
578
|
+
blend: 0.08
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
shape: "ellipsoid",
|
|
582
|
+
at: mid(top, acromion),
|
|
583
|
+
size: [dist(top, acromion) / 2 + 0.08 + g, 0.11 + 0.12 * m + g, 0.05 + 0.1 * m + g],
|
|
584
|
+
rotate: alongX(sub(acromion, top)),
|
|
585
|
+
blend: 0.08 + 0.08 * m
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
shape: "capsule",
|
|
589
|
+
at: [cx - 0.04, s * 0.8, b + 0.55],
|
|
590
|
+
to: [cx - 0.02, s * 0.9, b + 0.05],
|
|
591
|
+
size: 0.12 + 0.05 * m + g,
|
|
592
|
+
blend: 0.06
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
shape: "capsule",
|
|
596
|
+
at: [cx + 0.2 + 0.04 * m, 0.045, f.nz - 0.03],
|
|
597
|
+
to: [cx + 0, s * 0.68, b + 0.6 + 0.04 * m],
|
|
598
|
+
size: 0.02 + 0.006 * (1 - m) + g,
|
|
599
|
+
blend: 0.035
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
shape: "ellipsoid",
|
|
603
|
+
at: [cx - 0.1, s * 0.55, b + 0.3],
|
|
604
|
+
size: grow([0.17 + 0.05 * m, 0.12 + 0.1 * m, 0.2]),
|
|
605
|
+
blend: 0.08
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
shape: "ellipsoid",
|
|
609
|
+
at: [cx - 0.18, 0, f.nz + 0.04 + 0.08 * m],
|
|
610
|
+
size: grow([0.12 + 0.06 * m, s * 0.32, 0.16 + 0.12 * m]),
|
|
611
|
+
blend: 0.1
|
|
612
|
+
}
|
|
613
|
+
];
|
|
614
|
+
}
|
|
615
|
+
function cutField(f) {
|
|
616
|
+
const rz = 0.64;
|
|
617
|
+
const ry = f.s * 1.08;
|
|
618
|
+
const cz = f.cutZ + rz;
|
|
619
|
+
const e = sd2.ellipsoid([f.cx, 0, cz], [1.6, ry, rz]);
|
|
620
|
+
const box = sd2.box([f.cx, 0, cz + 1], [3.2, ry * 2, 2]);
|
|
621
|
+
return (q) => Math.min(e(q), box(q));
|
|
622
|
+
}
|
|
623
|
+
function bustCut(f, g = 0) {
|
|
624
|
+
const rz = 0.64;
|
|
625
|
+
const ry = f.s * 1.08 + g;
|
|
626
|
+
const cz = f.cutZ + rz - g;
|
|
627
|
+
return {
|
|
628
|
+
group: [
|
|
629
|
+
{ shape: "ellipsoid", at: [f.cx, 0, cz], size: [1.6, ry, rz] },
|
|
630
|
+
{ shape: "roundBox", at: [f.cx, 0, cz + 1], size: [3.2, ry * 2, 2] }
|
|
631
|
+
],
|
|
632
|
+
op: "intersect",
|
|
633
|
+
blend: 0.012
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function bodyEdits(p, f, color) {
|
|
637
|
+
const { cx, b, m, nz } = f;
|
|
638
|
+
const shade = p.colors.shade;
|
|
639
|
+
return [
|
|
640
|
+
{
|
|
641
|
+
group: [
|
|
642
|
+
...torsoForms(f),
|
|
643
|
+
{
|
|
644
|
+
shape: "sphere",
|
|
645
|
+
at: [cx + 0.24 + 0.04 * m, 0, nz - 0.04],
|
|
646
|
+
size: 0.035,
|
|
647
|
+
op: "subtract",
|
|
648
|
+
blend: 0.04,
|
|
649
|
+
color: shade
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
shape: "capsule",
|
|
653
|
+
at: [cx + 0.26 + 0.06 * m, 0, b + 0.5],
|
|
654
|
+
to: [cx + 0.26 + 0.05 * m, 0, b + 0.22],
|
|
655
|
+
size: 0.01 + 0.006 * m,
|
|
656
|
+
op: "subtract",
|
|
657
|
+
blend: 0.04,
|
|
658
|
+
color: shade
|
|
659
|
+
},
|
|
660
|
+
bustCut(f)
|
|
661
|
+
],
|
|
662
|
+
color
|
|
663
|
+
}
|
|
664
|
+
];
|
|
665
|
+
}
|
|
666
|
+
var cylinder = (at, r, z0, z1) => ({
|
|
667
|
+
group: [
|
|
668
|
+
{ shape: "capsule", at: [at[0], at[1], z0 - r], to: [at[0], at[1], z1 + r], size: r },
|
|
669
|
+
{
|
|
670
|
+
shape: "roundBox",
|
|
671
|
+
at: [at[0], at[1], (z0 + z1) / 2],
|
|
672
|
+
size: [4, 4, z1 - z0],
|
|
673
|
+
op: "intersect"
|
|
674
|
+
}
|
|
675
|
+
]
|
|
676
|
+
});
|
|
677
|
+
function plinthEdits(p, f, minT = 0) {
|
|
678
|
+
const c = p.colors.plinth ?? [0.16, 0.15, 0.15];
|
|
679
|
+
const light = [c[0] * 1.35, c[1] * 1.35, c[2] * 1.35];
|
|
680
|
+
const x = f.cx - 0.04;
|
|
681
|
+
const R = 0.3 + 0.08 * f.s;
|
|
682
|
+
if (minT > 0.07)
|
|
683
|
+
return [
|
|
684
|
+
{ ...cylinder([x, 0, 0], R * 1.05, f.floor - 0.1, f.cutZ + 0.02), color: c, mirror: false }
|
|
685
|
+
];
|
|
686
|
+
const disc = f.floor + 0.07;
|
|
687
|
+
return [
|
|
688
|
+
{ ...cylinder([x, 0, 0], R, f.floor - 0.1, disc), color: c, mirror: false },
|
|
689
|
+
{
|
|
690
|
+
shape: "torus",
|
|
691
|
+
at: [x, 0, disc],
|
|
692
|
+
size: [R - 0.03, 0.025],
|
|
693
|
+
color: light,
|
|
694
|
+
blend: 0.01,
|
|
695
|
+
mirror: false
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
...cylinder([x, 0, 0], R * 0.62, disc, f.cutZ + 0.02),
|
|
699
|
+
color: c,
|
|
700
|
+
blend: 0.02,
|
|
701
|
+
mirror: false
|
|
702
|
+
}
|
|
703
|
+
];
|
|
704
|
+
}
|
|
705
|
+
|
|
534
706
|
// src/kinds/head-armour.ts
|
|
535
707
|
var RAD2 = Math.PI / 180;
|
|
536
708
|
var shade = (c, k) => [c[0] * k, c[1] * k, c[2] * k];
|
|
537
|
-
var above = (p, deg
|
|
709
|
+
var above = (p, deg) => {
|
|
538
710
|
const n = [0, -Math.sin(deg * RAD2), Math.cos(deg * RAD2)];
|
|
539
711
|
return {
|
|
540
712
|
shape: "roundBox",
|
|
541
713
|
at: [p[0] + n[0], p[1] + n[1], p[2] + n[2]],
|
|
542
714
|
size: [4, 4, 2],
|
|
543
715
|
rotate: [deg, 0, 0],
|
|
544
|
-
op
|
|
716
|
+
op: "intersect"
|
|
545
717
|
};
|
|
546
718
|
};
|
|
547
719
|
var slab = (p, deg, t) => ({
|
|
@@ -551,73 +723,97 @@ var slab = (p, deg, t) => ({
|
|
|
551
723
|
rotate: [deg, 0, 0],
|
|
552
724
|
op: "intersect"
|
|
553
725
|
});
|
|
554
|
-
var
|
|
555
|
-
|
|
556
|
-
|
|
726
|
+
var ell = (at, r, g, roll) => ({
|
|
727
|
+
shape: "ellipsoid",
|
|
728
|
+
at,
|
|
729
|
+
size: [r[0] + g, r[1] + g, r[2] + g],
|
|
730
|
+
rotate: [roll, 0, 0]
|
|
557
731
|
});
|
|
558
|
-
function
|
|
732
|
+
function plate(at, r, roll, cut, tilt, c, t) {
|
|
733
|
+
return [
|
|
734
|
+
{
|
|
735
|
+
group: [
|
|
736
|
+
ell(at, r, 0, roll),
|
|
737
|
+
...t < Math.min(...r) * 0.6 ? [{ ...ell(at, r, -t, roll), op: "subtract" }] : [],
|
|
738
|
+
above(cut, tilt)
|
|
739
|
+
],
|
|
740
|
+
color: c,
|
|
741
|
+
blend: 0.006
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
group: [
|
|
745
|
+
ell(at, r, 0.022, roll),
|
|
746
|
+
...t < Math.min(...r) * 0.6 ? [{ ...ell(at, r, -t * 0.8, roll), op: "subtract" }] : [],
|
|
747
|
+
slab(cut, tilt, 0.05)
|
|
748
|
+
],
|
|
749
|
+
color: shade(c, 1.3),
|
|
750
|
+
blend: 0.006
|
|
751
|
+
}
|
|
752
|
+
];
|
|
753
|
+
}
|
|
754
|
+
function armour(p, f, cell = 0) {
|
|
755
|
+
const t = Math.max(0.085, cell * 2.5);
|
|
559
756
|
const c = p.colors;
|
|
757
|
+
const { cx, s, b, nz } = f;
|
|
560
758
|
const metal = c.metal;
|
|
561
759
|
const out = [];
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
const
|
|
565
|
-
const
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
color: shade(metal, 1 - k * 0.12),
|
|
570
|
-
blend: 0.008
|
|
571
|
-
}, {
|
|
572
|
-
group: [
|
|
573
|
-
{ shape: "ellipsoid", at, size: [r[0] + 0.018, r[1] + 0.018, r[2] + 0.018] },
|
|
574
|
-
slab(cut, tilt, 0.035)
|
|
575
|
-
],
|
|
576
|
-
color: shade(metal, 0.55),
|
|
577
|
-
blend: 0.004
|
|
578
|
-
});
|
|
760
|
+
const cap = [cx - 0.04, s * 0.8, b + 0.66];
|
|
761
|
+
for (let k = 1;k >= 0; k--) {
|
|
762
|
+
const at = [cap[0], cap[1] + k * 0.07 * s, cap[2] - k * 0.17];
|
|
763
|
+
const r = k === 0 ? [0.27, 0.29, 0.25] : [0.23, 0.25, 0.19];
|
|
764
|
+
const tilt = -(38 + k * 14);
|
|
765
|
+
const cut = [at[0], at[1], at[2] - r[2] * 0.45];
|
|
766
|
+
out.push(...plate(at, r, -25 - k * 10, cut, tilt, shade(metal, 1 - k * 0.15), t));
|
|
579
767
|
for (let j = 0;j < 4; j++) {
|
|
580
|
-
const
|
|
768
|
+
const x = at[0] + (j - 1.5) * 0.12;
|
|
581
769
|
out.push({
|
|
582
770
|
shape: "sphere",
|
|
583
|
-
at: [at[
|
|
584
|
-
size: 0.
|
|
585
|
-
color: shade(metal, 1.
|
|
771
|
+
at: [x, at[1] + r[1] * 0.62, cut[2] + 0.02 - r[1] * 0.62 * Math.tan(-tilt * RAD2) * 0.4],
|
|
772
|
+
size: 0.017,
|
|
773
|
+
color: shade(metal, 1.35),
|
|
586
774
|
blend: 0.004
|
|
587
775
|
});
|
|
588
776
|
}
|
|
589
777
|
}
|
|
778
|
+
const crest = [cap[0], cap[1] - 0.03, cap[2] + 0.25];
|
|
779
|
+
out.push({
|
|
780
|
+
shape: "ellipsoid",
|
|
781
|
+
at: crest,
|
|
782
|
+
size: [0.25, 0.028, 0.07],
|
|
783
|
+
rotate: [-22, 0, 0],
|
|
784
|
+
color: shade(metal, 0.75),
|
|
785
|
+
blend: 0.02
|
|
786
|
+
});
|
|
590
787
|
for (let k = 0;k < 3; k++)
|
|
591
788
|
out.push({
|
|
592
789
|
shape: "cone",
|
|
593
|
-
at: [
|
|
594
|
-
size: [0.
|
|
595
|
-
rotate: alongZ(unit([(k - 1) * 0.
|
|
790
|
+
at: [crest[0] - 0.14 + k * 0.14, crest[1] + 0.01, crest[2] + 0.02 - Math.abs(k - 1) * 0.03],
|
|
791
|
+
size: [0.075, 0.012, 0.36 - Math.abs(k - 1) * 0.12],
|
|
792
|
+
rotate: alongZ(unit([(k - 1) * 0.3, 0.55, 1])),
|
|
596
793
|
color: c.teeth,
|
|
597
|
-
blend: 0.
|
|
794
|
+
blend: 0.015
|
|
598
795
|
});
|
|
599
|
-
const
|
|
600
|
-
const grow = (g) => [chest.r[0] + g, chest.r[1] + g, chest.r[2] + g];
|
|
601
|
-
const band = [cx, 0, b + 0.28];
|
|
796
|
+
const band = [cx, 0, b + 0.36];
|
|
602
797
|
out.push({
|
|
603
|
-
group: [{
|
|
798
|
+
group: [{ group: torsoForms(f, 0.03) }, slab(band, 50, 0.15), bustCut(f)],
|
|
604
799
|
color: c.leather,
|
|
605
800
|
blend: 0.006,
|
|
606
801
|
mirror: false
|
|
607
802
|
}, {
|
|
608
803
|
group: [
|
|
609
|
-
{
|
|
804
|
+
{ group: torsoForms(f, 0.055) },
|
|
805
|
+
bustCut(f),
|
|
610
806
|
{
|
|
611
807
|
shape: "roundBox",
|
|
612
|
-
at: [cx + 0.3, 0.02, b + 0.
|
|
613
|
-
size: [0.3, 0.
|
|
614
|
-
rotate: [
|
|
808
|
+
at: [cx + 0.3, 0.02, b + 0.38],
|
|
809
|
+
size: [0.3, 0.14, 0.14],
|
|
810
|
+
rotate: [50, 0, 0],
|
|
615
811
|
op: "intersect"
|
|
616
812
|
},
|
|
617
813
|
{
|
|
618
814
|
shape: "ellipsoid",
|
|
619
|
-
at: [cx + 0.42, 0.02, b + 0.
|
|
620
|
-
size: [0.1, 0.
|
|
815
|
+
at: [cx + 0.42, 0.02, b + 0.38],
|
|
816
|
+
size: [0.1, 0.04, 0.04],
|
|
621
817
|
op: "subtract"
|
|
622
818
|
}
|
|
623
819
|
],
|
|
@@ -626,60 +822,193 @@ function armour(p, cx, s, b, nz) {
|
|
|
626
822
|
mirror: false
|
|
627
823
|
});
|
|
628
824
|
const fur = c.fur ?? c.leather;
|
|
629
|
-
const R =
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
color: shade(fur, 0.75),
|
|
635
|
-
blend: 0.04
|
|
636
|
-
});
|
|
637
|
-
for (let row = 0;row < 2; row++)
|
|
638
|
-
for (let i = 0;i < 10; i++) {
|
|
639
|
-
const a = (-85 + i * 20 + row * 10) * RAD2;
|
|
640
|
-
const rr = R + row * 0.05;
|
|
825
|
+
const R = f.n + 0.08;
|
|
826
|
+
for (let row = 0;row < 3; row++)
|
|
827
|
+
for (let i = 0;i < 8; i++) {
|
|
828
|
+
const a = (-80 + i * 22 + row * 11) * RAD2;
|
|
829
|
+
const rr = R + row * 0.07;
|
|
641
830
|
const root = [
|
|
642
|
-
cx - 0.
|
|
643
|
-
Math.abs(Math.sin(a)) * rr + 0.
|
|
644
|
-
nz + 0.
|
|
831
|
+
cx - 0.1 - Math.abs(Math.cos(a)) * rr * 0.9,
|
|
832
|
+
Math.abs(Math.sin(a)) * rr + 0.02,
|
|
833
|
+
nz + 0.16 - row * 0.05
|
|
645
834
|
];
|
|
646
|
-
const dir = unit([
|
|
835
|
+
const dir = unit([-0.7, Math.abs(Math.sin(a)) * 0.8, -0.55 - (i + row) % 2 * 0.3]);
|
|
647
836
|
out.push({
|
|
648
837
|
shape: "cone",
|
|
649
838
|
at: root,
|
|
650
|
-
size: [0.
|
|
839
|
+
size: [0.075 - row * 0.008, 0.012, 0.16 + (i + row) % 3 * 0.04],
|
|
651
840
|
rotate: alongZ(dir),
|
|
652
|
-
color: (i + row) % 2 ? fur : shade(fur, 0.
|
|
653
|
-
blend: 0.
|
|
841
|
+
color: (i + row) % 2 ? fur : shade(fur, 0.72),
|
|
842
|
+
blend: 0.035
|
|
654
843
|
});
|
|
655
844
|
}
|
|
656
845
|
return out;
|
|
657
846
|
}
|
|
658
847
|
|
|
659
|
-
// src/kinds/head-
|
|
660
|
-
|
|
848
|
+
// src/kinds/head-garb.ts
|
|
849
|
+
var shade2 = (c, k) => [c[0] * k, c[1] * k, c[2] * k];
|
|
850
|
+
function vest(p, f) {
|
|
661
851
|
const c = p.colors;
|
|
662
|
-
|
|
852
|
+
const { cx, s, b, nz, n } = f;
|
|
853
|
+
const scarf = c.scarf ?? c.cloth;
|
|
854
|
+
const hood = c.cape ?? shade2(c.cloth, 0.8);
|
|
855
|
+
const out = [
|
|
663
856
|
{
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
857
|
+
group: [
|
|
858
|
+
{ group: torsoForms(f, 0.032) },
|
|
859
|
+
{
|
|
860
|
+
shape: "ellipsoid",
|
|
861
|
+
at: [cx + 0.32, 0, nz + 0.01],
|
|
862
|
+
size: [0.2, 0.07, 0.11],
|
|
863
|
+
op: "subtract",
|
|
864
|
+
blend: 0.01
|
|
865
|
+
},
|
|
866
|
+
bustCut(f)
|
|
867
|
+
],
|
|
868
|
+
color: c.cloth,
|
|
869
|
+
blend: 0.006
|
|
670
870
|
},
|
|
671
871
|
{
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
872
|
+
group: [
|
|
873
|
+
{ group: torsoForms(f, 0.065) },
|
|
874
|
+
{
|
|
875
|
+
shape: "roundBox",
|
|
876
|
+
at: [cx + 0.4, 0, b + 0.3],
|
|
877
|
+
size: [0.5, 0.3, 1],
|
|
878
|
+
rotate: [0, -8, 0],
|
|
879
|
+
round: 0.08,
|
|
880
|
+
op: "subtract",
|
|
881
|
+
blend: 0.02
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
shape: "sphere",
|
|
885
|
+
at: [cx - 0.03, s * 0.98, b + 0.42],
|
|
886
|
+
size: 0.17,
|
|
887
|
+
op: "subtract",
|
|
888
|
+
blend: 0.02
|
|
889
|
+
},
|
|
890
|
+
bustCut(f)
|
|
891
|
+
],
|
|
892
|
+
color: c.leather,
|
|
893
|
+
blend: 0.006
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
group: [
|
|
897
|
+
{ group: torsoForms(f, 0.088) },
|
|
898
|
+
{
|
|
899
|
+
shape: "roundBox",
|
|
900
|
+
at: [cx, 0, b + 0.38],
|
|
901
|
+
size: [4, 4, 0.08],
|
|
902
|
+
rotate: [-48, 0, 0],
|
|
903
|
+
op: "intersect"
|
|
904
|
+
},
|
|
905
|
+
bustCut(f)
|
|
906
|
+
],
|
|
907
|
+
color: shade2(c.leather, 0.65),
|
|
908
|
+
blend: 0.004,
|
|
909
|
+
mirror: false
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
group: [
|
|
913
|
+
{ group: torsoForms(f, 0.105) },
|
|
914
|
+
{
|
|
915
|
+
shape: "roundBox",
|
|
916
|
+
at: [cx + 0.3, -0.06, b + 0.32],
|
|
917
|
+
size: [0.3, 0.1, 0.1],
|
|
918
|
+
rotate: [-48, 0, 0],
|
|
919
|
+
op: "intersect"
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
shape: "roundBox",
|
|
923
|
+
at: [cx + 0.4, -0.06, b + 0.32],
|
|
924
|
+
size: [0.16, 0.05, 0.05],
|
|
925
|
+
rotate: [-48, 0, 0],
|
|
926
|
+
op: "subtract"
|
|
927
|
+
}
|
|
928
|
+
],
|
|
929
|
+
color: c.metal,
|
|
930
|
+
blend: 0.003,
|
|
931
|
+
mirror: false
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
group: [
|
|
935
|
+
{
|
|
936
|
+
shape: "torus",
|
|
937
|
+
at: [cx - 0.1, 0, nz + 0.03],
|
|
938
|
+
size: [n + 0.12, 0.06],
|
|
939
|
+
rotate: [0, -28, 0]
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
shape: "roundBox",
|
|
943
|
+
at: [cx - 1.04, 0, nz],
|
|
944
|
+
size: [2, 4, 4],
|
|
945
|
+
op: "intersect",
|
|
946
|
+
blend: 0.04
|
|
947
|
+
}
|
|
948
|
+
],
|
|
949
|
+
color: hood,
|
|
950
|
+
blend: 0.03
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
group: [
|
|
954
|
+
{ shape: "ellipsoid", at: [cx - 0.33, 0, nz - 0.04], size: [0.13, s * 0.5, 0.25] },
|
|
955
|
+
{
|
|
956
|
+
shape: "cone",
|
|
957
|
+
at: [cx - 0.36, 0, nz - 0.12],
|
|
958
|
+
size: [0.1, 0.015, 0.34],
|
|
959
|
+
rotate: alongZ(unit([-0.35, 0, -1])),
|
|
960
|
+
blend: 0.05
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
shape: "ellipsoid",
|
|
964
|
+
at: [cx - 0.3, 0, nz + 0.12],
|
|
965
|
+
size: [0.08, s * 0.36, 0.1],
|
|
966
|
+
op: "subtract",
|
|
967
|
+
blend: 0.02,
|
|
968
|
+
color: shade2(hood, 0.35)
|
|
969
|
+
}
|
|
970
|
+
],
|
|
971
|
+
color: hood,
|
|
677
972
|
blend: 0.04,
|
|
678
|
-
color: c.shade,
|
|
679
973
|
mirror: false
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
shape: "torus",
|
|
977
|
+
at: [cx - 0.04, 0, nz + 0.17],
|
|
978
|
+
size: [n + 0.05, 0.065],
|
|
979
|
+
rotate: [0, -12, 0],
|
|
980
|
+
color: scarf,
|
|
981
|
+
blend: 0.02
|
|
680
982
|
}
|
|
681
983
|
];
|
|
984
|
+
const knot = [cx + n * 0.8, n + 0.04, nz + 0.13];
|
|
985
|
+
out.push({
|
|
986
|
+
shape: "ellipsoid",
|
|
987
|
+
at: knot,
|
|
988
|
+
size: [0.05, 0.06, 0.05],
|
|
989
|
+
color: shade2(scarf, 0.85),
|
|
990
|
+
blend: 0.02,
|
|
991
|
+
mirror: false
|
|
992
|
+
});
|
|
993
|
+
for (const [dy, len, tw] of [
|
|
994
|
+
[0.3, 0.2, 0.045],
|
|
995
|
+
[0.6, 0.16, 0.04]
|
|
996
|
+
]) {
|
|
997
|
+
const dir = unit([0.3, dy, -1]);
|
|
998
|
+
out.push({
|
|
999
|
+
shape: "cone",
|
|
1000
|
+
at: [knot[0] + 0.01, knot[1] + dy * 0.04, knot[2] - 0.02],
|
|
1001
|
+
size: [tw, tw * 0.7, len],
|
|
1002
|
+
rotate: alongZ(dir),
|
|
1003
|
+
color: dy > 0.5 ? scarf : shade2(scarf, 0.8),
|
|
1004
|
+
blend: 0.015,
|
|
1005
|
+
mirror: false
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
return out;
|
|
682
1009
|
}
|
|
1010
|
+
|
|
1011
|
+
// src/kinds/head-bust.ts
|
|
683
1012
|
function hood(p, cx, nz) {
|
|
684
1013
|
const c = p.colors;
|
|
685
1014
|
return [
|
|
@@ -725,14 +1054,17 @@ function hood(p, cx, nz) {
|
|
|
725
1054
|
}
|
|
726
1055
|
];
|
|
727
1056
|
}
|
|
728
|
-
function tunic(p,
|
|
1057
|
+
function tunic(p, f) {
|
|
729
1058
|
const c = p.colors;
|
|
730
|
-
const
|
|
731
|
-
const shell = (g) => ({
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
1059
|
+
const { cx, s, b, nz } = f;
|
|
1060
|
+
const shell = (g) => ({ group: torsoForms(f, g) });
|
|
1061
|
+
const torso = sculptField2(torsoForms(f), { color: c.cloth, mirror: "y" }).field;
|
|
1062
|
+
const front = (z) => {
|
|
1063
|
+
let x = cx + 0.7;
|
|
1064
|
+
for (let i = 0;i < 300 && torso([x, 0, z]) > 0; i++)
|
|
1065
|
+
x -= 0.004;
|
|
1066
|
+
return x;
|
|
1067
|
+
};
|
|
736
1068
|
const n = p.neck.radius;
|
|
737
1069
|
const axis = (z) => [cx - 0.08, 0, z];
|
|
738
1070
|
const mantle = (g) => ({
|
|
@@ -760,7 +1092,8 @@ function tunic(p, cx, s, b, nz) {
|
|
|
760
1092
|
group: [
|
|
761
1093
|
mantle(0),
|
|
762
1094
|
{ shape: "roundBox", at: [0, 0, b + 0.3 + 1], size: [4, 4, 2], op: "intersect" },
|
|
763
|
-
opening
|
|
1095
|
+
opening,
|
|
1096
|
+
bustCut(f)
|
|
764
1097
|
],
|
|
765
1098
|
color: c.cape ?? c.leather,
|
|
766
1099
|
blend: 0.01
|
|
@@ -796,66 +1129,41 @@ function tunic(p, cx, s, b, nz) {
|
|
|
796
1129
|
blend: 0.004,
|
|
797
1130
|
mirror: false
|
|
798
1131
|
},
|
|
799
|
-
...[0.
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
],
|
|
1132
|
+
...[0.5, 0.38, 0.26].map((z) => ({
|
|
1133
|
+
shape: "sphere",
|
|
1134
|
+
at: [front(b + z) + 0.014, 0, b + z],
|
|
1135
|
+
size: 0.028,
|
|
804
1136
|
color: c.metal,
|
|
805
|
-
blend: 0.
|
|
1137
|
+
blend: 0.004,
|
|
806
1138
|
mirror: false
|
|
807
1139
|
}))
|
|
808
1140
|
];
|
|
809
1141
|
}
|
|
810
|
-
function bustEdits(p, l) {
|
|
1142
|
+
function bustEdits(p, l, cell = 0) {
|
|
811
1143
|
const c = p.colors;
|
|
812
|
-
const
|
|
813
|
-
const
|
|
814
|
-
const
|
|
815
|
-
const nz = b + 0.6;
|
|
816
|
-
const body = p.bust.style === "pauldrons" ? c.skin : c.cloth;
|
|
1144
|
+
const f = frameOf(p, l);
|
|
1145
|
+
const style = p.bust.style;
|
|
1146
|
+
const bare = style === "pauldrons" || style === "vest";
|
|
817
1147
|
const e = [
|
|
818
|
-
|
|
819
|
-
{
|
|
820
|
-
shape: "capsule",
|
|
821
|
-
at: [cx - 0.16, 0.1, nz + 0.16],
|
|
822
|
-
to: [cx - 0.1, s * 0.78, b + 0.44],
|
|
823
|
-
size: 0.15,
|
|
824
|
-
color: body,
|
|
825
|
-
blend: 0.15
|
|
826
|
-
},
|
|
827
|
-
{ shape: "sphere", at: [cx - 0.04, s * 0.84, b + 0.3], size: 0.2, color: body, blend: 0.1 },
|
|
828
|
-
{
|
|
829
|
-
shape: "capsule",
|
|
830
|
-
at: [cx - 0.2, 0.08, nz + 0.3],
|
|
831
|
-
to: [cx - 0.1, s * 0.62, b + 0.5],
|
|
832
|
-
size: 0.1 + p.neck.radius * 0.2,
|
|
833
|
-
color: body,
|
|
834
|
-
blend: 0.12
|
|
835
|
-
},
|
|
1148
|
+
...bodyEdits(p, f, bare ? c.skin : c.cloth),
|
|
836
1149
|
{
|
|
837
|
-
shape: "
|
|
838
|
-
at: [cx - 0.
|
|
839
|
-
|
|
840
|
-
size: p.neck.radius * 1.05,
|
|
1150
|
+
shape: "ellipsoid",
|
|
1151
|
+
at: [f.cx - 0.09, 0, f.nz + 0.06],
|
|
1152
|
+
size: [f.n * 1.02, f.n * 1.02, 0.12],
|
|
841
1153
|
color: c.skin,
|
|
842
|
-
blend: 0.
|
|
1154
|
+
blend: 0.04
|
|
843
1155
|
}
|
|
844
1156
|
];
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
});
|
|
852
|
-
if (p.bust.style === "pauldrons")
|
|
853
|
-
e.push(...torso(p, cx, b), ...armour(p, cx, s, b, nz));
|
|
854
|
-
else if (p.bust.style === "hood")
|
|
855
|
-
e.push(...hood(p, cx, nz));
|
|
1157
|
+
if (style === "pauldrons")
|
|
1158
|
+
e.push(...armour(p, f, cell));
|
|
1159
|
+
else if (style === "hood")
|
|
1160
|
+
e.push(...hood(p, f.cx, f.nz));
|
|
1161
|
+
else if (style === "vest")
|
|
1162
|
+
e.push(...vest(p, f));
|
|
856
1163
|
else
|
|
857
|
-
e.push(...tunic(p,
|
|
858
|
-
e.push(
|
|
1164
|
+
e.push(...tunic(p, f));
|
|
1165
|
+
e.push(...plinthEdits(p, f, cell * 1.5));
|
|
1166
|
+
e.push({ shape: "roundBox", at: [0, 0, f.floor - 1], size: [4, 4, 2], op: "subtract" });
|
|
859
1167
|
return e;
|
|
860
1168
|
}
|
|
861
1169
|
|
|
@@ -990,6 +1298,100 @@ function wartEdits(p, l, rng) {
|
|
|
990
1298
|
});
|
|
991
1299
|
}
|
|
992
1300
|
|
|
1301
|
+
// src/kinds/head-mouth.ts
|
|
1302
|
+
function mouthEdits(p, l, teeth = true) {
|
|
1303
|
+
const c = p.colors;
|
|
1304
|
+
const lipT = p.mouth.lips;
|
|
1305
|
+
const mw = p.mouth.width;
|
|
1306
|
+
const g = p.mouth.grin;
|
|
1307
|
+
const out = [
|
|
1308
|
+
{
|
|
1309
|
+
shape: "ellipsoid",
|
|
1310
|
+
at: [l.mouthX - 0.01, 0, l.mouthZ + lipT * 0.7],
|
|
1311
|
+
size: [0.032, mw, lipT],
|
|
1312
|
+
color: c.lips,
|
|
1313
|
+
blend: 0.03
|
|
1314
|
+
},
|
|
1315
|
+
{
|
|
1316
|
+
shape: "ellipsoid",
|
|
1317
|
+
at: [l.mouthX - 0.015 + p.jaw.underbite * 0.7, 0, l.mouthZ - lipT * 0.8],
|
|
1318
|
+
size: [0.034 + p.jaw.underbite * 0.3, mw * 0.85, lipT * (1.1 + p.jaw.underbite * 4)],
|
|
1319
|
+
color: c.lips,
|
|
1320
|
+
blend: 0.03
|
|
1321
|
+
}
|
|
1322
|
+
];
|
|
1323
|
+
if (g < 0.4 || !teeth) {
|
|
1324
|
+
out.push({
|
|
1325
|
+
shape: "capsule",
|
|
1326
|
+
at: [l.mouthX + 0.05, 0, l.mouthZ],
|
|
1327
|
+
to: [l.mouthX - 0.03 - 0.02 * g, mw * 0.98, l.mouthZ + 0.012 + g * 0.05 - p.brow.scowl * 0.4],
|
|
1328
|
+
size: 0.006 + g * 0.022,
|
|
1329
|
+
op: "subtract",
|
|
1330
|
+
blend: 0.012,
|
|
1331
|
+
color: c.mouth
|
|
1332
|
+
});
|
|
1333
|
+
return out;
|
|
1334
|
+
}
|
|
1335
|
+
const h = 0.035 + g * 0.05;
|
|
1336
|
+
const z0 = l.mouthZ + h * 0.45;
|
|
1337
|
+
const back = mw * 0.55;
|
|
1338
|
+
out.push({
|
|
1339
|
+
group: [
|
|
1340
|
+
{ shape: "ellipsoid", at: [l.mouthX - back, 0, z0], size: [back + 0.06, mw, h] },
|
|
1341
|
+
{
|
|
1342
|
+
shape: "ellipsoid",
|
|
1343
|
+
at: [l.mouthX - back + 0.02, 0, z0 + h * 0.7],
|
|
1344
|
+
size: [back + 0.12, mw * 1.1, h * 0.9],
|
|
1345
|
+
op: "subtract"
|
|
1346
|
+
}
|
|
1347
|
+
],
|
|
1348
|
+
op: "subtract",
|
|
1349
|
+
blend: 0.012,
|
|
1350
|
+
color: c.mouth
|
|
1351
|
+
});
|
|
1352
|
+
if (teeth)
|
|
1353
|
+
out.push({
|
|
1354
|
+
shape: "ellipsoid",
|
|
1355
|
+
at: [l.mouthX - back * 0.9, 0, l.mouthZ - h * 0.4],
|
|
1356
|
+
size: [back * 0.9, mw * 0.62, h * 0.45],
|
|
1357
|
+
color: [0.42, 0.12, 0.12],
|
|
1358
|
+
blend: 0.01
|
|
1359
|
+
});
|
|
1360
|
+
out.push({
|
|
1361
|
+
shape: "ellipsoid",
|
|
1362
|
+
at: [l.mouthX - 0.06, mw * 0.95, z0 + h * 0.6],
|
|
1363
|
+
size: [0.05, 0.045, 0.04 + g * 0.01],
|
|
1364
|
+
rotate: [-30, 0, 0],
|
|
1365
|
+
blend: 0.035
|
|
1366
|
+
});
|
|
1367
|
+
const n = teeth ? 3 : 0;
|
|
1368
|
+
for (let i = 0;i < n; i++) {
|
|
1369
|
+
const a = (0.25 + i) * 0.36;
|
|
1370
|
+
const y = Math.sin(a) * mw * 0.82;
|
|
1371
|
+
const x = l.mouthX - 0.03 - (1 - Math.cos(a)) * back * 1.3;
|
|
1372
|
+
const lo = z0 - h * Math.sqrt(Math.max(0, 1 - (y / mw) ** 2));
|
|
1373
|
+
const hi = z0 + h * 0.7 - h * 0.9 * Math.sqrt(Math.max(0, 1 - (y / (mw * 1.1)) ** 2));
|
|
1374
|
+
const len = 0.03 + g * 0.008 - i * 0.004;
|
|
1375
|
+
const r = 0.014 + g * 0.004 - i * 0.0015;
|
|
1376
|
+
out.push({
|
|
1377
|
+
shape: "cone",
|
|
1378
|
+
at: [x, y, hi + 0.008],
|
|
1379
|
+
size: [r, 0.003, len],
|
|
1380
|
+
rotate: alongZ([0.15, 0, -1]),
|
|
1381
|
+
color: c.teeth,
|
|
1382
|
+
blend: 0.004
|
|
1383
|
+
}, {
|
|
1384
|
+
shape: "cone",
|
|
1385
|
+
at: [x - 0.006, y * 0.97, lo - 0.008],
|
|
1386
|
+
size: [r * 0.85, 0.003, len * 0.6],
|
|
1387
|
+
rotate: alongZ([0.1, 0, 1]),
|
|
1388
|
+
color: c.teeth,
|
|
1389
|
+
blend: 0.004
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
return out;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
993
1395
|
// src/kinds/head-face.ts
|
|
994
1396
|
function primaryEdits(l) {
|
|
995
1397
|
const [cx, , cz] = l.cranium.at;
|
|
@@ -1004,26 +1406,36 @@ function primaryEdits(l) {
|
|
|
1004
1406
|
}
|
|
1005
1407
|
];
|
|
1006
1408
|
}
|
|
1007
|
-
function skullEdits(p, l) {
|
|
1409
|
+
function skullEdits(p, l, cell = 0) {
|
|
1410
|
+
const fine = cell < 0.03;
|
|
1411
|
+
const tipR = Math.max(p.nose.tip, cell * 0.6);
|
|
1008
1412
|
const c = p.colors;
|
|
1009
1413
|
const cx = l.cranium.at[0];
|
|
1010
1414
|
const [ex, ey, ez] = l.eye;
|
|
1011
1415
|
const r = l.eyeR;
|
|
1012
|
-
const lipT = p.mouth.lips;
|
|
1013
1416
|
const mw = p.mouth.width;
|
|
1014
1417
|
const [ax, ay, az] = l.angle;
|
|
1015
1418
|
const [hx, hz] = l.hinge;
|
|
1016
1419
|
const chin = l.chin;
|
|
1017
1420
|
const tipX = l.faceX + 0.06 + p.nose.length * 0.25 + p.nose.bridge + p.jaw.muzzle * 0.5;
|
|
1018
1421
|
const tipZ = l.noseZ + 0.035 - p.nose.hook;
|
|
1422
|
+
const bIn = [ex + r * 0.75, 0.03, l.browZ - p.brow.scowl];
|
|
1423
|
+
const bOut = [ex + r * 0.05, ey + r * 1.3, l.browZ + p.brow.scowl * 0.5];
|
|
1019
1424
|
const e = [
|
|
1020
1425
|
...primaryEdits(l),
|
|
1021
1426
|
{
|
|
1022
1427
|
shape: "ellipsoid",
|
|
1023
1428
|
at: [ex - 0.03, (ey + 0.06) * p.cheeks.width, ez - r - 0.065 * p.cheeks.size],
|
|
1024
|
-
size: [0.
|
|
1429
|
+
size: [0.075 * p.cheeks.size, 0.07 * p.cheeks.size, 0.055 * p.cheeks.size],
|
|
1025
1430
|
rotate: [0, 0, 25],
|
|
1026
|
-
blend: 0.
|
|
1431
|
+
blend: 0.08
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
shape: "capsule",
|
|
1435
|
+
at: [ex - r * 0.2, (ey + 0.05) * p.cheeks.width, ez - r - 0.03],
|
|
1436
|
+
to: [cx + 0.06, l.cranium.r[1] * 0.92, ez - 0.07],
|
|
1437
|
+
size: 0.028 * p.cheeks.size,
|
|
1438
|
+
blend: 0.05
|
|
1027
1439
|
},
|
|
1028
1440
|
{
|
|
1029
1441
|
shape: "ellipsoid",
|
|
@@ -1054,9 +1466,10 @@ function skullEdits(p, l) {
|
|
|
1054
1466
|
},
|
|
1055
1467
|
{ shape: "sphere", at: [ax + 0.02, ay * 0.95, az], size: 0.065, blend: 0.07 },
|
|
1056
1468
|
{
|
|
1057
|
-
shape: "
|
|
1469
|
+
shape: "roundBox",
|
|
1058
1470
|
at: chin,
|
|
1059
|
-
size: [0.
|
|
1471
|
+
size: [0.13 * p.jaw.chin, 0.18 * p.jaw.chin, 0.14 * p.jaw.chin],
|
|
1472
|
+
round: 0.06 * p.jaw.chin,
|
|
1060
1473
|
blend: 0.06
|
|
1061
1474
|
},
|
|
1062
1475
|
{
|
|
@@ -1068,10 +1481,27 @@ function skullEdits(p, l) {
|
|
|
1068
1481
|
},
|
|
1069
1482
|
{
|
|
1070
1483
|
shape: "capsule",
|
|
1071
|
-
at: [
|
|
1072
|
-
to: [
|
|
1073
|
-
size: p.
|
|
1074
|
-
blend: 0.
|
|
1484
|
+
at: [cx - 0.03, l.cranium.r[1] * 0.68, ez - 0.28],
|
|
1485
|
+
to: [cx + p.neck.radius * 0.6, 0.05, l.base + 0.74],
|
|
1486
|
+
size: p.neck.radius * 0.26,
|
|
1487
|
+
blend: 0.05
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
shape: "ellipsoid",
|
|
1491
|
+
at: [(bIn[0] + bOut[0]) / 2, (bIn[1] + bOut[1]) / 2, (bIn[2] + bOut[2]) / 2],
|
|
1492
|
+
size: [
|
|
1493
|
+
Math.hypot(bOut[0] - bIn[0], bOut[1] - bIn[1], bOut[2] - bIn[2]) / 2 + p.brow.ridge * 0.6,
|
|
1494
|
+
p.brow.ridge * 1.25,
|
|
1495
|
+
p.brow.ridge * 0.85
|
|
1496
|
+
],
|
|
1497
|
+
rotate: alongX([bOut[0] - bIn[0], bOut[1] - bIn[1], bOut[2] - bIn[2]]),
|
|
1498
|
+
blend: 0.05
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
shape: "sphere",
|
|
1502
|
+
at: [bIn[0] - 0.01, 0, bIn[2] - p.brow.ridge * 0.15],
|
|
1503
|
+
size: p.brow.ridge * 1.05,
|
|
1504
|
+
blend: 0.05
|
|
1075
1505
|
},
|
|
1076
1506
|
{ shape: "sphere", at: l.eye, size: r * 1.12, op: "subtract", blend: r * 0.5, color: c.shade }
|
|
1077
1507
|
];
|
|
@@ -1094,56 +1524,50 @@ function skullEdits(p, l) {
|
|
|
1094
1524
|
};
|
|
1095
1525
|
};
|
|
1096
1526
|
e.push(lid(p.eyes.lid, true), lid(p.eyes.lowerLid, false));
|
|
1527
|
+
const long = p.nose.bridge > 0.06 ? 0.65 : 1;
|
|
1528
|
+
const wing = Math.min(1.4, Math.max(0.55, p.nose.width / 0.065)) * long;
|
|
1529
|
+
const rootR = Math.max(0.02 + p.nose.width * 0.6, cell * 0.65);
|
|
1530
|
+
const wingX = Math.min(tipX - p.nose.tip * 1.2, l.faceX + 0.1 + p.jaw.muzzle * 0.5);
|
|
1097
1531
|
const noseRoot = [ex + r * 0.4, 0, ez - r * 0.4];
|
|
1098
1532
|
const noseDir = [tipX - noseRoot[0], 0, tipZ + 0.01 - noseRoot[2]];
|
|
1099
1533
|
const midNose = [
|
|
1100
1534
|
(ex + r * 0.6 + tipX) / 2,
|
|
1101
1535
|
0,
|
|
1102
|
-
(ez - 0.02 + tipZ) / 2 + p.nose.hook * 0.
|
|
1536
|
+
(ez - 0.02 + tipZ) / 2 + p.nose.hook * 0.3 + 0.01
|
|
1103
1537
|
];
|
|
1104
1538
|
e.push({
|
|
1105
1539
|
shape: "cone",
|
|
1106
1540
|
at: noseRoot,
|
|
1107
|
-
size: [
|
|
1541
|
+
size: [rootR, tipR * 0.85, Math.hypot(...noseDir)],
|
|
1108
1542
|
rotate: alongZ(noseDir),
|
|
1109
|
-
blend: 0.
|
|
1110
|
-
}, {
|
|
1543
|
+
blend: 0.045
|
|
1544
|
+
}, {
|
|
1545
|
+
shape: "sphere",
|
|
1546
|
+
at: midNose,
|
|
1547
|
+
size: (rootR + tipR) / 2 * 0.85 + Math.max(0, p.nose.hook) * 0.12,
|
|
1548
|
+
blend: 0.05
|
|
1549
|
+
}, { shape: "sphere", at: [tipX, 0, tipZ], size: tipR, blend: 0.035 }, ...p.nose.hook > 0.04 ? [
|
|
1550
|
+
{
|
|
1551
|
+
shape: "cone",
|
|
1552
|
+
at: [tipX, 0, tipZ],
|
|
1553
|
+
size: [tipR * 0.9, 0.01, p.nose.tip + p.nose.hook * 1.2],
|
|
1554
|
+
rotate: alongZ([0.6, 0, -1]),
|
|
1555
|
+
blend: 0.03
|
|
1556
|
+
}
|
|
1557
|
+
] : [], {
|
|
1111
1558
|
shape: "ellipsoid",
|
|
1112
|
-
at: [
|
|
1113
|
-
size: [0.045, 0.035, 0.032],
|
|
1559
|
+
at: [wingX, p.nose.width, l.noseZ + 0.02],
|
|
1560
|
+
size: [0.045 * wing, 0.035 * wing, 0.032 * wing],
|
|
1114
1561
|
blend: 0.025
|
|
1115
1562
|
}, {
|
|
1116
1563
|
shape: "ellipsoid",
|
|
1117
|
-
at: [tipX - p.nose.tip * 0.6, p.nose.width * 0.55, l.noseZ + 0.005],
|
|
1118
|
-
size: [0.022, 0.014, 0.012],
|
|
1564
|
+
at: [Math.min(tipX - p.nose.tip * 0.6, wingX + 0.035), p.nose.width * 0.55, l.noseZ + 0.005],
|
|
1565
|
+
size: [0.022 * wing, 0.014 * wing, 0.012 * wing],
|
|
1119
1566
|
op: "subtract",
|
|
1120
1567
|
blend: 0.008,
|
|
1121
1568
|
color: c.mouth
|
|
1122
1569
|
});
|
|
1123
|
-
|
|
1124
|
-
e.push({
|
|
1125
|
-
shape: "ellipsoid",
|
|
1126
|
-
at: [l.mouthX - 0.01, 0, l.mouthZ + lipT * 0.7],
|
|
1127
|
-
size: [0.032, mw, lipT],
|
|
1128
|
-
color: c.lips,
|
|
1129
|
-
blend: 0.03
|
|
1130
|
-
}, {
|
|
1131
|
-
shape: "ellipsoid",
|
|
1132
|
-
at: [l.mouthX - 0.015 + p.jaw.underbite * 0.7, 0, l.mouthZ - lipT * 0.8],
|
|
1133
|
-
size: [0.034, mw * 0.85, lipT * 1.1],
|
|
1134
|
-
color: c.lips,
|
|
1135
|
-
blend: 0.03
|
|
1136
|
-
}, {
|
|
1137
|
-
shape: "capsule",
|
|
1138
|
-
at: [l.mouthX + 0.05, 0, l.mouthZ],
|
|
1139
|
-
to: [l.mouthX - 0.03 - 0.02 * g, mw * 0.98, l.mouthZ + 0.012 + g * 0.05],
|
|
1140
|
-
size: 0.006 + g * 0.022,
|
|
1141
|
-
op: "subtract",
|
|
1142
|
-
blend: 0.012,
|
|
1143
|
-
color: c.mouth
|
|
1144
|
-
});
|
|
1145
|
-
if (g > 0.15)
|
|
1146
|
-
e.push(...teethRows(p, l));
|
|
1570
|
+
e.push(...mouthEdits(p, l, fine));
|
|
1147
1571
|
const fold = unit([-0.02, mw - p.nose.width, l.mouthZ - l.noseZ]);
|
|
1148
1572
|
e.push({
|
|
1149
1573
|
shape: "ellipsoid",
|
|
@@ -1154,31 +1578,22 @@ function skullEdits(p, l) {
|
|
|
1154
1578
|
blend: 0.03,
|
|
1155
1579
|
color: c.shade
|
|
1156
1580
|
});
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
out.push({
|
|
1172
|
-
shape: "roundBox",
|
|
1173
|
-
at: [x, y, z + dz * (1 + p.mouth.grin)],
|
|
1174
|
-
size: [0.02, 0.028, h * (1 + p.mouth.grin * 0.6)],
|
|
1175
|
-
round: 0.006,
|
|
1176
|
-
rotate: [0, 0, a * 180 / Math.PI],
|
|
1177
|
-
color: p.colors.teeth,
|
|
1178
|
-
blend: 0.003
|
|
1179
|
-
});
|
|
1581
|
+
const [, , cz] = l.cranium.at;
|
|
1582
|
+
const [crx, , crz] = l.cranium.r;
|
|
1583
|
+
for (let i = 0;i < (p.wrinkles ?? 0); i++) {
|
|
1584
|
+
const z = l.browZ + 0.07 + i * 0.05;
|
|
1585
|
+
const x = cx + crx * Math.sqrt(Math.max(0, 1 - ((z - cz) / crz) ** 2)) + 0.005;
|
|
1586
|
+
e.push({
|
|
1587
|
+
shape: "ellipsoid",
|
|
1588
|
+
at: [x, 0.06, z - 0.008],
|
|
1589
|
+
size: [0.05, 0.08 - i * 0.012, 0.005],
|
|
1590
|
+
rotate: [-14, -12, 0],
|
|
1591
|
+
op: "paint",
|
|
1592
|
+
blend: 0.01,
|
|
1593
|
+
color: c.shade
|
|
1594
|
+
});
|
|
1180
1595
|
}
|
|
1181
|
-
return
|
|
1596
|
+
return e;
|
|
1182
1597
|
}
|
|
1183
1598
|
|
|
1184
1599
|
// src/kinds/head-hair.ts
|
|
@@ -1189,31 +1604,40 @@ function hairEdits(p, l) {
|
|
|
1189
1604
|
const [rx, ry, rz] = l.cranium.r;
|
|
1190
1605
|
const top = l.crown;
|
|
1191
1606
|
switch (p.hair) {
|
|
1192
|
-
case "topknot":
|
|
1607
|
+
case "topknot": {
|
|
1608
|
+
const root = [cx - 0.14, 0, top - 0.03];
|
|
1609
|
+
const rise = [cx - 0.2, 0, top + 0.13];
|
|
1610
|
+
const fall = [cx - 0.38, 0, top + 0.02];
|
|
1611
|
+
const tip = [cx - rx - 0.08, 0, cz - 0.12];
|
|
1612
|
+
const seg = (a, b, r0, r1) => ({
|
|
1613
|
+
shape: "cone",
|
|
1614
|
+
at: a,
|
|
1615
|
+
size: [r0, r1, Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2])],
|
|
1616
|
+
rotate: alongZ([b[0] - a[0], b[1] - a[1], b[2] - a[2]]),
|
|
1617
|
+
blend: 0.03
|
|
1618
|
+
});
|
|
1619
|
+
const ring = (at, deg) => ({
|
|
1620
|
+
shape: "torus",
|
|
1621
|
+
at,
|
|
1622
|
+
size: [0.07, 0.018],
|
|
1623
|
+
rotate: [0, deg, 0],
|
|
1624
|
+
color: p.colors.metal,
|
|
1625
|
+
blend: 0.004
|
|
1626
|
+
});
|
|
1193
1627
|
return [
|
|
1194
|
-
{ shape: "ellipsoid", at: [cx - 0.12, 0, top - 0.02], size: [0.11, 0.08, 0.07], color: h },
|
|
1195
1628
|
{
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
},
|
|
1202
|
-
{
|
|
1203
|
-
shape: "capsule",
|
|
1204
|
-
at: [cx - 0.2, 0, top + 0.08],
|
|
1205
|
-
to: [cx - 0.42, 0, top - 0.25],
|
|
1206
|
-
size: 0.04,
|
|
1629
|
+
group: [
|
|
1630
|
+
seg(root, rise, 0.085, 0.075),
|
|
1631
|
+
seg(rise, fall, 0.08, 0.07),
|
|
1632
|
+
seg(fall, tip, 0.07, 0.015)
|
|
1633
|
+
],
|
|
1207
1634
|
color: h,
|
|
1208
|
-
blend: 0.
|
|
1635
|
+
blend: 0.02
|
|
1209
1636
|
},
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
at: [cx - 0.17, 0, top + 0.02],
|
|
1213
|
-
size: [0.06, 0.018],
|
|
1214
|
-
color: p.colors.metal
|
|
1215
|
-
}
|
|
1637
|
+
ring([root[0] - 0.02, 0, root[2] + 0.06], -15),
|
|
1638
|
+
ring([root[0] - 0.04, 0, root[2] + 0.11], -25)
|
|
1216
1639
|
];
|
|
1640
|
+
}
|
|
1217
1641
|
case "mohawk":
|
|
1218
1642
|
return Array.from({ length: 6 }, (_, i) => {
|
|
1219
1643
|
const a = (-20 + i * 26) * RAD4;
|
|
@@ -1282,20 +1706,48 @@ function hairEdits(p, l) {
|
|
|
1282
1706
|
lock(120, 30, 30, 0.05, 0)
|
|
1283
1707
|
];
|
|
1284
1708
|
}
|
|
1285
|
-
case "tufts":
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1709
|
+
case "tufts": {
|
|
1710
|
+
const out = [];
|
|
1711
|
+
const spots = [
|
|
1712
|
+
[10, 78, 0.26],
|
|
1713
|
+
[-25, 70, 0.22],
|
|
1714
|
+
[40, 62, 0.22],
|
|
1715
|
+
[150, 55, 0.2],
|
|
1716
|
+
[115, 30, 0.2],
|
|
1717
|
+
[100, 16, 0.18],
|
|
1718
|
+
[-120, 40, 0.18]
|
|
1719
|
+
];
|
|
1720
|
+
for (const [az, el, len] of spots) {
|
|
1721
|
+
const a = az * RAD4;
|
|
1722
|
+
const e = el * RAD4;
|
|
1723
|
+
const n = [Math.cos(e) * Math.cos(a), Math.cos(e) * Math.sin(a), Math.sin(e)];
|
|
1724
|
+
const root = [cx - 0.04 + rx * 0.97 * n[0], ry * 0.97 * n[1], cz + rz * 0.97 * n[2]];
|
|
1725
|
+
const d1 = [n[0] - 0.6, n[1] * 1.3, n[2] * 0.6 + 0.25];
|
|
1726
|
+
const l1 = Math.hypot(...d1);
|
|
1727
|
+
const mid = [
|
|
1728
|
+
root[0] + d1[0] / l1 * len * 0.55,
|
|
1729
|
+
root[1] + d1[1] / l1 * len * 0.55,
|
|
1730
|
+
root[2] + d1[2] / l1 * len * 0.55
|
|
1731
|
+
];
|
|
1732
|
+
const d2 = [d1[0] - 0.5, d1[1] * 1.6, -0.9];
|
|
1733
|
+
out.push({
|
|
1734
|
+
group: [
|
|
1735
|
+
{ shape: "cone", at: root, size: [0.026, 0.014, len * 0.58], rotate: alongZ(d1) },
|
|
1736
|
+
{
|
|
1737
|
+
shape: "cone",
|
|
1738
|
+
at: mid,
|
|
1739
|
+
size: [0.015, 0.004, len * 0.6],
|
|
1740
|
+
rotate: alongZ(d2),
|
|
1741
|
+
blend: 0.008
|
|
1742
|
+
}
|
|
1743
|
+
],
|
|
1294
1744
|
color: h,
|
|
1295
|
-
blend: 0.
|
|
1296
|
-
mirror:
|
|
1297
|
-
};
|
|
1298
|
-
}
|
|
1745
|
+
blend: 0.012,
|
|
1746
|
+
mirror: az !== 10 && az !== -25 && az !== -120
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
return out;
|
|
1750
|
+
}
|
|
1299
1751
|
case "braids":
|
|
1300
1752
|
return [
|
|
1301
1753
|
{ ...capOf(l, h) },
|
|
@@ -1461,10 +1913,46 @@ function creaseNormals(m, minDot = 0.2) {
|
|
|
1461
1913
|
return { ...m, normals };
|
|
1462
1914
|
}
|
|
1463
1915
|
|
|
1916
|
+
// src/kinds/head-tone.ts
|
|
1917
|
+
function toned(field, colorAt, o) {
|
|
1918
|
+
const k = o.strength ?? 1;
|
|
1919
|
+
const d = o.reach;
|
|
1920
|
+
const e = d * 0.25;
|
|
1921
|
+
return (q) => {
|
|
1922
|
+
const c = colorAt(q);
|
|
1923
|
+
const [x, y, z] = q;
|
|
1924
|
+
const gx = field([x + e, y, z]) - field([x - e, y, z]);
|
|
1925
|
+
const gy = field([x, y + e, z]) - field([x, y - e, z]);
|
|
1926
|
+
const gz = field([x, y, z + e]) - field([x, y, z - e]);
|
|
1927
|
+
const gl = Math.hypot(gx, gy, gz) || 1;
|
|
1928
|
+
const n = [gx / gl, gy / gl, gz / gl];
|
|
1929
|
+
let occ = 0;
|
|
1930
|
+
for (let i = 1;i <= 3; i++) {
|
|
1931
|
+
const t = d * i / 3;
|
|
1932
|
+
occ += Math.max(0, t - field([x + n[0] * t, y + n[1] * t, z + n[2] * t])) / t / i;
|
|
1933
|
+
}
|
|
1934
|
+
const cav = Math.min(1, occ * 2.5) * k;
|
|
1935
|
+
const up = n[2] * k;
|
|
1936
|
+
const lift = up > 0 ? 1 + up * 0.22 : 1 + up * 0.3;
|
|
1937
|
+
const warm = up > 0 ? [1 + up * 0.12, 1 + up * 0.05, 1 - up * 0.15] : [1 + up * 0.1, 1, 1 - up * 0.12];
|
|
1938
|
+
const dark = 1 - cav * 0.55;
|
|
1939
|
+
const lum = (c[0] + c[1] + c[2]) / 3;
|
|
1940
|
+
const sat = 1 + cav * 0.35;
|
|
1941
|
+
return [
|
|
1942
|
+
clamp((lum + (c[0] - lum) * sat) * dark * lift * warm[0]),
|
|
1943
|
+
clamp((lum + (c[1] - lum) * sat) * dark * lift * warm[1]),
|
|
1944
|
+
clamp((lum + (c[2] - lum) * sat) * dark * lift * warm[2])
|
|
1945
|
+
];
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
var clamp = (v) => Math.min(Math.max(v, 0), 1);
|
|
1949
|
+
|
|
1464
1950
|
// src/kinds/head-mesh.ts
|
|
1951
|
+
var REACH = 0.05;
|
|
1952
|
+
var PLINTH2 = [0.16, 0.15, 0.15];
|
|
1465
1953
|
function jawRegion(p, l) {
|
|
1466
1954
|
const chin = l.chin;
|
|
1467
|
-
const reach = Math.max(p.mouth.width * 1.
|
|
1955
|
+
const reach = Math.max(p.mouth.width * 1.08, (p.tusks?.spread ?? 0) + p.mouth.width * 0.5);
|
|
1468
1956
|
const centre = [l.mouthX - 0.15, 0, l.mouthZ];
|
|
1469
1957
|
const radii = [Math.max(0.27, l.mouthX - chin[0] + 0.2), reach, l.mouthZ - chin[2] + 0.1];
|
|
1470
1958
|
const e = sd2.ellipsoid(centre, radii);
|
|
@@ -1496,7 +1984,7 @@ function headAndJaw(p, l, set, res) {
|
|
|
1496
1984
|
const region = jawRegion(p, l);
|
|
1497
1985
|
const cut = region.field;
|
|
1498
1986
|
const lap = res * 0.75;
|
|
1499
|
-
const proud = res * 0.
|
|
1987
|
+
const proud = res * 0.03;
|
|
1500
1988
|
const ears = set.ears.length > 0 ? [{ group: set.ears, blend: 0.02 }] : [];
|
|
1501
1989
|
const tusks = set.tusks.length > 0 ? [{ group: set.tusks, blend: 0.01 }] : [];
|
|
1502
1990
|
const h = sculptField2([...set.skull, ...ears, { ...regionGroup(l, region, 0), op: "subtract" }], opts);
|
|
@@ -1504,6 +1992,9 @@ function headAndJaw(p, l, set, res) {
|
|
|
1504
1992
|
const jField = (q) => jRaw.field(q) - proud;
|
|
1505
1993
|
const mouth = p.colors.mouth;
|
|
1506
1994
|
const skull = sculptField2(set.skull, opts).field;
|
|
1995
|
+
const extra = (e) => e.length > 0 ? ((f) => (q) => Math.min(skull(q), f(q)))(sculptField2(e, opts).field) : skull;
|
|
1996
|
+
const headTone = extra(set.ears);
|
|
1997
|
+
const jawTone = extra(set.tusks);
|
|
1507
1998
|
const deep = -Math.max(res * 4, 0.03);
|
|
1508
1999
|
const paint = (colorAt) => (q) => Math.abs(cut(q)) < res * 1.5 && skull(q) < deep ? mouth : colorAt(q);
|
|
1509
2000
|
const [ec, er] = [region.centre, region.radii];
|
|
@@ -1516,14 +2007,14 @@ function headAndJaw(p, l, set, res) {
|
|
|
1516
2007
|
field: h.field,
|
|
1517
2008
|
bounds: h.bounds,
|
|
1518
2009
|
resolution: res,
|
|
1519
|
-
color: paint(h.colorAt),
|
|
2010
|
+
color: toned(headTone, paint(h.colorAt), { reach: REACH }),
|
|
1520
2011
|
symmetry: "y"
|
|
1521
2012
|
});
|
|
1522
2013
|
const jaw = sdf2({
|
|
1523
2014
|
field: jField,
|
|
1524
2015
|
bounds: unionBounds(jb, tb),
|
|
1525
2016
|
resolution: res,
|
|
1526
|
-
color: paint(jRaw.colorAt),
|
|
2017
|
+
color: toned(jawTone, paint(jRaw.colorAt), { reach: REACH }),
|
|
1527
2018
|
symmetry: "y"
|
|
1528
2019
|
});
|
|
1529
2020
|
if (res > 0.03)
|
|
@@ -1534,13 +2025,29 @@ function headAndJaw(p, l, set, res) {
|
|
|
1534
2025
|
jaw: creaseNormals(sharpenRim(jaw, jawSkull, (q) => cut(q) - lap, jField, res))
|
|
1535
2026
|
};
|
|
1536
2027
|
}
|
|
2028
|
+
function onCut(cut, q, n, res) {
|
|
2029
|
+
if (Math.abs(cut(q)) > res * 0.8)
|
|
2030
|
+
return false;
|
|
2031
|
+
const e = res * 0.5;
|
|
2032
|
+
const g = [
|
|
2033
|
+
cut([q[0] + e, q[1], q[2]]) - cut([q[0] - e, q[1], q[2]]),
|
|
2034
|
+
cut([q[0], q[1] + e, q[2]]) - cut([q[0], q[1] - e, q[2]]),
|
|
2035
|
+
cut([q[0], q[1], q[2] + e]) - cut([q[0], q[1], q[2] - e])
|
|
2036
|
+
];
|
|
2037
|
+
const l = Math.hypot(g[0], g[1], g[2]) || 1;
|
|
2038
|
+
return (g[0] * n[0] + g[1] * n[1] + g[2] * n[2]) / l > 0.85;
|
|
2039
|
+
}
|
|
1537
2040
|
function bustMesh(p, set, res) {
|
|
1538
2041
|
const s = sculptField2(set.bust, { color: p.colors.skin, mirror: "y" });
|
|
2042
|
+
const tone = toned(s.field, s.colorAt, { reach: REACH * 1.4 });
|
|
2043
|
+
const cut = set.bustCut;
|
|
2044
|
+
const base = p.colors.plinth ?? PLINTH2;
|
|
2045
|
+
const face = [base[0] * 1.3, base[1] * 1.3, base[2] * 1.3];
|
|
1539
2046
|
return sdf2({
|
|
1540
2047
|
field: s.field,
|
|
1541
2048
|
bounds: s.bounds,
|
|
1542
2049
|
resolution: res,
|
|
1543
|
-
color: (q) =>
|
|
2050
|
+
color: cut ? (q, n) => onCut(cut, q, n, res) ? face : tone(q) : tone,
|
|
1544
2051
|
symmetry: "y"
|
|
1545
2052
|
});
|
|
1546
2053
|
}
|
|
@@ -1594,7 +2101,9 @@ var ZERO_OK = new Set([
|
|
|
1594
2101
|
"jaw.drop",
|
|
1595
2102
|
"jaw.muzzle",
|
|
1596
2103
|
"brow.overhang",
|
|
1597
|
-
"brow.hair"
|
|
2104
|
+
"brow.hair",
|
|
2105
|
+
"bust.mass",
|
|
2106
|
+
"wrinkles"
|
|
1598
2107
|
]);
|
|
1599
2108
|
function checkHead2(p) {
|
|
1600
2109
|
if (!(p.height >= 0.05 && p.height <= 3))
|
|
@@ -1658,33 +2167,33 @@ var human = {
|
|
|
1658
2167
|
};
|
|
1659
2168
|
var orc = {
|
|
1660
2169
|
height: 0.3,
|
|
1661
|
-
cranium: { width: 0.7, depth: 0.
|
|
1662
|
-
brow: { ridge: 0.
|
|
1663
|
-
cheeks: { size: 1.
|
|
1664
|
-
jaw: { muzzle: 0.1, width: 0.
|
|
1665
|
-
nose: { length: 0.15, width: 0.
|
|
1666
|
-
ears: { shape: "pointed", length: 0.
|
|
1667
|
-
eyes: { radius: 0.
|
|
1668
|
-
mouth: { width: 0.17, lips: 0.
|
|
1669
|
-
tusks: { length: 0.
|
|
1670
|
-
neck: { radius: 0.
|
|
1671
|
-
bust: { shoulders: 1
|
|
2170
|
+
cranium: { width: 0.7, depth: 0.74, height: 0.31 },
|
|
2171
|
+
brow: { ridge: 0.075, overhang: 0.06, scowl: 0.04 },
|
|
2172
|
+
cheeks: { size: 1.3, width: 1.15 },
|
|
2173
|
+
jaw: { muzzle: 0.1, width: 0.4, chin: 1.3, underbite: 0.1, drop: 0.1 },
|
|
2174
|
+
nose: { length: 0.15, width: 0.1, tip: 0.042, hook: -0.01, bridge: -0.05 },
|
|
2175
|
+
ears: { shape: "pointed", length: 0.38, width: 0.19, sweep: 30, lift: 10 },
|
|
2176
|
+
eyes: { radius: 0.054, spacing: 0.155, line: 0.56, lid: 10, lowerLid: 22 },
|
|
2177
|
+
mouth: { width: 0.17, lips: 0.034, grin: 0 },
|
|
2178
|
+
tusks: { length: 0.22, radius: 0.055, spread: 0.15, flare: 0.35 },
|
|
2179
|
+
neck: { radius: 0.38 },
|
|
2180
|
+
bust: { shoulders: 1, style: "pauldrons", mass: 1 },
|
|
1672
2181
|
hair: "topknot",
|
|
1673
2182
|
beard: "none",
|
|
1674
2183
|
warts: 6,
|
|
1675
2184
|
colors: {
|
|
1676
|
-
skin: hex2("#
|
|
1677
|
-
shade: hex2("#
|
|
2185
|
+
skin: hex2("#5c8034"),
|
|
2186
|
+
shade: hex2("#33501e"),
|
|
1678
2187
|
lips: hex2("#4f6f30"),
|
|
1679
2188
|
sclera: hex2("#8a5a1a"),
|
|
1680
2189
|
iris: hex2("#ffb030"),
|
|
1681
2190
|
pupil: hex2("#140a06"),
|
|
1682
2191
|
teeth: hex2("#e2d6b0"),
|
|
1683
2192
|
mouth: hex2("#2a0e0c"),
|
|
1684
|
-
hair: hex2("#
|
|
2193
|
+
hair: hex2("#231a14"),
|
|
1685
2194
|
cloth: hex2("#6b2a20"),
|
|
1686
2195
|
leather: hex2("#5a3a22"),
|
|
1687
|
-
metal: hex2("#
|
|
2196
|
+
metal: hex2("#55524d"),
|
|
1688
2197
|
fur: hex2("#5e4a34"),
|
|
1689
2198
|
paint: hex2("#8a1c12")
|
|
1690
2199
|
}
|
|
@@ -1692,19 +2201,20 @@ var orc = {
|
|
|
1692
2201
|
var goblin = {
|
|
1693
2202
|
height: 0.19,
|
|
1694
2203
|
cranium: { width: 0.66, depth: 0.84, height: 0.5 },
|
|
1695
|
-
brow: { ridge: 0.
|
|
1696
|
-
cheeks: { size: 1.
|
|
1697
|
-
jaw: { muzzle: 0.
|
|
1698
|
-
nose: { length: 0.2, width: 0.
|
|
1699
|
-
ears: { shape: "pointed", length: 0.
|
|
1700
|
-
eyes: { radius: 0.
|
|
1701
|
-
mouth: { width: 0.
|
|
2204
|
+
brow: { ridge: 0.032, overhang: 0.02, scowl: 0.03 },
|
|
2205
|
+
cheeks: { size: 1.05, width: 1.05 },
|
|
2206
|
+
jaw: { muzzle: 0.05, width: 0.19, chin: 0.72, underbite: 0, drop: 0 },
|
|
2207
|
+
nose: { length: 0.2, width: 0.06, tip: 0.046, hook: 0.065, bridge: 0.13 },
|
|
2208
|
+
ears: { shape: "pointed", length: 0.66, width: 0.3, sweep: 24, lift: 6 },
|
|
2209
|
+
eyes: { radius: 0.08, spacing: 0.155, line: 0.5, lid: 30, lowerLid: 20 },
|
|
2210
|
+
mouth: { width: 0.21, lips: 0.014, grin: 0.8 },
|
|
1702
2211
|
tusks: null,
|
|
1703
|
-
neck: { radius: 0.
|
|
1704
|
-
bust: { shoulders: 0.
|
|
2212
|
+
neck: { radius: 0.14 },
|
|
2213
|
+
bust: { shoulders: 0.52, style: "vest", mass: 0 },
|
|
1705
2214
|
hair: "tufts",
|
|
1706
2215
|
beard: "none",
|
|
1707
2216
|
warts: 4,
|
|
2217
|
+
wrinkles: 3,
|
|
1708
2218
|
colors: {
|
|
1709
2219
|
skin: hex2("#9cb84a"),
|
|
1710
2220
|
shade: hex2("#6a8a2c"),
|
|
@@ -1714,10 +2224,12 @@ var goblin = {
|
|
|
1714
2224
|
pupil: hex2("#120c04"),
|
|
1715
2225
|
teeth: hex2("#e8dcae"),
|
|
1716
2226
|
mouth: hex2("#3a1010"),
|
|
1717
|
-
hair: hex2("#
|
|
1718
|
-
cloth: hex2("#
|
|
1719
|
-
|
|
1720
|
-
|
|
2227
|
+
hair: hex2("#c8c0b0"),
|
|
2228
|
+
cloth: hex2("#b8a47c"),
|
|
2229
|
+
cape: hex2("#4e5e3a"),
|
|
2230
|
+
leather: hex2("#6b4428"),
|
|
2231
|
+
metal: hex2("#a88a4a"),
|
|
2232
|
+
scarf: hex2("#9a3a24")
|
|
1721
2233
|
}
|
|
1722
2234
|
};
|
|
1723
2235
|
var dwarf = {
|
|
@@ -1783,6 +2295,7 @@ function seatEyes(p, l) {
|
|
|
1783
2295
|
const r = l.eyeR;
|
|
1784
2296
|
return { ...l, eye: [x - r * 0.7 - p.brow.overhang * 0.3, ey, ez] };
|
|
1785
2297
|
}
|
|
2298
|
+
var BUST_CELL = 1.6;
|
|
1786
2299
|
var HEAD_RES2 = [0.02, 0.045, 0.14];
|
|
1787
2300
|
function headEdits2(p, rng, lod = 0) {
|
|
1788
2301
|
const l = seatEyes(p, headLayout(p));
|
|
@@ -1792,7 +2305,7 @@ function headEdits2(p, rng, lod = 0) {
|
|
|
1792
2305
|
return {
|
|
1793
2306
|
layout: l,
|
|
1794
2307
|
skull: [
|
|
1795
|
-
...skullEdits(p, l),
|
|
2308
|
+
...skullEdits(p, l, res),
|
|
1796
2309
|
...hair,
|
|
1797
2310
|
...browEdits(p, l),
|
|
1798
2311
|
...beardEdits(p, l),
|
|
@@ -1801,7 +2314,8 @@ function headEdits2(p, rng, lod = 0) {
|
|
|
1801
2314
|
],
|
|
1802
2315
|
ears: earEdits(p, l, res * 0.7),
|
|
1803
2316
|
tusks: tuskEdits(p, l, res * 0.45),
|
|
1804
|
-
bust: bustEdits(p, l)
|
|
2317
|
+
bust: bustEdits(p, l, res * BUST_CELL),
|
|
2318
|
+
bustCut: cutField(frameOf(p, l))
|
|
1805
2319
|
};
|
|
1806
2320
|
}
|
|
1807
2321
|
function head2(ctx, o = {}) {
|
|
@@ -1811,7 +2325,7 @@ function head2(ctx, o = {}) {
|
|
|
1811
2325
|
const H = p.height;
|
|
1812
2326
|
const res = HEAD_RES2[ctx.lod];
|
|
1813
2327
|
const { head: hm, jaw: jm } = headAndJaw(p, l, set, res);
|
|
1814
|
-
const bm = bustMesh(p, set, res *
|
|
2328
|
+
const bm = bustMesh(p, set, res * BUST_CELL);
|
|
1815
2329
|
const eye = eyeMesh(p, l.eyeR, l.eyeR / ctx.pick([7, 3.5, 2.2]));
|
|
1816
2330
|
const [ox, oy, oz] = o.at ?? [0, 0, 0];
|
|
1817
2331
|
const toWorld = (m, at = [0, 0, 0]) => place2(m, { scale: H, at: [ox + at[0] * H, oy + at[1] * H, oz + (at[2] - l.base) * H] });
|
|
@@ -3567,5 +4081,5 @@ function propeller2(ctx, o) {
|
|
|
3567
4081
|
}
|
|
3568
4082
|
export { mass2, opening2, facade2, setbacks2, checkHead2, HEADS2, headParams2, HEAD_RES2, headEdits2, head2, hullLines2, hullMesh2, hull2, creature2, roofHeightAt2, ridgeHeight2, roofMesh2, roof2, roofInfo2, oak2, pine2, palm2, birch2, willow2, SPECIES2, treeParams2, tree2, treeReal2, trees2, axle2, whyteAxles2, trackRun2, propeller2 };
|
|
3569
4083
|
|
|
3570
|
-
//# debugId=
|
|
3571
|
-
//# sourceMappingURL=chunk-
|
|
4084
|
+
//# debugId=AF041752F55E532164756E2164756E21
|
|
4085
|
+
//# sourceMappingURL=chunk-8j4c28jt.js.map
|