@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,391 +0,0 @@
|
|
|
1
|
-
// The white-tailed deer's coat: summer red-brown or winter grey-brown (hollow guard hair, longer),
|
|
2
|
-
// darker along the back and on the forehead, white belly / inner legs / groin, white throat patch,
|
|
3
|
-
// white eye ring, white band behind the black nose, white chin and lower lip with dark lip-corner
|
|
4
|
-
// spots, ears grey-brown outside with a dark rim and white hair inside, the tail brown above with a
|
|
5
|
-
// white fringe and a white underside, tan lower legs with dark hooves, the tarsal gland tuft (dark in
|
|
6
|
-
// bucks) and the fawn's rows of white spots. Hair flow follows the cervid hair tracts. Antlers:
|
|
7
|
-
// bone-coloured keratin, dark at the burr, polished pale tips (velvet when growing).
|
|
8
|
-
// Works in the reference space (see rig.js); seeded variation picks the season, shade and spots.
|
|
9
|
-
import { HEAD_O, HZ, HY, hl, bz } from './rig.js';
|
|
10
|
-
import { neckS } from './regions.js';
|
|
11
|
-
import { SDFModel } from '../../core/sdf/sdf.js';
|
|
12
|
-
const lerp3 = (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t];
|
|
13
|
-
import { norm, sub, dot, cross, len, add, mul, smoothstep, clamp, mix, rng, fbm3, vnoise3 } from '../../core/math/vec.js';
|
|
14
|
-
import { srgb, mix3, MAT, poissonFeatures, featureDistance, smoothField, distPolyline } from '../../core/build/coatKit.js';
|
|
15
|
-
|
|
16
|
-
// sRGB swatches sampled from the reference photos in neutral light
|
|
17
|
-
export const COATS = {
|
|
18
|
-
summer: { body: 0x9a6f50, dorsal: 0x825a3e, side: 0xa87e5e, head: 0x8e6c50, forehead: 0x684a34, face: 0x8e7a68, legs: 0x9e7c5c, fur: 0.007 },
|
|
19
|
-
winter: { body: 0x988670, dorsal: 0x7a6a56, side: 0xa8977f, head: 0x928675, forehead: 0x645240, face: 0xa39d94, legs: 0x9e8a6e, fur: 0.012 },
|
|
20
|
-
fawn: { body: 0x93603e, dorsal: 0x7c5034, side: 0xa06e4c, head: 0x8c6646, forehead: 0x6e4a30, face: 0x8c7462, legs: 0x9a7656, fur: 0.008 },
|
|
21
|
-
};
|
|
22
|
-
const WHITE = 0xefeae0, SPOT = 0xeee4d0, NOSE = 0x1a1a1a, BAND = 0x1e1a18, HOOF = 0x262220, EAR_RIM = 0x3a2e26, EAR_IN = 0xede7dc;
|
|
23
|
-
const ANTLER = { burr: 0x5e4a36, beam: 0x7e6650, tip: 0xd8ccb4, velvet: 0x6b5445 };
|
|
24
|
-
|
|
25
|
-
function palette(p) {
|
|
26
|
-
const C = COATS[p.age === 'juvenile' ? 'fawn' : p.coat] || COATS.winter;
|
|
27
|
-
const k = p.coatShade || 0, l = p.coatLightness || 0;
|
|
28
|
-
// shade: - greyer / + redder, lightness +-
|
|
29
|
-
const tw = (hex) => { const c = srgb(hex); return [c[0] * (1 + 0.07 * k + l), c[1] * (1 + 0.01 * k + l), c[2] * (1 - 0.08 * k + l)]; };
|
|
30
|
-
const out = {};
|
|
31
|
-
for (const key of ['body', 'dorsal', 'side', 'head', 'forehead', 'face', 'legs']) out[key] = tw(C[key]);
|
|
32
|
-
out.fur = C.fur;
|
|
33
|
-
out.white = srgb(WHITE); out.spot = srgb(SPOT); out.nose = srgb(NOSE); out.band = srgb(BAND); out.hoof = srgb(HOOF);
|
|
34
|
-
out.earRim = srgb(EAR_RIM); out.earIn = srgb(EAR_IN);
|
|
35
|
-
return out;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const HOOF_TAGS = new Set(['hoof', 'heelbulb', 'dewclaw']);
|
|
39
|
-
|
|
40
|
-
export function deerCoat(ctx) {
|
|
41
|
-
const { model, rig, pos, nrm, regionOf, regionNames, weights, nV, params, lists } = ctx;
|
|
42
|
-
const { BONES } = rig;
|
|
43
|
-
const J = rig.J;
|
|
44
|
-
const R = rng(4243 + (params.coatSeed || 0));
|
|
45
|
-
const COL = palette(params);
|
|
46
|
-
const fawn = params.age === 'juvenile';
|
|
47
|
-
const buck = params.sex === 'male' && !fawn;
|
|
48
|
-
const { dominant, axialS, skinIndex, skinWeight, limbMember } = weights;
|
|
49
|
-
const AX_LEN = weights.axialLengths;
|
|
50
|
-
const P = (v) => [pos[v * 3], pos[v * 3 + 1], pos[v * 3 + 2]];
|
|
51
|
-
const N = (v) => [nrm[v * 3], nrm[v * 3 + 1], nrm[v * 3 + 2]];
|
|
52
|
-
const sOcc = AX_LEN[1], sNeckBase = AX_LEN[3], sTailBase = AX_LEN[8];
|
|
53
|
-
const eyePrims = model.prims.filter((p) => p.tag === 'eyesocket');
|
|
54
|
-
const jawPrims = model.forPart('jaw');
|
|
55
|
-
const headPrims = model.forPart('body').filter((p) => p.bone === 'head' && !p.carve);
|
|
56
|
-
const nostrilPrims = model.prims.filter((p) => p.tag === 'nostril');
|
|
57
|
-
const glandPrims = model.prims.filter((p) => p.tag === 'preorbital');
|
|
58
|
-
const isLimb = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw|fhoof|femur|tibia|metatarsus|hpaw|hhoof)/.test(b.name));
|
|
59
|
-
const tailIdx = (name) => (name.startsWith('tail') ? +name.slice(4) : -1);
|
|
60
|
-
const HL = (p) => { const d = sub(p, HEAD_O); return [d[0], dot(d, HY), dot(d, HZ)]; };
|
|
61
|
-
const rn = regionNames.map((n) => n);
|
|
62
|
-
const JAW_R = rn.indexOf('jaw'), ANT_R = rn.indexOf('antler'), HEAD_R = rn.indexOf('head');
|
|
63
|
-
|
|
64
|
-
// --- nearest primitive tag per vertex
|
|
65
|
-
const tagOf = new Array(nV);
|
|
66
|
-
for (let v = 0; v < nV; v++) {
|
|
67
|
-
const L = lists[v], p = P(v);
|
|
68
|
-
let best = 1e9, t = '';
|
|
69
|
-
for (const pr of L) {
|
|
70
|
-
if (pr.carve) continue;
|
|
71
|
-
const d = SDFModel.dist(pr, p[0], p[1], p[2]);
|
|
72
|
-
if (d < best) { best = d; t = pr.tag; }
|
|
73
|
-
}
|
|
74
|
-
tagOf[v] = t;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// --- regions: 0 torso, 1 neck, 2 head, 4 tail, 5 ear, 6 jaw, 8 antler
|
|
78
|
-
const region = new Uint8Array(nV);
|
|
79
|
-
const legness = new Float32Array(nV);
|
|
80
|
-
const legBone = new Int16Array(nV).fill(-1);
|
|
81
|
-
for (let v = 0; v < nV; v++) {
|
|
82
|
-
const bn = BONES[dominant[v]].name, p = P(v);
|
|
83
|
-
let lb = -1, lw = 0;
|
|
84
|
-
for (let k = 0; k < 4; k++) {
|
|
85
|
-
const b = skinIndex[v * 4 + k], w = skinWeight[v * 4 + k];
|
|
86
|
-
if (isLimb[b] && w > lw) { lw = w; lb = b; }
|
|
87
|
-
}
|
|
88
|
-
legBone[v] = lb;
|
|
89
|
-
legness[v] = lb >= 0 ? smoothstep(0.15, 0.85, limbMember[v]) : 0;
|
|
90
|
-
const ti = tailIdx(bn);
|
|
91
|
-
if (regionOf[v] === ANT_R) region[v] = 8;
|
|
92
|
-
else if (regionOf[v] === JAW_R) region[v] = 6;
|
|
93
|
-
else if (bn.startsWith('ear')) region[v] = 5;
|
|
94
|
-
else if (ti >= 0 && axialS[v] > sTailBase + 0.01 || tagOf[v] === 'tail') region[v] = 4;
|
|
95
|
-
else if (axialS[v] < sOcc + 0.01 || (regionOf[v] === HEAD_R && neckS(p[0], p[1], p[2]) > 0.015)) region[v] = 2;
|
|
96
|
-
else if (axialS[v] < sNeckBase) region[v] = 1;
|
|
97
|
-
else region[v] = 0;
|
|
98
|
-
if (region[v] >= 2) legness[v] = 0;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// --- tail frame: which side of the flat tail a vertex is on (dorsal = brown, ventral = white)
|
|
102
|
-
const tailSide = (v) => {
|
|
103
|
-
const bone = BONES[dominant[v]];
|
|
104
|
-
const d = norm(sub(bone.tail, bone.head));
|
|
105
|
-
const lat = [1, 0, 0];
|
|
106
|
-
const back = norm(cross(lat, d)); // points away from the rump (the tail's outer / dorsal face)
|
|
107
|
-
return dot(N(v), back);
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
// --- white areas as one signed field (< 0 inside), with softly jagged edges
|
|
111
|
-
const throatC = lerp3(hl([0, -0.068, -0.045]), [0, 0.64, 0.39], 0.45); // white throat patch on the upper throat, below the jaw
|
|
112
|
-
const throatN = norm([0, -0.35, 1]);
|
|
113
|
-
const throatD = (p, n, rx, ry) => (dot(n, throatN) < 0.1 ? 1 : Math.hypot(p[0] / rx, (p[1] - throatC[1]) / ry, (p[2] - throatC[2]) / 0.06) * 0.03 - 0.03);
|
|
114
|
-
const whiteSDF = (v) => {
|
|
115
|
-
const p = P(v), r = region[v], n = N(v);
|
|
116
|
-
const jag = (fbm3(p[0] * 70, p[1] * 70, p[2] * 70, 2) - 0.5) * 0.012;
|
|
117
|
-
let d = 1;
|
|
118
|
-
if (r === 2 || r === 6) {
|
|
119
|
-
const h = HL(p), ax = Math.abs(h[0]);
|
|
120
|
-
// chin and lower lip (the jaw), the white band behind the nose, around the muzzle
|
|
121
|
-
if (r === 6) d = -0.006;
|
|
122
|
-
const band = Math.max(Math.abs(h[2] - 0.158) - 0.011 - 0.004 * smoothstep(0.0, -0.03, h[1]), -0.03 - h[1]);
|
|
123
|
-
d = Math.min(d, band);
|
|
124
|
-
// lower lip line / under the chin on the head surface too
|
|
125
|
-
if (h[1] < -0.036 && h[2] > 0.12) d = Math.min(d, (h[1] + 0.036) * 0.5 - 0.002);
|
|
126
|
-
// eye ring
|
|
127
|
-
for (const e of eyePrims) {
|
|
128
|
-
const de = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
129
|
-
d = Math.min(d, Math.abs(de + 0.0005) - 0.0075);
|
|
130
|
-
}
|
|
131
|
-
// throat patch continues under the jaw angle (head region skin of the throat latch)
|
|
132
|
-
d = Math.min(d, throatD(p, n, 0.034, 0.04));
|
|
133
|
-
if (ax > 0.05 && h[2] < 0.1) d = Math.max(d, 0.02);
|
|
134
|
-
return d + jag * 0.5;
|
|
135
|
-
}
|
|
136
|
-
if (r === 1 || r === 0) {
|
|
137
|
-
// throat patch: an oval bib on the upper throat
|
|
138
|
-
d = Math.min(d, throatD(p, n, 0.036, 0.045));
|
|
139
|
-
// belly, groin and the insides of the legs: below the flank line on the underside
|
|
140
|
-
const belly = r === 0 ? (p[1] - (0.5 + 0.05 * smoothstep(0.1, bz(-0.35), p[2]) + 0.06 * smoothstep(bz(-0.2), bz(-0.45), p[2]))) + 0.06 * (n[1] + 0.5) + 0.12 * smoothstep(0.1, 0.24, p[2]) : 1;
|
|
141
|
-
if (legness[v] < 0.5) d = Math.min(d, belly);
|
|
142
|
-
// buttocks: a white band along the inside of the thighs under the tail
|
|
143
|
-
if (r === 0 && p[2] < bz(-0.5)) d = Math.min(d, Math.abs(p[0]) - 0.04 * smoothstep(0.72, 0.6, p[1]) + (p[1] > 0.72 ? 1 : 0));
|
|
144
|
-
const L = legness[v];
|
|
145
|
-
if (L > 0) {
|
|
146
|
-
const side = p[0] >= 0 ? 1 : -1;
|
|
147
|
-
const inner = n[0] * side; // < 0: faces the other leg
|
|
148
|
-
const lbn = BONES[legBone[v]].name;
|
|
149
|
-
const hind = /femur|tibia|metatarsus|hpaw|hhoof/.test(lbn);
|
|
150
|
-
// inside of the upper legs white down to the knee / hock
|
|
151
|
-
// (hind: the inner thigh down to the hock; fore: only the inside of the cannon, below the
|
|
152
|
-
// carpus: a white edge over the elbow crease smeared as the elbow folds)
|
|
153
|
-
const top = hind ? 0.5 : 0.26, bottom = hind ? 0.36 : 0.12;
|
|
154
|
-
const dIn = inner + 0.35;
|
|
155
|
-
d = Math.min(d, mix(1, dIn * 0.05, L) + (p[1] > top ? (p[1] - top) * 0.5 : 0) + (p[1] < bottom ? (bottom - p[1]) * 0.5 : 0));
|
|
156
|
-
// white fetlock band above the hooves (front of the pasterns)
|
|
157
|
-
if (/metacarpus|metatarsus|fpaw|hpaw/.test(lbn) && p[1] < 0.075 && p[1] > 0.035) d = Math.min(d, 0.012 - (0.075 - p[1]) * 0.5 * smoothstep(-0.2, 0.3, n[2]));
|
|
158
|
-
}
|
|
159
|
-
return d + jag;
|
|
160
|
-
}
|
|
161
|
-
if (r === 4) {
|
|
162
|
-
// tail: white underside and a white fringe on the edges
|
|
163
|
-
const ts = tailSide(v);
|
|
164
|
-
return Math.min(ts + 0.25, 0.012 - Math.abs(n[0]) * 0.02) + jag * 0.5;
|
|
165
|
-
}
|
|
166
|
-
return 1;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
// --- fawn spots: rows along the spine, scattered on the flanks
|
|
170
|
-
let spots = null;
|
|
171
|
-
if (fawn) {
|
|
172
|
-
spots = poissonFeatures({
|
|
173
|
-
pos, nrm, nV, R, cell: 0.05, spacing: 2.6, gap: 0.006,
|
|
174
|
-
radius: (v) => {
|
|
175
|
-
const p = P(v), n = N(v);
|
|
176
|
-
if (region[v] > 0 || legness[v] > 0.3 || n[1] < 0.0 || p[2] < bz(-0.52) || p[2] > 0.3) return 0;
|
|
177
|
-
// rows either side of the spine, thinning out down the flanks
|
|
178
|
-
const ax = Math.abs(p[0]);
|
|
179
|
-
const row = Math.min(Math.abs(ax - 0.035), Math.abs(ax - 0.075));
|
|
180
|
-
if (p[1] < 0.66 || (row > 0.012 && R() < 0.55)) return 0;
|
|
181
|
-
return 0.006 + 0.002 * R();
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// --- comb (hair flow)
|
|
187
|
-
const comb = new Float32Array(nV * 3);
|
|
188
|
-
const whorl = [0, 0.03, 0.02]; // forehead whorl, head-local
|
|
189
|
-
for (let v = 0; v < nV; v++) {
|
|
190
|
-
const p = P(v), n = N(v), r = region[v];
|
|
191
|
-
const bone = BONES[dominant[v]];
|
|
192
|
-
let d;
|
|
193
|
-
if (r === 5 || r === 8) d = norm(sub(bone.tail, bone.head));
|
|
194
|
-
else if (r === 2 || r === 6) {
|
|
195
|
-
const h = HL(p);
|
|
196
|
-
const rel = [h[0] - whorl[0], (h[1] - whorl[1]) * 0.4 - 0.04, h[2] - whorl[2] + 0.05];
|
|
197
|
-
d = norm(add(mul(HY, rel[1]), add(mul(HZ, rel[2]), [rel[0], 0, 0])));
|
|
198
|
-
if (h[2] < -0.06) d = norm(add(d, [0, -0.6, -0.8]));
|
|
199
|
-
} else if (r === 4) {
|
|
200
|
-
d = norm(sub(bone.tail, bone.head));
|
|
201
|
-
d = norm(add(d, [0, 0, 0]));
|
|
202
|
-
} else {
|
|
203
|
-
const seg = weights.segT[v * 2] | 0;
|
|
204
|
-
const a = rig.AXIAL.points[seg], b = rig.AXIAL.points[Math.min(seg + 1, rig.AXIAL.points.length - 1)];
|
|
205
|
-
d = norm(sub(b, a));
|
|
206
|
-
if (r === 0) d = norm(add(d, [0, -0.45 * Math.abs(n[0]), 0]));
|
|
207
|
-
if (r === 1) d = norm(add(d, [0, -0.6, 0.05]));
|
|
208
|
-
const L = legness[v];
|
|
209
|
-
if (L > 0 && legBone[v] >= 0) {
|
|
210
|
-
const lbn = BONES[legBone[v]];
|
|
211
|
-
let dl = norm(sub(lbn.tail, lbn.head));
|
|
212
|
-
if (/hoof/.test(lbn.name)) dl = [0, -1, 0.1];
|
|
213
|
-
else dl = norm(add(dl, [0, -0.3, 0]));
|
|
214
|
-
d = norm(add(mul(d, 1 - L), mul(dl, L)));
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
let t = sub(d, mul(n, dot(d, n)));
|
|
218
|
-
if (len(t) < 1e-4) t = cross(n, [1, 0, 0]);
|
|
219
|
-
t = norm(t);
|
|
220
|
-
comb[v * 3] = t[0]; comb[v * 3 + 1] = t[1]; comb[v * 3 + 2] = t[2];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// --- antler colour along its length (distance from the burr)
|
|
224
|
-
const A = params.antlers;
|
|
225
|
-
const burrs = A ? [1, -1].map((s) => hl([A.burr[0] * s, A.burr[1], A.burr[2]])) : [];
|
|
226
|
-
|
|
227
|
-
// --- per-vertex fields
|
|
228
|
-
const pattern = new Float32Array(nV).fill(1);
|
|
229
|
-
const patInt = new Float32Array(nV);
|
|
230
|
-
const patCol = new Float32Array(nV * 3);
|
|
231
|
-
const markSDF = new Float32Array(nV).fill(1);
|
|
232
|
-
const furLen = new Float32Array(nV);
|
|
233
|
-
const tint = new Float32Array(nV * 4);
|
|
234
|
-
const surf = new Float32Array(nV * 4);
|
|
235
|
-
const coatFur = COL.fur;
|
|
236
|
-
|
|
237
|
-
for (let v = 0; v < nV; v++) {
|
|
238
|
-
const p = P(v), n = N(v), r = region[v], tag = tagOf[v];
|
|
239
|
-
let col, mat = MAT.FUR, fl = coatFur, mark = 1, gloss = 0.5;
|
|
240
|
-
let wsdf = whiteSDF(v);
|
|
241
|
-
const lb = legBone[v];
|
|
242
|
-
const lbName = lb >= 0 ? BONES[lb].name : '';
|
|
243
|
-
if (r === 0 || r === 1) {
|
|
244
|
-
const up = clamp(n[1], -1, 1);
|
|
245
|
-
// countershading: dark along the spine, lighter low on the flanks
|
|
246
|
-
col = mix3(COL.body, COL.dorsal, smoothstep(0.35, 0.95, up) * 0.85);
|
|
247
|
-
col = mix3(col, COL.side, smoothstep(0.0, -0.6, up) * 0.6);
|
|
248
|
-
if (r === 1) col = mix3(col, COL.head, 0.25);
|
|
249
|
-
fl = coatFur * (r === 1 ? 1.1 : 1);
|
|
250
|
-
// chest between the forelegs: darker
|
|
251
|
-
if (r === 0 && p[2] > 0.3 && p[1] < 0.66) col = mix3(col, COL.dorsal, 0.35 * smoothstep(0.3, 0.42, p[2]));
|
|
252
|
-
const L = legness[v];
|
|
253
|
-
if (L > 0) {
|
|
254
|
-
let lc = mix3(col, COL.legs, smoothstep(0.55, 0.3, p[1]));
|
|
255
|
-
// front of the cannons a little darker, backs of the legs paler
|
|
256
|
-
if (p[1] < 0.35) lc = mix3(lc, COL.dorsal, 0.25 * smoothstep(0.1, 0.8, n[2]));
|
|
257
|
-
col = mix3(col, lc, L);
|
|
258
|
-
fl = mix(fl, mix(0.004, coatFur * 0.8, smoothstep(0.2, 0.55, p[1])), L);
|
|
259
|
-
// tarsal gland: a tuft on the inside of the hock, stained dark in bucks
|
|
260
|
-
const hind = /tibia|metatarsus/.test(lbName);
|
|
261
|
-
if (hind) {
|
|
262
|
-
const side = p[0] >= 0 ? 1 : -1;
|
|
263
|
-
const Hk = J['hock' + BONES[lb].side];
|
|
264
|
-
const dg = Math.hypot((p[1] - Hk[1] - 0.015) / 0.028, (p[2] - Hk[2] + 0.012) / 0.02);
|
|
265
|
-
if (dg < 1.2 && n[0] * side < -0.2) { col = mix3(col, buck ? srgb(0x2e2218) : srgb(0x6a5440), smoothstep(1.2, 0.7, dg)); fl = Math.max(fl, 0.02 * smoothstep(1.2, 0.5, dg)); }
|
|
266
|
-
// metatarsal gland: a small pale-rimmed tuft on the outside of the hind cannon
|
|
267
|
-
const dm = Math.hypot((p[1] - (Hk[1] - 0.12)) / 0.018, (p[2] - Hk[2] - 0.004) / 0.012);
|
|
268
|
-
if (dm < 1.3 && n[0] * side > 0.3) { col = mix3(col, dm < 0.7 ? srgb(0x4a3a2a) : srgb(0xd8d0c0), smoothstep(1.3, 0.9, dm)); fl = Math.max(fl, 0.012); }
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
// hoof wall, dew claws
|
|
272
|
-
const Cj = /hoof|paw/.test(lbName) ? J[(lbName[0] === 'f' ? 'fcoffin' : 'hcoffin') + BONES[lb].side] : null;
|
|
273
|
-
if (Cj && HOOF_TAGS.has(tag) && (tag === 'dewclaw' || p[1] < Cj[1] + 0.006 + 0.35 * (p[2] - Cj[2]))) {
|
|
274
|
-
mat = MAT.KERATIN; fl = 0; gloss = 0.5; col = COL.hoof;
|
|
275
|
-
if (tag === 'heelbulb') col = mix3(col, srgb(0x3a3430), 0.5);
|
|
276
|
-
wsdf = 1;
|
|
277
|
-
}
|
|
278
|
-
} else if (r === 4) {
|
|
279
|
-
// tail: brown on top (darker along the midline), long white hair on the edges and below
|
|
280
|
-
const ts = tailSide(v);
|
|
281
|
-
col = mix3(COL.dorsal, COL.body, smoothstep(0.3, 0.9, Math.abs(n[0])));
|
|
282
|
-
fl = 0.02 + 0.03 * smoothstep(0.2, 0.9, Math.abs(n[0])) + 0.015 * smoothstep(0.2, -0.5, ts);
|
|
283
|
-
const ti = tailIdx(BONES[dominant[v]].name);
|
|
284
|
-
if (ti >= 4) col = mix3(col, srgb(0x3a2c20), 0.4 * smoothstep(0.2, 0.9, ts)); // dark tip above
|
|
285
|
-
} else if (r === 5) {
|
|
286
|
-
// ears: coat colour outside with a dark rim, white hair inside
|
|
287
|
-
const earP = model.prims.find((q) => q.tag === 'ear' && (q.bone === (p[0] > 0 ? 'earL' : 'earR')));
|
|
288
|
-
const faceDir = [earP.P[9], earP.P[10], earP.P[11]];
|
|
289
|
-
const front = dot(n, faceDir);
|
|
290
|
-
col = mix3(COL.head, COL.face, 0.4);
|
|
291
|
-
fl = 0.005;
|
|
292
|
-
// rim: distance from the pinna's edge ~ where the normal turns sideways
|
|
293
|
-
const bone = BONES[dominant[v]];
|
|
294
|
-
const ax = norm(sub(bone.tail, bone.head));
|
|
295
|
-
const along = dot(sub(p, bone.head), ax) / Math.max(1e-4, len(sub(bone.tail, bone.head)));
|
|
296
|
-
const edge = 1 - Math.abs(front);
|
|
297
|
-
col = mix3(col, COL.earRim, smoothstep(0.55, 0.9, edge) * 0.7 + 0.5 * smoothstep(0.8, 1.0, along));
|
|
298
|
-
if (front > 0.25) { fl = 0.011 * smoothstep(0.95, 0.5, along); col = mix3(col, COL.earIn, smoothstep(0.25, 0.6, front) * 0.85 * smoothstep(1.0, 0.75, along)); }
|
|
299
|
-
} else if (r === 8) {
|
|
300
|
-
// antler: dark rough burr and beam base, lighter beam, polished pale tips
|
|
301
|
-
mat = MAT.KERATIN; fl = 0; gloss = 0.35;
|
|
302
|
-
let db = 1e9;
|
|
303
|
-
for (const b of burrs) db = Math.min(db, len(sub(p, b)));
|
|
304
|
-
const tipness = smoothstep(0.02, 0.01, SDFModel.evalList(model.forPart('antler').filter((q) => q.tag === 'tine' || q.tag === 'beam'), p[0], p[1], p[2]) + 0.012);
|
|
305
|
-
col = mix3(srgb(ANTLER.burr), srgb(ANTLER.beam), smoothstep(0.012, 0.05, db));
|
|
306
|
-
const tipT = smoothstep(0.1, 0.35, db);
|
|
307
|
-
col = mix3(col, srgb(ANTLER.tip), tipT * 0.45);
|
|
308
|
-
if (tag === 'tine') col = mix3(col, srgb(ANTLER.tip), 0.2);
|
|
309
|
-
void tipness;
|
|
310
|
-
if (A && A.velvet) { mat = MAT.FUR; fl = 0.003; col = srgb(ANTLER.velvet); gloss = 0.3; }
|
|
311
|
-
// grooves / pearling: fine dark streaks along the beam
|
|
312
|
-
const st = vnoise3(p[0] * 300, p[1] * 90, p[2] * 300);
|
|
313
|
-
col = mul(col, 0.85 + 0.3 * st);
|
|
314
|
-
wsdf = 1;
|
|
315
|
-
} else {
|
|
316
|
-
// head & jaw
|
|
317
|
-
const h = HL(p);
|
|
318
|
-
col = mix3(COL.head, COL.face, smoothstep(-0.02, 0.1, h[2]) * 0.6);
|
|
319
|
-
fl = 0.0045;
|
|
320
|
-
// darker forehead patch (bucks especially) and the dark bridge of the nose
|
|
321
|
-
const fh = smoothstep(0.015, 0.035, h[1]) * smoothstep(0.09, 0.0, h[2]) * smoothstep(-0.1, -0.04, h[2]);
|
|
322
|
-
col = mix3(col, COL.forehead, fh * (buck ? 0.9 : 0.55));
|
|
323
|
-
col = mix3(col, COL.forehead, smoothstep(0.012, 0.024, h[1]) * smoothstep(0.02, 0.1, h[2]) * smoothstep(0.17, 0.12, h[2]) * 0.35 * smoothstep(0.02, 0.0, Math.abs(h[0])));
|
|
324
|
-
if (h[2] < -0.07) col = mix3(col, COL.body, smoothstep(-0.07, -0.11, h[2]));
|
|
325
|
-
// black nose leather (rhinarium)
|
|
326
|
-
if (h[2] > 0.168 && h[1] > -0.03 && tag !== 'upperlip' || (tag === 'nose' && h[2] > 0.16)) {
|
|
327
|
-
const nz = smoothstep(0.168, 0.176, h[2]);
|
|
328
|
-
if (nz > 0.5) { mat = MAT.NOSE; fl = 0; col = COL.nose; gloss = 0.8; wsdf = 1; }
|
|
329
|
-
else col = mix3(col, COL.band, nz * 2);
|
|
330
|
-
}
|
|
331
|
-
// dark spots at the corners of the lower lip / chin sides
|
|
332
|
-
if (r === 6 || h[1] < -0.035) {
|
|
333
|
-
const dc = Math.hypot((Math.abs(h[0]) - 0.014) / 0.01, (h[2] - 0.145) / 0.014);
|
|
334
|
-
if (dc < 1 && Math.abs(h[0]) > 0.006) { col = mix3(col, COL.band, smoothstep(1, 0.6, dc)); wsdf = Math.max(wsdf, 0.004); }
|
|
335
|
-
}
|
|
336
|
-
// eye rims (dark skin), preorbital gland
|
|
337
|
-
for (const e of eyePrims) {
|
|
338
|
-
const de = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
339
|
-
if (Math.abs(de) < 0.0035) mark = Math.min(mark, Math.abs(de) - 0.002);
|
|
340
|
-
if (Math.abs(de) < 0.0014) { mat = MAT.DARK_SKIN; fl = 0; wsdf = Math.max(wsdf, 0.003); }
|
|
341
|
-
else if (Math.abs(de) < 0.0035) fl = Math.min(fl, 0.0015);
|
|
342
|
-
// upper lashes
|
|
343
|
-
}
|
|
344
|
-
for (const g of glandPrims) {
|
|
345
|
-
const dg = SDFModel.dist(g, p[0], p[1], p[2]);
|
|
346
|
-
if (dg < 0.003) { col = srgb(0x2e2622); fl = 0.001; mark = Math.min(mark, dg - 0.002); wsdf = Math.max(wsdf, 0.003); }
|
|
347
|
-
}
|
|
348
|
-
// nostrils: dark rims
|
|
349
|
-
for (const e of nostrilPrims) {
|
|
350
|
-
const dn = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
351
|
-
if (dn < 0.0025) { mat = MAT.NOSE; col = COL.nose; fl = 0; mark = Math.min(mark, dn - 0.0015); wsdf = 1; }
|
|
352
|
-
}
|
|
353
|
-
// lips
|
|
354
|
-
if (r !== 6) {
|
|
355
|
-
const dj = SDFModel.evalList(jawPrims, p[0], p[1], p[2]);
|
|
356
|
-
if (dj < 0.0012 && h[2] > 0.1) { mat = MAT.MOUTH; fl = 0; wsdf = 1; }
|
|
357
|
-
else if (dj < 0.0035 && h[2] > 0.1) { mark = Math.min(mark, dj - 0.0028); fl = Math.min(fl, 0.0015); }
|
|
358
|
-
} else {
|
|
359
|
-
const dh = SDFModel.evalList(headPrims, p[0], p[1], p[2]);
|
|
360
|
-
if (dh < 0.0) { mat = MAT.MOUTH; fl = 0; wsdf = 1; }
|
|
361
|
-
else if (dh < 0.003) { mark = Math.min(mark, dh - 0.0025); fl = Math.min(fl, 0.0015); }
|
|
362
|
-
}
|
|
363
|
-
// whiskers area on the muzzle: very short hair
|
|
364
|
-
if (h[2] > 0.13) fl = Math.min(fl, 0.003);
|
|
365
|
-
}
|
|
366
|
-
// white areas and fawn spots through the crisp pattern field (continuous: capped just above 0)
|
|
367
|
-
const CAP = 0.02;
|
|
368
|
-
let pc = COL.white, pi = 1, pd = CAP;
|
|
369
|
-
if (mat === MAT.FUR && r !== 8) pd = Math.min(CAP, wsdf);
|
|
370
|
-
if (spots && (r === 0 || r === 1) && mat === MAT.FUR) {
|
|
371
|
-
const [sd] = featureDistance(spots, p, n, 1 + 0.2 * (vnoise3(p[0] * 60, p[1] * 60, p[2] * 60) - 0.5));
|
|
372
|
-
if (sd < pd) { pd = Math.min(CAP, sd); pc = COL.spot; pi = 0.92; }
|
|
373
|
-
}
|
|
374
|
-
// white hair is longer on the belly, the tail and the throat patch
|
|
375
|
-
if (pd < 0 && mat === MAT.FUR && r !== 2 && r !== 6) fl = Math.max(fl, r === 4 ? fl : coatFur * 1.3);
|
|
376
|
-
// low-frequency colour variation
|
|
377
|
-
const cv = fbm3(p[0] * 7, p[1] * 7, p[2] * 7, 3) - 0.5;
|
|
378
|
-
if (mat === MAT.FUR && r !== 8) col = [col[0] * (1 + 0.14 * cv), col[1] * (1 + 0.12 * cv), col[2] * (1 + 0.1 * cv)];
|
|
379
|
-
pattern[v] = pd; patInt[v] = pi;
|
|
380
|
-
patCol[v * 3] = pc[0]; patCol[v * 3 + 1] = pc[1]; patCol[v * 3 + 2] = pc[2];
|
|
381
|
-
markSDF[v] = mark;
|
|
382
|
-
furLen[v] = fl;
|
|
383
|
-
tint[v * 4] = col[0]; tint[v * 4 + 1] = col[1]; tint[v * 4 + 2] = col[2]; tint[v * 4 + 3] = mat;
|
|
384
|
-
surf[v * 4] = gloss;
|
|
385
|
-
}
|
|
386
|
-
smoothField(furLen, weights.neighbors, 2, (v) => tint[v * 4 + 3] !== MAT.FUR);
|
|
387
|
-
|
|
388
|
-
const patternColor = new Float32Array(nV * 4);
|
|
389
|
-
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]; }
|
|
390
|
-
return { comb, tint, pattern, mark: markSDF, furLen, patternColor, surf, stats: { spots: spots ? spots.spots.length : 0 }, region, ventral: new Float32Array(nV) };
|
|
391
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// White-tailed deer (Odocoileus virginianus). Hooves with hoof bones (the horse's anatomy at deer
|
|
2
|
-
// proportions: very slender long legs), large mobile ears, the white flag of a tail, antlers on bucks
|
|
3
|
-
// (rigid bone-coloured geometry on the head, grown by age: spike yearling, 6-8 points, 8-10
|
|
4
|
-
// points), spotted fawns, summer red-brown and winter grey-brown coats.
|
|
5
|
-
import { deerRig, HEAD_O } from './rig.js';
|
|
6
|
-
import { sculptDeer, EYE } from './sculpt.js';
|
|
7
|
-
import { deerRegions } from './regions.js';
|
|
8
|
-
import { deerCoat, COATS } from './coat.js';
|
|
9
|
-
import { srgb } from '../../core/build/coatKit.js';
|
|
10
|
-
import { motion } from './motion.js';
|
|
11
|
-
|
|
12
|
-
const pick = (R, table) => {
|
|
13
|
-
let x = R() * table.reduce((s, [, w]) => s + w, 0);
|
|
14
|
-
for (const [k, w] of table) { x -= w; if (x <= 0) return k; }
|
|
15
|
-
return table[table.length - 1][0];
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Antlers by age class: burr on the frontal pedicle, main beam curving out,
|
|
19
|
-
// back and then forward and in, tines rising near-vertically from its top. Tine rows: [position
|
|
20
|
-
// along the beam 0..1, length (m), outward lean].
|
|
21
|
-
function antlersFor(R, ageClass, g) {
|
|
22
|
-
const burr = [0.024, 0.042, -0.022];
|
|
23
|
-
if (ageClass === 'yearling') {
|
|
24
|
-
if (R() < 0.6) return { spike: true, beam: 0.11 + 0.07 * R(), base: 0.0105, burr, seed: Math.floor(R() * 1e6), points: 2 };
|
|
25
|
-
return { spike: false, beam: 0.2 + 0.05 * R(), base: 0.012, spread: 0.85 + 0.1 * g(), rise: 1.15, curl: 0.8, burr, tines: [[0.45, 0.07 + 0.03 * R(), 0.2]], seed: Math.floor(R() * 1e6), points: 4 };
|
|
26
|
-
}
|
|
27
|
-
const mature = ageClass === 'mature';
|
|
28
|
-
const beam = mature ? 0.44 + 0.08 * R() : 0.33 + 0.07 * R();
|
|
29
|
-
const tines = [];
|
|
30
|
-
const brow = mature ? R() < 0.9 : R() < 0.6;
|
|
31
|
-
if (brow) tines.push([0.09, 0.04 + 0.05 * R(), 0.15]);
|
|
32
|
-
tines.push([0.37, (mature ? 0.13 : 0.1) + 0.05 * R(), 0.3]);
|
|
33
|
-
if (mature || R() < 0.55) tines.push([0.6, (mature ? 0.11 : 0.08) + 0.04 * R(), 0.3]);
|
|
34
|
-
if (mature && R() < 0.65) tines.push([0.8, 0.06 + 0.04 * R(), 0.25]);
|
|
35
|
-
return {
|
|
36
|
-
spike: false, beam, base: mature ? 0.022 : 0.018,
|
|
37
|
-
spread: (mature ? 1.2 : 1.08) + 0.1 * g(), rise: 1 + 0.12 * g(), curl: 1 + 0.12 * g(),
|
|
38
|
-
burr, tines, seed: Math.floor(R() * 1e6), points: 2 * (tines.length + 1),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default {
|
|
43
|
-
id: 'deer',
|
|
44
|
-
name: 'White-tailed deer',
|
|
45
|
-
latin: 'Odocoileus virginianus',
|
|
46
|
-
group: 'hooves',
|
|
47
|
-
plan: 'quadruped',
|
|
48
|
-
covering: 'fur',
|
|
49
|
-
// coat seasons as variants (createAnimal('deer', { variant: 'winter' }))
|
|
50
|
-
variants: [
|
|
51
|
-
{ id: 'summer', name: 'White-tailed deer (summer coat)', latin: 'Odocoileus virginianus' },
|
|
52
|
-
{ id: 'winter', name: 'White-tailed deer (winter coat)', latin: 'Odocoileus virginianus' },
|
|
53
|
-
],
|
|
54
|
-
|
|
55
|
-
// Seeded individual. Sex: doe or buck; age: adult (bucks by age class: yearling, 2.5 years,
|
|
56
|
-
// mature) or juvenile (fawn: spotted reddish coat, long legs, big head and ears); size and
|
|
57
|
-
// proportions within the species' range; summer red-brown or winter grey-brown coat (o.variant
|
|
58
|
-
// forces 'summer' / 'winter'); bucks in summer carry antlers in velvet.
|
|
59
|
-
variation(R, o) {
|
|
60
|
-
const sex = o.sex || (R() < 0.5 ? 'male' : 'female');
|
|
61
|
-
const age = o.age || (R() < 0.12 ? 'juvenile' : 'adult');
|
|
62
|
-
const fawn = age === 'juvenile';
|
|
63
|
-
const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
|
|
64
|
-
const coat = o.variant === 'summer' || o.variant === 'winter' ? o.variant : R() < 0.5 ? 'summer' : 'winter';
|
|
65
|
-
const ageClass = fawn ? 'fawn' : sex === 'male' ? pick(R, [['yearling', 30], ['prime', 35], ['mature', 35]]) : 'adult';
|
|
66
|
-
const buckSize = { yearling: 0.97, prime: 1.05, mature: 1.12 }[ageClass] || 1;
|
|
67
|
-
const size = (sex === 'male' ? buckSize : 0.98) * (1 + 0.04 * g()) * (fawn ? 0.52 : 1);
|
|
68
|
-
const antlers = sex === 'male' && !fawn ? antlersFor(R, ageClass, g) : null;
|
|
69
|
-
if (antlers) antlers.velvet = coat === 'summer' && R() < 0.75;
|
|
70
|
-
const type = g(); // - leggier / lighter, + stockier
|
|
71
|
-
return {
|
|
72
|
-
sex, age, ageClass, size, coat, antlers,
|
|
73
|
-
variant: coat, // the variant this individual was built as (the showcase and tools read params.variant)
|
|
74
|
-
neck: sex === 'male' && !fawn ? (ageClass === 'mature' ? 0.7 : ageClass === 'prime' ? 0.45 : 0.15) * (coat === 'winter' ? 1 : 0.5) : 0,
|
|
75
|
-
coatShade: g(), coatLightness: 0.06 * g(),
|
|
76
|
-
coatSeed: Math.floor(R() * 1e6),
|
|
77
|
-
minThick: 0.004,
|
|
78
|
-
warps: [
|
|
79
|
-
{ type: 'legs', k: (1 + 0.03 * g() - 0.02 * type) * (fawn ? 1.22 : 1), top: 0.5 },
|
|
80
|
-
{ type: 'length', k: (1 + 0.03 * g() + ({ prime: 0.02, mature: 0.04 }[ageClass] || 0)) * (fawn ? 0.86 : 1), z0: -0.5, z1: 0.35 },
|
|
81
|
-
{ type: 'girth', k: 1 + 0.045 * type + ({ yearling: 0.02, prime: 0.05, mature: 0.08 }[ageClass] || 0), cy: 0.68, z0: -0.55, z1: 0.42 },
|
|
82
|
-
fawn
|
|
83
|
-
? { type: 'scaleAbout', c: HEAD_O, k: 1.28, r0: 0.1, r1: 0.26 }
|
|
84
|
-
: { type: 'scaleAbout', c: HEAD_O, k: 1 + 0.025 * g(), r0: 0.2, r1: 0.5 },
|
|
85
|
-
],
|
|
86
|
-
};
|
|
87
|
-
},
|
|
88
|
-
rig: () => deerRig(),
|
|
89
|
-
sculpt: (m, rig, params) => sculptDeer(m, rig, params),
|
|
90
|
-
regions: deerRegions,
|
|
91
|
-
coat: deerCoat,
|
|
92
|
-
eyeSpecs: () => [1, -1].map((side) => ({ side, spec: EYE, headOrigin: HEAD_O, bone: 'head', look: EYE_LOOK })),
|
|
93
|
-
motion,
|
|
94
|
-
render: { markColor: srgb(0x1c1816), strandDensity: 1000, clumpDensity: 1, shellScale: 1, finWidth: 0.45 },
|
|
95
|
-
};
|
|
96
|
-
void COATS;
|
|
97
|
-
|
|
98
|
-
// Horizontal bar pupil, dark brown iris (looks black), sclera hidden, dark lids.
|
|
99
|
-
export const EYE_LOOK = {
|
|
100
|
-
pupil: 'bar',
|
|
101
|
-
lids: 'mammal',
|
|
102
|
-
iris: { inner: srgb(0x160d08), mid: srgb(0x2a1a10), hi: srgb(0x40281a), outer: srgb(0x0e0805) },
|
|
103
|
-
sclera: { color: [0.5, 0.45, 0.4], visible: false },
|
|
104
|
-
lidColor: [0.02, 0.018, 0.016],
|
|
105
|
-
pupilSize: [0.12, 0.38],
|
|
106
|
-
};
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// White-tailed deer motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
|
|
2
|
-
// Numbers are for the reference individual (params.size = 1, 0.92 m at the withers); the engine
|
|
3
|
-
// scales them by dynamic similarity for fawns and big bucks.
|
|
4
|
-
//
|
|
5
|
-
// Gaits: lateral-sequence walk (hind foot into the fore track),
|
|
6
|
-
// a brief diagonal trot with high knee action when wary, the transverse gallop, and the bounding
|
|
7
|
-
// gallop of the escape (long suspension, forefeet landing almost together, hind feet planted ahead
|
|
8
|
-
// of the fore tracks, tail flagged). Walk -> trot ~1.6 m/s (Froude ~0.4), trot -> gallop ~4.3 m/s,
|
|
9
|
-
// gallop -> bound ~9 m/s; top speed 13.5 m/s (48 km/h).
|
|
10
|
-
import { hooks } from './behaviour.js';
|
|
11
|
-
|
|
12
|
-
const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
|
|
13
|
-
|
|
14
|
-
export const motion = {
|
|
15
|
-
maxSpeed: 13.5,
|
|
16
|
-
accel: [4.5, 6.5],
|
|
17
|
-
decel: 8,
|
|
18
|
-
// turns: a walking deer comes round over 2-3 steps on a path of one to two body lengths (~1.2 rad/s
|
|
19
|
-
// at 1.2 m/s); at speed the cornering limit (~0.5 g) keeps the lean of a sharp escape turn near
|
|
20
|
-
// 23 deg (0.85 atan(a / g)) instead of the 34 deg clamp (a long-legged body rolled like a motorbike)
|
|
21
|
-
turnRate: 1.5,
|
|
22
|
-
latAccelMax: 5,
|
|
23
|
-
gears: { walk: 1.1, trot: 2.9, gallop: 7, bound: 11.5 },
|
|
24
|
-
gallopBlend: [3.8, 7.5],
|
|
25
|
-
// name v f D [FL, FR, HL, HR]
|
|
26
|
-
gaits: [
|
|
27
|
-
G('walk', 0.0, 0.85, 0.72, [0.25, 0.75, 0.0, 0.5], { liftF: 0.06, liftH: 0.05, bobF: 0.015, bobH: 0.015, flex: 0, lat: 0.02, fold: 0.7, heel: 30, tail: 0, drop: 0 }),
|
|
28
|
-
G('walk', 1.5, 1.15, 0.62, [0.25, 0.75, 0.0, 0.5], { liftF: 0.085, liftH: 0.065, bobF: 0.03, bobH: 0.03, flex: 0, lat: 0.025, fold: 0.9, heel: 40, tail: 0.1, drop: 0.02 }),
|
|
29
|
-
G('trot', 2.1, 1.85, 0.45, [0.51, 0.01, 0.0, 0.5], { liftF: 0.12, liftH: 0.09, bobF: 0.03, bobH: 0.03, flex: 0.01, lat: 0.0, fold: 1.2, heel: 50, tail: 0.3, drop: 0.03 }),
|
|
30
|
-
G('trot', 3.8, 2.15, 0.41, [0.51, 0.01, 0.0, 0.5], { liftF: 0.14, liftH: 0.11, bobF: 0.035, bobH: 0.035, flex: 0.015, lat: 0.0, fold: 1.3, heel: 55, tail: 0.4, drop: 0.035 }),
|
|
31
|
-
// (the fast gaits run low: the long, near-straight forelegs only sweep through a real stance, fore
|
|
32
|
-
// duty 0.2-0.25 in the gallop and ~0.13 in the bound, when the forequarters ride ~10 % of the
|
|
33
|
-
// withers height lower than they stand; at the standing height a forefoot touched down for one or
|
|
34
|
-
// two frames and the deer floated on its hind legs)
|
|
35
|
-
G('gallop', 4.8, 2.35, 0.3, [0.4, 0.52, 0.0, 0.12], { liftF: 0.14, liftH: 0.12, bobF: 0.015, bobH: 0.04, flex: 0.12, lat: 0, fold: 1.35, heel: 45, tail: 0.6, drop: 0.08 }),
|
|
36
|
-
G('gallop', 8, 2.55, 0.25, [0.4, 0.52, 0.0, 0.12], { liftF: 0.16, liftH: 0.14, bobF: 0.015, bobH: 0.045, flex: 0.17, lat: 0, fold: 1.4, heel: 40, tail: 0.8, drop: 0.1 }),
|
|
37
|
-
// bound: the back gathers and stretches with each leap (bounding.jpg)
|
|
38
|
-
G('bound', 10, 2.5, 0.21, [0.45, 0.5, 0.0, 0.06], { liftF: 0.2, liftH: 0.17, bobF: 0.02, bobH: 0.055, flex: 0.27, lat: 0, fold: 1.45, heel: 40, tail: 1.0, drop: 0.12 }),
|
|
39
|
-
G('bound', 13.5, 2.6, 0.18, [0.45, 0.5, 0.0, 0.06], { liftF: 0.22, liftH: 0.19, bobF: 0.02, bobH: 0.06, flex: 0.3, lat: 0, fold: 1.5, heel: 40, tail: 1.0, drop: 0.13 }),
|
|
40
|
-
],
|
|
41
|
-
feet: {
|
|
42
|
-
// small cloven hooves: the fetlock gives under load, the digit flips in swing, breakover at the toe
|
|
43
|
-
front: { type: 'unguligrade', contact: 0.95, curl: 75, flex: 4, sink: 16, hoofFlex: 20, swingBack: 0.12 },
|
|
44
|
-
hind: { type: 'unguligrade', contact: 0.95, curl: 75, flex: 4, sink: 10, hoofFlex: 20, swingBack: 0.03 },
|
|
45
|
-
},
|
|
46
|
-
stance: { width: 1, gallopWidth: 0.8, sprawl: 0, crouch: 0, scuff: [10, 20, 0] },
|
|
47
|
-
// torso cross-sections (bind pose, reference size): centre height, half height, half width
|
|
48
|
-
body: {
|
|
49
|
-
// (half heights include the legs folded under the chest and thighs when lying down)
|
|
50
|
-
chest: { y: 0.66, hh: 0.26, hw: 0.19 },
|
|
51
|
-
mid: { y: 0.67, hh: 0.22, hw: 0.18 },
|
|
52
|
-
pelvis: { y: 0.74, hh: 0.3, hw: 0.2 },
|
|
53
|
-
back: 0.08,
|
|
54
|
-
},
|
|
55
|
-
head: {
|
|
56
|
-
// [speed, raise (m), reach (m), pitch (rad, + = nose down)]: lowered and nodding at the walk, up
|
|
57
|
-
// at the wary trot, stretched forward in the gallop and bound
|
|
58
|
-
carriage: [[0, 0, 0, 0], [1.2, -0.07, 0.04, 0.05], [3, -0.01, 0.02, 0.0], [6, -0.1, 0.08, 0.06], [12, -0.16, 0.12, 0.1]],
|
|
59
|
-
stab: [[0, 0], [1.2, 0.1], [3, 0.4], [6, 0.3], [12, 0.35]],
|
|
60
|
-
neckBend: 45, neckPivot: 0.6, yaw: 0.9, pitchUp: 0.6, pitchDown: 0.9, mouth: 'jawTip',
|
|
61
|
-
},
|
|
62
|
-
tail: {
|
|
63
|
-
// [speed, pitch per segment from horizontal (deg), root -> tip]: flat on the rump at rest, lifting
|
|
64
|
-
// with speed (the flag itself is the behaviour layer)
|
|
65
|
-
carriage: [
|
|
66
|
-
[0.0, [-45, -62, -72, -78, -80, -80]],
|
|
67
|
-
[1.5, [-40, -58, -68, -74, -78, -80]],
|
|
68
|
-
[3.5, [-25, -45, -58, -66, -72, -76]],
|
|
69
|
-
[7, [0, -20, -35, -45, -52, -58]],
|
|
70
|
-
],
|
|
71
|
-
stiffness: 1.1, sway: 4, flick: 0.6, wag: 0, swish: 0.45, curl: 0, balance: 0,
|
|
72
|
-
radius: [0.035, 0.03],
|
|
73
|
-
},
|
|
74
|
-
ears: { rest: [0, 0], mobility: 1.1, speedFlatten: 0.35, flattenSpeeds: [5, 12], twitch: 1.3, prick: 0.55 },
|
|
75
|
-
breath: { rate: 0.28, amp: 0.006, pant: false, pantRate: 1.5, pantAmp: 0.015, heatSpeed: 11 },
|
|
76
|
-
actions: {
|
|
77
|
-
attack: { style: 'headbutt', kick: 'rear' }, // (hooks: buck antler thrust, doe rears and flails)
|
|
78
|
-
// grazing / drinking on straight forelegs (drinking.jpg): the long neck swings down from the
|
|
79
|
-
// chest, the head hangs near vertical (bind 50 deg + 43 deg), the muzzle a little ahead of the
|
|
80
|
-
// forefeet; the forehand stays at its standing height (it dropped 30-36 cm, a play bow, when the
|
|
81
|
-
// neck could not reach)
|
|
82
|
-
eat: { style: 'graze', dropF: 0, dropH: 0, pitch: 0.75, ahead: 0.25 },
|
|
83
|
-
drink: { dropF: 0, dropH: 0, pitch: 0.7, ahead: 0.25 },
|
|
84
|
-
// an everyday obstacle jump: the body rises ~1.1 m, 3.8 m long (play('jump', { height: 2 }) is the
|
|
85
|
-
// record escape leap: clears ~2.4 m, 6.5 m standing, up to ~9 m from a gallop); lands on
|
|
86
|
-
// near-straight forelegs, the hinds swing under
|
|
87
|
-
jump: { height: 1.1, distance: 3.8, land: [0.14, 0.14] },
|
|
88
|
-
// sit: deer do not sit like a dog (only briefly while rising, or hurt): a sit is sternal bedding
|
|
89
|
-
// with the head up and alert (hooks: behaviour.js), lie the same, relaxed
|
|
90
|
-
sit: { down: 'front', up: 'hind' },
|
|
91
|
-
// kneels on both carpi first, then lowers the hindquarters; rises hind end first
|
|
92
|
-
lie: { down: 'front', up: 'hind' },
|
|
93
|
-
sleep: { style: 'curl', down: 'front', up: 'hind' },
|
|
94
|
-
fold: { front: { z: -0.24, k: 1.5, beta: 0.9 } },
|
|
95
|
-
},
|
|
96
|
-
hooks,
|
|
97
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Meshing plan: body at 6.2 mm (0.67 % of the withers height), head at 2.9 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) and, in bucks, the antlers as a rigid region on the head bone.
|
|
4
|
-
import { EYE, antlerCurves } from './sculpt.js';
|
|
5
|
-
import { HEAD_O, deerJoints } from './rig.js';
|
|
6
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
7
|
-
import { norm, smoothstep } from '../../core/math/vec.js';
|
|
8
|
-
|
|
9
|
-
const J = deerJoints();
|
|
10
|
-
// the head is carried nose-down on a steep neck: cut just behind the poll - throat latch line
|
|
11
|
-
export const NECK_CUT = { c: [0, J.occiput[1] - 0.1, J.occiput[2] - 0.02], d: norm([0, 1, 0.35]), band: 0.013 };
|
|
12
|
-
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];
|
|
13
|
-
|
|
14
|
-
export const EYE_PATCH = { R: 0.024, B: 0.004, h: 0.0009, centres: [1, -1].map((s) => eyeFrameOf(EYE, HEAD_O, s).c) };
|
|
15
|
-
export function eyePatchWeight(x, y, z) {
|
|
16
|
-
let dmin = 1e9;
|
|
17
|
-
for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
|
|
18
|
-
return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function antlerBox(A) {
|
|
22
|
-
const lo = [1e9, 1e9, 1e9], hi = [-1e9, -1e9, -1e9];
|
|
23
|
-
for (const side of antlerCurves(A)) {
|
|
24
|
-
for (const p of [...side.beam, ...side.tines.flatMap((t) => t.pts)]) for (let i = 0; i < 3; i++) { lo[i] = Math.min(lo[i], p[i]); hi[i] = Math.max(hi[i], p[i]); }
|
|
25
|
-
for (let i = 0; i < 3; i++) { lo[i] = Math.min(lo[i], side.burr[i]); hi[i] = Math.max(hi[i], side.burr[i]); }
|
|
26
|
-
}
|
|
27
|
-
const pad = A.base * 1.6 + 0.01;
|
|
28
|
-
return { bmin: lo.map((v) => v - pad), bmax: hi.map((v) => v + pad) };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function deerRegions(rig, params, Q) {
|
|
32
|
-
const B = NECK_CUT.band, r = Q.res;
|
|
33
|
-
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) })) : [];
|
|
34
|
-
const headJobs = [
|
|
35
|
-
{ name: 'head', part: 'body', bmin: [-0.2, HEAD_O[1] - 0.22, HEAD_O[2] - 0.2], bmax: [0.2, HEAD_O[1] + 0.24, HEAD_O[2] + 0.2], h: 0.003 * r, F: 6, clip: (x, y, z) => neckS(x, y, z) > -B, patches },
|
|
36
|
-
{ name: 'jaw', part: 'jaw', bmin: [-0.04, HEAD_O[1] - 0.24, HEAD_O[2] + 0.02], bmax: [0.04, HEAD_O[1] - 0.02, HEAD_O[2] + 0.2], h: 0.0029 * r, F: 6, rigidBone: 'jaw' },
|
|
37
|
-
];
|
|
38
|
-
const jobs = [
|
|
39
|
-
[{ name: 'body', part: 'body', bmin: [-0.26, -0.01, -0.84], bmax: [0.26, 1.3, 0.66], h: 0.0064 * r, F: 4, clip: (x, y, z) => neckS(x, y, z) < B }],
|
|
40
|
-
headJobs,
|
|
41
|
-
];
|
|
42
|
-
if (params.antlers) {
|
|
43
|
-
// (antler cell 3.5 mm at the hero tier, coarsening a little more slowly than the body)
|
|
44
|
-
const bx = antlerBox(params.antlers);
|
|
45
|
-
jobs.push([{ name: 'antler', part: 'antler', ...bx, h: 0.0035 * Math.pow(r, 0.85), F: 6, rigidBone: 'head' }]);
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
jobs,
|
|
49
|
-
fade(x, y, z, name, patch) {
|
|
50
|
-
const sN = neckS(x, y, z);
|
|
51
|
-
if (name === 'body') return 1 - smoothstep(-B, B, sN);
|
|
52
|
-
if (name === 'head') {
|
|
53
|
-
let f = smoothstep(-B, B, sN);
|
|
54
|
-
if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
|
|
55
|
-
return f;
|
|
56
|
-
}
|
|
57
|
-
return 1;
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|