@bitefoundry/retrieviewer 0.0.2 → 0.0.4
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/ASSET-PROVENANCE.md +6 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +65 -0
- package/DESKTOP-PLATFORMS.md +75 -0
- package/INSTALLING.md +8 -5
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +110 -0
- package/README.md +119 -58
- package/RELEASING.md +27 -14
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/desktop/platform.mjs +27 -0
- package/integrations/linux-overlay/README.md +83 -0
- package/integrations/linux-overlay/overlay.py +1094 -0
- package/integrations/macos-overlay/README.md +83 -0
- package/integrations/macos-overlay/overlay.jxa +639 -0
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +4 -4
- package/integrations/windows-overlay/desktop.mjs +40 -8
- package/integrations/windows-overlay/protocol.mjs +11 -7
- package/integrations/windows-overlay/worker.mjs +13 -7
- package/package.json +41 -14
- package/puppy-comfort-sprites.mjs +25 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +77 -0
- package/puppy-companion-life.mjs +49 -16
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +65 -14
- package/retrieviewer-cli.mjs +10 -3
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +10 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- package/vendor/procedural-animals/src/worker.js +0 -29
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
// Pig ear leaves: the geometry shared by the rig (the ear bone runs from the root to the leaf's tip), the
|
|
2
|
-
// sculpt (tiles), the meshing plan (the region box) and the coat (the hollow side, how far out along the ear).
|
|
3
|
-
//
|
|
4
|
-
// A leaf is one smooth curved sheet with a mid-surface P(s, a) (s 0 root .. 1 tip, a -1 .. 1 across):
|
|
5
|
-
// - the spine leaves the head along the root direction `root` (WORLD, standing pig, left ear), runs straight
|
|
6
|
-
// for the first s0 of its length and then bends toward the hollow side by `bend` degrees in all (bendPow
|
|
7
|
-
// > 1: the bend comes late, toward the tip);
|
|
8
|
-
// - its cross-section is a circular arc that rolls both edges toward the hollow by `cup` (rad, root -> tip:
|
|
9
|
-
// the root rolled into the funnel of the ear canal, flatter toward the tip), half width W earW(s);
|
|
10
|
-
// - it is thick at the root and thins toward the rim (`thick`: [root, rim] full thickness, m): cartilage and
|
|
11
|
-
// skin ~1.2-1.5 cm where the pinna leaves the head, 3-4 mm at its free edge, with a round rim.
|
|
12
|
-
// The sheet is tiled with small exact slabs (m.fin with a thickness gradient, core sdf.js), each its quad
|
|
13
|
-
// projected on its own plane and run one rim radius past every edge it shares with a neighbour, so the
|
|
14
|
-
// rounded ends of neighbours make one cylinder there and the sheet runs on smoothly.
|
|
15
|
-
//
|
|
16
|
-
// Forms (from photos):
|
|
17
|
-
// - erect (Large White, Hampshire, Berkshire; face1, face2, front1): a broad leaf up and forward, the hollow
|
|
18
|
-
// facing forward and out, a rounded tip curling a little forward;
|
|
19
|
-
// - semi (Duroc; face3): up and out from the top corners of the poll with the hollow facing forward, curving
|
|
20
|
-
// out and down as it goes (sweep) and the outer part folding forward and down (bend), a thick, soft leaf
|
|
21
|
-
// hanging beside the eyes;
|
|
22
|
-
// - lop (Landrace, Gloucester Old Spot): the leaf leaves the poll corner forward along the head and a little out
|
|
23
|
-
// and up, then droops forward and down over the eye toward the snout, a soft visor with air under it (its
|
|
24
|
-
// convex back out and up, the hollow facing the face below it), the forehead showing between the two.
|
|
25
|
-
const PI = Math.PI;
|
|
26
|
-
const add = (a, b) => [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
27
|
-
const sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
28
|
-
const mul = (a, k) => [a[0] * k, a[1] * k, a[2] * k];
|
|
29
|
-
const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
30
|
-
const cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
31
|
-
const norm = (a) => { const l = Math.hypot(a[0], a[1], a[2]) || 1; return [a[0] / l, a[1] / l, a[2] / l]; };
|
|
32
|
-
const clamp01 = (x) => (x < 0 ? 0 : x > 1 ? 1 : x);
|
|
33
|
-
const sstep = (a, b, x) => { const t = clamp01((x - a) / (b - a)); return t * t * (3 - 2 * t); };
|
|
34
|
-
|
|
35
|
-
// ear root on the head (head-local, rig.js hl()): the top corners of the broad poll (face2 / front1: the
|
|
36
|
-
// ear bases well out from the midline)
|
|
37
|
-
export const EAR_BASE = [0.07, 0.056, -0.074];
|
|
38
|
-
// the ears' meshing cell at the hero tier (regions.js: x the tier's res)
|
|
39
|
-
export const EAR_CELL = 0.003;
|
|
40
|
-
|
|
41
|
-
// leaf outlines: half width (x W) along the leaf
|
|
42
|
-
const OUTLINE = {
|
|
43
|
-
// (broad, the widest a third of the way up, a rounded tip: face2, front1)
|
|
44
|
-
// (a pointed tip, lw_show, head_hausschwein5, face2; the rounded tip read as a mouse's ear)
|
|
45
|
-
erect: [[0, 0.5], [0.08, 0.68], [0.22, 0.94], [0.4, 1.0], [0.6, 0.9], [0.78, 0.66], [0.9, 0.38], [1.0, 0.06]],
|
|
46
|
-
// (broad and blunt: face3)
|
|
47
|
-
semi: [[0, 0.5], [0.08, 0.7], [0.24, 0.95], [0.45, 1.0], [0.66, 0.9], [0.84, 0.64], [0.95, 0.36], [1.0, 0.12]],
|
|
48
|
-
// (long, widest past the middle, a rounded point toward the snout)
|
|
49
|
-
lop: [[0, 0.46], [0.08, 0.64], [0.24, 0.9], [0.46, 1.0], [0.66, 0.92], [0.84, 0.66], [0.95, 0.36], [1.0, 0.1]],
|
|
50
|
-
};
|
|
51
|
-
// root / facing: WORLD directions of the standing pig (left ear); rootH / facingH: the same in head-local
|
|
52
|
-
// coordinates (x out, y dorsal, z along the head toward the disc; the head is carried HEAD_PITCH nose-down)
|
|
53
|
-
export const EAR_FORM = {
|
|
54
|
-
// (splayed out ~36 deg from upright and a broader leaf, as in lw_show, face2, head_hausschwein5: at 29 deg
|
|
55
|
-
// and 0.38 wide they stood up like a rabbit's)
|
|
56
|
-
erect: { root: [0.58, 0.8, 0.2], len: 0.2, facing: [0.45, -0.4, 0.9], bend: 12, s0: 0.1, bendPow: 2, cup: [0.95, 0.28], width: 0.41, thick: [0.012, 0.0055], wave: 0, ns: 12, na: 10 },
|
|
57
|
-
// (up and out from the poll corner with the hollow forward, the outer part folding forward and down to hang
|
|
58
|
-
// beside the eye, the tips about level with the eyes: face3, Duroc photos; held out flat as brims)
|
|
59
|
-
semi: { root: [0.9, 0.0, 0.45], len: 0.235, facing: [0.1, -0.45, 1], bend: 45, s0: 0.4, bendPow: 1.2, sweep: 75, sweepS0: 0.2, sweepPow: 1.3, cup: [0.7, 0.35], width: 0.29, thick: [0.014, 0.0055], wave: 0, ns: 22, na: 10 },
|
|
60
|
-
// (forward from the poll corners along the head and angled out, then drooping over the eyes like a soft visor
|
|
61
|
-
// with air under it, the forehead showing between the two: Landrace photos; 0.68 as wide as long and
|
|
62
|
-
// rolled round the head, the two leaves covered the whole upper face like a helmet)
|
|
63
|
-
// (the root rising ~8 deg above level before the leaf droops (it left the poll 12 deg nose-down
|
|
64
|
-
// and lay along the forehead like a decal from the front 3/4; lr_heads: forward and level from the
|
|
65
|
-
// poll, then down over the eye))
|
|
66
|
-
lop: { rootH: [0.3, 0.55, 0.78], len: 0.22, facingH: [-0.5, -0.85, 0.15], bend: 95, s0: 0.3, bendPow: 1.5, cup: [0.45, 0.2], width: 0.28, thick: [0.015, 0.0055], wave: 0.015, ns: 14, na: 10 },
|
|
67
|
-
};
|
|
68
|
-
// (rig.js HEAD_PITCH: kept here as a number, rig.js imports this module)
|
|
69
|
-
const HP = (35 * PI) / 180;
|
|
70
|
-
const fromHead = (v) => [v[0], v[1] * Math.cos(HP) - v[2] * Math.sin(HP), v[1] * Math.sin(HP) + v[2] * Math.cos(HP)];
|
|
71
|
-
const rootOf = (F) => (F.rootH ? fromHead(F.rootH) : F.root);
|
|
72
|
-
const facingOf = (F) => (F.facingH ? fromHead(F.facingH) : F.facing);
|
|
73
|
-
export const earType = (params) => (params.ear === 'lop' || params.ear === 'semi' ? params.ear : 'erect');
|
|
74
|
-
export const earW = (type, t) => {
|
|
75
|
-
const W = OUTLINE[type];
|
|
76
|
-
for (let i = 1; i < W.length; i++) if (t <= W[i][0]) { const [t0, w0] = W[i - 1], [t1, w1] = W[i]; return w0 + ((w1 - w0) * (t - t0)) / (t1 - t0); }
|
|
77
|
-
return W[W.length - 1][1];
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// the root direction of the left ear (world, standing) and the leaf length for this individual (the pinnae
|
|
81
|
-
// carried more forward / more out, params.earFwd / earOut; params.earSize)
|
|
82
|
-
// (params.earForm: overrides of the form's numbers, for tools)
|
|
83
|
-
const formOf = (params) => (params.earForm ? { ...EAR_FORM[earType(params)], ...params.earForm } : EAR_FORM[earType(params)]);
|
|
84
|
-
export function earRoot(params) {
|
|
85
|
-
const F = formOf(params);
|
|
86
|
-
const d = norm(rootOf(F));
|
|
87
|
-
return { dir: norm([d[0] + 0.25 * (params.earOut || 0), d[1], d[2] + 0.35 * (params.earFwd || 0)]), len: F.len * (params.earSize ?? 1) };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// the spine of one leaf: stations 0..steps from the root; per station the point and the leaf's frame: d along
|
|
91
|
-
// the spine, h the hollow side, l across the leaf (l = d x h). The frame folds toward the hollow (`bend`
|
|
92
|
-
// degrees in all from s0 on, bendPow > 1: late) and sweeps within the leaf's plane toward +l (`sweep`
|
|
93
|
-
// degrees from sweepS0 on, sweepPow): a leaf held out sideways with its hollow forward that curves down as
|
|
94
|
-
// it goes (face3) sweeps; one that tips over toward its hollow folds. (Left ear; mirrored for the right.)
|
|
95
|
-
export function earSpine(base, S, params, steps = 96) {
|
|
96
|
-
const s = S === 'L' || S === 1 ? 1 : -1;
|
|
97
|
-
const type = earType(params);
|
|
98
|
-
const F = formOf(params);
|
|
99
|
-
const { dir, len } = earRoot(params);
|
|
100
|
-
const d0 = [dir[0] * s, dir[1], dir[2]];
|
|
101
|
-
const fc = facingOf(F);
|
|
102
|
-
const fw = [fc[0] * s, fc[1], fc[2]];
|
|
103
|
-
const f0 = norm(sub(fw, mul(d0, dot(fw, d0))));
|
|
104
|
-
const lat = norm(cross(d0, f0));
|
|
105
|
-
const B = (F.bend * PI) / 180, Bs = ((F.sweep || 0) * PI) / 180 * s, Bt = ((F.twist || 0) * PI) / 180 * s;
|
|
106
|
-
const ramp = (u, u0, p) => Math.pow(clamp01((u - u0) / (1 - u0)), p);
|
|
107
|
-
const foldAt = (u) => B * ramp(u, F.s0, F.bendPow);
|
|
108
|
-
const sweepAt = (u) => Bs * ramp(u, F.sweepS0 ?? F.s0, F.sweepPow ?? 1);
|
|
109
|
-
const twistAt = (u) => Bt * ramp(u, F.twistS0 ?? F.s0, F.twistPow ?? 1);
|
|
110
|
-
const pts = [base], fr = [{ d: d0, h: f0, l: lat }];
|
|
111
|
-
let o = base, d = d0, h = f0, l = lat;
|
|
112
|
-
for (let k = 1; k <= steps; k++) {
|
|
113
|
-
const u0 = (k - 1) / steps, u1 = k / steps;
|
|
114
|
-
const da = foldAt(u1) - foldAt(u0), db = sweepAt(u1) - sweepAt(u0), dt = twistAt(u1) - twistAt(u0);
|
|
115
|
-
const dPrev = d;
|
|
116
|
-
// fold: d toward h about l
|
|
117
|
-
{ const c = Math.cos(da), sn = Math.sin(da); const d2 = add(mul(d, c), mul(h, sn)); h = sub(mul(h, c), mul(d, sn)); d = d2; }
|
|
118
|
-
// sweep: d toward l about h (the right ear sweeps the mirrored way: its l is the mirror's -l)
|
|
119
|
-
{ const c = Math.cos(db), sn = Math.sin(db); const d2 = add(mul(d, c), mul(l, sn)); l = sub(mul(l, c), mul(d, sn)); d = d2; }
|
|
120
|
-
// twist: the leaf turns about its spine, h toward l (a lop ear's leaf turns from a visor over the eye to a
|
|
121
|
-
// flap hanging down the side of the face)
|
|
122
|
-
{ const c = Math.cos(dt), sn = Math.sin(dt); const h2 = add(mul(h, c), mul(l, sn)); l = sub(mul(l, c), mul(h, sn)); h = h2; }
|
|
123
|
-
d = norm(d); h = norm(sub(h, mul(d, dot(h, d)))); l = cross(d, h);
|
|
124
|
-
o = add(o, mul(norm(add(dPrev, d)), len / steps));
|
|
125
|
-
pts.push(o);
|
|
126
|
-
fr.push({ d, h, l });
|
|
127
|
-
}
|
|
128
|
-
return { type, F, s, d0, f0, lat, pts, fr, L: len, W: F.width * len * (params.earWide ?? 1), steps, tip: o };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// the leaf: tiles for the sculpt, the mid-surface for tools, the outline points for the region box.
|
|
132
|
-
// res: the quality tier's cell scale (params.tierRes): the leaf is at least 1.8 ear cells thick at every tier
|
|
133
|
-
// (EAR_CELL x res, regions.js; a sheet thinner than that has both faces in one cell and meshes with rows of
|
|
134
|
-
// pinholes: a 3.6 mm rim at the 3 mm hero cells did).
|
|
135
|
-
// Each tile is a curved, tapered slab (core fin({ grad, curve })): its mid-surface a quadric fitted to 9
|
|
136
|
-
// points of the leaf's mid-surface, its half thickness a plane fitted to its corners, so neighbouring tiles
|
|
137
|
-
// meet with the same tangent plane and thickness (a smooth sheet: planar tiles showed a grid of facets).
|
|
138
|
-
export function earLeaf(base, S, params) {
|
|
139
|
-
const sp = earSpine(base, S, params);
|
|
140
|
-
const { F, type, pts: spine, fr, steps: STEPS, W, L } = sp;
|
|
141
|
-
const res = params.tierRes ?? 1;
|
|
142
|
-
const tMin = (res >= 1.9 ? 2.3 : 1.8) * EAR_CELL * res; // (medium and below 2.3 cells: at 1.8 the round rim, thinner than a 6 mm cell, meshed scalloped like torn paper)
|
|
143
|
-
// (fractional stations: linear between the spine's 96 steps)
|
|
144
|
-
const at = (kf) => {
|
|
145
|
-
const k = Math.min(STEPS - 1, Math.max(0, Math.floor(kf))), f = kf - k, A = fr[k], Bf = fr[k + 1];
|
|
146
|
-
const h = norm(add(mul(A.h, 1 - f), mul(Bf.h, f))), l = norm(add(mul(A.l, 1 - f), mul(Bf.l, f)));
|
|
147
|
-
return { p: add(mul(spine[k], 1 - f), mul(spine[k + 1], f)), h, l };
|
|
148
|
-
};
|
|
149
|
-
// (a soft, slightly uneven rim: the half width wanders by F.wave along the leaf, three to four times, face3;
|
|
150
|
-
// the phase differs per side and individual)
|
|
151
|
-
const wph = ((params.coatSeed || 0) % 628) / 100 + (S === 'L' || S === 1 ? 0 : 2.1);
|
|
152
|
-
const half = (kf) => { const t = kf / STEPS; return Math.max(1e-4, earW(type, t) * W * (1 + (F.wave || 0) * Math.sin(2 * PI * 3.4 * t + wph) * sstep(0.1, 0.35, t))); };
|
|
153
|
-
const cupAt = (kf) => F.cup[0] + (F.cup[1] - F.cup[0]) * (kf / STEPS);
|
|
154
|
-
// mid-surface point and hollow-side normal at station kf (0..STEPS), across a (-1..1)
|
|
155
|
-
const P = (kf, a) => {
|
|
156
|
-
const { p, h, l } = at(kf), w = half(kf), kap = cupAt(kf) / w, x = a * w;
|
|
157
|
-
return add(add(p, mul(l, Math.sin(kap * x) / kap)), mul(h, (1 - Math.cos(kap * x)) / kap));
|
|
158
|
-
};
|
|
159
|
-
const Nrm = (kf, a) => {
|
|
160
|
-
const { h, l } = at(kf), w = half(kf), kap = cupAt(kf) / w, x = a * w;
|
|
161
|
-
return norm(add(mul(h, Math.cos(kap * x)), mul(l, -Math.sin(kap * x))));
|
|
162
|
-
};
|
|
163
|
-
// thickness (full, m): thick where the pinna leaves the head, thinning toward the tip and the edges
|
|
164
|
-
const thick = (u, a) => {
|
|
165
|
-
const tr = F.thick[0], te = F.thick[1];
|
|
166
|
-
const t = te + (tr - te) * (1 - sstep(0, 0.55, u)) * (1 - sstep(0.25, 1, Math.abs(a)));
|
|
167
|
-
return Math.max(t, tMin);
|
|
168
|
-
};
|
|
169
|
-
const NS = F.ns, NA = F.na;
|
|
170
|
-
const st = (i) => (i * STEPS) / NS;
|
|
171
|
-
const segs = [], outline = [base];
|
|
172
|
-
for (let i = 0; i < NS; i++) {
|
|
173
|
-
for (let j = 0; j < NA; j++) {
|
|
174
|
-
const a0 = -1 + (2 * j) / NA, a1 = -1 + (2 * (j + 1)) / NA, k0 = st(i), k1 = st(i + 1);
|
|
175
|
-
const Q = [P(k0, a0), P(k1, a0), P(k1, a1), P(k0, a1)];
|
|
176
|
-
const C = mul(add(add(Q[0], Q[1]), add(Q[2], Q[3])), 0.25);
|
|
177
|
-
const v = norm(sub(add(Q[1], Q[2]), add(Q[0], Q[3])));
|
|
178
|
-
let u = sub(add(Q[3], Q[2]), add(Q[0], Q[1]));
|
|
179
|
-
u = norm(sub(u, mul(v, dot(u, v))));
|
|
180
|
-
// (the fin's normal u x v points into the hollow: the coat reads the hollow side from it)
|
|
181
|
-
if (dot(cross(u, v), Nrm((k0 + k1) / 2, (a0 + a1) / 2)) < 0) u = mul(u, -1);
|
|
182
|
-
const n = cross(u, v);
|
|
183
|
-
const q2 = Q.map((q) => [dot(sub(q, C), u), dot(sub(q, C), v)]);
|
|
184
|
-
// the mid-surface over the tile: z = m0 + mu x + mv y + (muu x^2 + 2 muv x y + mvv y^2) / 2 (least squares, 9 points)
|
|
185
|
-
const rows = [], zs = [];
|
|
186
|
-
for (const kf of [k0, (k0 + k1) / 2, k1]) for (const a of [a0, (a0 + a1) / 2, a1]) {
|
|
187
|
-
const d = sub(P(kf, a), C), x = dot(d, u), y = dot(d, v);
|
|
188
|
-
rows.push([1, x, y, 0.5 * x * x, x * y, 0.5 * y * y]); zs.push(dot(d, n));
|
|
189
|
-
}
|
|
190
|
-
const curve = lsq(rows, zs);
|
|
191
|
-
// half thickness at the corners, fitted by a plane h0 + gu x + gv y
|
|
192
|
-
const hc = [thick(k0 / STEPS, a0), thick(k1 / STEPS, a0), thick(k1 / STEPS, a1), thick(k0 / STEPS, a1)].map((t) => t / 2);
|
|
193
|
-
const [h0, gu, gv] = lsq(q2.map(([x, y]) => [1, x, y]), hc);
|
|
194
|
-
// edges: Q0-Q1 the a0 side (the rim if j = 0), Q1-Q2 the tip side (the rim if last), Q2-Q3 the a1
|
|
195
|
-
// side (the rim if j = NA - 1), Q3-Q0 the root side (the first row runs into the head)
|
|
196
|
-
const hEdge = (c0, c1) => (hc[c0] + hc[c1]) / 2;
|
|
197
|
-
const ext = [j === 0 ? 0 : hEdge(0, 1), i === NS - 1 ? 0 : hEdge(1, 2), j === NA - 1 ? 0 : hEdge(2, 3), hEdge(3, 0)];
|
|
198
|
-
const poly = offsetPoly(q2, ext);
|
|
199
|
-
segs.push({ o: C, u, v, poly, t: 2 * h0, grad: [gu, gv], curve });
|
|
200
|
-
for (const [x, y] of poly) {
|
|
201
|
-
const z = curve[0] + curve[1] * x + curve[2] * y + 0.5 * (curve[3] * x * x + 2 * curve[4] * x * y + curve[5] * y * y);
|
|
202
|
-
outline.push(add(add(add(C, mul(u, x)), mul(v, y)), mul(n, z)));
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// (mid-surface for tools: s 0..1, a -1..1)
|
|
207
|
-
const mid = (s, a) => ({ p: P(clamp01(s) * STEPS, a), n: Nrm(clamp01(s) * STEPS, a) });
|
|
208
|
-
return { base, along: norm(sub(sp.tip, base)), L, W, segs, pts: outline, mid, tip: sp.tip, type };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// least squares: argmin |A m - z| (normal equations, Gaussian elimination with partial pivoting)
|
|
212
|
-
function lsq(A, z) {
|
|
213
|
-
const n = A[0].length;
|
|
214
|
-
const M = Array.from({ length: n }, () => new Array(n + 1).fill(0));
|
|
215
|
-
for (let r = 0; r < A.length; r++) for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) M[i][j] += A[r][i] * A[r][j]; M[i][n] += A[r][i] * z[r]; }
|
|
216
|
-
for (let c = 0; c < n; c++) {
|
|
217
|
-
let pr = c;
|
|
218
|
-
for (let r = c + 1; r < n; r++) if (Math.abs(M[r][c]) > Math.abs(M[pr][c])) pr = r;
|
|
219
|
-
[M[c], M[pr]] = [M[pr], M[c]];
|
|
220
|
-
const d = M[c][c] || 1e-30;
|
|
221
|
-
for (let r = 0; r < n; r++) if (r !== c) { const f = M[r][c] / d; for (let j = c; j <= n; j++) M[r][j] -= f * M[c][j]; }
|
|
222
|
-
}
|
|
223
|
-
return M.map((row, i) => row[n] / (row[i] || 1e-30));
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// a convex polygon (2D) with each edge k pushed out by ext[k]
|
|
227
|
-
function offsetPoly(q, ext) {
|
|
228
|
-
const n = q.length;
|
|
229
|
-
let area = 0;
|
|
230
|
-
for (let k = 0; k < n; k++) { const [x0, y0] = q[k], [x1, y1] = q[(k + 1) % n]; area += x0 * y1 - x1 * y0; }
|
|
231
|
-
const sg = area > 0 ? 1 : -1;
|
|
232
|
-
const lines = q.map((p, k) => {
|
|
233
|
-
const p1 = q[(k + 1) % n], dx = p1[0] - p[0], dy = p1[1] - p[1], l = Math.hypot(dx, dy) || 1;
|
|
234
|
-
return { px: p[0] + ((sg * dy) / l) * ext[k], py: p[1] - ((sg * dx) / l) * ext[k], dx: dx / l, dy: dy / l };
|
|
235
|
-
});
|
|
236
|
-
return q.map((_, k) => {
|
|
237
|
-
const A = lines[(k + n - 1) % n], B = lines[k], den = A.dx * B.dy - A.dy * B.dx;
|
|
238
|
-
if (Math.abs(den) < 1e-9) return [B.px, B.py];
|
|
239
|
-
const t = ((B.px - A.px) * B.dy - (B.py - A.py) * B.dx) / den;
|
|
240
|
-
return [A.px + A.dx * t, A.py + A.dy * t];
|
|
241
|
-
});
|
|
242
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
// Domestic pig (Sus scrofa domesticus). Cloven-hoofed (two main claws and two dew claws per foot,
|
|
2
|
-
// on the cow's hoof-bone rig), a long fat barrel on short legs, the wedge head with the flat rostral
|
|
3
|
-
// disc on its own bone, small deep-set eyes with round pupils and pale lashes, erect / semi / lop
|
|
4
|
-
// ears per breed, and the corkscrew tail. Bare skin (material 4, subsurface-lit) under sparse
|
|
5
|
-
// bristles. Seeded breeds (variants): Large White / Yorkshire (default), Landrace, Duroc, Hampshire,
|
|
6
|
-
// Berkshire, spotted (Gloucester Old Spot / Pietrain).
|
|
7
|
-
// Behaviours: rooting, sniffing with the disc, grunting, tail curling and wagging, flopping onto the
|
|
8
|
-
// side to lie, the waddling trot, bouncing piglets; attack: a shoulder shove and bite, the boar's
|
|
9
|
-
// upward tusk slash.
|
|
10
|
-
import { pigRig, HEAD_O } from './rig.js';
|
|
11
|
-
import { sculptPig, EYE } from './sculpt.js';
|
|
12
|
-
import { pigRegions } from './regions.js';
|
|
13
|
-
import { pigCoat } from './coat.js';
|
|
14
|
-
import { srgb } from '../../core/build/coatKit.js';
|
|
15
|
-
import { QUALITY } from '../../core/build/pipeline.js';
|
|
16
|
-
import { rng } from '../../core/math/vec.js';
|
|
17
|
-
import { motion } from './motion.js';
|
|
18
|
-
|
|
19
|
-
const pick = (R, table) => {
|
|
20
|
-
let x = R() * table.reduce((s, [, w]) => s + w, 0);
|
|
21
|
-
for (const [k, w] of table) { x -= w; if (x <= 0) return k; }
|
|
22
|
-
return table[table.length - 1][0];
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Breeds: withers height of an adult sow (boars ~5-10 % taller), ears, face, build
|
|
26
|
-
// (a finisher of 0.72 m is the reference individual)
|
|
27
|
-
const BREED = {
|
|
28
|
-
largewhite: { name: 'Large White / Yorkshire', h: [0.7, 0.9], ear: 'erect', dish: 0.35, snout: 1.0, length: 1.0, legs: 1.0, girth: 1.0, ham: 1.0, earSize: 1.0 },
|
|
29
|
-
landrace: { name: 'Landrace', h: [0.68, 0.88], ear: 'lop', dish: 0.0, snout: 1.1, length: 1.08, legs: 0.98, girth: 0.97, ham: 0.95, earSize: 1.05 },
|
|
30
|
-
duroc: { name: 'Duroc', h: [0.72, 0.92], ear: 'semi', dish: 0.25, snout: 1.0, length: 0.98, legs: 1.02, girth: 1.04, ham: 1.1, earSize: 0.95 },
|
|
31
|
-
hampshire: { name: 'Hampshire', h: [0.7, 0.88], ear: 'erect', dish: 0.15, snout: 1.02, length: 0.98, legs: 1.0, girth: 1.02, ham: 1.08, earSize: 0.9 },
|
|
32
|
-
berkshire: { name: 'Berkshire', h: [0.64, 0.82], ear: 'erect', dish: 0.9, snout: 0.86, length: 0.96, legs: 0.96, girth: 1.03, ham: 1.02, earSize: 0.9 },
|
|
33
|
-
spotted: { name: 'Spotted (Gloucester Old Spot)', h: [0.7, 0.88], ear: 'lop', dish: 0.2, snout: 1.0, length: 1.0, legs: 0.98, girth: 1.05, ham: 1.0, earSize: 1.0 },
|
|
34
|
-
};
|
|
35
|
-
const VARIANT_KEYS = Object.keys(BREED);
|
|
36
|
-
|
|
37
|
-
export default {
|
|
38
|
-
id: 'pig',
|
|
39
|
-
name: 'Pig',
|
|
40
|
-
latin: 'Sus scrofa domesticus',
|
|
41
|
-
group: 'hooves',
|
|
42
|
-
plan: 'quadruped',
|
|
43
|
-
covering: 'skin',
|
|
44
|
-
variants: VARIANT_KEYS.map((id) => ({ id, name: BREED[id].name, latin: 'Sus scrofa domesticus' })),
|
|
45
|
-
|
|
46
|
-
// Seeded individual. opts.variant picks the breed (default Large White); sex: sow (teat row, a
|
|
47
|
-
// sagging belly with age) or boar (heavier shoulders and neck shield, visible small tusks, sheath
|
|
48
|
-
// and testes); age: adult (finisher to mature breeding stock) or juvenile (a piglet: big head and
|
|
49
|
-
// ears, short snout and body, fine hair, bouncy); size, build, ears, face, tail curl side, coat
|
|
50
|
-
// shade, mud, spots / belt / points.
|
|
51
|
-
variation(R0, o) {
|
|
52
|
-
const R = rng(Math.floor(R0() * 4294967296) ^ Math.imul(o.seed ?? 1, 0x9e3779b1) ^ 0x5bd1e995);
|
|
53
|
-
const variant = BREED[o.variant] ? o.variant : 'largewhite';
|
|
54
|
-
const B = BREED[variant];
|
|
55
|
-
const sex = o.sex || (R() < 0.6 ? 'female' : 'male');
|
|
56
|
-
const age = o.age || 'adult';
|
|
57
|
-
const piglet = age === 'juvenile';
|
|
58
|
-
const male = sex === 'male';
|
|
59
|
-
const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
|
|
60
|
-
// maturity: 0 finisher (6 months) .. 1 mature breeding sow / boar
|
|
61
|
-
const mature = piglet ? 0 : Math.pow(R(), 1.4);
|
|
62
|
-
const boar = male && !piglet ? 0.5 + 0.5 * mature : 0;
|
|
63
|
-
const hRef = B.h[0] + (B.h[1] - B.h[0]) * mature;
|
|
64
|
-
// (piglet: a weaner of 4-10 weeks, 0.30-0.45 m at the withers, built like side1 / threequarter3: a long, rounded
|
|
65
|
-
// body with its underline tucked up, on thick straight legs, the head and ears still big; a newborn's
|
|
66
|
-
// shape at a weaner's size, 1.42-1.49 withers heights long on thin stilts)
|
|
67
|
-
const size = piglet ? (0.36 + 0.14 * R()) : (hRef / 0.74) * (male ? 1.06 : 1) * (1 + 0.03 * g()); // (0.74: the withers after the legs warp)
|
|
68
|
-
const belly = male || piglet ? 0.1 : 0.2 + 0.45 * mature * (0.6 + 0.4 * R());
|
|
69
|
-
// (a piglet's erect ears big and broad and held out to the sides, front1 / front2; its lop and semi-lop leaves
|
|
70
|
-
// only a little bigger for its size. The head warp enlarges the ears too, at no cost in vertices: the mesh is
|
|
71
|
-
// made in reference space, and 1.25 x 1.3 bigger leaves put a piglet over the vertex budgets)
|
|
72
|
-
const erect = B.ear === 'erect';
|
|
73
|
-
const earSize = B.earSize * (1 + 0.06 * g()) * (piglet ? (erect ? 1.12 : 1.02) : 1);
|
|
74
|
-
return {
|
|
75
|
-
variant, sex, age, size,
|
|
76
|
-
boar, mature,
|
|
77
|
-
belly,
|
|
78
|
-
fat: 1 + 0.04 * g() + 0.03 * mature,
|
|
79
|
-
ham: B.ham * (1 + 0.05 * g()) * (piglet ? 1.06 : 1),
|
|
80
|
-
ear: B.ear, earSize, earWide: piglet && erect ? 1.18 : 1, earFwd: 0.5 * g(), earOut: 0.6 * g() + (piglet && erect ? 0.6 : 0),
|
|
81
|
-
dish: B.dish * (0.8 + 0.4 * R()) + (piglet ? 0.1 : 0),
|
|
82
|
-
snoutLen: B.snout * (1 + 0.04 * g()) * (piglet ? 0.85 : 1),
|
|
83
|
-
tusks: male && !piglet ? 0.35 + 0.65 * mature * (0.7 + 0.3 * R()) : 0,
|
|
84
|
-
teats: R() < 0.5 ? 7 : R() < 0.7 ? 6 : 8,
|
|
85
|
-
tailSide: R() < 0.5 ? 1 : -1,
|
|
86
|
-
docked: false,
|
|
87
|
-
wrinkles: 0.3 + 0.5 * mature + (variant === 'berkshire' ? 0.2 : 0),
|
|
88
|
-
bristle: (1 + 0.15 * g()) * (male ? 1.2 : 1),
|
|
89
|
-
mud: R() < 0.35 ? 0.35 + 0.6 * R() : 0,
|
|
90
|
-
// Hampshire belt edges: the front one across the head behind the eyes (head-local z), the back one
|
|
91
|
-
// at mid-ribcage (bind z); coat.js says why
|
|
92
|
-
belt: [-0.055 + 0.012 * g(), 0.02 + 0.04 * g()],
|
|
93
|
-
blaze: 0.6 + 0.6 * R(), socks: 0.8 + 0.5 * R(),
|
|
94
|
-
spotCount: 5 + Math.floor(R() * 7), spotSize: 0.8 + 0.5 * R(),
|
|
95
|
-
coatShade: g(), coatLightness: 0.05 * g(),
|
|
96
|
-
coatSeed: Math.floor(R() * 1e6),
|
|
97
|
-
// thin parts (ears, the tail tip) at the coarse tiers: at least sqrt(3) cells thick (a slab
|
|
98
|
-
// thinner than that slips between the samples: rows of pinholes in the ears at medium)
|
|
99
|
-
minThick: 0.0027,
|
|
100
|
-
// (the quality tier's cell scale: the ear leaf's tiles overlap by the rim radius the core inflates them to)
|
|
101
|
-
tierRes: QUALITY[o.quality]?.res ?? 1,
|
|
102
|
-
warps: [
|
|
103
|
-
// (the head scale first: its centre is the unwarped head origin)
|
|
104
|
-
// (piglet, with its tucked-up underline, sculpt.js: snout -> buttock 1.72-1.82 withers heights, belly 0.45-0.47
|
|
105
|
-
// above the ground, head (disc -> ear base) 0.41-0.42, elbow 0.47, width 0.53: side1 1.73-1.76 / 0.47-0.49 /
|
|
106
|
-
// 0.43 / 0.48, a weaner 1.8-1.9 long, research 2; an earlier piglet measured 1.42-1.49 long, 0.46 wide, elbow 0.50)
|
|
107
|
-
{ type: 'scaleAbout', c: HEAD_O, k: 1.13 * (1 + 0.03 * g()) * (piglet ? 1.24 : 1) * (male && !piglet ? 1.05 : 1), r0: 0.12, r1: 0.24 },
|
|
108
|
-
{ type: 'legs', k: 1.06 * B.legs * (1 + 0.045 * g()) * (piglet ? 1.19 : 1), top: 0.36 },
|
|
109
|
-
{ type: 'length', k: 0.95 * B.length * (1 + 0.045 * g()) * (piglet ? 1.16 : 1) * (1 + 0.03 * mature), z0: -0.42, z1: 0.3 },
|
|
110
|
-
{ type: 'girth', k: B.girth * (1 + 0.06 * g()) * (piglet ? 0.95 : 1) * (1 + 0.04 * mature), cy: 0.52, z0: -0.55, z1: 0.36 },
|
|
111
|
-
...(boar > 0 ? [{ type: 'girth', k: 1 + 0.07 * boar, cy: 0.55, z0: 0.12, z1: 0.5 }] : []),
|
|
112
|
-
],
|
|
113
|
-
};
|
|
114
|
-
},
|
|
115
|
-
rig: (params) => pigRig(params),
|
|
116
|
-
sculpt: (m, rig, params) => sculptPig(m, rig, params),
|
|
117
|
-
regions: pigRegions,
|
|
118
|
-
coat: pigCoat,
|
|
119
|
-
eyeSpecs: (params) => [1, -1].map((side) => ({ side, spec: EYE, headOrigin: HEAD_O, bone: 'head', look: eyeLook(params) })),
|
|
120
|
-
motion,
|
|
121
|
-
// (a piglet's hair is finer and denser than a finisher's bristles: side1, threequarter3, front2 show a pale
|
|
122
|
-
// velvet over the skin, no single hairs. On the adult grid, 1.85 mm cells, a piglet's short hairs stacked
|
|
123
|
-
// every shell into one crisp speck: 6.6-9.5 % bright specks on a lit cheek; on a finer grid each
|
|
124
|
-
// hair is below a pixel from half a metre on and the shells draw their expected coverage, a haze)
|
|
125
|
-
// (and the Duroc's longer red-gold hair sparser, face3: individual hairs, not a fine speckle)
|
|
126
|
-
render: (params) => ({ ...RENDER, strandDensity: params && params.age === 'juvenile' ? PIGLET_STRANDS : params && params.variant === 'duroc' ? 3400 : RENDER.strandDensity }),
|
|
127
|
-
};
|
|
128
|
-
// (strands on a 12000 /m grid (piglets 13000): the shells draw a bristle 0.3 of its cell wide, and the hair
|
|
129
|
-
// shader lights it darker than the wrapped skin near the terminator, so the 6000 grid's 0.25 mm hairs drew a dark
|
|
130
|
-
// hatching over the face from half a metre; on the finer grid they fall below a pixel there and blend to a faint
|
|
131
|
-
// haze, single pale hairs showing only up close and in the silhouette fins. skinScatter less red: the wrap past the
|
|
132
|
-
// terminator tinted the pale skin brick; it is also the colour of the light through the ears, coat.js)
|
|
133
|
-
const RENDER = { markColor: srgb(0x3a2a28), strandDensity: 12000, skinScatter: [0.86, 0.58, 0.52, 0.42], skinTrans: [0, 1], clumpDensity: 1, shellScale: 1, finWidth: 0.35, raiseLen: [0.02, 0.04] };
|
|
134
|
-
const PIGLET_STRANDS = 13000;
|
|
135
|
-
|
|
136
|
-
// Round pupil (slightly horizontally oval), brown iris (light amber to deep chocolate; a few blue),
|
|
137
|
-
// sclera hidden, pink or dark lids.
|
|
138
|
-
// (the amber iris read olive-green in the showcase's daylight; the photos show warm mid to dark brown)
|
|
139
|
-
const IRISES = [
|
|
140
|
-
{ inner: 0x3a2214, mid: 0x6a4026, hi: 0x8c5a36, outer: 0x24140c }, // brown
|
|
141
|
-
{ inner: 0x4a2c16, mid: 0x7c4c2a, hi: 0x9c6a3e, outer: 0x2e1a0c }, // light brown
|
|
142
|
-
{ inner: 0x1e120a, mid: 0x321e12, hi: 0x4c2e1c, outer: 0x120a06 }, // dark chocolate
|
|
143
|
-
{ inner: 0x4a5a66, mid: 0x7a8c98, hi: 0x9aacb6, outer: 0x2e3840 }, // blue-grey
|
|
144
|
-
];
|
|
145
|
-
function eyeLook(params) {
|
|
146
|
-
const s = ((params.coatSeed || 0) % 100) / 100;
|
|
147
|
-
// (blue-grey only in the white breeds; a Duroc's blue-grey iris read milky in daylight)
|
|
148
|
-
const pinkBreed = !params.variant || params.variant === 'largewhite' || params.variant === 'landrace' || params.variant === 'spotted';
|
|
149
|
-
const ir = IRISES[s < 0.5 ? 0 : s < 0.75 ? 1 : s < 0.95 || !pinkBreed ? 2 : 3];
|
|
150
|
-
const dark = params.variant === 'berkshire' || params.variant === 'hampshire';
|
|
151
|
-
return {
|
|
152
|
-
pupil: 'round',
|
|
153
|
-
lids: 'mammal',
|
|
154
|
-
iris: { inner: srgb(ir.inner), mid: srgb(ir.mid), hi: srgb(ir.hi), outer: srgb(ir.outer) },
|
|
155
|
-
sclera: { color: [0.6, 0.55, 0.52], visible: false },
|
|
156
|
-
// (the Duroc's lids its red skin, coat.js COATS.red body #8A5846 in linear: the pink of the white
|
|
157
|
-
// breeds drew a pale lilac disc over the eye in a blink, in the shade under the ear)
|
|
158
|
-
lidColor: dark ? [0.06, 0.05, 0.05] : params.variant === 'duroc' ? [0.25, 0.1, 0.065] : [0.42, 0.22, 0.2],
|
|
159
|
-
pupilSize: [0.2, 0.42],
|
|
160
|
-
};
|
|
161
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
// Pig motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
|
|
2
|
-
// Numbers are for the reference individual (params.size = 1, a 0.72 m Large White finisher); the
|
|
3
|
-
// engine scales them by dynamic similarity for piglets and big sows / boars.
|
|
4
|
-
//
|
|
5
|
-
// Gaits: lateral-sequence walk (Yucatan minipig and 100-113 kg
|
|
6
|
-
// finishers: 1.0-1.7 Hz, duty 0.65 -> 0.55, the hind -> fore interval 0.25 -> 0.3 of the stride),
|
|
7
|
-
// a diagonal trot (duty 0.45 -> 0.40, 2.0-2.4 Hz), walk -> trot at Froude ~0.45 (~1.6 m/s), and a
|
|
8
|
-
// short transverse gallop (LH, RH, LF, RF) from ~3.5 m/s up to the domestic top speed of ~5 m/s
|
|
9
|
-
// (Heglund et al. 1974: trot -> gallop 4.7 m/s at 2.3 Hz for 110 kg). Heavy pigs roll their trunk
|
|
10
|
-
// from side to side when walking and trotting (the waddle: behaviour hook).
|
|
11
|
-
import { behaviour } from './behaviour.js';
|
|
12
|
-
|
|
13
|
-
const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
|
|
14
|
-
// torso sections for a breed's leg length (legs warp k, top 0.36 m) and width factor w
|
|
15
|
-
const bodyFor = (legs, w) => {
|
|
16
|
-
const dy = 0.36 * 1.06 * (legs - 1);
|
|
17
|
-
return {
|
|
18
|
-
chest: { y: 0.535 + dy, hh: 0.245, hw: 0.275 * w },
|
|
19
|
-
// (mid and rump measured on the body: barrel 0.199-0.209, rump 0.225-0.24 m; the barrel
|
|
20
|
-
// later widened to 0.21-0.22 over the ribs)
|
|
21
|
-
mid: { y: 0.53 + dy, hh: 0.26, hw: 0.215 * w },
|
|
22
|
-
pelvis: { y: 0.54 + dy, hh: 0.24, hw: 0.255 * w },
|
|
23
|
-
rump: { z: -0.47, y: 0.57 + dy, hh: 0.21, hw: 0.24 * w },
|
|
24
|
-
back: 0.05,
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const motion = {
|
|
29
|
-
maxSpeed: 5.2,
|
|
30
|
-
accel: [2.5, 4.5],
|
|
31
|
-
decel: 6,
|
|
32
|
-
// a heavy, stiff-backed animal: a walking turn of 0.7 body lengths radius (research 4: 0.5-1), a
|
|
33
|
-
// cornering limit of 0.3 g (2.2 / 6 were a dog's: 0.61 g, the gallop leaned 23 deg like a motorbike)
|
|
34
|
-
turnRate: 1.6,
|
|
35
|
-
latAccelMax: 3,
|
|
36
|
-
gears: { walk: 1.0, trot: 2.4, gallop: 4.4 },
|
|
37
|
-
gallopBlend: [3.4, 5.2],
|
|
38
|
-
// name v f D [FL, FR, HL, HR]
|
|
39
|
-
gaits: [
|
|
40
|
-
G('walk', 0.0, 0.95, 0.66, [0.25, 0.75, 0.0, 0.5], { liftF: 0.04, liftH: 0.035, bobF: 0.01, bobH: 0.01, flex: 0, lat: 0.03, fold: 0.7, heel: 26, tail: 0, drop: 0 }),
|
|
41
|
-
G('walk', 1.3, 1.55, 0.56, [0.3, 0.8, 0.0, 0.5], { liftF: 0.05, liftH: 0.045, bobF: 0.018, bobH: 0.018, flex: 0, lat: 0.04, fold: 0.85, heel: 36, tail: 0.1, drop: 0 }),
|
|
42
|
-
G('trot', 1.7, 1.95, 0.46, [0.52, 0.02, 0.0, 0.5], { liftF: 0.065, liftH: 0.055, bobF: 0.022, bobH: 0.022, flex: 0.008, lat: 0.0, fold: 1.0, heel: 45, tail: 0.3, drop: 0.004 }),
|
|
43
|
-
G('trot', 3.2, 2.35, 0.4, [0.52, 0.02, 0.0, 0.5], { liftF: 0.08, liftH: 0.07, bobF: 0.028, bobH: 0.028, flex: 0.012, lat: 0.0, fold: 1.1, heel: 50, tail: 0.4, drop: 0.008 }),
|
|
44
|
-
G('gallop', 3.6, 2.45, 0.34, [0.55, 0.65, 0.0, 0.12], { liftF: 0.09, liftH: 0.08, bobF: 0.02, bobH: 0.028, flex: 0.06, lat: 0, fold: 1.2, heel: 45, tail: 0.6, drop: 0.012 }),
|
|
45
|
-
G('gallop', 5.2, 2.75, 0.29, [0.56, 0.66, 0.0, 0.12], { liftF: 0.1, liftH: 0.09, bobF: 0.022, bobH: 0.032, flex: 0.08, lat: 0, fold: 1.3, heel: 40, tail: 0.8, drop: 0.02 }),
|
|
46
|
-
],
|
|
47
|
-
feet: {
|
|
48
|
-
// on the tips of the two main claws, fairly upright pasterns: the fetlock sinks a little under
|
|
49
|
-
// load, the claws flip in swing
|
|
50
|
-
front: { type: 'unguligrade', contact: 0.9, curl: 62, flex: 4, sink: 10, hoofFlex: 16, swingBack: 0.04 },
|
|
51
|
-
hind: { type: 'unguligrade', contact: 0.9, curl: 62, flex: 4, sink: 9, hoofFlex: 16, swingBack: 0.015 },
|
|
52
|
-
},
|
|
53
|
-
stance: { width: 1, gallopWidth: 0.85, sprawl: 0, crouch: 0, scuff: [10, 20, 0] },
|
|
54
|
-
// torso cross-sections (bind pose, reference size): centre height, half height, half width
|
|
55
|
-
// (measured on the bind mesh at the girdles, shoulder and thigh muscles included: tools sec.mjs)
|
|
56
|
-
body: bodyFor(1, 1),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
head: {
|
|
60
|
-
// [speed, raise (m), reach (m), pitch (rad, + = nose down)]: low and forward, the snout near the
|
|
61
|
-
// ground at the walk (side3, side4_walk, research 3), a little higher at the trot, stretched forward
|
|
62
|
-
// when galloping
|
|
63
|
-
carriage: [[0, 0, 0, 0], [1.0, -0.08, 0.03, 0.25], [2.4, -0.02, 0.03, 0.04], [4.4, -0.02, 0.05, 0.0]],
|
|
64
|
-
stab: [[0, 0], [1.0, 0.15], [2.4, 0.35], [4.4, 0.3]],
|
|
65
|
-
neckBend: 22, neckPivot: 0.5, yaw: 0.7, pitchUp: 0.5, pitchDown: 0.7, mouth: 'jawTip',
|
|
66
|
-
},
|
|
67
|
-
tail: {
|
|
68
|
-
// [speed, pitch per segment from horizontal (deg), root -> tip]: the curled carriage (rig.js);
|
|
69
|
-
// the behaviour hook adds the helix yaw and uncurls it when the pig rests or is afraid
|
|
70
|
-
carriage: [
|
|
71
|
-
[0.0, [14, -6, -24, -30, -32, -32, -32, -32, -32, -32]],
|
|
72
|
-
[2.4, [18, -2, -20, -27, -30, -30, -30, -30, -30, -30]],
|
|
73
|
-
[4.4, [24, 6, -12, -22, -26, -28, -28, -28, -28, -28]],
|
|
74
|
-
],
|
|
75
|
-
stiffness: 1.6, sway: 3, flick: 0, wag: 0, swish: 0, curl: 0, balance: 0,
|
|
76
|
-
radius: [0.012, 0.006],
|
|
77
|
-
},
|
|
78
|
-
ears: { rest: [0, 0], mobility: 0.8, speedFlatten: 0.15, twitch: 1.0, prick: 0.35 },
|
|
79
|
-
breath: { rate: 0.35, amp: 0.008, pant: false, pantRate: 2.2, pantAmp: 0.015, heatSpeed: 5 },
|
|
80
|
-
actions: {
|
|
81
|
-
// rooting: the snout goes down to the ground in front of the forefeet (behaviour: nudges)
|
|
82
|
-
eat: { style: 'graze', dropF: 0.06, dropH: 0, pitch: 0.95, ahead: 0.55 },
|
|
83
|
-
drink: { dropF: 0.06, dropH: 0, pitch: 0.95, ahead: 0.55 },
|
|
84
|
-
// poor jumpers: a low scrambling hop (research 4: they step or scramble over 0.3-0.5 m at most; the
|
|
85
|
-
// body rises ~0.2 m, 0.4 s in the air; 0.42 m floated a 120 kg pig over its own withers height)
|
|
86
|
-
jump: { height: 0.16, distance: 0.8, land: [0.24, 0.2] },
|
|
87
|
-
sit: { dropH: 0.85 },
|
|
88
|
-
// kneels on both carpi first, then drops the hindquarters, then flops onto the side
|
|
89
|
-
lie: { style: 'lateral', down: 'front', up: 'front' },
|
|
90
|
-
wallow: { style: 'lateral', down: 'front', up: 'front' },
|
|
91
|
-
sleep: { style: 'lateral', down: 'front', up: 'front' },
|
|
92
|
-
fold: { front: { z: -0.18, k: 1.45, beta: 0.9 } },
|
|
93
|
-
idle: { shift: 0.7 },
|
|
94
|
-
},
|
|
95
|
-
// per breed: the torso sits lower on shorter legs (the legs warp, index.js BREED) and the
|
|
96
|
-
// heavier-hammed breeds rest on wider sections (a body lying on its side)
|
|
97
|
-
variants: {
|
|
98
|
-
landrace: { body: bodyFor(0.98, 1) },
|
|
99
|
-
duroc: { body: bodyFor(1.02, 1.07) },
|
|
100
|
-
hampshire: { body: bodyFor(1, 1.05) },
|
|
101
|
-
berkshire: { body: bodyFor(0.96, 1.03) },
|
|
102
|
-
spotted: { body: bodyFor(0.98, 1.04) },
|
|
103
|
-
},
|
|
104
|
-
hooks: behaviour,
|
|
105
|
-
};
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// Meshing plan: body at 7.8 mm (1.1 % of the withers height: the barrel's skin area is ~1.6x the
|
|
2
|
-
// cheetah's), the face at 4.1 mm overlapping the body just behind the eyes and cross-faded, the feet
|
|
3
|
-
// below mid-cannon at 3.5 mm (the cleft and the dew claws read), eyelid patches at 0.9 mm, and
|
|
4
|
-
// separate surfaces: the lower jaw (lower lip, chin; rigid), the boar's tusks (1.2 mm, rigid on the jaw), the ears (rigid on the
|
|
5
|
-
// ear bones, their thick roots buried in the head) and the corkscrew tail (its own skinned surface at
|
|
6
|
-
// 2 mm, the root buried in the rump).
|
|
7
|
-
//
|
|
8
|
-
// Seams. The skinning relaxes the axial coordinate and solves the limb fields over each surface
|
|
9
|
-
// separately, so two overlapping surfaces agree only where the weights do not depend on the
|
|
10
|
-
// surface: the face cut lies in front of the jowls (the jowls touch the shoulders, and the body's
|
|
11
|
-
// limb field reached into them while the head surface had no limb at all: the neck cracked open
|
|
12
|
-
// when the head went down), the foot cut on the rigid cannon; the overlaps run on well past the
|
|
13
|
-
// fade line (M), since the relaxation is one-sided next to a surface's open edge.
|
|
14
|
-
import { EYE, earShape, tuskCones } from './sculpt.js';
|
|
15
|
-
import { EAR_CELL } from './ears.js';
|
|
16
|
-
import { HEAD_O, HZ, hl } from './rig.js';
|
|
17
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
18
|
-
import { smoothstep, norm } from '../../core/math/vec.js';
|
|
19
|
-
|
|
20
|
-
// The face is cut off across the head behind the eyes: below the eye line by a plane slanting forward
|
|
21
|
-
// to the throat (in front of the jowls, see above), above it by a plane across the head axis 5 cm behind
|
|
22
|
-
// the eyes. The upper plane keeps the switch line in front of the poll: behind it (the slanted plane
|
|
23
|
-
// alone reached 16 cm back there, behind the occiput) both surfaces carry ~25 % neck2 weight, relaxed
|
|
24
|
-
// differently on each, and they parted by up to 6 mm when the head lay on its side (lie, sleep, death).
|
|
25
|
-
// Here both carry the head bone alone. (smooth minimum of the two signed distances, k 2 cm)
|
|
26
|
-
export const NECK_CUT = { c: hl([0, 0, -0.035]), d: norm([0, 0.4, 1]), top: hl([0, 0, -0.05]), band: 0.012 };
|
|
27
|
-
export const neckS = (x, y, z) => {
|
|
28
|
-
const a = (x - NECK_CUT.c[0]) * NECK_CUT.d[0] + (y - NECK_CUT.c[1]) * NECK_CUT.d[1] + (z - NECK_CUT.c[2]) * NECK_CUT.d[2];
|
|
29
|
-
const b = (y - NECK_CUT.top[1]) * HZ[1] + (z - NECK_CUT.top[2]) * HZ[2];
|
|
30
|
-
const k = 0.02, h = Math.min(1, Math.max(0, 0.5 + (0.5 * (b - a)) / k));
|
|
31
|
-
return b + (a - b) * h - k * h * (1 - h);
|
|
32
|
-
};
|
|
33
|
-
// feet: below mid-cannon
|
|
34
|
-
export const FOOT_CUT = { y: 0.105, band: 0.007 };
|
|
35
|
-
|
|
36
|
-
export const EYE_PATCH = { R: 0.023, B: 0.003, h: 0.0009, centres: [1, -1].map((s) => eyeFrameOf(EYE, HEAD_O, s).c) };
|
|
37
|
-
export function eyePatchWeight(x, y, z) {
|
|
38
|
-
let dmin = 1e9;
|
|
39
|
-
for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
|
|
40
|
-
return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function boxOf(pts, pad) {
|
|
44
|
-
const mn = [1e9, 1e9, 1e9], mx = [-1e9, -1e9, -1e9];
|
|
45
|
-
for (const p of pts) for (let i = 0; i < 3; i++) { mn[i] = Math.min(mn[i], p[i] - pad); mx[i] = Math.max(mx[i], p[i] + pad); }
|
|
46
|
-
return [mn, mx];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function pigRegions(rig, params, Q) {
|
|
50
|
-
// (the cross-fade bands are wider than the coarser surface's cells at every tier)
|
|
51
|
-
const r = Q.res, B = NECK_CUT.band * (0.6 + 0.4 * r), FB = FOOT_CUT.band * (0.3 + 0.7 * r), FY = FOOT_CUT.y;
|
|
52
|
-
const J = rig.J;
|
|
53
|
-
// eyelid patches at hero / high (0.9 / 1.2 mm) and, the pig's own, at medium (1.8 mm): the lids of the
|
|
54
|
-
// 22 x 12 mm aperture meshed at the medium head cells (8.6 mm) came out as a jagged notch (Safari, phones)
|
|
55
|
-
const patches = Q.eyePatches || r <= 2 ? EYE_PATCH.centres.map((c) => ({ c, R: EYE_PATCH.R, B: EYE_PATCH.B * Math.max(1, r), h: r > 1.5 ? 0.0021 : EYE_PATCH.h * Math.max(1, r) })) : [];
|
|
56
|
-
const crowd = r >= 4;
|
|
57
|
-
const hBody = 0.0078 * r, hHead = 0.0041 * r * (1 + 0.05 * (r - 1)), hFeet = 0.0035 * (crowd ? 4.2 : Math.min(r, 2.4));
|
|
58
|
-
// overlapping surfaces sample the field on the same coarse spacing as the body (F x h ~ 4 body
|
|
59
|
-
// cells): the primitive lists a vertex is skinned from are then culled alike on both sides
|
|
60
|
-
const Fof = (h) => Math.max(3, Math.round((4 * hBody) / h));
|
|
61
|
-
const M = Math.min(3.5 * hBody, 0.04);
|
|
62
|
-
const tailPts = [J.tailBase];
|
|
63
|
-
for (let i = 1; i <= 10; i++) if (J['tail' + i]) tailPts.push(J['tail' + i]);
|
|
64
|
-
const [tmin, tmax] = boxOf(tailPts, 0.025);
|
|
65
|
-
const [hmin, hmax] = boxOf([J.nose, J.jawHinge, J.jawTip, hl([0, 0.1, -0.05]), hl([0.12, -0.15, -0.05]), hl([-0.12, -0.15, -0.05])], 0.06);
|
|
66
|
-
const ear = (S, h, F) => { const [bmin, bmax] = boxOf(earShape(J, params, S).pts, 0.05); return { name: 'ear' + S, part: 'ear' + S, bmin, bmax, h, F, rigidBone: 'ear' + S }; };
|
|
67
|
-
// the boar's tusks: a small rigid surface each at 1.2 mm (x res), their roots buried in the lower lip (in the jaw's
|
|
68
|
-
// 3 mm cells the 1.2-7 mm cone meshed as a crumpled blade)
|
|
69
|
-
const tusks = (params.tusks || 0) > 0.05 ? [1, -1].map((s) => {
|
|
70
|
-
const pts = []; for (const c of tuskCones(params, s)) pts.push(c.a, c.b);
|
|
71
|
-
const [bmin, bmax] = boxOf(pts, 0.012);
|
|
72
|
-
return { name: s > 0 ? 'tuskL' : 'tuskR', part: 'tusk', bmin, bmax, h: 0.0012 * r, F: 3, rigidBone: 'jaw' };
|
|
73
|
-
}) : [];
|
|
74
|
-
return {
|
|
75
|
-
jobs: [
|
|
76
|
-
[{ name: 'body', part: 'body', bmin: [-0.3, Math.max(-0.01, FY - FB - M - hBody), -0.72], bmax: [0.3, 0.84, 0.8], h: hBody, F: 4, clip: (x, y, z) => neckS(x, y, z) < B + M && y > FY - FB - M }],
|
|
77
|
-
[
|
|
78
|
-
{ name: 'head', part: 'body', bmin: hmin, bmax: hmax, h: hHead, F: Fof(hHead), clip: (x, y, z) => neckS(x, y, z) > -B - M, patches },
|
|
79
|
-
{ name: 'jaw', part: 'jaw', bmin: [-0.1, 0.3, 0.5], bmax: [0.1, 0.62, 0.84], h: 0.003 * r * (r > 2 ? 0.8 : 1), F: 6, rigidBone: 'jaw' },
|
|
80
|
-
// (the leaves are at least 1.8 of these cells thick at every tier, ears.js)
|
|
81
|
-
ear('L', EAR_CELL * r, 3), ear('R', EAR_CELL * r, 3),
|
|
82
|
-
...tusks,
|
|
83
|
-
],
|
|
84
|
-
[
|
|
85
|
-
{ name: 'feet', part: 'body', bmin: [-0.16, -0.01, -0.45], bmax: [0.16, FY + FB + M + hFeet, 0.45], h: hFeet, F: Fof(hFeet), clip: (x, y, z) => y < FY + FB + M },
|
|
86
|
-
{ name: 'tail', part: 'tail', bmin: tmin, bmax: tmax, h: 0.002 * Math.min(r, 3.6), F: 3 },
|
|
87
|
-
],
|
|
88
|
-
],
|
|
89
|
-
fade(x, y, z, name, patch) {
|
|
90
|
-
if (name === 'body') return (1 - smoothstep(-B, B, neckS(x, y, z))) * smoothstep(FY - FB, FY + FB, y);
|
|
91
|
-
if (name === 'feet') return 1 - smoothstep(FY - FB, FY + FB, y);
|
|
92
|
-
if (name === 'head') {
|
|
93
|
-
let f = smoothstep(-B, B, neckS(x, y, z));
|
|
94
|
-
if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
|
|
95
|
-
return f;
|
|
96
|
-
}
|
|
97
|
-
return 1;
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
}
|