@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,509 +0,0 @@
|
|
|
1
|
-
// Goat behaviour layer for the quadruped engine (species.motion.hooks, see core/motion/actions.js):
|
|
2
|
-
//
|
|
3
|
-
// pose(engine, dt) after the engine's solve: the ruminant's sideways grinding of the lower
|
|
4
|
-
// jaw while chewing the cud, quick ear flicks (fly flicks, one ear at a time)
|
|
5
|
-
// update(P, dt, layer) every frame over the action layer: cud chewing bouts (standing or lying),
|
|
6
|
-
// the short tail flicking up, automatic idle variants (browsing, rearing to
|
|
7
|
-
// browse, bleating, head shake, pawing, ear flicks), the buck's raised mane
|
|
8
|
-
// in a threat
|
|
9
|
-
// actions browse (reach up, or rear onto the hind legs: opts.rear), bleat, headshake,
|
|
10
|
-
// paw (scrape the ground with a foreleg), attack (rear up, twist the head,
|
|
11
|
-
// drop and clash head-down), sleep (sternal, head turned back to the flank)
|
|
12
|
-
//
|
|
13
|
-
// Posture lengths (headRaise, neckReach, fwd) are engine units (x cfg.k): species metres / cfg.unit.
|
|
14
|
-
import * as THREE from 'three';
|
|
15
|
-
import { clamp, lerp, smooth, TAU, tv, tqa } from '../../core/motion/common.js';
|
|
16
|
-
import { mx, mxLeg, POSTURES, ONESHOTS } from '../../core/motion/actions.js';
|
|
17
|
-
|
|
18
|
-
const _q = new THREE.Quaternion(), _q2 = new THREE.Quaternion(), _qh = new THREE.Quaternion(), _qI = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1), _m = new THREE.Matrix4();
|
|
19
|
-
const PI = Math.PI;
|
|
20
|
-
// lop ears hang with gravity: the share of the way to the standing hang and the largest turn about the root (25 deg:
|
|
21
|
-
// a lop ear's root lies in the head / neck skin blend, and turned further the skin round the root stretched 3x)
|
|
22
|
-
export const HANG = { f: 0.8, max: 0.44 };
|
|
23
|
-
const sm = (w) => w * w * (3 - 2 * w);
|
|
24
|
-
|
|
25
|
-
function B(e) {
|
|
26
|
-
if (!e._goat) {
|
|
27
|
-
e._goat = {
|
|
28
|
-
cud: 0, cudOn: e.rand() < 0.6, cudT: 6 + e.rand() * 10, chewPh: 0, grind: 0,
|
|
29
|
-
ear: [{ a: 0, age: 9, next: 2 + e.rand() * 4 }, { a: 0, age: 9, next: 3 + e.rand() * 5 }],
|
|
30
|
-
tailT: 1 + e.rand() * 2, tailAge: 9,
|
|
31
|
-
idleT: 5 + e.rand() * 6,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
return e._goat;
|
|
35
|
-
}
|
|
36
|
-
const busy = (L) => L.postures.length > 0 || L.oneshots.some((a) => !a.stopping);
|
|
37
|
-
|
|
38
|
-
// ------------------------------------------------------------------------------------------------
|
|
39
|
-
// pose: jaw grinding (lateral swing of the mandible) and ear flicks
|
|
40
|
-
function pose(e, dt) {
|
|
41
|
-
const b = B(e);
|
|
42
|
-
// udder / scrotum: drawn up out of the ground when the body rests on it (lying, sleeping, dead)
|
|
43
|
-
const ud = e.bone.udder;
|
|
44
|
-
if (ud) {
|
|
45
|
-
// (a buck's scrotum hangs 12.5 cm below the udder bone's top, its bottom 0.325 m in the bind pose; held up until the
|
|
46
|
-
// hindquarters have risen)
|
|
47
|
-
const male = e.params?.sex === 'male';
|
|
48
|
-
const m = ud.matrixWorld.elements, sY = e.J.udderTop.y / 0.44;
|
|
49
|
-
const drop = (male ? 0.125 : 0.168 + 0.065 * (e.params?.udder || 0)) * sY;
|
|
50
|
-
const dl = Math.hypot(m[4], m[5], m[6]) || 1;
|
|
51
|
-
// (lying on its side the udder's axis is level: a lift toward the sky moved it out of the flank, and the rigid bag
|
|
52
|
-
// stood out sideways from the belly like a ball, floating beside the rump. There it hangs toward the ground about
|
|
53
|
-
// its attachment and draws up into the belly along its own axis, against the belly and the lower thigh)
|
|
54
|
-
const side = smooth(0.2, 0.75, 1 + m[5] / dl);
|
|
55
|
-
b.udSide = (b.udSide || 0) + (side - (b.udSide || 0)) * (1 - Math.exp(-dt * 6));
|
|
56
|
-
const top = tv().setFromMatrixPosition(ud.matrixWorld);
|
|
57
|
-
_q.setFromRotationMatrix(ud.matrixWorld);
|
|
58
|
-
if (b.udSide > 1e-3) {
|
|
59
|
-
_qh.setFromUnitVectors(tv(0, 1, 0).applyQuaternion(_q), tv(0, -1, 0)).slerp(_qI, 1 - 0.55 * b.udSide);
|
|
60
|
-
_q.premultiply(_qh);
|
|
61
|
-
top.addScaledVector(tv(0, 1, 0).applyQuaternion(_q), -(0.05 + 0.05 * (e.params?.udder || 0)) * sY * b.udSide);
|
|
62
|
-
}
|
|
63
|
-
// (the udder is its own rigid surface: all of it must clear the ground, up to 20 cm for a doe in milk; a buck's scrotum,
|
|
64
|
-
// 18 cm from the groin, 8 cm: lifted 14.5 cm it vanished into the body when he sat or lay down)
|
|
65
|
-
let want = Math.max(e.P.groundW, e.P.dropH > 0 ? 0.6 * Math.min(1, e.P.dropH) : 0) * (male ? 0.08 : 0.1 + 0.14 * (e.params?.udder || 0)) * e.cfg.s * (1 - b.udSide);
|
|
66
|
-
// ... and at least as much as its lowest point (the teat tips, the scrotum) needs to clear the ground: rising
|
|
67
|
-
// hind end first the posture's weights fell faster than the hindquarters rose, and the udder dipped 7 mm
|
|
68
|
-
// into the ground
|
|
69
|
-
const low = top.y + tv(0, 1, 0).applyQuaternion(_q).y * drop;
|
|
70
|
-
want = Math.max(want, e.terrainH(top.x, top.z) + 0.02 * e.cfg.s - low);
|
|
71
|
-
b.udLift = (b.udLift || 0) + (want - (b.udLift || 0)) * (1 - Math.exp(-dt * 12));
|
|
72
|
-
if (b.udLift > 1e-5 || b.udSide > 1e-3) {
|
|
73
|
-
top.y += Math.max(0, b.udLift);
|
|
74
|
-
ud.matrixWorld.compose(top, _q, _s);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// beard: a long beard that would reach into the ground (grazing, drinking, lying) swings back
|
|
78
|
-
// about the chin just enough, smoothly
|
|
79
|
-
const bd = e.bone.beard;
|
|
80
|
-
if (bd && (e.params?.beard || 0) > 0.01) {
|
|
81
|
-
const base = tv().setFromMatrixPosition(bd.matrixWorld);
|
|
82
|
-
_q.setFromRotationMatrix(bd.matrixWorld);
|
|
83
|
-
// the beard hangs from the chin skin: it follows the skull more than the opening jaw (the long
|
|
84
|
-
// lock amplified every jaw movement into a whip at its tip)
|
|
85
|
-
if (e.bone.head) { _q2.setFromRotationMatrix(e.bone.head.matrixWorld).multiply(b.beardRel || (b.beardRel = beardRelQ(e))); _q.slerp(_q2, 0.75); }
|
|
86
|
-
const len = b.beardLen ?? (b.beardLen = e.J.beardTop.distanceTo(e.J.beardTip));
|
|
87
|
-
liftOut(e, b.beardSt || (b.beardSt = {}), base, _q, len, dt, 0.04 * e.cfg.s);
|
|
88
|
-
bd.matrixWorld.compose(base, _q, _s);
|
|
89
|
-
}
|
|
90
|
-
// long lop ears (Nubian, Boer) hang below the muzzle: swung forward and out of the ground when
|
|
91
|
-
// grazing or lying
|
|
92
|
-
if (e.params?.ear === 'lop' && e.lod < 2) {
|
|
93
|
-
// ... and they hang with gravity: turned about the root toward the ear's standing hang (turned with the head's yaw),
|
|
94
|
-
// most of the way, while the head is upright (a rigid ear kept its standing angle to the skull, so with the head
|
|
95
|
-
// down to graze or drink it stood out behind the jaw like a plate; the Nubian standard: pendulous ears fall along
|
|
96
|
-
// the face). A head rolled onto its side (dead, lying flat) leaves the ears to the posture.
|
|
97
|
-
const qRel = _q2.setFromRotationMatrix(e.bone.head.matrixWorld).multiply(b.headInv || (b.headInv = e.bindQ.head.clone().invert()));
|
|
98
|
-
const lat = tv(1, 0, 0).applyQuaternion(qRel);
|
|
99
|
-
const psi = Math.atan2(-lat.z, lat.x);
|
|
100
|
-
const hang = HANG.f * (1 - smooth(0.35, 0.7, Math.abs(lat.y)));
|
|
101
|
-
for (let k = 0; k < 2 && hang > 1e-3; k++) {
|
|
102
|
-
const S = k === 0 ? 'L' : 'R', bone = e.bone['ear' + S];
|
|
103
|
-
if (!bone) continue;
|
|
104
|
-
const d0 = b['hang' + S] || (b['hang' + S] = tv(0, 1, 0).applyQuaternion(e.bindQ['ear' + S]).clone());
|
|
105
|
-
const want = tv().copy(d0).applyAxisAngle(tv(0, 1, 0), psi);
|
|
106
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
107
|
-
const now = tv(0, 1, 0).applyQuaternion(_q);
|
|
108
|
-
_qh.setFromUnitVectors(now, want);
|
|
109
|
-
const ang = 2 * Math.acos(Math.min(1, Math.abs(_qh.w)));
|
|
110
|
-
_qh.slerp(_qI, 1 - Math.min(hang, ang > 1e-4 ? HANG.max / ang : 1));
|
|
111
|
-
bone.matrixWorld.compose(tv().setFromMatrixPosition(bone.matrixWorld), _q.premultiply(_qh), _s);
|
|
112
|
-
}
|
|
113
|
-
for (let k = 0; k < 2; k++) {
|
|
114
|
-
const S = k === 0 ? 'L' : 'R', bone = e.bone['ear' + S];
|
|
115
|
-
if (!bone) continue;
|
|
116
|
-
const st = b['lop' + S] || (b['lop' + S] = {});
|
|
117
|
-
const base = tv().setFromMatrixPosition(bone.matrixWorld);
|
|
118
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
119
|
-
const len = st.len ?? (st.len = e.J['earBase' + S].distanceTo(e.J['earTip' + S]));
|
|
120
|
-
if (liftOut(e, st, base, _q, len, dt, 0.02 * e.cfg.s)) bone.matrixWorld.compose(base, _q, _s);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
if (e.lod >= 2) return;
|
|
124
|
-
const jaw = e.bone.jaw;
|
|
125
|
-
if (jaw && b.grind > 1e-3) {
|
|
126
|
-
const base = tv().setFromMatrixPosition(jaw.matrixWorld);
|
|
127
|
-
_q.setFromRotationMatrix(jaw.matrixWorld);
|
|
128
|
-
const ax = tv(0, 0, 1).applyQuaternion(_q); // perpendicular to the jaw and to the lateral axis
|
|
129
|
-
const a = 0.07 * b.grind * Math.sin(b.chewPh);
|
|
130
|
-
jaw.matrixWorld.compose(base, tqa(ax, a).multiply(_q), _s);
|
|
131
|
-
}
|
|
132
|
-
for (let k = 0; k < 2; k++) {
|
|
133
|
-
const E = b.ear[k];
|
|
134
|
-
if (E.age > 0.5) continue;
|
|
135
|
-
const bone = k === 0 ? e.bone.earL : e.bone.earR;
|
|
136
|
-
if (!bone) continue;
|
|
137
|
-
// a flick: fast twist about the ear's long axis and a flap, decaying in ~0.4 s
|
|
138
|
-
const f = Math.sin(Math.min(1, E.age / 0.45) * PI * 2) * Math.exp(-E.age * 5) * (k === 0 ? 1 : -1);
|
|
139
|
-
const base = tv().setFromMatrixPosition(bone.matrixWorld);
|
|
140
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
141
|
-
const along = tv(0, 1, 0).applyQuaternion(_q), flap = tv(0, 0, 1).applyQuaternion(_q);
|
|
142
|
-
_q.premultiply(tqa(along, 0.5 * f * E.a)).premultiply(tqa(flap, 0.35 * f * E.a));
|
|
143
|
-
bone.matrixWorld.compose(base, _q, _s);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Keeps a hanging part (beard, lop ear) out of the ground: the smallest swing up about its root that
|
|
148
|
-
// lifts sample points along it (fractions of its length) above the terrain, followed by a critically
|
|
149
|
-
// damped spring (st: { lift, v }). Returns the rotated quaternion in _q (world) for the bone at base.
|
|
150
|
-
function liftOut(e, st, base, q, len, dt, margin) {
|
|
151
|
-
const dir = tv(0, 1, 0).applyQuaternion(q);
|
|
152
|
-
let need = 0;
|
|
153
|
-
if (base.y - e.terrainH(base.x, base.z) < len + margin + 0.02 * e.cfg.s) {
|
|
154
|
-
for (const f of [1.12, 0.8, 0.5]) {
|
|
155
|
-
const pt = tv().copy(base).addScaledVector(dir, len * f);
|
|
156
|
-
const floor = e.terrainH(pt.x, pt.z) + margin;
|
|
157
|
-
if (pt.y < floor) need = Math.max(need, Math.asin(clamp((floor - pt.y) / (len * f), 0, 1)) * 1.35);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
const om = 28, h = Math.min(dt, 0.05);
|
|
161
|
-
st.v = (st.v || 0) + (om * om * (need - (st.lift || 0)) - 2 * om * (st.v || 0)) * h;
|
|
162
|
-
st.lift = Math.max(0, (st.lift || 0) + st.v * h);
|
|
163
|
-
if (st.lift > 1e-4) {
|
|
164
|
-
const axis = tv().crossVectors(dir, tv(0, 1, 0));
|
|
165
|
-
if (axis.lengthSq() > 1e-8) q.premultiply(tqa(axis.normalize(), st.lift));
|
|
166
|
-
}
|
|
167
|
-
return st.lift > 1e-4;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// the beard bone's bind rotation relative to the head bone's (so the head-following beard keeps its
|
|
171
|
-
// bind hang)
|
|
172
|
-
function beardRelQ(e) {
|
|
173
|
-
return e.bindQ.head.clone().invert().multiply(e.bindQ.beard);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// ------------------------------------------------------------------------------------------------
|
|
177
|
-
// update: cud chewing, tail flicks, ear flicks, idle variants
|
|
178
|
-
function update(P, dt, L) {
|
|
179
|
-
const e = L.engine, b = B(e), cfg = e.cfg;
|
|
180
|
-
// a kid runs slower than dynamic similarity would give it (a 20 kg kid: ~5.2 m/s, not 6.5): requests
|
|
181
|
-
// above 0.8 of its scaled top speed are capped there (a cap on every speed also slowed the trot it jumps
|
|
182
|
-
// from, and the jump's crouch caught a foreleg mid-stride)
|
|
183
|
-
if (e.params?.age === 'juvenile' && e.wantSpeed > 0.8 * cfg.maxSpeed) P.speedScale *= 0.8 * cfg.maxSpeed / e.wantSpeed;
|
|
184
|
-
// a kid carries its head lower and further forward, on a less upright neck (kid_side, front2: with the
|
|
185
|
-
// adult's high, alert carriage its long legs and upright neck read as a llama); not in actions
|
|
186
|
-
if (e.params?.age === 'juvenile') {
|
|
187
|
-
let act = 0;
|
|
188
|
-
for (const a of L.oneshots) act = Math.max(act, a.w || 0);
|
|
189
|
-
for (const p of L.postures) act = Math.max(act, p.w || 0);
|
|
190
|
-
const kw = 1 - act;
|
|
191
|
-
P.headRaise -= (0.045 / cfg.unit) * kw;
|
|
192
|
-
P.neckReach += (0.025 / cfg.unit) * kw;
|
|
193
|
-
P.headPitch += 0.1 * kw;
|
|
194
|
-
}
|
|
195
|
-
const vn = e.speed / cfg.sq;
|
|
196
|
-
const still = 1 - smooth(0.1, 0.6, vn);
|
|
197
|
-
// --- rumination: chewing bouts of 20-40 s with pauses, standing or lying (not while asleep,
|
|
198
|
-
// eating, bleating or fighting)
|
|
199
|
-
b.cudT -= dt;
|
|
200
|
-
if (b.cudT <= 0) { b.cudOn = !b.cudOn; b.cudT = b.cudOn ? 18 + e.rand() * 22 : 8 + e.rand() * 14; }
|
|
201
|
-
const lying = L.postures.some((p) => p.name === 'lie') ? 1 : 0;
|
|
202
|
-
const quiet = L.oneshots.some((a) => !a.stopping && a.name !== 'hit' && a.name !== 'headshake') ? 0 : 1;
|
|
203
|
-
const asleep = L.postures.some((p) => p.name === 'sleep' || p.name === 'death') ? 1 : 0;
|
|
204
|
-
const want = b.cudOn && quiet && !asleep ? Math.max(still * L.idle.w, lying) : 0;
|
|
205
|
-
b.cud += (want - b.cud) * (1 - Math.exp(-dt * 3));
|
|
206
|
-
// chew rate ~1.3 Hz; every ~40 chews a bolus is swallowed (a short pause)
|
|
207
|
-
const rate = 1.3 * (1 - 0.8 * smooth(0.85, 1, (b.chewPh / TAU) % 40 / 40));
|
|
208
|
-
b.chewPh += dt * TAU * rate;
|
|
209
|
-
const chew = b.cud * (0.5 + 0.5 * Math.sin(b.chewPh));
|
|
210
|
-
b.grind = b.cud;
|
|
211
|
-
// (ruminating goats chew with the lips closed: a small drop of the jaw under the sideways grind, less
|
|
212
|
-
// than the lips' overlap; 0.1 rad opened the mouth 2 cm at the lips for most of an idle goat's time)
|
|
213
|
-
if (b.cud > 1e-3) { P.jaw = Math.max(P.jaw, 0.015 * chew); P.jawOmega = Math.max(P.jawOmega, 18); mx(P, 'eyelid', 0.25, b.cud * 0.6); }
|
|
214
|
-
// --- tail: held up, flicks in quick bursts (a few rapid side flicks)
|
|
215
|
-
b.tailT -= dt;
|
|
216
|
-
if (b.tailT <= 0) { b.tailT = 2 + e.rand() * 5; b.tailAge = 0; }
|
|
217
|
-
b.tailAge += dt;
|
|
218
|
-
const tw = b.tailAge < 0.8 ? Math.sin(PI * b.tailAge / 0.8) : 0;
|
|
219
|
-
if (tw > 0) { P.tailWag = Math.max(P.tailWag, 0.9 * tw * (1 - P.groundW)); mx(P, 'tailLift', 0.25, tw * 0.5); }
|
|
220
|
-
// --- ear flicks (one ear at a time, more often standing)
|
|
221
|
-
for (const E of b.ear) {
|
|
222
|
-
E.age += dt; E.next -= dt * (0.5 + 0.5 * still);
|
|
223
|
-
if (E.next <= 0) { E.next = 2.5 + e.rand() * 7; E.age = 0; E.a = (0.7 + 0.5 * e.rand()) * (1 - P.eyelid * 0.8) * (e.params?.ear === 'lop' ? 0.3 : 1); }
|
|
224
|
-
}
|
|
225
|
-
// --- lying on the side (dead): the ears fold back along the neck, out of the ground
|
|
226
|
-
const dead = L.postures.reduce((m, p) => (p.name === 'death' ? Math.max(m, p.w) : m), 0);
|
|
227
|
-
const flat = Math.max(smooth(0.3, 1.0, Math.abs(P.roll)), dead * smooth(0.3, 1, dead));
|
|
228
|
-
if (flat > 0) { mx(P, 'earFlat', 1.1, flat); mx(P, 'earTwitch', 0, flat); }
|
|
229
|
-
// ... and the head rests on the lower horn and ear, a little higher than a bare skull would
|
|
230
|
-
// (a long lop ear lies flat under the cheek: without the lift it was folded sharply about its root, out of
|
|
231
|
-
// the ground, and its root tore)
|
|
232
|
-
const lopLift = e.params?.ear === 'lop' ? 0.03 : 0;
|
|
233
|
-
if (dead > 0 && P.headW > 0) P.headPos.y += (0.035 + lopLift + 0.12 * (e.params?.horns?.len || 0)) * cfg.s * flat;
|
|
234
|
-
// (the head rolls over with the body rather than twisting on the atlas: the long throat stretched)
|
|
235
|
-
if (dead > 0) P.headRoll *= 1 - 0.45 * dead;
|
|
236
|
-
// --- lop ears hang: they hardly swivel, prick or flatten
|
|
237
|
-
if (e.params?.ear === 'lop') { P.earTwitch *= 0.25; P.earSwivel *= 0.3; P.earFlat *= 0.3; }
|
|
238
|
-
// --- lying / sleeping: the short tail lies flat, not curled round on the ground like a long tail
|
|
239
|
-
P.tailSide *= 0.2;
|
|
240
|
-
// --- grazing / drinking: the head pitches down ahead of the neck as it goes down (with both blended by
|
|
241
|
-
// the action's fade the neck was down before the nose had turned, and the poll opened 25 deg further than
|
|
242
|
-
// in the pose itself for a moment: the throat stretched)
|
|
243
|
-
for (const a of L.oneshots) {
|
|
244
|
-
if ((a.name !== 'eat' && a.name !== 'drink') || a.stopping || !(a.w > 0 && a.w < 1)) continue;
|
|
245
|
-
const pitch = a.tune?.pitch ?? 1.3;
|
|
246
|
-
const lead = Math.min(1, 3 * a.w) - a.w;
|
|
247
|
-
P.headPitch += lead * (pitch - P.headPitch);
|
|
248
|
-
}
|
|
249
|
-
// --- any other action interrupts grazing
|
|
250
|
-
if (L.oneshots.some((a) => !a.stopping && ['attack', 'jump', 'bleat', 'browse', 'paw'].includes(a.name))) for (const a of L.oneshots) if (a.name === 'eat' || a.name === 'drink') a.stopping = true;
|
|
251
|
-
// --- idle variants
|
|
252
|
-
if (e.idleVariants !== false && L.idle.w > 0.98 && !busy(L) && !e.input.look && !e.input.follow) {
|
|
253
|
-
b.idleT -= dt;
|
|
254
|
-
if (b.idleT <= 0) {
|
|
255
|
-
b.idleT = 7 + e.rand() * 10;
|
|
256
|
-
const r = e.rand();
|
|
257
|
-
if (r < 0.22) L.play('browse', { rear: e.rand() < 0.55 });
|
|
258
|
-
else if (r < 0.4) L.play('bleat');
|
|
259
|
-
else if (r < 0.58) L.play('headshake');
|
|
260
|
-
else if (r < 0.7) L.play('paw');
|
|
261
|
-
else if (r < 0.85) { b.ear[0].next = 0; b.ear[1].next = 0.25; }
|
|
262
|
-
}
|
|
263
|
-
} else if (busy(L)) b.idleT = Math.max(b.idleT, 3);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// ------------------------------------------------------------------------------------------------
|
|
267
|
-
// browse: stretches the neck up to strip leaves (opts.rear: rises onto the hind legs, forelegs
|
|
268
|
-
// raised as if resting on a trunk). Lips work, the head pulls back after each bite.
|
|
269
|
-
const browse = {
|
|
270
|
-
kind: 'oneshot', fade: 0.5, needsStand: true,
|
|
271
|
-
start(inst, L) {
|
|
272
|
-
const e = L.engine;
|
|
273
|
-
inst.rear = inst.opts.rear ?? true;
|
|
274
|
-
inst.dur = inst.opts.loop ? Infinity : (inst.opts.duration ?? (inst.rear ? 5 : 4.5));
|
|
275
|
-
inst.yaw = (e.rand() - 0.5) * 0.5;
|
|
276
|
-
},
|
|
277
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
278
|
-
apply(P, w, inst, L) {
|
|
279
|
-
const e = L.engine, cfg = e.cfg, t = inst.t, u = 1 / cfg.unit;
|
|
280
|
-
const up = w * smooth(0, 0.9, t);
|
|
281
|
-
// reach and bite cycle (~0.9 s): stretch, bite, pull back and chew
|
|
282
|
-
const c = (t * 1.1) % 1;
|
|
283
|
-
const bite = smooth(0.2, 0.35, c) * (1 - smooth(0.4, 0.7, c));
|
|
284
|
-
mx(P, 'lookW', 0, up);
|
|
285
|
-
mx(P, 'headPitch', -0.75 - 0.12 * bite, up); mx(P, 'headRaise', (0.1 + 0.015 * bite) * u, up); mx(P, 'neckReach', 0.03 * u, up);
|
|
286
|
-
mx(P, 'headYaw', inst.yaw + 0.1 * Math.sin(t * 0.8), up);
|
|
287
|
-
mx(P, 'jaw', 0.05 + 0.18 * bite, up); mx(P, 'jawOmega', 16, up);
|
|
288
|
-
mx(P, 'earFlat', -0.1, up); mx(P, 'tailLift', 0.15, up);
|
|
289
|
-
if (inst.rear) {
|
|
290
|
-
// up on the hind legs: the body comes down first, then the forefeet reach the ground again
|
|
291
|
-
const body = w * smooth(0.2, 1.3, t) * (1 - smooth(inst.dur - 1.2, inst.dur - 0.2, t));
|
|
292
|
-
const legs = Math.min(w * smooth(0.2, 0.7, t), w * smooth(0.004 * cfg.k, 0.04 * cfg.k, e.shY.x) + body);
|
|
293
|
-
mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
|
|
294
|
-
// (body ~55 deg up: the neck still reaches up and forward, the forelegs half folded as if
|
|
295
|
-
// resting on a trunk)
|
|
296
|
-
mx(P, 'dropF', -1.2, body); mx(P, 'dropH', 0.15, body);
|
|
297
|
-
for (let i = 0; i < 2; i++) { mxLeg(P, i, 'tuck', 1, legs); P.legs[i].extend = lerp(P.legs[i].extend, 0.3, legs); }
|
|
298
|
-
mx(P, 'headPitch', 0.1 - 0.1 * bite, body); mx(P, 'headRaise', 0.0, body); mx(P, 'neckReach', 0.045 * u, body);
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// bleat: head up, mouth open, jaw quiver, ears back a little
|
|
304
|
-
const bleat = {
|
|
305
|
-
kind: 'oneshot', fade: 0.25,
|
|
306
|
-
start(inst) { inst.dur = inst.opts.duration ?? 1.7; inst.said = false; },
|
|
307
|
-
update(inst, dt, L) {
|
|
308
|
-
if (!inst.said && inst.t > 0.4) { inst.said = true; L.engine.emit('vocalize', { kind: 'bleat' }); }
|
|
309
|
-
return inst.t >= inst.dur;
|
|
310
|
-
},
|
|
311
|
-
apply(P, w, inst, L) {
|
|
312
|
-
const e = L.engine, t = inst.t, u = 1 / e.cfg.unit;
|
|
313
|
-
const up = w * smooth(0, 0.35, t);
|
|
314
|
-
const call = smooth(0.35, 0.5, t) * (1 - smooth(inst.dur - 0.45, inst.dur - 0.15, t));
|
|
315
|
-
mx(P, 'lookW', 0.3, up);
|
|
316
|
-
mx(P, 'headPitch', -0.55, up); mx(P, 'headRaise', 0.04 * u, up); mx(P, 'neckReach', 0.015 * u, up);
|
|
317
|
-
mx(P, 'jaw', 0.42 + 0.07 * Math.sin(t * TAU * 11), call * w); mx(P, 'jawOmega', 30, w);
|
|
318
|
-
mx(P, 'earFlat', 0.3, up); mx(P, 'breathAmp', 2.2, call * w); mx(P, 'tailLift', 0.2, up);
|
|
319
|
-
},
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
// head shake: fast rotations about the nose axis (flies, water), ears flapping
|
|
323
|
-
const headshake = {
|
|
324
|
-
kind: 'oneshot', fade: 0.12,
|
|
325
|
-
start(inst) { inst.dur = 1.0; },
|
|
326
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
327
|
-
apply(P, w, inst) {
|
|
328
|
-
const t = inst.t;
|
|
329
|
-
const env = smooth(0, 0.12, t) * (1 - smooth(0.55, 0.95, t)) * w;
|
|
330
|
-
const s = Math.sin(t * TAU * 4.2);
|
|
331
|
-
mx(P, 'headOmega', 5, env); // (the head springs follow the fast shake)
|
|
332
|
-
mx(P, 'headRoll', 0.42 * s, env); mx(P, 'headYaw', 0.16 * s, env); mx(P, 'headPitch', -0.1, env);
|
|
333
|
-
mx(P, 'earTwitch', 2.5, env); mx(P, 'eyelid', 0.5, env); mx(P, 'lookW', 0, env);
|
|
334
|
-
},
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
// paw: scrapes the ground two or three times with one foreleg (before lying down, or in agitation)
|
|
338
|
-
// Each scrape (0.9 s): the hoof comes up and forward and is held there (~0.4 s, so the lifted foreleg reads:
|
|
339
|
-
// a continuous 0.55 s loop was never caught lifted in the action strip), strikes down and drags back along
|
|
340
|
-
// the ground.
|
|
341
|
-
const PAW_T0 = 0.35, PAW_CYC = 0.9, PAW_N = 2;
|
|
342
|
-
// hoof path per cycle phase f (0..1): [forward (x 0.07 m), height (x 0.1 m)]
|
|
343
|
-
function pawPath(f) {
|
|
344
|
-
const up = smooth(0.0, 0.16, f) * (1 - smooth(0.6, 0.7, f));
|
|
345
|
-
const fwd = -0.15 + 1.15 * smooth(0.0, 0.2, f) - 1.15 * smooth(0.62, 0.98, f); // (periodic: -0.15 at both ends)
|
|
346
|
-
return [fwd, up];
|
|
347
|
-
}
|
|
348
|
-
const paw = {
|
|
349
|
-
kind: 'oneshot', fade: 0.3, needsStand: true,
|
|
350
|
-
start(inst, L) { const e = L.engine; inst.dur = PAW_T0 + PAW_N * PAW_CYC + 0.45; inst.leg = inst.opts.side === -1 ? 1 : inst.opts.side === 1 ? 0 : (e.rand() < 0.5 ? 0 : 1); inst.hits = 0; },
|
|
351
|
-
update(inst, dt, L) {
|
|
352
|
-
const e = L.engine;
|
|
353
|
-
// the strike lands at 0.68 of each cycle
|
|
354
|
-
const n = Math.floor(clamp((inst.t - PAW_T0 - 0.68 * PAW_CYC) / PAW_CYC + 1, 0, PAW_N));
|
|
355
|
-
if (n > inst.hits && inst.hits < PAW_N) {
|
|
356
|
-
inst.hits = n;
|
|
357
|
-
e.emit('footstep', { foot: e.legs[inst.leg].def.key, position: e.legs[inst.leg].contact.clone(), speed: 0, strength: 0.6, paw: true });
|
|
358
|
-
}
|
|
359
|
-
return inst.t >= inst.dur;
|
|
360
|
-
},
|
|
361
|
-
apply(P, w, inst, L) {
|
|
362
|
-
const e = L.engine, cfg = e.cfg, s = cfg.s, t = inst.t, i = inst.leg;
|
|
363
|
-
const tEnd = PAW_T0 + PAW_N * PAW_CYC;
|
|
364
|
-
const k = w * smooth(0.15, 0.35, t) * (1 - smooth(tEnd + 0.05, tEnd + 0.35, t));
|
|
365
|
-
mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
|
|
366
|
-
mx(P, 'headPitch', 0.35, k); mx(P, 'headRaise', -0.05 / cfg.unit, k); mx(P, 'lookW', 0, k);
|
|
367
|
-
mx(P, 'side', -0.012 * (i === 0 ? 1 : -1) / cfg.unit, k); // weight onto the other three legs
|
|
368
|
-
const u = clamp((t - PAW_T0) / PAW_CYC, 0, PAW_N);
|
|
369
|
-
const f = u >= PAW_N ? 1 : u - Math.floor(u);
|
|
370
|
-
const [pf, pu] = u >= PAW_N ? [-0.15, 0] : pawPath(f);
|
|
371
|
-
const leg = e.legs[i];
|
|
372
|
-
const fwd = e.forward(e.heading, tv());
|
|
373
|
-
// (a clear lift, the hoof raised ~10 cm and brought forward, then struck down and dragged back: a 3.5 cm
|
|
374
|
-
// scrape did not read)
|
|
375
|
-
const tp = tv().copy(leg.plant).addScaledVector(fwd, 0.07 * s * pf);
|
|
376
|
-
tp.y += 0.1 * s * pu + 0.004 * s;
|
|
377
|
-
P.legs[i].target.lerp(tp, k / Math.max(1e-3, P.legs[i].reach + k));
|
|
378
|
-
mxLeg(P, i, 'reach', 1, k);
|
|
379
|
-
},
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
// attack: the goat's clash. Rises on the hind legs with the head twisted to one side, then drops
|
|
383
|
-
// forward and brings the horns / forehead down onto the opponent (the impact at the forefeet's
|
|
384
|
-
// landing). Buck: mane raised.
|
|
385
|
-
const attack = {
|
|
386
|
-
kind: 'oneshot', fade: 0.15, needsStand: true,
|
|
387
|
-
start(inst, L) {
|
|
388
|
-
const e = L.engine;
|
|
389
|
-
inst.dur = 2.1; inst.hit = false;
|
|
390
|
-
inst.side = inst.opts.side ?? (e.rand() < 0.5 ? -1 : 1);
|
|
391
|
-
inst.run = smooth(0.8, 2.5, e.speed / e.cfg.sq);
|
|
392
|
-
inst.target = inst.opts.target ? inst.opts.target.clone() : null;
|
|
393
|
-
},
|
|
394
|
-
update(inst, dt, L) {
|
|
395
|
-
const e = L.engine;
|
|
396
|
-
if (!inst.hit && inst.t >= 1.18) {
|
|
397
|
-
inst.hit = true;
|
|
398
|
-
const p = new THREE.Vector3().copy(e.headPose.position);
|
|
399
|
-
const dir = inst.target ? inst.target.clone().sub(e.pos).setY(0).normalize() : e.forward(e.heading, new THREE.Vector3());
|
|
400
|
-
e.emit('attackHit', { position: p, direction: dir, style: 'headbutt' });
|
|
401
|
-
}
|
|
402
|
-
return inst.t >= inst.dur;
|
|
403
|
-
},
|
|
404
|
-
apply(P, w, inst, L) {
|
|
405
|
-
const e = L.engine, cfg = e.cfg, t = inst.t, u = 1 / cfg.unit;
|
|
406
|
-
if (inst.target) { P.look = inst.target; mx(P, 'lookW', 0.6, w); }
|
|
407
|
-
const rise = smooth(0.1, 0.8, t);
|
|
408
|
-
const drop = smooth(0.92, 1.2, t);
|
|
409
|
-
// (running: no rearing, a lowered-head charge into the clash)
|
|
410
|
-
const still = 1 - inst.run;
|
|
411
|
-
const up = rise * (1 - drop) * w * still;
|
|
412
|
-
const clash = smooth(0.98, 1.2, t) * (1 - smooth(1.45, 2.0, t)) * w;
|
|
413
|
-
const legsW = Math.max(up, w * still * smooth(0.1, 0.4, t) * (1 - smooth(1.02, 1.16, t)));
|
|
414
|
-
mx(P, 'gaitW', 0, w * still * (1 - smooth(1.6, 2.05, t))); mx(P, 'legGait', 0, w * still * (1 - smooth(1.5, 2.0, t)));
|
|
415
|
-
if (inst.run > 0) { const low = smooth(0.3, 0.9, t) * (1 - smooth(1.3, 1.9, t)) * w * inst.run; mx(P, 'headPitch', 0.8, low); mx(P, 'headRaise', -0.06 * u, low); }
|
|
416
|
-
// rear
|
|
417
|
-
mx(P, 'dropF', -1.35, up); mx(P, 'dropH', 0.2, up); mx(P, 'pitch', 0.05, up);
|
|
418
|
-
for (let i = 0; i < 2; i++) { mxLeg(P, i, 'tuck', 1, legsW); P.legs[i].extend = lerp(P.legs[i].extend, lerp(0.25, 0.9, smooth(0.85, 1.1, t)), legsW); }
|
|
419
|
-
mx(P, 'headRoll', 0.45 * inst.side, up); mx(P, 'headYaw', -0.2 * inst.side, up); mx(P, 'headPitch', 0.15, up);
|
|
420
|
-
mx(P, 'headRaise', 0.03 * u, up);
|
|
421
|
-
// drop and clash: head down, forehead first, body lunging forward, forequarters low
|
|
422
|
-
mx(P, 'dropF', 0.28 * still, clash); mx(P, 'fwd', 0.07 * u, clash); mx(P, 'headPitch', 0.95, clash);
|
|
423
|
-
mx(P, 'headRaise', -0.07 * u, clash); mx(P, 'neckReach', 0.03 * u, clash);
|
|
424
|
-
mx(P, 'earFlat', 0.8, w * smooth(0, 0.2, t)); mx(P, 'earTwitch', 0, w);
|
|
425
|
-
mx(P, 'tailLift', 0.4, w);
|
|
426
|
-
// (the buck's mane rises in the threat)
|
|
427
|
-
if (e.params?.sex === 'male' && e.params?.age !== 'juvenile') P.furRaise = Math.max(P.furRaise || 0, 0.6 * w);
|
|
428
|
-
},
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
// lie: the engine's kneeling lie (actions.lie: down front, up hind), with the rise finished a little
|
|
432
|
-
// before the posture is released: its end-first springs (kF / kH) must settle at zero before the
|
|
433
|
-
// posture instance is removed, or the legs jump in the last frame of standing up
|
|
434
|
-
function lieApply(P, w, inst, L) {
|
|
435
|
-
const we = inst.target > 0 ? w : smooth(0.3, 1, w);
|
|
436
|
-
POSTURES.lie.apply(P, we, inst, L);
|
|
437
|
-
}
|
|
438
|
-
const lie = { kind: 'posture', fadeIn: 1.4, fadeOut: 1.3, apply: lieApply };
|
|
439
|
-
|
|
440
|
-
// sleep: sternal (goats rarely sleep flat out), head turned back and resting against the flank,
|
|
441
|
-
// eyes closed
|
|
442
|
-
const sleep = {
|
|
443
|
-
kind: 'posture', fadeIn: 1.3, fadeOut: 1.0,
|
|
444
|
-
apply(P, w, inst, L) {
|
|
445
|
-
lieApply(P, w, inst, L);
|
|
446
|
-
const e = L.engine;
|
|
447
|
-
const c = sm(clamp(w, 0, 1)) * smooth(1.2, 3.2, inst.t);
|
|
448
|
-
mx(P, 'headYaw', inst.side * 0.8, c); mx(P, 'headPitch', 0.45, c); mx(P, 'headRaise', -0.07 / e.cfg.unit, c);
|
|
449
|
-
mx(P, 'bend', inst.side * 0.35, c);
|
|
450
|
-
mx(P, 'earFlat', 0.45, c); mx(P, 'earTwitch', 0.2, c);
|
|
451
|
-
mx(P, 'eyelid', 1, smooth(1.8, 3.2, inst.t) * w);
|
|
452
|
-
mx(P, 'breathRate', 0.6, c); mx(P, 'lookW', 0, c); mx(P, 'tailIdle', 0.2, c);
|
|
453
|
-
},
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
// death: the engine's collapse (legs buckle, topple onto the side, settle), with the body sinking level and
|
|
457
|
-
// leaning to its side while the legs buckle (falls onto its side): the forelegs, the
|
|
458
|
-
// longer pair, buckled further than the hind ones and the goat pitched onto its nose with its hindquarters
|
|
459
|
-
// high before it rolled over
|
|
460
|
-
const death = {
|
|
461
|
-
kind: 'posture', fadeIn: POSTURES.death.fadeIn, fadeOut: POSTURES.death.fadeOut,
|
|
462
|
-
apply(P, w, inst, L) {
|
|
463
|
-
POSTURES.death.apply(P, w, inst, L);
|
|
464
|
-
const e = L.engine, cfg = e.cfg, t = inst.t, side = inst.side;
|
|
465
|
-
const buckle = smooth(0, 0.35, t), fall = clamp((t - 0.3) / 0.55, 0, 1), fallE = fall * fall;
|
|
466
|
-
const settle = fall >= 1 ? Math.exp(-(t - 0.85) * 6) * Math.sin((t - 0.85) * 18) * 0.06 : 0;
|
|
467
|
-
const mv = e.air.active ? 0 : smooth(0.08, 0.45, e.speed / cfg.sk) * (1 - smooth(0.3, 0.7, t));
|
|
468
|
-
const kb = 1 - mv;
|
|
469
|
-
mx(P, 'dropF', lerp(0.42 * buckle * kb, 1, fallE), w);
|
|
470
|
-
mx(P, 'roll', side * (1.42 * (fallE + 0.22 * buckle * kb * (1 - fallE)) - settle), w);
|
|
471
|
-
// (the head goes down with the body as it goes over, not ahead of it: the engine drops it to the ground
|
|
472
|
-
// from 0.35 s, and the goat dived onto its nose before it rolled)
|
|
473
|
-
P.headW *= smooth(0.5, 1.05, t);
|
|
474
|
-
},
|
|
475
|
-
};
|
|
476
|
-
|
|
477
|
-
// hit: the engine's flinch (a shove away from the blow and a restep), held long enough to read on a goat: the
|
|
478
|
-
// body leans and bends away for ~0.4 s with the head thrown up and away, then the goat shakes it off (the
|
|
479
|
-
// engine's 0.12 s recoil barely showed in any frame)
|
|
480
|
-
const hit = {
|
|
481
|
-
...ONESHOTS.hit,
|
|
482
|
-
kind: 'oneshot',
|
|
483
|
-
start(inst, L) {
|
|
484
|
-
ONESHOTS.hit.start(inst, L);
|
|
485
|
-
inst.dur = 1.4;
|
|
486
|
-
inst.dead = L.postures.some((p) => p.name === 'death');
|
|
487
|
-
},
|
|
488
|
-
apply(P, w, inst) {
|
|
489
|
-
const t = inst.t;
|
|
490
|
-
const k = smooth(0, 0.1, t) * (1 - 0.55 * smooth(0.3, 0.75, t)) * (1 - smooth(0.75, 1.25, t)) * w * (inst.dead ? 0.4 : 1);
|
|
491
|
-
mx(P, 'roll', inst.lx * 0.22, k); mx(P, 'bend', -inst.lx * 0.36, k);
|
|
492
|
-
mx(P, 'pitch', inst.lz * 0.1, k); mx(P, 'dropF', 0.2, k); mx(P, 'dropH', 0.13, k);
|
|
493
|
-
P.headLocal.set(inst.lx * 0.08, 0.03, inst.lz * 0.07 - 0.03); mx(P, 'headLocalW', 1, k);
|
|
494
|
-
mx(P, 'headYaw', -inst.lx * 0.5, k); mx(P, 'headPitch', -0.3, k);
|
|
495
|
-
mx(P, 'earFlat', 1, w * (1 - smooth(0.55, 0.95, t))); mx(P, 'eyelid', 0.7, k);
|
|
496
|
-
mx(P, 'jaw', 0.16, k); mx(P, 'tailLift', -0.15, k);
|
|
497
|
-
if (inst.dead) return;
|
|
498
|
-
// shaking it off
|
|
499
|
-
const sh = smooth(0.7, 0.85, t) * (1 - smooth(1.12, 1.32, t)) * w;
|
|
500
|
-
mx(P, 'headOmega', 5, sh); mx(P, 'headRoll', 0.3 * Math.sin((t - 0.7) * TAU * 4.2), sh);
|
|
501
|
-
mx(P, 'earTwitch', 2.5, sh);
|
|
502
|
-
},
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
export const hooks = {
|
|
506
|
-
pose,
|
|
507
|
-
update,
|
|
508
|
-
actions: { browse, bleat, headshake, paw, attack, hit, lie, sleep, death },
|
|
509
|
-
};
|