@bitefoundry/retrieviewer 0.0.3 → 0.0.5
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 +11 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +95 -0
- package/DESKTOP-PLATFORMS.md +6 -1
- package/INSTALLING.md +4 -0
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +116 -0
- package/README.md +121 -59
- package/RELEASING.md +33 -13
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/linux-overlay/overlay.py +8 -2
- package/integrations/macos-overlay/overlay.jxa +9 -7
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +7 -6
- package/integrations/windows-overlay/desktop.mjs +2 -1
- package/integrations/windows-overlay/protocol.mjs +13 -7
- package/integrations/windows-overlay/worker.mjs +1 -1
- package/package.json +34 -13
- package/puppy-comfort-sprites.mjs +33 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +140 -0
- package/puppy-companion-life.mjs +58 -18
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-companion-sprites.mjs +4 -2
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-actions.mjs +4 -2
- package/puppy-paper-behaviors.mjs +1 -1
- package/puppy-paper-contact.mjs +4 -2
- package/puppy-paper-seat.mjs +4 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +79 -21
- package/retrieviewer-cli.mjs +8 -6
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +12 -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,372 +0,0 @@
|
|
|
1
|
-
// The wild boar's coat: coarse, grizzled bristles (pale tips, dark band, brown woolly roots) over a
|
|
2
|
-
// dark grey-brown body, a mane of long bristles from the nape to mid-back (it rises when the boar is
|
|
3
|
-
// alarmed: P.furRaise with render.raiseLen), flaring grizzled "sideburns" on the cheeks, a paler
|
|
4
|
-
// grizzled snout, near-black legs, a bare dark snout disc, hairy erect ears with a fringe, a thin tail
|
|
5
|
-
// with a long tassel, ivory tusks and dark cloven hooves.
|
|
6
|
-
// Age classes: striped piglets ("humbugs": crisp cream stripes on rufous-brown, dark bands between
|
|
7
|
-
// them, running from the shoulder to the rump, broken lines on the face and the thighs) and the
|
|
8
|
-
// uniform red-brown yearling coat. Colour morphs of adults: dark (default), black, pale grey-fawn.
|
|
9
|
-
// Works in the reference space (see rig.js).
|
|
10
|
-
import { HEAD_O, HZ, HY } from './rig.js';
|
|
11
|
-
import { neckS } from './regions.js';
|
|
12
|
-
import { tuskPath } from './sculpt.js';
|
|
13
|
-
import { SDFModel } from '../../core/sdf/sdf.js';
|
|
14
|
-
import { norm, sub, dot, cross, len, add, mul, smoothstep, clamp, mix, rng, fbm3, vnoise3 } from '../../core/math/vec.js';
|
|
15
|
-
import { srgb, mix3, MAT, smoothField } from '../../core/build/coatKit.js';
|
|
16
|
-
|
|
17
|
-
// sRGB swatches sampled from the reference photos. The shells darken
|
|
18
|
-
// hair roots and add a dark agouti band, so the albedo here is the bristle colour, lighter than the
|
|
19
|
-
// animal reads in photos (#3C3B41 overall on side2).
|
|
20
|
-
export const COATS = {
|
|
21
|
-
dark: { base: 0x6c625a, dorsal: 0x4a423c, belly: 0x524842, face: 0x857c72, snout: 0x948a80, legs: 0x2a2826, mane: 0x2e2a27, agouti: 0.6, under: 0.35 },
|
|
22
|
-
black: { base: 0x4a4542, dorsal: 0x33302e, belly: 0x433e3a, face: 0x68625c, snout: 0x7a746c, legs: 0x1c1a1a, mane: 0x1e1c1b, agouti: 0.55, under: 0.25 },
|
|
23
|
-
pale: { base: 0x948a7e, dorsal: 0x72695f, belly: 0x867c70, face: 0xa39a8e, snout: 0x9e968c, legs: 0x2e2a28, mane: 0x3a3430, agouti: 0.8, under: 0.45 },
|
|
24
|
-
brown: { base: 0x7e6654, dorsal: 0x5a4a3c, belly: 0x6a5646, face: 0x8e7e6c, snout: 0x8e806e, legs: 0x2a2420, mane: 0x352b24, agouti: 0.7, under: 0.35 },
|
|
25
|
-
yearling: { base: 0x86603e, dorsal: 0x6c4a30, belly: 0x8a6444, face: 0x8e6644, snout: 0x7e5c40, legs: 0x4a3222, mane: 0x6a4428, agouti: 0.25, under: 0.2 },
|
|
26
|
-
piglet: { base: 0xb07a4a, dorsal: 0x7a4e2c, belly: 0xd8b088, face: 0xa8764a, snout: 0x94683e, legs: 0x8a5a36, mane: 0x6e4526, agouti: 0, under: 0.1, stripe: 0xe4bf8e, band: 0x6e4526 },
|
|
27
|
-
};
|
|
28
|
-
const DISC = 0x3a3440, DISC_PIG = 0x5a4038, HOOF = 0x26221f, TUSK = 0xede6d2, TUSK_BASE = 0xb7a585;
|
|
29
|
-
|
|
30
|
-
function palette(p) {
|
|
31
|
-
const C = COATS[p.coat] || COATS.dark;
|
|
32
|
-
const k = p.coatShade || 0, l = p.coatLightness || 0;
|
|
33
|
-
const tw = (hex) => { const c = srgb(hex); return [c[0] * (1 + 0.1 * k + l), c[1] * (1 + 0.03 * k + l), c[2] * (1 - 0.07 * k + l)]; };
|
|
34
|
-
const out = {};
|
|
35
|
-
for (const key of ['base', 'dorsal', 'belly', 'face', 'snout', 'legs', 'mane']) out[key] = tw(C[key]);
|
|
36
|
-
out.agouti = C.agouti; out.under = C.under;
|
|
37
|
-
out.stripe = C.stripe ? srgb(C.stripe) : null; out.band = C.band ? tw(C.band) : null;
|
|
38
|
-
out.disc = srgb(p.coat === 'piglet' ? DISC_PIG : DISC); out.hoof = srgb(HOOF);
|
|
39
|
-
out.tusk = srgb(TUSK); out.tuskBase = srgb(TUSK_BASE);
|
|
40
|
-
return out;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const HOOF_TAGS = new Set(['hoof', 'heelbulb', 'dewclaw']);
|
|
44
|
-
|
|
45
|
-
export function boarCoat(ctx) {
|
|
46
|
-
const { model, rig, pos, nrm, regionOf, regionNames, weights, nV, params, lists } = ctx;
|
|
47
|
-
const { BONES } = rig;
|
|
48
|
-
const J = rig.J;
|
|
49
|
-
const R = rng(9173 + (params.coatSeed || 0));
|
|
50
|
-
const COL = palette(params);
|
|
51
|
-
const piglet = params.coat === 'piglet';
|
|
52
|
-
const young = params.age === 'juvenile';
|
|
53
|
-
const winter = params.winter ?? 0.5; // 0 sparse summer bristles .. 1 long winter coat
|
|
54
|
-
const maneK = params.mane ?? 1;
|
|
55
|
-
const { dominant, axialS, skinIndex, skinWeight, limbMember } = weights;
|
|
56
|
-
const AX_LEN = weights.axialLengths;
|
|
57
|
-
const P = (v) => [pos[v * 3], pos[v * 3 + 1], pos[v * 3 + 2]];
|
|
58
|
-
const N = (v) => [nrm[v * 3], nrm[v * 3 + 1], nrm[v * 3 + 2]];
|
|
59
|
-
const sOcc = AX_LEN[1], sNeckBase = AX_LEN[3], sTailBase = AX_LEN[8];
|
|
60
|
-
const eyePrims = model.prims.filter((p) => p.tag === 'eyesocket');
|
|
61
|
-
const jawPrims = model.forPart('jaw');
|
|
62
|
-
const headPrims = model.forPart('body').filter((p) => p.bone === 'head' && !p.carve);
|
|
63
|
-
const nostrilPrims = model.prims.filter((p) => p.tag === 'nostril');
|
|
64
|
-
const discPrims = model.prims.filter((p) => p.tag === 'disc');
|
|
65
|
-
const isLimb = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw|fhoof|femur|tibia|metatarsus|hpaw|hhoof)/.test(b.name));
|
|
66
|
-
const isFront = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw|fhoof)/.test(b.name));
|
|
67
|
-
const HL = (p) => { const d = sub(p, HEAD_O); return [d[0], dot(d, HY), dot(d, HZ)]; };
|
|
68
|
-
// the snout's length varies (sculpt.js hz(): piglets short): landmarks along it move with it
|
|
69
|
-
const snoutL = params.snout ?? 1;
|
|
70
|
-
const hz = (z) => (z > 0.12 ? 0.12 + (z - 0.12) * snoutL : z);
|
|
71
|
-
const partName = (v) => regionNames[regionOf[v]];
|
|
72
|
-
const tusks = [['lower', 1], ['lower', -1], ['upper', 1], ['upper', -1]].map(([w, s]) => tuskPath(params, s, w));
|
|
73
|
-
|
|
74
|
-
// --- nearest primitive tag per vertex
|
|
75
|
-
const tagOf = new Array(nV);
|
|
76
|
-
for (let v = 0; v < nV; v++) {
|
|
77
|
-
const L = lists[v], p = P(v);
|
|
78
|
-
let best = 1e9, t = '';
|
|
79
|
-
for (const pr of L) {
|
|
80
|
-
if (pr.carve) continue;
|
|
81
|
-
const d = SDFModel.dist(pr, p[0], p[1], p[2]);
|
|
82
|
-
if (d < best) { best = d; t = pr.tag; }
|
|
83
|
-
}
|
|
84
|
-
tagOf[v] = t;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// --- regions: 0 torso, 1 neck, 2 head, 4 tail, 5 ear, 6 jaw, 7 tusk
|
|
88
|
-
const region = new Uint8Array(nV);
|
|
89
|
-
const legness = new Float32Array(nV);
|
|
90
|
-
const legBone = new Int16Array(nV).fill(-1);
|
|
91
|
-
for (let v = 0; v < nV; v++) {
|
|
92
|
-
const bn = BONES[dominant[v]].name, p = P(v), pn = partName(v);
|
|
93
|
-
let lb = -1, lw = 0;
|
|
94
|
-
for (let k = 0; k < 4; k++) {
|
|
95
|
-
const b = skinIndex[v * 4 + k], w = skinWeight[v * 4 + k];
|
|
96
|
-
if (isLimb[b] && w > lw) { lw = w; lb = b; }
|
|
97
|
-
}
|
|
98
|
-
legBone[v] = lb;
|
|
99
|
-
legness[v] = lb >= 0 ? smoothstep(0.15, 0.85, limbMember[v]) : 0;
|
|
100
|
-
if (pn === 'tusk' || pn === 'tuskup') region[v] = 7;
|
|
101
|
-
else if (pn === 'jaw') region[v] = 6;
|
|
102
|
-
else if (bn.startsWith('ear')) region[v] = 5;
|
|
103
|
-
else if (bn.startsWith('tail') && axialS[v] > sTailBase + 0.01) region[v] = 4;
|
|
104
|
-
else if (axialS[v] < sOcc + 0.01 || (pn === 'head' && neckS(p[0], p[1], p[2]) > 0.02)) region[v] = 2;
|
|
105
|
-
else if (axialS[v] < sNeckBase) region[v] = 1;
|
|
106
|
-
else region[v] = 0;
|
|
107
|
-
if (region[v] >= 2) legness[v] = 0;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// --- piglet stripes: longitudinal bands around the body axis (angle from the dorsal midline in the
|
|
111
|
-
// cross-section), seeded wobble and breaks. Returns the signed distance (m) to the pale stripes.
|
|
112
|
-
const axisY = (z) => mix(0.47, 0.45, smoothstep(0.2, -0.4, z));
|
|
113
|
-
const stripeAng = [0.26, 0.52, 0.79, 1.06, 1.33, 1.62]; // radians from the dorsal midline (pale stripes)
|
|
114
|
-
const stripeW = [0.06, 0.055, 0.055, 0.055, 0.06, 0.07];
|
|
115
|
-
const stripeSeed = R() * 100;
|
|
116
|
-
const stripeSDF = (p, r) => {
|
|
117
|
-
if (r === 7 || r === 5 || r === 4) return 1;
|
|
118
|
-
let yc = axisY(p[2]);
|
|
119
|
-
let ang = Math.atan2(Math.abs(p[0]), p[1] - yc);
|
|
120
|
-
let rad = Math.hypot(p[0], p[1] - yc);
|
|
121
|
-
// the stripes run from behind the ears to the rump, fading out on the legs
|
|
122
|
-
const zf = smoothstep(0.42, 0.3, p[2]) * smoothstep(-0.6, -0.5, p[2]);
|
|
123
|
-
if (r === 2 || r === 6) {
|
|
124
|
-
// face: a stripe from the eye along the side of the snout (broken lines on the head)
|
|
125
|
-
const h = HL(p);
|
|
126
|
-
const ay = Math.atan2(Math.abs(h[0]), h[1] + 0.02);
|
|
127
|
-
const d = (Math.abs(ay - 1.05) - 0.07) * Math.hypot(h[0], h[1] + 0.02);
|
|
128
|
-
return Math.max(d, (h[2] - 0.2) * 0.3, (-0.08 - h[2]) * 0.3) + (fbm3(h[0] * 60 + stripeSeed, h[1] * 60, h[2] * 30, 2) - 0.5) * 0.008;
|
|
129
|
-
}
|
|
130
|
-
let d = 1;
|
|
131
|
-
const wob = (fbm3(p[0] * 9 + stripeSeed, p[1] * 9, p[2] * 5, 3) - 0.5) * 0.12;
|
|
132
|
-
for (let i = 0; i < stripeAng.length; i++) {
|
|
133
|
-
const a = stripeAng[i] + wob + 0.05 * Math.sin(p[2] * 6 + i);
|
|
134
|
-
d = Math.min(d, (Math.abs(ang - a) - stripeW[i] * 0.5) * rad);
|
|
135
|
-
}
|
|
136
|
-
// breaks: stripes split into dashes here and there
|
|
137
|
-
const br = vnoise3(p[2] * 18 + stripeSeed, ang * 6, 3.1);
|
|
138
|
-
d = Math.max(d, (br - 0.8) * 0.05);
|
|
139
|
-
d = d * zf + (1 - zf) * Math.max(d, 0.01 + 0.02 * (1 - zf));
|
|
140
|
-
return d;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
// --- ventral factor
|
|
144
|
-
const ventral = new Float32Array(nV);
|
|
145
|
-
for (let v = 0; v < nV; v++) {
|
|
146
|
-
const n = N(v), r = region[v], p = P(v);
|
|
147
|
-
let w = 0;
|
|
148
|
-
if (r === 0) w = smoothstep(-0.2, -0.8, n[1]) * smoothstep(0.4, 0.28, p[1]);
|
|
149
|
-
else if (r === 1) w = smoothstep(0.0, -0.7, n[1]) * 0.5;
|
|
150
|
-
const L = legness[v];
|
|
151
|
-
if (L > 0) { const side = p[0] >= 0 ? 1 : -1; w = mix(w, smoothstep(0.1, -0.7, n[0] * side) * 0.5 * smoothstep(0.2, 0.35, p[1]), L); }
|
|
152
|
-
ventral[v] = w;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// --- mane: the dorsal strip from the crown between the ears (world z ~0.45) down the nape to mid-back
|
|
156
|
-
// (0..1); the head mesh paints it too, so the crest runs on over the crown instead of starting at the
|
|
157
|
-
// neck seam
|
|
158
|
-
const maneOf = (p, n) => {
|
|
159
|
-
const along = smoothstep(0.52, 0.38, p[2]) * smoothstep(-0.22, -0.02, p[2]);
|
|
160
|
-
const across = 1 - smoothstep(0.025, 0.07, Math.abs(p[0]));
|
|
161
|
-
return along * across * smoothstep(0.3, 0.7, n[1] + 0.2);
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// --- comb (hair flow)
|
|
165
|
-
const comb = new Float32Array(nV * 3);
|
|
166
|
-
for (let v = 0; v < nV; v++) {
|
|
167
|
-
const p = P(v), n = N(v), r = region[v], tag = tagOf[v];
|
|
168
|
-
const bone = BONES[dominant[v]];
|
|
169
|
-
let d;
|
|
170
|
-
if (r === 5) d = norm(sub(bone.tail, bone.head));
|
|
171
|
-
else if (r === 7) d = [0, 1, 0];
|
|
172
|
-
else if (r === 2 || r === 6) {
|
|
173
|
-
// face: from the disc back along the snout; the cheek bristles flare back and down
|
|
174
|
-
// ("sideburns"), the crown hair runs back to the nape
|
|
175
|
-
const h = HL(p);
|
|
176
|
-
d = norm(add(mul(HZ, -1), [0, 0, 0]));
|
|
177
|
-
if (h[1] < 0.01 && Math.abs(h[0]) > 0.03) d = norm(add(mul(HZ, -1), add(mul(HY, -0.7), [Math.sign(h[0]) * 0.4, 0, 0])));
|
|
178
|
-
// the crest over the crown stands up and back like the mane it runs into
|
|
179
|
-
const mn = r === 2 ? maneOf(p, n) : 0;
|
|
180
|
-
if (mn > 0) d = norm(add(mul(d, 1 - 0.4 * mn), [Math.sign(p[0] || 1) * 0.25 * mn, 0.6 * mn, 0]));
|
|
181
|
-
} else if (r === 4) {
|
|
182
|
-
d = norm(sub(bone.tail, bone.head));
|
|
183
|
-
} else {
|
|
184
|
-
const seg = weights.segT[v * 2] | 0;
|
|
185
|
-
const a = rig.AXIAL.points[seg], b = rig.AXIAL.points[Math.min(seg + 1, rig.AXIAL.points.length - 1)];
|
|
186
|
-
d = norm(sub(b, a));
|
|
187
|
-
if (r === 0) d = norm(add(d, [0, -0.6 * Math.abs(n[0]), 0]));
|
|
188
|
-
if (r === 1) d = norm(add(d, [0, -0.5, 0.1]));
|
|
189
|
-
// mane bristles stand up and back, parted along the spine
|
|
190
|
-
const mn = maneOf(p, n);
|
|
191
|
-
if (mn > 0) d = norm(add(mul(d, 1 - 0.4 * mn), [Math.sign(p[0] || 1) * 0.25 * mn, 0.6 * mn, 0]));
|
|
192
|
-
const L = legness[v];
|
|
193
|
-
if (L > 0 && legBone[v] >= 0) {
|
|
194
|
-
const lbn = BONES[legBone[v]];
|
|
195
|
-
let dl = norm(sub(lbn.tail, lbn.head));
|
|
196
|
-
if (/hoof/.test(lbn.name)) dl = [0, -1, 0.1];
|
|
197
|
-
else dl = norm(add(dl, [0, -0.3, 0]));
|
|
198
|
-
d = norm(add(mul(d, 1 - L), mul(dl, L)));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
void tag;
|
|
202
|
-
let t = sub(d, mul(n, dot(d, n)));
|
|
203
|
-
if (len(t) < 1e-4) t = cross(n, [1, 0, 0]);
|
|
204
|
-
t = norm(t);
|
|
205
|
-
comb[v * 3] = t[0]; comb[v * 3 + 1] = t[1]; comb[v * 3 + 2] = t[2];
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// --- per-vertex fields
|
|
209
|
-
const pattern = new Float32Array(nV).fill(1);
|
|
210
|
-
const patInt = new Float32Array(nV);
|
|
211
|
-
const patCol = new Float32Array(nV * 3);
|
|
212
|
-
const markSDF = new Float32Array(nV).fill(1);
|
|
213
|
-
const furLen = new Float32Array(nV);
|
|
214
|
-
const tint = new Float32Array(nV * 4);
|
|
215
|
-
const surf = new Float32Array(nV * 4);
|
|
216
|
-
const bodyFl = mix(0.022, 0.04, winter) * (young ? 0.6 : 1);
|
|
217
|
-
|
|
218
|
-
for (let v = 0; v < nV; v++) {
|
|
219
|
-
const p = P(v), n = N(v), r = region[v], tag = tagOf[v];
|
|
220
|
-
let col, mat = MAT.FUR, fl = bodyFl, mark = 1, gloss = 0.45, agouti = COL.agouti, under = COL.under, finOff = 0;
|
|
221
|
-
let pd = 0.02;
|
|
222
|
-
const lb = legBone[v];
|
|
223
|
-
const lbName = lb >= 0 ? BONES[lb].name : '';
|
|
224
|
-
if (r === 0 || r === 1) {
|
|
225
|
-
const up = clamp(n[1], -1, 1);
|
|
226
|
-
col = mix3(COL.base, COL.dorsal, smoothstep(0.2, 0.95, up) * 0.8);
|
|
227
|
-
col = mix3(col, COL.belly, ventral[v]);
|
|
228
|
-
fl = mix(bodyFl, bodyFl * 0.6, ventral[v]);
|
|
229
|
-
// neck and shoulders: longer, coarser bristles
|
|
230
|
-
fl *= (1 + 0.2 * smoothstep(0.0, 0.3, p[2])) * (1 - 0.3 * smoothstep(-0.15, -0.45, p[2]));
|
|
231
|
-
const mn = maneOf(p, n) * maneK;
|
|
232
|
-
if (mn > 0) { fl = mix(fl, (young ? 0.045 : 0.11 + 0.04 * winter), mn); col = mix3(col, COL.mane, mn * 0.8); }
|
|
233
|
-
if (tag === 'teat') { mat = MAT.SKIN; fl = 0.002; col = [0.12, 0.08, 0.07]; }
|
|
234
|
-
if (tag === 'sheath') fl = 0.05; // (the tuft)
|
|
235
|
-
const L = legness[v];
|
|
236
|
-
if (L > 0) {
|
|
237
|
-
const lfl = mix(0.012, 0.03, smoothstep(0.08, 0.3, p[1])) * (young ? 0.8 : 1);
|
|
238
|
-
fl = mix(fl, lfl, L);
|
|
239
|
-
// legs darken to near-black below the elbows / stifles
|
|
240
|
-
col = mix3(col, COL.legs, L * smoothstep(0.34, 0.2, p[1]) + (piglet ? 0 : 0.3 * L));
|
|
241
|
-
}
|
|
242
|
-
if (/hoof|paw/.test(lbName) && HOOF_TAGS.has(tag)) {
|
|
243
|
-
const Cj = J[(lbName[0] === 'f' ? 'fcoffin' : 'hcoffin') + BONES[lb].side];
|
|
244
|
-
if (tag === 'dewclaw' || p[1] < Cj[1] + 0.006 + 0.35 * (p[2] - Cj[2])) {
|
|
245
|
-
mat = MAT.KERATIN; fl = 0; gloss = 0.45;
|
|
246
|
-
col = COL.hoof;
|
|
247
|
-
if (tag === 'heelbulb') col = mix3(col, [0.06, 0.05, 0.045], 0.5);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
if (piglet && mat === MAT.FUR) {
|
|
251
|
-
pd = stripeSDF(p, r);
|
|
252
|
-
// dark bands between the pale stripes (a second, wider field)
|
|
253
|
-
const band = clamp(-pd / 0.012 + 1.6, 0, 1);
|
|
254
|
-
col = mix3(col, COL.band, 0.55 * (1 - band) * smoothstep(0.28, 0.45, p[1]) * (1 - L));
|
|
255
|
-
pd = pd + 0.4 * L * smoothstep(0.32, 0.2, p[1]); // (not on the lower legs)
|
|
256
|
-
}
|
|
257
|
-
} else if (r === 4) {
|
|
258
|
-
col = mix3(COL.dorsal, COL.legs, 0.3);
|
|
259
|
-
fl = 0.012;
|
|
260
|
-
if (tag === 'tassel') { fl = young ? 0.035 : 0.075; col = COL.mane; }
|
|
261
|
-
} else if (r === 5) {
|
|
262
|
-
// ears: densely haired, with a long fringe along the edges and tip
|
|
263
|
-
const earP = model.prims.find((q) => q.tag === 'ear' && (q.bone === (p[0] > 0 ? 'earL' : 'earR')));
|
|
264
|
-
const faceDir = [earP.P[9], earP.P[10], earP.P[11]];
|
|
265
|
-
const front = dot(n, faceDir);
|
|
266
|
-
col = mix3(COL.dorsal, COL.face, 0.2);
|
|
267
|
-
fl = young ? 0.012 : 0.02;
|
|
268
|
-
const eb = BONES[dominant[v]], ab = sub(eb.tail, eb.head);
|
|
269
|
-
const t = dot(sub(p, eb.head), ab) / dot(ab, ab);
|
|
270
|
-
if (front > 0.3) { fl = 0.016; col = mix3(col, [0.05, 0.045, 0.04], 0.3); }
|
|
271
|
-
const edge = 1 - Math.abs(front);
|
|
272
|
-
fl += (young ? 0.01 : 0.03) * smoothstep(0.3, 0.9, edge) * smoothstep(0.3, 0.9, t);
|
|
273
|
-
if (piglet) pd = 1;
|
|
274
|
-
} else if (r === 7) {
|
|
275
|
-
// tusk: ivory, stained brownish at the base, a sharp whetted edge
|
|
276
|
-
let bt = 0, bd = 1e9;
|
|
277
|
-
for (const H of tusks) for (let i = 0; i + 1 < H.length; i++) {
|
|
278
|
-
const a = H[i].p, b = H[i + 1].p, ab = sub(b, a);
|
|
279
|
-
const u = clamp(dot(sub(p, a), ab) / dot(ab, ab), 0, 1);
|
|
280
|
-
const q = add(a, mul(ab, u)), dd = len(sub(p, q));
|
|
281
|
-
if (dd < bd) { bd = dd; bt = H[i].t + (H[i + 1].t - H[i].t) * u; }
|
|
282
|
-
}
|
|
283
|
-
mat = MAT.KERATIN; fl = 0; gloss = 0.7;
|
|
284
|
-
col = mix3(COL.tuskBase, COL.tusk, smoothstep(0.1, 0.5, bt));
|
|
285
|
-
col = mul(col, 0.92 + 0.12 * vnoise3(p[0] * 400, p[1] * 400, p[2] * 400));
|
|
286
|
-
pd = 1;
|
|
287
|
-
} else {
|
|
288
|
-
// head & jaw: grizzled face, paler along the snout and cheeks, short bristles on the snout,
|
|
289
|
-
// long flaring cheek bristles, bare dark disc
|
|
290
|
-
// (no silhouette fins on the head (render finMask): its sparse cards drew a see-through fringe round
|
|
291
|
-
// the face, the skin's outline showing inside it; the shells carry the face's coat)
|
|
292
|
-
const h = HL(p);
|
|
293
|
-
col = mix3(COL.dorsal, COL.face, smoothstep(-0.02, 0.1, h[2]) * 0.8);
|
|
294
|
-
const side = smoothstep(0.02, 0.05, Math.abs(h[0]));
|
|
295
|
-
col = mix3(col, COL.snout, smoothstep(0.08, hz(0.2), h[2]) * (1 - smoothstep(hz(0.24), hz(0.28), h[2])) * (0.5 + 0.5 * side));
|
|
296
|
-
// dark crown and around the eyes
|
|
297
|
-
col = mix3(col, COL.dorsal, smoothstep(0.01, 0.06, h[1]) * smoothstep(0.1, -0.02, h[2]) * 0.6);
|
|
298
|
-
fl = mix(0.03, 0.012, smoothstep(0.05, hz(0.22), h[2])) * (young ? 0.7 : 1);
|
|
299
|
-
// sideburns: long bristles on the jowls flaring back
|
|
300
|
-
const jowl = smoothstep(0.0, -0.05, h[1]) * smoothstep(0.09, -0.02, h[2]) * smoothstep(0.03, 0.06, Math.abs(h[0]));
|
|
301
|
-
fl = mix(fl, young ? 0.03 : 0.06 + 0.02 * winter, jowl);
|
|
302
|
-
// (the face and jowls only: the crest at the back of the skull keeps its fins with the mane)
|
|
303
|
-
finOff = Math.max(smoothstep(-0.03, 0.04, h[2]), jowl);
|
|
304
|
-
col = mix3(col, COL.face, jowl * 0.5);
|
|
305
|
-
// the bristly crest from the crown on into the mane
|
|
306
|
-
if (r === 2) {
|
|
307
|
-
const mn = maneOf(p, n) * maneK;
|
|
308
|
-
if (mn > 0) { fl = mix(fl, (young ? 0.045 : 0.11 + 0.04 * winter), mn); col = mix3(col, COL.mane, mn * 0.8); }
|
|
309
|
-
}
|
|
310
|
-
// the jaw underside darker
|
|
311
|
-
if (r === 6) col = mix3(col, COL.dorsal, 0.35);
|
|
312
|
-
for (const e of eyePrims) {
|
|
313
|
-
const de = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
314
|
-
if (Math.abs(de) < 0.0035) mark = Math.min(mark, Math.abs(de) - 0.0018);
|
|
315
|
-
if (Math.abs(de) < 0.0014) { mat = MAT.DARK_SKIN; fl = 0; }
|
|
316
|
-
else if (Math.abs(de) < 0.005) fl = Math.min(fl, 0.004);
|
|
317
|
-
else if (de < 0.016) fl = Math.min(fl, mix(0.004, 0.014, (de - 0.005) / 0.011));
|
|
318
|
-
}
|
|
319
|
-
// snout disc: bare, dark, moist; its rim a crisp mark
|
|
320
|
-
let dd = 1e9;
|
|
321
|
-
for (const e of discPrims) dd = Math.min(dd, SDFModel.dist(e, p[0], p[1], p[2]));
|
|
322
|
-
const discFace = dot(n, HZ);
|
|
323
|
-
if (h[2] > hz(0.265) && dd < 0.004 && discFace > 0.25) { mat = MAT.NOSE; fl = 0; col = COL.disc; gloss = 0.7; }
|
|
324
|
-
else if (h[2] > hz(0.25)) { fl = Math.min(fl, 0.006); col = mix3(col, COL.disc, 0.5 * smoothstep(hz(0.25), hz(0.28), h[2])); }
|
|
325
|
-
for (const e of nostrilPrims) {
|
|
326
|
-
const dn = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
327
|
-
if (dn < 0.003) { mat = MAT.NOSE; col = mul(COL.disc, 0.4); fl = 0; mark = Math.min(mark, dn - 0.0015); }
|
|
328
|
-
}
|
|
329
|
-
// lips and mouth
|
|
330
|
-
// (the closed mouth shows only a dark lip line: the red mouth lining is painted where the two
|
|
331
|
-
// surfaces lie inside each other, which shows only when the jaw opens)
|
|
332
|
-
if (regionNames[regionOf[v]] !== 'jaw') {
|
|
333
|
-
const dj = SDFModel.evalList(jawPrims, p[0], p[1], p[2]);
|
|
334
|
-
if (dj < -0.001 && h[2] > 0.0) { mat = MAT.MOUTH; fl = 0; }
|
|
335
|
-
else if (dj < 0.002 && h[2] > 0.0) { mat = MAT.DARK_SKIN; fl = 0; col = [0.03, 0.026, 0.024]; }
|
|
336
|
-
else if (dj < 0.006 && h[2] > 0.0) { mark = Math.min(mark, dj - 0.004); fl = Math.min(fl, 0.004); }
|
|
337
|
-
} else {
|
|
338
|
-
const dh = SDFModel.evalList(headPrims, p[0], p[1], p[2]);
|
|
339
|
-
if (dh < -0.001) { mat = MAT.MOUTH; fl = 0; }
|
|
340
|
-
else if (dh < 0.002) { mat = MAT.DARK_SKIN; fl = 0; col = [0.03, 0.026, 0.024]; }
|
|
341
|
-
else if (dh < 0.0045) { mark = Math.min(mark, dh - 0.0035); fl = Math.min(fl, 0.003); }
|
|
342
|
-
}
|
|
343
|
-
// short hair where the tusks come out of the lips (the tusks stay visible)
|
|
344
|
-
if (tag === 'tuskboss' || tag === 'upperlip') fl = Math.min(fl, 0.006);
|
|
345
|
-
if (piglet && mat === MAT.FUR) pd = stripeSDF(p, r);
|
|
346
|
-
agouti *= 0.7;
|
|
347
|
-
}
|
|
348
|
-
// low-frequency colour variation
|
|
349
|
-
const cv = fbm3(p[0] * 6, p[1] * 6, p[2] * 6, 3) - 0.5;
|
|
350
|
-
if (mat === MAT.FUR) col = [col[0] * (1 + 0.16 * cv), col[1] * (1 + 0.13 * cv), col[2] * (1 + 0.1 * cv)];
|
|
351
|
-
// coarse bristles: lock-to-lock shade streaks
|
|
352
|
-
if (mat === MAT.FUR && fl > 0.02) {
|
|
353
|
-
const c = [comb[v * 3], comb[v * 3 + 1], comb[v * 3 + 2]];
|
|
354
|
-
const along = dot(p, c), q = sub(p, mul(c, along));
|
|
355
|
-
const st = vnoise3(q[0] * 120, q[1] * 120, q[2] * 120 + along * 3);
|
|
356
|
-
col = mul(col, 0.84 + 0.32 * st);
|
|
357
|
-
}
|
|
358
|
-
if (mat !== MAT.FUR) pd = Math.max(pd, 0.02);
|
|
359
|
-
pattern[v] = piglet ? Math.min(0.02, pd) : 0.02;
|
|
360
|
-
patInt[v] = piglet ? 1 : 0;
|
|
361
|
-
if (piglet) { patCol[v * 3] = COL.stripe[0]; patCol[v * 3 + 1] = COL.stripe[1]; patCol[v * 3 + 2] = COL.stripe[2]; }
|
|
362
|
-
markSDF[v] = mark;
|
|
363
|
-
furLen[v] = fl;
|
|
364
|
-
tint[v * 4] = col[0]; tint[v * 4 + 1] = col[1]; tint[v * 4 + 2] = col[2]; tint[v * 4 + 3] = mat;
|
|
365
|
-
surf[v * 4] = gloss; surf[v * 4 + 1] = mat === MAT.FUR ? finOff : 0; surf[v * 4 + 2] = mat === MAT.FUR ? agouti : 0; surf[v * 4 + 3] = mat === MAT.FUR ? under : 0;
|
|
366
|
-
}
|
|
367
|
-
smoothField(furLen, weights.neighbors, 2, (v) => tint[v * 4 + 3] !== MAT.FUR);
|
|
368
|
-
|
|
369
|
-
const patternColor = new Float32Array(nV * 4);
|
|
370
|
-
for (let v = 0; v < nV; v++) { patternColor[v * 4] = patCol[v * 3]; patternColor[v * 4 + 1] = patCol[v * 3 + 1]; patternColor[v * 4 + 2] = patCol[v * 3 + 2]; patternColor[v * 4 + 3] = patInt[v]; }
|
|
371
|
-
return { comb, tint, pattern, mark: markSDF, furLen, patternColor, surf, stats: {}, region, ventral };
|
|
372
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
// Wild boar (Sus scrofa). Cloven-hoofed forager built on the horse / goat hoof rig: a wedge-shaped
|
|
2
|
-
// body with massive high shoulders sloping to narrow hips, a long wedge head ending in the snout
|
|
3
|
-
// disc, small eyes, erect hairy ears, a coarse grizzled coat with a dorsal mane that rises when the
|
|
4
|
-
// boar is alarmed, tusks (the lower canines curving up and out, whetted by the uppers), a thin
|
|
5
|
-
// tasselled tail, short slim legs. Rooting, sniffing, the trot as its travelling gait, charges that
|
|
6
|
-
// end in an upward tusk hook.
|
|
7
|
-
import { boarRig, HEAD_O } from './rig.js';
|
|
8
|
-
import { sculptBoar, EYE } from './sculpt.js';
|
|
9
|
-
import { boarRegions } from './regions.js';
|
|
10
|
-
import { boarCoat } from './coat.js';
|
|
11
|
-
import { srgb } from '../../core/build/coatKit.js';
|
|
12
|
-
import { rng } from '../../core/math/vec.js';
|
|
13
|
-
import { motion } from './motion.js';
|
|
14
|
-
|
|
15
|
-
const pick = (R, table) => {
|
|
16
|
-
let x = R() * table.reduce((s, [, w]) => s + w, 0);
|
|
17
|
-
for (const [k, w] of table) { x -= w; if (x <= 0) return k; }
|
|
18
|
-
return table[table.length - 1][0];
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default {
|
|
22
|
-
id: 'boar',
|
|
23
|
-
name: 'Wild boar',
|
|
24
|
-
latin: 'Sus scrofa',
|
|
25
|
-
group: 'hooves',
|
|
26
|
-
plan: 'quadruped',
|
|
27
|
-
covering: 'fur',
|
|
28
|
-
// age classes: adults (dark, black, grey-brown or pale grizzled), red-brown yearlings, striped piglets
|
|
29
|
-
variants: ['adult', 'yearling', 'piglet'],
|
|
30
|
-
|
|
31
|
-
// Seeded individual. Sex: male (larger, heavier forequarters and shoulder shield, long tusks) or
|
|
32
|
-
// female (small tusks, teats); age class (o.variant, or o.age 'juvenile' -> yearling or piglet):
|
|
33
|
-
// adult, yearling (0.55 m, uniform red-brown, short tusks), piglet (0.25 m, striped "humbug", big
|
|
34
|
-
// head, short snout, no tusks). Size from the regional range (Mediterranean small .. Eastern
|
|
35
|
-
// large), coat morph and tone, winter / summer coat length, mane.
|
|
36
|
-
variation(R0, o) {
|
|
37
|
-
const R = rng(Math.floor(R0() * 4294967296) ^ Math.imul(o.seed ?? 1, 0x9e3779b1) ^ 173);
|
|
38
|
-
const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
|
|
39
|
-
let variant = ['adult', 'yearling', 'piglet'].includes(o.variant) ? o.variant : null;
|
|
40
|
-
if (!variant) {
|
|
41
|
-
if (o.age === 'juvenile') variant = R() < 0.5 ? 'piglet' : 'yearling';
|
|
42
|
-
else if (o.age === 'adult') variant = 'adult';
|
|
43
|
-
else variant = pick(R, [['adult', 72], ['yearling', 14], ['piglet', 14]]);
|
|
44
|
-
}
|
|
45
|
-
const age = variant === 'adult' ? 'adult' : 'juvenile';
|
|
46
|
-
const piglet = variant === 'piglet', yearling = variant === 'yearling';
|
|
47
|
-
const sex = o.sex || (R() < 0.5 ? 'male' : 'female');
|
|
48
|
-
const male = sex === 'male';
|
|
49
|
-
const coat = piglet ? 'piglet' : yearling ? 'yearling' : pick(R, [['dark', 55], ['black', 15], ['brown', 15], ['pale', 15]]);
|
|
50
|
-
// regional build: Central European default, sometimes a big Eastern boar or
|
|
51
|
-
// a small Mediterranean one
|
|
52
|
-
const region = variant === 'adult' ? pick(R, [['central', 80], ['eastern', 10], ['mediterranean', 10]]) : 'central';
|
|
53
|
-
const regK = region === 'eastern' ? 1.18 : region === 'mediterranean' ? 0.86 : 1;
|
|
54
|
-
const size = (piglet ? 0.34 : yearling ? 0.73 : male ? 1.06 : 0.94) * regK * (1 + 0.045 * g());
|
|
55
|
-
let tusks = null;
|
|
56
|
-
if (!piglet) {
|
|
57
|
-
if (male && !yearling) tusks = { lower: 0.085 + 0.04 * R(), upper: 0.04 + 0.015 * R(), r: 0.0085 + 0.002 * R(), curve: 0.75 + 0.25 * R() };
|
|
58
|
-
else if (male) tusks = { lower: 0.035 + 0.01 * R(), upper: 0.018, r: 0.006, curve: 0.5 };
|
|
59
|
-
else tusks = { lower: yearling ? 0.02 : 0.03 + 0.012 * R(), upper: 0.012, r: 0.0055, curve: 0.45 };
|
|
60
|
-
}
|
|
61
|
-
const shield = male && !yearling && !piglet ? 0.55 + 0.45 * R() : 0;
|
|
62
|
-
return {
|
|
63
|
-
sex, age, size, variant, stage: variant, coat, region,
|
|
64
|
-
tusks, shield,
|
|
65
|
-
snout: piglet ? 0.72 : yearling ? 0.9 : 1 + 0.05 * g(),
|
|
66
|
-
earSpread: R(),
|
|
67
|
-
winter: R(),
|
|
68
|
-
mane: piglet ? 0.4 : (male ? 1 : 0.8) * (0.85 + 0.3 * R()),
|
|
69
|
-
coatShade: g(), coatLightness: 0.1 * g(),
|
|
70
|
-
coatSeed: Math.floor(R() * 1e6),
|
|
71
|
-
minThick: 0.004,
|
|
72
|
-
warps: [
|
|
73
|
-
// (the head scale first: its centre is the unwarped head origin)
|
|
74
|
-
{ type: 'scaleAbout', c: HEAD_O, k: 1.06 * (1 + 0.035 * g()) * (piglet ? 1.18 : yearling ? 1.06 : 1) * (male && !yearling ? 1.05 : 1), r0: 0.14, r1: 0.26 },
|
|
75
|
-
{ type: 'legs', k: (1 + 0.035 * g()) * (piglet ? 1.08 : 1), top: 0.3 },
|
|
76
|
-
{ type: 'length', k: (1 + 0.035 * g()) * (piglet ? 0.86 : 1), z0: -0.45, z1: 0.25 },
|
|
77
|
-
{ type: 'girth', k: (1 + 0.04 * g()) * (male && !yearling ? 1.05 : 1) * (piglet ? 0.94 : 1), cy: 0.46, z0: -0.5, z1: 0.35 },
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
},
|
|
81
|
-
rig: (params) => boarRig(params),
|
|
82
|
-
sculpt: (m, rig, params) => sculptBoar(m, rig, params),
|
|
83
|
-
regions: boarRegions,
|
|
84
|
-
coat: boarCoat,
|
|
85
|
-
eyeSpecs: (params) => [1, -1].map((side) => ({ side, spec: EYE, headOrigin: HEAD_O, bone: 'head', look: eyeLook(params) })),
|
|
86
|
-
motion,
|
|
87
|
-
// (the head's silhouette fins are masked off in coat.js: with strandDensity 360 its sparse bristle cards drew a
|
|
88
|
-
// see-through fringe round the face, the skin's outline inside it; denser strands and a thicker undercoat
|
|
89
|
-
// keep the coat closed, the clumps keep it coarse)
|
|
90
|
-
render: { markColor: srgb(0x1a1716), strandDensity: 520, undercoat: 6, clumpDensity: 1.6, shellScale: 1, finWidth: 0.45, finMask: true, raiseLen: [0.06, 0.1] },
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// Small dark eyes, round pupil in a dark brown iris (amber-brown in bright light: face1), sclera hidden,
|
|
94
|
-
// dark lids.
|
|
95
|
-
const IRISES = [
|
|
96
|
-
{ inner: 0x3b2618, mid: 0x4e331f, hi: 0x6a4524, outer: 0x1e130c },
|
|
97
|
-
{ inner: 0x4a2e18, mid: 0x6a4524, hi: 0x8a5e30, outer: 0x2a1a0e },
|
|
98
|
-
];
|
|
99
|
-
function eyeLook(params) {
|
|
100
|
-
const s = ((params.coatSeed || 0) % 100) / 100;
|
|
101
|
-
const ir = IRISES[s < 0.7 ? 0 : 1];
|
|
102
|
-
return {
|
|
103
|
-
pupil: 'round',
|
|
104
|
-
lids: 'mammal',
|
|
105
|
-
iris: { inner: srgb(ir.inner), mid: srgb(ir.mid), hi: srgb(ir.hi), outer: srgb(ir.outer) },
|
|
106
|
-
sclera: { color: [0.5, 0.45, 0.4], visible: false },
|
|
107
|
-
lidColor: [0.02, 0.018, 0.016],
|
|
108
|
-
pupilSize: [0.25, 0.5],
|
|
109
|
-
};
|
|
110
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// Wild boar motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
|
|
2
|
-
// Numbers are for the reference individual (params.size = 1, a 0.75 m adult); the engine scales them
|
|
3
|
-
// by dynamic similarity for piglets, yearlings and big boars.
|
|
4
|
-
//
|
|
5
|
-
// Gaits (domestic-pig kinematics scaled to boar size and leg length):
|
|
6
|
-
// lateral-sequence walk (duty 0.68 -> 0.6, the slow foraging walk at 0.3-0.8 m/s), the trot as the
|
|
7
|
-
// main travelling gait (duty 0.45 -> 0.36, 2.0-2.4 Hz: short quick steps, head low and steady, the
|
|
8
|
-
// "scurrying" look of side3) and the transverse gallop with a suspension (LH, RH, LF, RF; up to
|
|
9
|
-
// ~11 m/s = 40 km/h). Walk -> trot at Froude ~0.45 (1.7 m/s for a 0.72 m hip height), trot -> gallop
|
|
10
|
-
// 4.5 m/s at 2.4 Hz (Heglund et al. 1974 for 90 kg).
|
|
11
|
-
import { hooks } from './behaviour.js';
|
|
12
|
-
|
|
13
|
-
const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
|
|
14
|
-
|
|
15
|
-
export const motion = {
|
|
16
|
-
maxSpeed: 10.5,
|
|
17
|
-
stride: { gallop: 0.5 }, // (short legs under a heavy forehand: half the gallop drop and reach, more stretched the neck)
|
|
18
|
-
accel: [4, 8],
|
|
19
|
-
decel: 8,
|
|
20
|
-
turnRate: 3.0, // agile for its mass: tight turns pivoting on the forehand
|
|
21
|
-
latAccelMax: 9,
|
|
22
|
-
gears: { walk: 0.9, trot: 2.8, gallop: 6.5 },
|
|
23
|
-
gallopBlend: [4.0, 6.5],
|
|
24
|
-
// name v f D [FL, FR, HL, HR]
|
|
25
|
-
gaits: [
|
|
26
|
-
G('walk', 0.0, 0.85, 0.68, [0.25, 0.75, 0.0, 0.5], { liftF: 0.04, liftH: 0.035, bobF: 0.01, bobH: 0.01, flex: 0, lat: 0.025, fold: 0.7, heel: 28, tail: 0, drop: 0 }),
|
|
27
|
-
G('walk', 1.4, 1.35, 0.6, [0.28, 0.78, 0.0, 0.5], { liftF: 0.05, liftH: 0.045, bobF: 0.018, bobH: 0.018, flex: 0, lat: 0.03, fold: 0.85, heel: 38, tail: 0.1, drop: 0 }),
|
|
28
|
-
G('trot', 1.9, 2.0, 0.45, [0.52, 0.02, 0.0, 0.5], { liftF: 0.065, liftH: 0.055, bobF: 0.02, bobH: 0.02, flex: 0.01, lat: 0.0, fold: 1.0, heel: 48, tail: 0.3, drop: 0.006 }),
|
|
29
|
-
G('trot', 4.0, 2.4, 0.36, [0.52, 0.02, 0.0, 0.5], { liftF: 0.08, liftH: 0.07, bobF: 0.026, bobH: 0.026, flex: 0.015, lat: 0.0, fold: 1.12, heel: 55, tail: 0.45, drop: 0.01 }),
|
|
30
|
-
G('gallop', 4.8, 2.45, 0.3, [0.55, 0.65, 0.0, 0.12], { liftF: 0.1, liftH: 0.09, bobF: 0.02, bobH: 0.028, flex: 0.07, lat: 0, fold: 1.3, heel: 45, tail: 0.7, drop: 0.018 }),
|
|
31
|
-
G('gallop', 10.5, 2.95, 0.22, [0.56, 0.66, 0.0, 0.12], { liftF: 0.12, liftH: 0.11, bobF: 0.022, bobH: 0.032, flex: 0.09, lat: 0, fold: 1.4, heel: 40, tail: 1.0, drop: 0.03 }),
|
|
32
|
-
],
|
|
33
|
-
feet: {
|
|
34
|
-
// cloven hooves on the claw tips: little fetlock sink, the digit flips in swing, breakover about
|
|
35
|
-
// the claw tips
|
|
36
|
-
front: { type: 'unguligrade', contact: 0.9, curl: 70, flex: 4, sink: 10, hoofFlex: 20, swingBack: 0.05 },
|
|
37
|
-
hind: { type: 'unguligrade', contact: 0.9, curl: 70, flex: 4, sink: 9, hoofFlex: 20, swingBack: 0.02 },
|
|
38
|
-
},
|
|
39
|
-
stance: { width: 1, gallopWidth: 0.8, sprawl: 0, crouch: 0, scuff: [10, 20, 0] },
|
|
40
|
-
// torso cross-sections (bind pose, reference size): centre height, half height, half width
|
|
41
|
-
// (measured on the bind mesh; half heights include the legs folded under the chest and thighs)
|
|
42
|
-
body: {
|
|
43
|
-
chest: { y: 0.47, hh: 0.24, hw: 0.2 },
|
|
44
|
-
mid: { y: 0.45, hh: 0.22, hw: 0.18 },
|
|
45
|
-
pelvis: { y: 0.47, hh: 0.22, hw: 0.16 },
|
|
46
|
-
back: 0.05,
|
|
47
|
-
},
|
|
48
|
-
head: {
|
|
49
|
-
// [speed, raise (m), reach (m), pitch (rad, + = nose down)]: the long head is carried low, the
|
|
50
|
-
// snout 20-35 cm off the ground walking; the trot keeps it low and steady; stretched forward in the
|
|
51
|
-
// gallop
|
|
52
|
-
carriage: [[0, 0.0, 0.0, -0.05], [0.9, -0.03, 0.01, 0.08], [2.8, -0.03, 0.03, 0.02], [5, -0.04, 0.05, 0.0], [9, -0.05, 0.07, -0.02]],
|
|
53
|
-
stab: [[0, 0], [0.9, 0.2], [2.8, 0.6], [5, 0.45], [9, 0.45]],
|
|
54
|
-
neckBend: 22, neckPivot: 0.6, yaw: 0.75, pitchUp: 0.75, pitchDown: 0.8, mouth: 'jawTip',
|
|
55
|
-
},
|
|
56
|
-
tail: {
|
|
57
|
-
// [speed, pitch per segment from horizontal (deg), base -> tip]: hangs against the buttocks at
|
|
58
|
-
// rest and walking, held out when trotting, straight up with the tassel flagging in the gallop
|
|
59
|
-
carriage: [
|
|
60
|
-
[0.0, [-35, -60, -72, -78, -82, -84]],
|
|
61
|
-
[1.4, [-30, -55, -68, -75, -80, -82]],
|
|
62
|
-
[2.5, [-5, -25, -40, -52, -60, -66]],
|
|
63
|
-
[5, [15, 12, 5, -5, -15, -25]],
|
|
64
|
-
[9, [32, 30, 25, 18, 8, 0]],
|
|
65
|
-
],
|
|
66
|
-
stiffness: 1.0, sway: 10, flick: 0, wag: 0, swish: 0.5, curl: 0, balance: 0,
|
|
67
|
-
radius: [0.02, 0.018],
|
|
68
|
-
},
|
|
69
|
-
ears: { rest: [0, 0], mobility: 1.1, speedFlatten: 0.35, flattenSpeeds: [3, 8], twitch: 1.2, prick: 0.5 },
|
|
70
|
-
breath: { rate: 0.3, amp: 0.006, pant: false, pantRate: 2, pantAmp: 0.015, heatSpeed: 6 },
|
|
71
|
-
actions: {
|
|
72
|
-
// rooting: the snout disc on the ground ahead of the forefeet (boar.js hooks: the ploughing thrusts)
|
|
73
|
-
eat: { style: 'graze', dropF: 0.05, dropH: 0, pitch: 0.75, ahead: 0.42 },
|
|
74
|
-
drink: { dropF: 0.06, dropH: 0, pitch: 0.7, ahead: 0.45 },
|
|
75
|
-
// jumps high for its size (1.4-1.5 m fences, research); a compact tuck
|
|
76
|
-
jump: { height: 0.8, distance: 1.6, land: [0.25, 0.22] },
|
|
77
|
-
sit: { dropH: 0.85 },
|
|
78
|
-
// down on the carpi first, then the hindquarters; up forelegs first (dog-sitting)
|
|
79
|
-
lie: { down: 'front', up: 'front' },
|
|
80
|
-
sleep: { style: 'lateral', down: 'front', up: 'front' },
|
|
81
|
-
fold: { front: { z: -0.2, k: 1.45, beta: 0.9 } },
|
|
82
|
-
attack: { style: 'charge' },
|
|
83
|
-
},
|
|
84
|
-
hooks,
|
|
85
|
-
};
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// Meshing plan: body at 6.7 mm (0.9 % of the withers height), head at 3.3 mm overlapping the body
|
|
2
|
-
// across the upper neck and cross-faded, eyelid patches at 0.9 mm, the lower lip / chin as its own
|
|
3
|
-
// rigid surface (the mouth opens), the tusks as rigid ivory surfaces (lower on the jaw, upper on the
|
|
4
|
-
// skull).
|
|
5
|
-
//
|
|
6
|
-
// Seam. The skinning relaxes the axial coordinate and solves the limb fields over each surface
|
|
7
|
-
// separately, so the two overlapping surfaces move alike only where their weights do not depend on the
|
|
8
|
-
// surface. The throat and the lower neck lie beside the upper arms, and the forelimb field of the body
|
|
9
|
-
// surface reaches into them (the head surface has no limb at all): a cut through them tore open
|
|
10
|
-
// whenever a foreleg or the head moved. So the cut leans forward at the bottom (like the horse's and
|
|
11
|
-
// the cow's): behind the ears at the top, in front of the throat below (the throat, the jowl angle and
|
|
12
|
-
// the lower neck belong to the body surface), and far in front of the forefeet (a cut leaning back
|
|
13
|
-
// reached the ground at z 0.21 m and cut off the fore claws). Both surfaces carry on past the band by
|
|
14
|
-
// M (the relaxation is one-sided next to a surface's open edge), and the band widens with the tier so
|
|
15
|
-
// it is always wider than a body cell.
|
|
16
|
-
import { EYE, tuskPath } from './sculpt.js';
|
|
17
|
-
import { HEAD_O, hl } from './rig.js';
|
|
18
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
19
|
-
import { norm, smoothstep } from '../../core/math/vec.js';
|
|
20
|
-
|
|
21
|
-
const ENV = (typeof process !== 'undefined' && process.env) || {};
|
|
22
|
-
const cutC = ENV.BOAR_CUT_C ? ENV.BOAR_CUT_C.split(',').map(Number) : [0, 0.62, 0.40];
|
|
23
|
-
const cutD = ENV.BOAR_CUT_D ? ENV.BOAR_CUT_D.split(',').map(Number) : [0, 0.45, 1];
|
|
24
|
-
export const NECK_CUT = { c: cutC, d: norm(cutD), band: 0.014 };
|
|
25
|
-
export const neckS = (x, y, z) => (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];
|
|
26
|
-
|
|
27
|
-
export const EYE_PATCH = { R: 0.02, B: 0.004, h: 0.0009, centres: [1, -1].map((c) => eyeFrameOf(EYE, HEAD_O, c).c) };
|
|
28
|
-
export function eyePatchWeight(x, y, z) {
|
|
29
|
-
let dmin = 1e9;
|
|
30
|
-
for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
|
|
31
|
-
return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// head-local box -> world bounds
|
|
35
|
-
function boxOf(lo, hi, pad = 0) {
|
|
36
|
-
const mn = [1e9, 1e9, 1e9], mx = [-1e9, -1e9, -1e9];
|
|
37
|
-
for (const x of [lo[0], hi[0]]) for (const y of [lo[1], hi[1]]) for (const z of [lo[2], hi[2]]) {
|
|
38
|
-
const p = hl([x, y, z]);
|
|
39
|
-
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); }
|
|
40
|
-
}
|
|
41
|
-
return [mn, mx];
|
|
42
|
-
}
|
|
43
|
-
function pathBox(paths, pad) {
|
|
44
|
-
const mn = [1e9, 1e9, 1e9], mx = [-1e9, -1e9, -1e9];
|
|
45
|
-
for (const P of paths) for (const q of P) for (let i = 0; i < 3; i++) { mn[i] = Math.min(mn[i], q.p[i] - q.r - pad); mx[i] = Math.max(mx[i], q.p[i] + q.r + pad); }
|
|
46
|
-
return [mn, mx];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function boarRegions(rig, params, Q) {
|
|
50
|
-
const r = Q.res;
|
|
51
|
-
const hBody = 0.0067 * r, hHead = 0.0033 * r;
|
|
52
|
-
// the band is wider than a body cell at every tier; both surfaces run on past it by M
|
|
53
|
-
const B = Math.max(NECK_CUT.band, 1.2 * hBody), M = Math.min(3 * hBody, 0.04);
|
|
54
|
-
const patches = Q.eyePatches ? EYE_PATCH.centres.map((c) => ({ c, R: EYE_PATCH.R, B: EYE_PATCH.B, h: EYE_PATCH.h * Math.max(1, r) })) : [];
|
|
55
|
-
const [hmn, hmx] = boxOf([-0.16, -0.22, -0.3], [0.16, 0.26, 0.36], 0.02);
|
|
56
|
-
const [jmn, jmx] = boxOf([-0.06, -0.14, -0.12], [0.06, -0.03, 0.32], 0.01);
|
|
57
|
-
const head = [
|
|
58
|
-
{ name: 'head', part: 'body', bmin: hmn, bmax: hmx, h: hHead, F: 6, clip: (x, y, z) => neckS(x, y, z) > -B - M, patches },
|
|
59
|
-
{ name: 'jaw', part: 'jaw', bmin: jmn, bmax: jmx, h: hHead, F: 6, rigidBone: 'jaw' },
|
|
60
|
-
];
|
|
61
|
-
const lower = [tuskPath(params, 1, 'lower'), tuskPath(params, -1, 'lower')].filter((p) => p.length);
|
|
62
|
-
const upper = [tuskPath(params, 1, 'upper'), tuskPath(params, -1, 'upper')].filter((p) => p.length);
|
|
63
|
-
if (lower.length) {
|
|
64
|
-
const [a, b] = pathBox(lower, 0.012);
|
|
65
|
-
head.push({ name: 'tusk', part: 'tusk', bmin: a, bmax: b, h: 0.0015 * r, F: 6, rigidBone: 'jaw' });
|
|
66
|
-
}
|
|
67
|
-
if (upper.length) {
|
|
68
|
-
const [a, b] = pathBox(upper, 0.012);
|
|
69
|
-
head.push({ name: 'tuskup', part: 'tuskup', bmin: a, bmax: b, h: 0.0015 * r, F: 6, rigidBone: 'head' });
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
jobs: [
|
|
73
|
-
// (the box floor lies a few cells under the soles: the claws are meshed whole at every tier)
|
|
74
|
-
[{ name: 'body', part: 'body', bmin: [-0.28, -0.03, -0.68], bmax: [0.28, 0.82, 0.62], h: hBody, F: 4, clip: (x, y, z) => neckS(x, y, z) < B + M }],
|
|
75
|
-
head,
|
|
76
|
-
],
|
|
77
|
-
fade(x, y, z, name, patch) {
|
|
78
|
-
const sN = neckS(x, y, z);
|
|
79
|
-
if (name === 'body') return 1 - smoothstep(-B, B, sN);
|
|
80
|
-
if (name === 'head') {
|
|
81
|
-
let f = smoothstep(-B, B, sN);
|
|
82
|
-
if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
|
|
83
|
-
return f;
|
|
84
|
-
}
|
|
85
|
-
return 1;
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|