@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,152 +0,0 @@
|
|
|
1
|
-
// Pig skeleton in bind pose (metres). Forward = +Z, up = +Y, the animal's left = +X.
|
|
2
|
-
// Reference individual: a Large White finisher / young gilt, 0.72 m at the withers, ~120 kg.
|
|
3
|
-
// Landmarks from side1.jpg / side2.jpg (normalised to the withers height) and the
|
|
4
|
-
// porcine limb table: point of shoulder 0.48 m, elbow 0.31, carpus 0.15, fore fetlock
|
|
5
|
-
// 0.065, stifle 0.36, hock 0.17 (point of hock 0.21), hind fetlock 0.065; snout tip -> buttock
|
|
6
|
-
// 1.35 m (1.87 x withers), belly 0.30 m above the ground.
|
|
7
|
-
//
|
|
8
|
-
// Hooves: like the cow, a hoof bone per leg below the pastern (fpaw / hpaw = pastern: fetlock ->
|
|
9
|
-
// coffin joint; fhoof / hhoof = the two main claws: coffin joint -> toe), the dew claws ride on the
|
|
10
|
-
// pastern. A snout bone carries the rostral disc (twitches and wiggles while sniffing).
|
|
11
|
-
//
|
|
12
|
-
// The tail is a corkscrew (pigTail below): the rest chain is the curled tail, which the behaviour
|
|
13
|
-
// hook holds rigidly on the root bone at runtime (no stretch); uncurling (resting, fear) blends to
|
|
14
|
-
// the engine's hanging tail.
|
|
15
|
-
import { buildRig } from '../../core/rig/rig.js';
|
|
16
|
-
import { quadrupedBones, quadrupedLimbs } from '../../core/rig/quadruped.js';
|
|
17
|
-
import { EAR_BASE, earSpine } from './ears.js';
|
|
18
|
-
|
|
19
|
-
export const TAIL_SEGS = 10;
|
|
20
|
-
export const TAIL_LENS = [0.052, 0.03, 0.025, 0.023, 0.022, 0.021, 0.02, 0.019, 0.018, 0.017];
|
|
21
|
-
// Head frame: modelled along its own axis (poll -> snout disc), pitched 35 degrees nose-down in the
|
|
22
|
-
// bind pose (relaxed standing carriage, research 3: snout 30-45 deg below horizontal). Head-local
|
|
23
|
-
// coordinates: x lateral, y dorsal (forehead side), z along the head toward the disc; origin on the
|
|
24
|
-
// axis level with the eyes.
|
|
25
|
-
export const HEAD_PITCH = (35 * Math.PI) / 180;
|
|
26
|
-
export const HZ = [0, -Math.sin(HEAD_PITCH), Math.cos(HEAD_PITCH)];
|
|
27
|
-
export const HY = [0, Math.cos(HEAD_PITCH), Math.sin(HEAD_PITCH)];
|
|
28
|
-
export const HEAD_O = [0, 0.585, 0.59];
|
|
29
|
-
export const SNOUT_K = 1.15; // (the sculpt's snout length factor at params.snoutLen = 1)
|
|
30
|
-
export const hl = (v) => [HEAD_O[0] + v[0], HEAD_O[1] + v[1] * HY[1] + v[2] * HZ[1], HEAD_O[2] + v[1] * HY[2] + v[2] * HZ[2]];
|
|
31
|
-
export const hdir = (v) => [v[0], v[1] * HY[1] + v[2] * HZ[1], v[1] * HY[2] + v[2] * HZ[2]];
|
|
32
|
-
|
|
33
|
-
// ears: the root on the head and the leaf geometry are in ears.js (the ear bone runs from the root to the
|
|
34
|
-
// leaf's tip, wherever the leaf's bend puts it)
|
|
35
|
-
export function pigJoints(params = {}) {
|
|
36
|
-
const K = (params.snoutLen ?? 1) * SNOUT_K;
|
|
37
|
-
const sz = (z) => (z > 0.06 ? 0.06 + (z - 0.06) * K : z);
|
|
38
|
-
const eb = hl(EAR_BASE);
|
|
39
|
-
const J = {
|
|
40
|
-
nose: hl([0, -0.012, sz(0.198)]),
|
|
41
|
-
snoutBase: hl([0, 0.0, sz(0.12)]),
|
|
42
|
-
occiput: hl([0, -0.015, -0.115]),
|
|
43
|
-
neckMid: [0, 0.59, 0.415],
|
|
44
|
-
neckBase: [0, 0.56, 0.33],
|
|
45
|
-
chestMid: [0, 0.625, 0.16],
|
|
46
|
-
thoraxRear: [0, 0.645, -0.02],
|
|
47
|
-
lumbarMid: [0, 0.655, -0.19],
|
|
48
|
-
lumbosacral: [0, 0.66, -0.36],
|
|
49
|
-
tailBase: [0, 0.69, -0.59],
|
|
50
|
-
// fore: scapula sloping ~65 deg, the humerus down and back, radius and cannon near vertical,
|
|
51
|
-
// an upright pastern (pigs stand on the tips of the claws)
|
|
52
|
-
scapTopL: [0.065, 0.66, 0.255],
|
|
53
|
-
shoulderL: [0.105, 0.48, 0.395],
|
|
54
|
-
elbowL: [0.1, 0.31, 0.29],
|
|
55
|
-
wristL: [0.088, 0.15, 0.305],
|
|
56
|
-
mcpL: [0.083, 0.064, 0.322],
|
|
57
|
-
fcoffinL: [0.083, 0.028, 0.345],
|
|
58
|
-
ftoeL: [0.083, 0.002, 0.388],
|
|
59
|
-
// hind: hip joint, stifle, hock, fetlock, coffin joint, toe
|
|
60
|
-
hipL: [0.09, 0.55, -0.4],
|
|
61
|
-
kneeL: [0.11, 0.36, -0.27],
|
|
62
|
-
hockL: [0.086, 0.17, -0.395],
|
|
63
|
-
mtpL: [0.082, 0.064, -0.362],
|
|
64
|
-
hcoffinL: [0.082, 0.028, -0.338],
|
|
65
|
-
htoeL: [0.082, 0.002, -0.296],
|
|
66
|
-
jawHinge: hl([0, -0.052, -0.06]),
|
|
67
|
-
jawTip: hl([0, -0.085, sz(0.15)]),
|
|
68
|
-
earBaseL: eb,
|
|
69
|
-
earTipL: earSpine(eb, 'L', params).tip,
|
|
70
|
-
};
|
|
71
|
-
pigTail(J, params);
|
|
72
|
-
return J;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// the bind tail: a corkscrew. The root runs back from the tail head, then every joint turns by the
|
|
76
|
-
// same relative rotation (TAIL_BETA about the local axis cos(TAU) lateral + sin(TAU) along), which
|
|
77
|
-
// makes a helix: the loops roll down behind the buttocks and progress to one side (params.tailSide).
|
|
78
|
-
// The behaviour hook keeps this shape rigid on the root bone when the tail is curled, and blends
|
|
79
|
-
// toward the engine's hanging chain when it uncurls.
|
|
80
|
-
export const TAIL_ROOT_PITCH = 4; // deg above horizontal
|
|
81
|
-
export const TAIL_BETA = 58; // deg per joint (curling up)
|
|
82
|
-
export const TAIL_TAU = 0.45; // rad (helix lead)
|
|
83
|
-
const rot = (v, a, ang) => {
|
|
84
|
-
const c = Math.cos(ang), s = Math.sin(ang), d = a[0] * v[0] + a[1] * v[1] + a[2] * v[2];
|
|
85
|
-
const cr = [a[1] * v[2] - a[2] * v[1], a[2] * v[0] - a[0] * v[2], a[0] * v[1] - a[1] * v[0]];
|
|
86
|
-
return [0, 1, 2].map((i) => v[i] * c + cr[i] * s + a[i] * d * (1 - c));
|
|
87
|
-
};
|
|
88
|
-
const norm3 = (v) => { const l = Math.hypot(v[0], v[1], v[2]) || 1; return [v[0] / l, v[1] / l, v[2] / l]; };
|
|
89
|
-
export function pigTail(J, params = {}) {
|
|
90
|
-
const n = TAIL_SEGS, side = params.tailSide ?? 1;
|
|
91
|
-
const docked = params.docked ? 0.35 : 1;
|
|
92
|
-
const r0 = (TAIL_ROOT_PITCH * Math.PI) / 180;
|
|
93
|
-
let y = [0, Math.sin(r0), -Math.cos(r0)], x = [1, 0, 0];
|
|
94
|
-
const beta = (TAIL_BETA * Math.PI) / 180, tau = TAIL_TAU * side;
|
|
95
|
-
let p = J.tailBase.slice();
|
|
96
|
-
J.tail0 = p.slice();
|
|
97
|
-
for (let i = 0; i < n; i++) {
|
|
98
|
-
const l = TAIL_LENS[i] * (i < 2 ? 1 : docked);
|
|
99
|
-
p = [p[0] + y[0] * l, p[1] + y[1] * l, p[2] + y[2] * l];
|
|
100
|
-
J['tail' + (i + 1)] = p;
|
|
101
|
-
const ax = norm3([x[0] * Math.cos(tau) + y[0] * Math.sin(tau), x[1] * Math.cos(tau) + y[1] * Math.sin(tau), x[2] * Math.cos(tau) + y[2] * Math.sin(tau)]);
|
|
102
|
-
// (the root bends less into the first loop)
|
|
103
|
-
const b = beta * (i === 0 ? 0.6 : 1);
|
|
104
|
-
y = rot(y, ax, b); x = rot(x, ax, b);
|
|
105
|
-
}
|
|
106
|
-
return J;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function pigBones() {
|
|
110
|
-
const b = quadrupedBones({ tailSegs: TAIL_SEGS, ears: true, jaw: true, extra: [['snout', 'snoutBase', 'nose', 'head', { region: 'head', group: 'snout' }]] });
|
|
111
|
-
for (const d of b) {
|
|
112
|
-
if (d[0] === 'fpaw{S}') { d[2] = 'fcoffin{S}'; d[4] = { region: 'limb', group: 'F{S}' }; }
|
|
113
|
-
if (d[0] === 'hpaw{S}') { d[2] = 'hcoffin{S}'; d[4] = { region: 'limb', group: 'H{S}' }; }
|
|
114
|
-
}
|
|
115
|
-
b.push(
|
|
116
|
-
['fhoof{S}', 'fcoffin{S}', 'ftoe{S}', 'fpaw{S}', { region: 'foot', group: 'F{S}' }],
|
|
117
|
-
['hhoof{S}', 'hcoffin{S}', 'htoe{S}', 'hpaw{S}', { region: 'foot', group: 'H{S}' }],
|
|
118
|
-
);
|
|
119
|
-
return b;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function pigRig(params = {}, J = pigJoints(params)) {
|
|
123
|
-
const limbs = quadrupedLimbs({
|
|
124
|
-
// (the short legs are sunk deep in the fat body: the limb cores stop well below the girdles)
|
|
125
|
-
front: { tCore: 0.62, aCore: 0.05, aBody: -0.09, midX: 0.05 },
|
|
126
|
-
hind: { tCore: 0.55, aCore: 0.022, aBody: -0.08, midX: 0.02 },
|
|
127
|
-
});
|
|
128
|
-
for (const L of Object.values(limbs)) { L.bones.push((L.front ? 'fhoof' : 'hhoof') + L.S); L.distal.push((L.front ? 'fhoof' : 'hhoof') + L.S); }
|
|
129
|
-
return buildRig({
|
|
130
|
-
joints: J,
|
|
131
|
-
unit: 0.72 / 0.76,
|
|
132
|
-
headOrigin: HEAD_O,
|
|
133
|
-
bones: pigBones(),
|
|
134
|
-
axial: {
|
|
135
|
-
points: ['nose', 'occiput', 'neckMid', 'neckBase', 'chestMid', 'thoraxRear', 'lumbarMid', 'lumbosacral', 'tailBase', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + (i + 1))],
|
|
136
|
-
bones: ['head', 'neck2', 'neck1', 'chest', 'spine3', 'spine2', 'spine1', 'pelvis', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + i)],
|
|
137
|
-
// the heavy jowl hangs far below the axis: the skull's influence runs back into the throat;
|
|
138
|
-
// the short thick neck blends broadly into the shoulders
|
|
139
|
-
blend: { 1: [-0.05, 0.1, 2], 2: [-0.05, 0.05, 1], 3: [-0.08, 0.08, 1] },
|
|
140
|
-
bodyTail: 0, // the thin tail is set on the rump: body skin blends into it only at the root
|
|
141
|
-
},
|
|
142
|
-
limbs,
|
|
143
|
-
appendages: [
|
|
144
|
-
{ group: 'earL', bone: 'earL', blend: [-0.002, 0.005] },
|
|
145
|
-
{ group: 'earR', bone: 'earR', blend: [-0.002, 0.005] },
|
|
146
|
-
{ group: 'snout', bone: 'snout', blend: [-0.01, 0.02] },
|
|
147
|
-
// the skin under the chin rides on the jaw and blends into the throat (sculpt.js 'jawskin')
|
|
148
|
-
{ group: 'jawskin', bone: 'jaw', blend: [-0.004, 0.012] },
|
|
149
|
-
],
|
|
150
|
-
webTags: ['flankfold', 'thighfront', 'scapmuscle', 'pectoral', 'forearmweb', 'ham'],
|
|
151
|
-
});
|
|
152
|
-
}
|
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
// The pig, sculpted as a signed distance field.
|
|
2
|
-
// Every primitive is attached to a bone (skinning) and a group (axial / limb / ear / snout / jaw).
|
|
3
|
-
// The head is modelled in its own frame (rig.js: hl()), measured from the profile and frontal
|
|
4
|
-
// references (face1, front1, face2); the body relative to the joints so the sculpt follows the
|
|
5
|
-
// skeleton.
|
|
6
|
-
//
|
|
7
|
-
// A pig is a barrel on four short legs sunk into it: the shoulders, the back and the hams are one
|
|
8
|
-
// smooth fat-covered mass (no visible withers, no waist), the neck is hidden in the jowls, and the
|
|
9
|
-
// wedge-shaped head ends in the flat rostral disc with its two nostrils.
|
|
10
|
-
//
|
|
11
|
-
// Individual knobs (params, see index.js): boar (0 sow .. 1 boar: shoulder shield, crest over the
|
|
12
|
-
// neck, bigger jowls, tusks, sheath and testes instead of the teat row), belly (0 lean .. 1 a sow's
|
|
13
|
-
// sagging belly), teats (pairs), ear ('erect' | 'semi' | 'lop'), earSize, dish (dished face,
|
|
14
|
-
// Berkshire), snoutLen, ham (fullness of the hams), piglet.
|
|
15
|
-
import { HEAD_O, HZ, HY, hl, hdir, TAIL_SEGS, SNOUT_K } from './rig.js';
|
|
16
|
-
import { add, sub, mul, lerp, norm, cross } from '../../core/math/vec.js';
|
|
17
|
-
import { eyeFrameOf, apertureTiltAlong } from '../../core/sdf/eyeSocket.js';
|
|
18
|
-
import { earLeaf } from './ears.js';
|
|
19
|
-
|
|
20
|
-
// Eye (head-local centre -> offset from HEAD_O): globe ~23 mm, visible opening ~20 x 11 mm, under
|
|
21
|
-
// a fat-padded brow, at the side of a face that narrows in front of it (face2, front1: both eyes
|
|
22
|
-
// show from straight in front). EYE_OUT moves the ball out along its axis so its front sits at the
|
|
23
|
-
// skin (the lids are the surface, not a tunnel through the brow and jowl: AUTHORING section 7).
|
|
24
|
-
const EYE_LOCAL = [0.058, 0.026, 0.006];
|
|
25
|
-
const EYE_FWD = 40; // deg forward of lateral (along the head)
|
|
26
|
-
const EYE_OUT = 0.016;
|
|
27
|
-
const eyeDir = (() => {
|
|
28
|
-
const a = (EYE_FWD * Math.PI) / 180;
|
|
29
|
-
return norm(add(add([Math.cos(a), 0, 0], mul(HZ, Math.sin(a))), mul(HY, 0.1)));
|
|
30
|
-
})();
|
|
31
|
-
// (the aperture: 20 x 14 mm, a rounder opening than the 22 x 12 mm almond, which read as a narrow slit: front1,
|
|
32
|
-
// face2 show round dark eyes with level lids)
|
|
33
|
-
// (the 20 x 14 mm opening showed the whole round iris, a doll's eye; the photos (eye_lwshow_R,
|
|
34
|
-
// eye_mochyn, eye_gifu) show a small almond, ~19 x 10.5 mm, with pointed corners, the upper lid hooding the top of
|
|
35
|
-
// the iris: R 11.2 / d 6.0 mm)
|
|
36
|
-
const EYE_BASE = {
|
|
37
|
-
c: add(sub(hl(EYE_LOCAL), HEAD_O), mul(eyeDir, EYE_OUT)), r: 0.0128, back: 0.003, yaw: Math.atan2(eyeDir[0], eyeDir[2]), pitch: Math.asin(eyeDir[1]),
|
|
38
|
-
lid: 0.0028, R: 0.0112, d: 0.006, off: 0.0006, tilt: 0, irisZ: 0.0074, irisR: 0.0088,
|
|
39
|
-
};
|
|
40
|
-
// the lid line level in the standing carriage (laid along the head axis, which is carried 35 deg
|
|
41
|
-
// nose-down, and rolled 0.12 further, the almond sloped 24 deg down toward the snout: a sly, angry look; the
|
|
42
|
-
// untilted frame is level, apertureTiltAlong(EYE_BASE, HEAD_O, HZ) - 0.12 was 0.44)
|
|
43
|
-
// (a slight roll, the inner corner a little lower: eye_lwshow_R, eye_mochyn)
|
|
44
|
-
EYE_BASE.tilt = 0.1;
|
|
45
|
-
void apertureTiltAlong; void HZ;
|
|
46
|
-
export const EYE = EYE_BASE;
|
|
47
|
-
|
|
48
|
-
const X = [1, 0, 0];
|
|
49
|
-
const UP = [0, 1, 0];
|
|
50
|
-
|
|
51
|
-
// tusk centre line (head-local, left): the lower canine grows out of the jaw beside the snout and
|
|
52
|
-
// curves up and back outside the upper lip
|
|
53
|
-
// (rooted in the jaw a third of the way from the disc to the eye, out through the mouth line at the
|
|
54
|
-
// side, then up and back clear of the lip)
|
|
55
|
-
export function tuskPath(params, s) {
|
|
56
|
-
const L = params.tusks || 0;
|
|
57
|
-
const a = [0.03 * s, -0.078, 0.128];
|
|
58
|
-
const b = [0.066 * s, -0.066, 0.132];
|
|
59
|
-
const m = [0.077 * s, -0.052 + 0.014 * L, 0.13 - 0.008 * L];
|
|
60
|
-
const c = [0.082 * s, -0.05 + 0.04 * L, 0.127 - 0.04 * L];
|
|
61
|
-
return [a, b, m, c];
|
|
62
|
-
}
|
|
63
|
-
// the tusk as a smooth arched cone (reference space, the bind pose): a chain of round cones along a cubic Bezier
|
|
64
|
-
// from just inside the lower lip (a little way from the root toward b) over b and m to the tip c, tapering from
|
|
65
|
-
// 4.5-7 mm to a 1.2 mm point. Its own part, meshed finely (regions.js): in the jaw's 3 mm cells the 2-6 mm cone
|
|
66
|
-
// meshed as a crumpled, faceted blade, and the lip crease painted round it.
|
|
67
|
-
export const TUSK_N = 8;
|
|
68
|
-
export function tuskCones(params, s) {
|
|
69
|
-
const T = tuskPath(params, s).map(hl), L = params.tusks || 0;
|
|
70
|
-
const P0 = lerp(T[0], T[1], 0.55), P1 = T[1], P2 = T[2], P3 = T[3];
|
|
71
|
-
const at = (t) => { const u = 1 - t; return add(add(mul(P0, u * u * u), mul(P1, 3 * u * u * t)), add(mul(P2, 3 * u * t * t), mul(P3, t * t * t))); };
|
|
72
|
-
const r0 = 0.0045 + 0.0025 * L, r1 = 0.0012;
|
|
73
|
-
const rad = (t) => r1 + (r0 - r1) * (1 - Math.pow(t, 1.3));
|
|
74
|
-
const out = [];
|
|
75
|
-
for (let i = 0; i < TUSK_N; i++) { const t0 = i / TUSK_N, t1 = (i + 1) / TUSK_N; out.push({ a: at(t0), b: at(t1), ra: rad(t0), rb: rad(t1) }); }
|
|
76
|
-
return out;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Ear leaves (ears.js): the tiles of one smooth curved sheet, thick at the root and thinning to a round rim.
|
|
80
|
-
// (Exported under the old name for the meshing plan and the tools.)
|
|
81
|
-
export function earShape(J, params, S) {
|
|
82
|
-
return earLeaf(J['earBase' + S], S, params);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// The eye in its socket (core sculptEyeSocket, plus the lids): an orbit hollow, the lid shell over the ball, a soft
|
|
86
|
-
// roll of the upper lid along the top of the opening and a thinner lower lid, then the almond cut through them, so
|
|
87
|
-
// the lid margins stand as rounded rims round the eye instead of a hole cut in a smooth shell (which read as a
|
|
88
|
-
// ragged dark speck; eye_lwshow_R, eye_mochyn, eye_gifu: a thick, rounded upper lid with a fold above it, a
|
|
89
|
-
// slim lower lid). The rolls are straight along the opening, so they sink into the ball toward the corners.
|
|
90
|
-
function pigEye(m, s) {
|
|
91
|
-
const E = EYE, ef = eyeFrameOf(E, HEAD_O, s), bone = 'head';
|
|
92
|
-
const at = (u, v, w) => add(add(add(ef.c, mul(ef.x, u)), mul(ef.y, v)), mul(ef.z, w));
|
|
93
|
-
m.ell({ bone, tag: 'orbit', c: at(0, 0.0015, 0.014), axis: ef.z, up: ef.y, r: [0.016, 0.0115, 0.008], k: 0.011, carve: true });
|
|
94
|
-
m.sphere({ bone, tag: 'eyelid', c: ef.c, rad: E.r + E.lid, k: E.r * 0.4 });
|
|
95
|
-
const h = E.R - E.d, rl = E.r + E.lid;
|
|
96
|
-
const onShell = (y) => Math.sqrt(Math.max(0, rl * rl - y * y));
|
|
97
|
-
// upper lid: a roll ~2 mm proud of the shell over the top of the opening
|
|
98
|
-
const yu = E.off + h + 0.0016;
|
|
99
|
-
m.ell({ bone, tag: 'lidroll', c: at(0, yu, onShell(yu) - 0.0012), axis: ef.z, up: ef.y, r: [0.0105, 0.0032, 0.0028], k: 0.003 });
|
|
100
|
-
// lower lid: slimmer, ~1 mm proud
|
|
101
|
-
const yl = E.off - h - 0.0012;
|
|
102
|
-
// (soft and broad: a thinner roll meshed a droplet-shaped knot under the lid at medium's 2.1 mm eyelid cells)
|
|
103
|
-
m.ell({ bone, tag: 'lidroll', c: at(0, yl, onShell(yl) - 0.0017), axis: ef.z, up: ef.y, r: [0.0088, 0.0028, 0.0026], k: 0.0035 });
|
|
104
|
-
m.lens({ bone, tag: 'eyesocket', c: add(ef.c, mul(ef.y, E.off)), x: ef.x, y: ef.y, z: ef.z, R: E.R, d: E.d, zMin: -E.r * 0.16, zMax: E.r * 2, k: E.r * 0.18, carve: true });
|
|
105
|
-
return ef;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function sculptPig(m, rig, params = {}) {
|
|
109
|
-
const J = rig.J;
|
|
110
|
-
const piglet = params.age === 'juvenile';
|
|
111
|
-
const boar = params.boar ?? 0;
|
|
112
|
-
const belly = params.belly ?? 0.3;
|
|
113
|
-
const hamK = params.ham ?? 1;
|
|
114
|
-
const fat = params.fat ?? 1;
|
|
115
|
-
const snoutK = (params.snoutLen ?? 1) * SNOUT_K;
|
|
116
|
-
const dish = params.dish ?? 0.2;
|
|
117
|
-
|
|
118
|
-
const ellY = (o) => {
|
|
119
|
-
const y = norm(o.ydir);
|
|
120
|
-
const lat = o.lateral || X;
|
|
121
|
-
const z = norm(cross(lat, y));
|
|
122
|
-
return m.ell({ ...o, axis: z, up: y, r: [o.r[0], o.r[1], o.r[2]] });
|
|
123
|
-
};
|
|
124
|
-
// ellipsoid in head-local coordinates: r = [lateral, dorsal, along the head]
|
|
125
|
-
const H = { bone: 'head' };
|
|
126
|
-
const hell = (o) => m.ell({ ...H, ...o, c: hl(o.c), axis: o.axisL ? norm(hdir(o.axisL)) : HZ, up: o.upL ? norm(hdir(o.upL)) : HY });
|
|
127
|
-
const SN = { bone: 'snout', group: 'snout' };
|
|
128
|
-
// snout-local along coordinate: the snout is longer or shorter per breed / individual (the
|
|
129
|
-
// rostral end moves, the eyes stay)
|
|
130
|
-
const sz = (z) => (z > 0.06 ? 0.06 + (z - 0.06) * snoutK : z);
|
|
131
|
-
|
|
132
|
-
// ---------------------------------------------------------------- TORSO
|
|
133
|
-
// one long barrel: shoulders, back and hams blend into a single fat-covered mass; a level (or
|
|
134
|
-
// slightly arched) top line 0.72-0.74 m, belly 0.30 m above the ground, half width ~0.18 m
|
|
135
|
-
const wB = (1 + 0.05 * boar) * fat;
|
|
136
|
-
// (a piglet's underline tucked up: side1 / research 2, a young gilt's chest 0.53 withers heights deep and its
|
|
137
|
-
// belly 0.47 above the ground, against 0.58-0.60 and 0.38 on a finisher; the top line stays)
|
|
138
|
-
const tuck = piglet ? 0.03 : 0;
|
|
139
|
-
// (side2: the chest 0.58 withers heights deep behind the elbow, the belly 0.39 above the ground; the
|
|
140
|
-
// barrel as wide in the middle as over the shoulders and hams from above, front2)
|
|
141
|
-
m.ell({ tag: 'barrel', bone: 'spine2', c: [0, 0.525 + tuck / 2, -0.08], r: [0.186 * wB, 0.2 - tuck / 2, 0.5], k: 0 });
|
|
142
|
-
// (the ribs and the fat over them: as wide over the middle as over the shoulder and thigh muscles, a finisher is
|
|
143
|
-
// straight-sided from above; the barrel alone was 5-6 cm narrower a side than the hams there, which showed as a
|
|
144
|
-
// saddle in the back when the pig lay on its side. Only over the middle: a wider barrel
|
|
145
|
-
// also pushed the flank by the thigh out, and a dead pig's lower thigh into a slope)
|
|
146
|
-
m.ell({ tag: 'ribs', bone: 'spine2', c: [0, 0.535 + tuck / 2, -0.055], r: [0.21 * wB, 0.15, 0.295], k: 0.07 });
|
|
147
|
-
// (the chest floor behind the elbows level with the belly line: side2, chest depth ~0.58 withers heights)
|
|
148
|
-
m.ell({ tag: 'shoulder', bone: 'spine3', c: [0, 0.535 + tuck / 2, 0.21], r: [0.166 * wB + 0.012 * boar, 0.178 + 0.01 * boar - tuck / 2, 0.2], k: 0.08 });
|
|
149
|
-
m.ell({ tag: 'hamball', bone: 'pelvis', c: [0, 0.53 + tuck / 3, -0.43], r: [0.172 * wB * (0.94 + 0.06 * hamK), 0.195 - tuck / 3, 0.2 * (0.95 + 0.05 * hamK)], k: 0.08 });
|
|
150
|
-
m.ell({ tag: 'back', bone: 'spine2', c: [0, 0.665, -0.08], r: [0.132 * wB, 0.07, 0.44], k: 0.1 });
|
|
151
|
-
m.ell({ tag: 'rump', bone: 'pelvis', c: [0, 0.665, -0.4], r: [0.13 * wB, 0.07, 0.18], axis: norm([0, -0.1, 1]), k: 0.08 });
|
|
152
|
-
// belly: a flat underline, sagging in older sows
|
|
153
|
-
m.ell({ tag: 'belly', bone: 'spine2', c: [0, 0.398 - 0.04 * belly + tuck, -0.1], r: [0.148 * wB, 0.08 + 0.022 * belly, 0.33], k: 0.1 });
|
|
154
|
-
m.ell({ tag: 'brisket', bone: 'chest', c: [0, 0.445 + tuck * 0.8, 0.3], r: [0.105, 0.095, 0.11], k: 0.06 });
|
|
155
|
-
// hind end: the rounded buttocks over the hams; the tail is set on high between them
|
|
156
|
-
m.ell({ tag: 'buttock', bone: 'pelvis', c: [0, 0.6, -0.54], r: [0.12 * wB, 0.11, 0.08], k: 0.08 });
|
|
157
|
-
m.ell({ tag: 'tailroot', bone: 'pelvis', c: [0, 0.675, -0.575], r: [0.04, 0.035, 0.035], k: 0.05 });
|
|
158
|
-
if (boar >= 0.5 && !piglet) {
|
|
159
|
-
// testes: two large rounded bulges under the tail, between the hams
|
|
160
|
-
for (const s of [1, -1]) m.ell({ tag: 'scrotum', bone: 'pelvis', c: [0.038 * s, 0.5, -0.585], r: [0.045, 0.06, 0.045], k: 0.04 });
|
|
161
|
-
// sheath: the preputial pouch in front of the navel
|
|
162
|
-
m.ell({ tag: 'sheath', bone: 'spine2', c: [0, 0.305, -0.02], r: [0.028, 0.03, 0.07], axis: norm([0, 0.25, 1]), k: 0.05 });
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// ---------------------------------------------------------------- NECK (short, thick, hidden in the jowls)
|
|
166
|
-
const nk = 1 + 0.25 * boar;
|
|
167
|
-
m.ell({ tag: 'neck', bone: 'neck1', c: [0, 0.54, 0.38], r: [0.14 * nk * fat, 0.16, 0.13], axis: norm([0, 0.3, 1]), k: 0.1 });
|
|
168
|
-
m.ell({ tag: 'neck', bone: 'neck2', c: [0, 0.56, 0.45], r: [0.12 * nk * fat, 0.13, 0.1], axis: norm([0, 0.4, 1]), k: 0.08 });
|
|
169
|
-
// the top line runs almost straight from the withers to the poll (a crest / shield in boars)
|
|
170
|
-
m.ell({ tag: 'nape', bone: 'neck1', c: [0, 0.655 + 0.012 * boar, 0.39], r: [0.1 * nk, 0.065 + 0.012 * boar, 0.14], axis: norm([0, -0.12, 1]), k: 0.09 });
|
|
171
|
-
// throat / double chin: from under the jaw into the brisket
|
|
172
|
-
m.cone({ tag: 'throat', bone: 'neck1', a: [0, 0.43, 0.36], b: [0, 0.46, 0.44], ra: 0.085 * fat, rb: 0.08, k: 0.09 });
|
|
173
|
-
m.cone({ tag: 'throat', bone: 'neck2', a: [0, 0.46, 0.44], b: hl([0, -0.115, -0.03]), ra: 0.075, rb: 0.06, k: 0.08 });
|
|
174
|
-
|
|
175
|
-
// ---------------------------------------------------------------- HEAD (head-local, see rig.js)
|
|
176
|
-
// landmarks (face1 / side1): skull top y 0.085 at z -0.1, forehead 0.075 at z 0, a slightly dished
|
|
177
|
-
// nasal bridge, the disc (centre y -0.012, z 0.19) 7 cm wide and 5.5 cm high, mouth corner below
|
|
178
|
-
// the front of the eye, heavy jowls down to y -0.15 behind the jaw angle
|
|
179
|
-
const hb = 1 + 0.08 * boar;
|
|
180
|
-
hell({ tag: 'cranium', c: [0, 0.008, -0.06], r: [0.088 * hb, 0.064, 0.085], k: 0.05 });
|
|
181
|
-
hell({ tag: 'poll', c: [0, 0.042, -0.08], r: [0.075 * hb, 0.04, 0.05], k: 0.04 });
|
|
182
|
-
// (the boar's broader skull stays behind and below the eyes: a wider forehead and cheek would bury them)
|
|
183
|
-
hell({ tag: 'forehead', c: [0, 0.036, 0.01], r: [0.074, 0.03, 0.08], k: 0.04 });
|
|
184
|
-
// snout: a tapering cylinder from the face to the disc
|
|
185
|
-
// (tapering a little more toward the disc, so the disc's rim stands a touch proud of the snout behind it: lw_show,
|
|
186
|
-
// head_hausschwein5, side1)
|
|
187
|
-
m.cone({ ...H, tag: 'snout', a: hl([0, -0.004, 0.05]), b: hl([0, -0.007, sz(0.16)]), ra: 0.057, rb: 0.05, k: 0.04 });
|
|
188
|
-
hell({ tag: 'nasal', c: [0, 0.018, sz(0.1)], r: [0.05, 0.022, 0.07 * snoutK], k: 0.03 });
|
|
189
|
-
// the dished profile (params.dish: Berkshire ~0.9, Large White ~0.35, Landrace 0 straight): the bridge sags in front
|
|
190
|
-
// of the eyes between the forehead and the disc (side1, lw_show, bk_sow; an earlier sculpt ignored the knob and
|
|
191
|
-
// every breed had the same straight, slightly Roman line)
|
|
192
|
-
// (broad across the bridge, 0.11 half width: at 0.075 the carve's side walls ran from the inner eye corners
|
|
193
|
-
// down to the snout as two ridges, a V that read as a frown from the front; face2, head_mochyn: a broad, flat bridge)
|
|
194
|
-
if (dish > 0.01) hell({ tag: 'dish', c: [0, 0.089 - 0.02 * dish, sz(0.11)], r: [0.11, 0.04, 0.075 * snoutK], k: 0.03, carve: true });
|
|
195
|
-
// the full face under and in front of the eyes (the maxilla under the cheek fat): no waist between the snout
|
|
196
|
-
// and the jowls (face2, front1, threequarter2)
|
|
197
|
-
hell({ tag: 'muzzle', c: [0, -0.03, 0.05], r: [0.064 * hb, 0.05, 0.09], k: 0.04 });
|
|
198
|
-
for (const s of [1, -1]) {
|
|
199
|
-
// jowls / cheeks: the big fat pads behind and below the eyes
|
|
200
|
-
hell({ tag: 'jowl', c: [0.066 * s * hb, -0.075, -0.035], r: [0.06 * hb * fat, 0.08, 0.085], k: 0.05 });
|
|
201
|
-
// cheek: the zygomatic arch and the masseter under their fat, behind and below the eye: the face's
|
|
202
|
-
// outline beside the eyes (face2, front1, face3: the eyes set in from it by a third of their spacing)
|
|
203
|
-
hell({ tag: 'cheek', c: [0.07 * s, -0.01, -0.05], r: [0.05 * fat, 0.055, 0.07], k: 0.03 });
|
|
204
|
-
// upper lip along the side of the snout (the flews), rising to the disc; the mouth corner lies a
|
|
205
|
-
// third of the way from the disc to the eye (face1, side1)
|
|
206
|
-
m.cone({ ...H, tag: 'lip', a: hl([0.058 * s, -0.058, 0.045]), b: hl([0.042 * s, -0.042, sz(0.155)]), ra: 0.03, rb: 0.02, k: 0.03 });
|
|
207
|
-
// heavy fat-padded brow over the small eye
|
|
208
|
-
hell({ tag: 'brow', c: [0.058 * s, 0.05, 0.0], r: [0.022, 0.012, 0.03], k: 0.025 });
|
|
209
|
-
// eye: orbit hollow, lids, almond aperture
|
|
210
|
-
pigEye(m, s);
|
|
211
|
-
// ear base muscles on the side of the poll
|
|
212
|
-
// (a soft swelling, not a knob: a lying pig's lop ear swings off it)
|
|
213
|
-
m.sphere({ ...H, tag: 'earbase', c: add(J['earBase' + (s > 0 ? 'L' : 'R')], [-0.014 * s, -0.006, 0]), rad: 0.02, k: 0.045 });
|
|
214
|
-
}
|
|
215
|
-
if (boar > 0) {
|
|
216
|
-
// boar: the heavy cheeks and the ridge over the snout where the tusks' sockets bulge
|
|
217
|
-
for (const s of [1, -1]) hell({ tag: 'jowl', c: [0.06 * s, -0.09, -0.06], r: [0.04 * boar, 0.05 * boar, 0.06], k: 0.05 });
|
|
218
|
-
for (const s of [1, -1]) hell({ tag: 'lip', c: [0.036 * s, -0.04, sz(0.105)], r: [0.014, 0.018, 0.026], k: 0.025 });
|
|
219
|
-
}
|
|
220
|
-
// the soft floor between the mandibles: the chin's underside runs back into the throat (face1: a heavy rounded
|
|
221
|
-
// chin tucked under the upper lip, no step behind it). The skin over the back half of the chin is the head's
|
|
222
|
-
// surface, riding on the jaw (rig appendage 'jawskin') and blending into the throat, so it follows the mouth
|
|
223
|
-
// as it opens; it meets the jaw part's underside almost tangentially a third of the way from the disc to the
|
|
224
|
-
// eye, and only the chin's front and the lower lip are the jaw part (a jaw part exposed from the throat to
|
|
225
|
-
// the lip read as a separate plate from below, outlined by the crease where it met the head)
|
|
226
|
-
hell({ tag: 'underjaw', c: [0, -0.083, 0.0], r: [0.05, 0.028, 0.06], k: 0.04 });
|
|
227
|
-
{
|
|
228
|
-
// (a flat sheet under the chin: it ends 2.5 cm past the crossing at the mouth corner, sz(0.105), where it
|
|
229
|
-
// runs into the chin's underside at a shallow angle; its top stays ~1.5 cm below the snout's underside and
|
|
230
|
-
// its blend is tighter than the head's, so that in front of the corner it barely joins the upper lip: a
|
|
231
|
-
// thicker sheet with a 4 cm blend fused with the snout there, and that skin from the upper lip to the jaw
|
|
232
|
-
// stretched 3x when the mouth opened wide)
|
|
233
|
-
const zx = sz(0.105), zc = 0.02, rz = zx + 0.025 - zc, u = (zx - zc) / rz, ry = 0.018;
|
|
234
|
-
hell({ tag: 'underjaw', bone: 'jaw', group: 'jawskin', c: [0, -0.1045 + ry * Math.sqrt(1 - u * u), zc], r: [0.054, ry, rz], k: 0.03 });
|
|
235
|
-
}
|
|
236
|
-
// mouth line: the lower lip is tucked inside the upper lip (no slit: where the two surfaces overlap the coat
|
|
237
|
-
// paints the mouth, which shows when the jaw drops; a carved slit's sharp lip margin meshed as a sawtooth)
|
|
238
|
-
|
|
239
|
-
// snout disc (rostral plate on its own bone): a flat oval plate with a raised rim
|
|
240
|
-
const dz = sz(0.178);
|
|
241
|
-
// (the plate is cut close to its widest section: its flat face spans almost the whole snout end,
|
|
242
|
-
// with a rounded rim standing a little proud of the snout behind it)
|
|
243
|
-
m.ell({ ...SN, tag: 'disc', c: hl([0, -0.006, dz]), r: [0.058, 0.045, 0.026], axis: HZ, up: HY, k: 0.012 });
|
|
244
|
-
m.cone({ ...SN, tag: 'snoutend', a: hl([0, -0.006, sz(0.13)]), b: hl([0, -0.006, dz - 0.008]), ra: 0.049, rb: 0.048, k: 0.02 });
|
|
245
|
-
// flat face of the disc: a big carving sphere in front of it
|
|
246
|
-
m.sphere({ ...SN, tag: 'discface', c: hl([0, -0.006, dz + 0.012 + 0.4]), rad: 0.4, k: 0.004, carve: true });
|
|
247
|
-
for (const s of [1, -1]) {
|
|
248
|
-
// nostrils: two large vertical ovals in the lower middle of the disc (each about a quarter of its
|
|
249
|
-
// width), a septum between them (face2, front1, front2)
|
|
250
|
-
// (smaller, flatter ovals tilted outer end down (front1, face2: two tilted ovals about a sixth
|
|
251
|
-
// of the disc's width each, deepest at their inner upper end); the 2.6 x 3.6 cm round pits read as two black
|
|
252
|
-
// buttons with a lit floor)
|
|
253
|
-
const a = 0.4 * s, up = [-Math.sin(a), Math.cos(a) * HY[1], Math.cos(a) * HY[2]];
|
|
254
|
-
m.ell({ ...SN, tag: 'nostril', c: hl([0.025 * s, -0.009, dz + 0.012]), r: [0.0135, 0.0088, 0.017], axis: HZ, up, k: 0.005, carve: true });
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// ---------------------------------------------------------------- JAW (lower lip and chin: the mouth opens)
|
|
258
|
-
const JW = { bone: 'jaw', group: 'jaw', part: 'jaw' };
|
|
259
|
-
// (the chin's front 1 cm further back and a little higher, and the lower lip tucked further under the upper lip:
|
|
260
|
-
// from the side and below they read as a thin pale ledge under the snout)
|
|
261
|
-
m.ell({ ...JW, tag: 'chin', c: hl([0, -0.077, sz(0.09)]), r: [0.04, 0.027, 0.064 * snoutK], axis: HZ, up: HY, k: 0 });
|
|
262
|
-
m.ell({ ...JW, tag: 'lowerlip', c: hl([0, -0.067, sz(0.122)]), r: [0.026, 0.015, 0.02], axis: HZ, up: HY, k: 0.015 });
|
|
263
|
-
// the tongue on the floor of the mouth, inside the closed mouth (shows when the jaw drops: squeal, bite)
|
|
264
|
-
m.ell({ ...JW, tag: 'tongue', c: hl([0, -0.053, sz(0.085)]), r: [0.024, 0.011, 0.05 * snoutK], axis: HZ, up: HY, k: 0.012 });
|
|
265
|
-
for (const s of [1, -1]) {
|
|
266
|
-
m.cone({ ...JW, tag: 'mandible', a: hl([0.032 * s, -0.08, 0.02]), b: hl([0.026 * s, -0.076, sz(0.13)]), ra: 0.02, rb: 0.016, k: 0.02 });
|
|
267
|
-
}
|
|
268
|
-
if ((params.tusks || 0) > 0.05) {
|
|
269
|
-
// tusks: the lower canines, ivory, riding rigidly on the jaw (coat paints them keratin): their own part and
|
|
270
|
-
// surface, meshed at ~1 mm (tuskCones above, regions.js)
|
|
271
|
-
for (const s of [1, -1]) for (const c of tuskCones(params, s)) m.cone({ bone: 'jaw', group: 'jaw', part: 'tusk', tag: 'tusk', ...c, k: 0 });
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// ---------------------------------------------------------------- EARS (leaves)
|
|
275
|
-
// Each pinna is a curved sheet tiled with exact slabs (m.fin), thick at the root and thinning to a round rim
|
|
276
|
-
// (ears.js): an erect ear curls its tip forward, a semi-lop tips its outer half forward and down, a lop ear
|
|
277
|
-
// rises from the poll and droops forward over the eyes like a hood. (Exact slab distances keep the ears'
|
|
278
|
-
// skin weights off the neck. The leaf's base rolls into the funnel of the ear canal inside the head's
|
|
279
|
-
// 'earbase' swelling; no root cone in the ear part: a lying pig's ear turns on its bone about the base,
|
|
280
|
-
// and a cone reaching into the skull stood out of it as a peg.)
|
|
281
|
-
for (const S of ['L', 'R']) {
|
|
282
|
-
const E = earShape(J, params, S);
|
|
283
|
-
const ear = { bone: 'ear' + S, group: 'ear' + S, part: 'ear' + S, tag: 'ear' };
|
|
284
|
-
// (the thickness at the coarse tiers is the leaf's own business, ears.js: tiles are not marked thin)
|
|
285
|
-
for (const g of E.segs) m.fin({ ...ear, o: g.o, u: g.u, v: g.v, poly: g.poly, t: g.t, round: g.t / 2, grad: g.grad, curve: g.curve, k: 0 });
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// ---------------------------------------------------------------- LEGS (short, sunk in the body)
|
|
289
|
-
// (a piglet's legs as thick for its size as a finisher's, a touch thicker: threequarter3, side1)
|
|
290
|
-
const legK = (1 + 0.1 * boar) * (piglet ? 1.05 : 1);
|
|
291
|
-
for (const S of ['L', 'R']) {
|
|
292
|
-
const s = S === 'L' ? 1 : -1;
|
|
293
|
-
const lat = [s, 0, 0];
|
|
294
|
-
const sx = (v) => [v[0] * s, v[1], v[2]];
|
|
295
|
-
// front
|
|
296
|
-
const g = 'F' + S;
|
|
297
|
-
const Sc = J['scapTop' + S], Sh = J['shoulder' + S], E = J['elbow' + S], W = J['wrist' + S], M = J['mcp' + S], C = J['fcoffin' + S], T = J['ftoe' + S];
|
|
298
|
-
ellY({ tag: 'scapmuscle', bone: 'scapula' + S, group: g, c: add(lerp(Sc, Sh, 0.5), sx([0.055, 0, -0.01])), ydir: sub(Sh, Sc), lateral: lat, r: [0.06 + 0.02 * boar, 0.15, 0.11], k: 0.1, bias: 0.006 });
|
|
299
|
-
m.sphere({ tag: 'shoulderpoint', bone: 'humerus' + S, group: g, c: add(Sh, sx([0.02, 0.0, 0.01])), rad: 0.06 * legK, k: 0.08 });
|
|
300
|
-
m.cone({ tag: 'upperarm', bone: 'humerus' + S, group: g, a: Sh, b: E, ra: 0.072 * legK, rb: 0.058 * legK, k: 0.08 });
|
|
301
|
-
ellY({ tag: 'triceps', bone: 'humerus' + S, group: g, c: add(lerp(Sh, E, 0.55), sx([0.012, 0.0, -0.055])), ydir: sub(E, Sh), lateral: lat, r: [0.062 * legK, 0.1, 0.075], k: 0.08 });
|
|
302
|
-
m.sphere({ tag: 'olecranon', bone: 'radius' + S, group: g, c: add(E, [0, 0.015, -0.04]), rad: 0.035, k: 0.04 });
|
|
303
|
-
m.cone({ tag: 'forearm', bone: 'radius' + S, group: g, a: add(E, [0, 0, -0.005]), b: W, ra: 0.05 * legK, rb: 0.029 * legK, k: 0.04 });
|
|
304
|
-
ellY({ tag: 'forearmmuscle', bone: 'radius' + S, group: g, c: add(lerp(E, W, 0.25), sx([0.006, 0, 0.008])), ydir: sub(W, E), lateral: lat, r: [0.045 * legK, 0.075, 0.048 * legK], k: 0.04 });
|
|
305
|
-
// (the web from the chest wall onto the forearm, 0.3 of its length: at 0.2 the raised upper foreleg of a pig
|
|
306
|
-
// lying on its side pulled a long thin sheet of skin to the chest with folded back faces in its crease,
|
|
307
|
-
// red back faces in the armpit 560 -> 278 px over three views; at 0.4, 946)
|
|
308
|
-
m.cone({ tag: 'forearmweb', bone: 'radius' + S, group: g, a: add(E, sx([-0.03, 0.05, -0.01])), b: add(lerp(E, W, 0.3), sx([-0.012, 0, 0])), ra: 0.045, rb: 0.03, k: 0.05 });
|
|
309
|
-
// knee (carpus), cannon, fetlock
|
|
310
|
-
ellY({ tag: 'knee', bone: 'metacarpus' + S, group: g, c: add(W, [0, 0.0, 0.002]), ydir: UP, lateral: lat, r: [0.03 * legK, 0.033, 0.029 * legK], k: 0.02 });
|
|
311
|
-
m.cone({ tag: 'cannon', bone: 'metacarpus' + S, group: g, a: add(W, [0, -0.012, 0.0]), b: add(M, [0, 0.01, -0.002]), ra: 0.024 * legK, rb: 0.022 * legK, k: 0.015 });
|
|
312
|
-
ellY({ tag: 'fetlock', bone: 'metacarpus' + S, group: g, c: add(M, [0, 0.0, -0.006]), ydir: [0, 1, 0.3], lateral: lat, r: [0.026 * legK, 0.026, 0.028], k: 0.015 });
|
|
313
|
-
sculptDigits(m, 'fpaw' + S, 'fhoof' + S, g, M, C, T, s, legK);
|
|
314
|
-
|
|
315
|
-
// hind: the ham (the biggest muscle mass of the pig) sweeps down to the stifle and the hock
|
|
316
|
-
const h = 'H' + S;
|
|
317
|
-
const Hp = J['hip' + S], K = J['knee' + S], Hk = J['hock' + S], Mt = J['mtp' + S], Ch = J['hcoffin' + S], Tt = J['htoe' + S];
|
|
318
|
-
ellY({ tag: 'thigh', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.45), sx([0.035, 0, -0.045])), ydir: sub(K, Hp), lateral: lat, r: [0.075 * hamK, 0.18, 0.15 * hamK], k: 0.1, bias: 0.006 });
|
|
319
|
-
m.cone({ tag: 'thighfront', bone: 'femur' + S, group: h, a: sx([0.13, 0.6, -0.3]), b: add(K, sx([0.0, 0.04, 0.03])), ra: 0.08, rb: 0.055, k: 0.08 });
|
|
320
|
-
m.cone({ tag: 'ham', bone: 'femur' + S, group: h, a: sx([0.08, 0.6, -0.56]), b: add(lerp(K, Hk, 0.35), [0, 0, -0.045]), ra: 0.1 * hamK, rb: 0.048, k: 0.08 });
|
|
321
|
-
ellY({ tag: 'flankfold', bone: 'femur' + S, group: h, c: sx([0.13, 0.4, -0.2]), ydir: [-0.1, 0.3, 0.12], lateral: lat, r: [0.04, 0.09, 0.06], k: 0.08 });
|
|
322
|
-
m.sphere({ tag: 'stifle', bone: 'tibia' + S, group: h, c: add(K, sx([0.008, 0.01, 0.02])), rad: 0.045, k: 0.06 });
|
|
323
|
-
ellY({ tag: 'gaskin', bone: 'tibia' + S, group: h, c: add(lerp(K, Hk, 0.35), sx([0.004, 0, -0.03])), ydir: sub(Hk, K), lateral: lat, r: [0.048 * legK, 0.095, 0.06 * legK], k: 0.05 });
|
|
324
|
-
m.cone({ tag: 'shin', bone: 'tibia' + S, group: h, a: lerp(K, Hk, 0.1), b: Hk, ra: 0.042 * legK, rb: 0.029 * legK, k: 0.04 });
|
|
325
|
-
m.cone({ tag: 'achilles', bone: 'tibia' + S, group: h, a: add(lerp(K, Hk, 0.45), [0, 0, -0.045]), b: add(Hk, [0, 0.04, -0.04]), ra: 0.02, rb: 0.016, k: 0.025 });
|
|
326
|
-
m.sphere({ tag: 'calcaneus', bone: 'metatarsus' + S, group: h, c: add(Hk, [0, 0.04, -0.038]), rad: 0.021, k: 0.02 });
|
|
327
|
-
ellY({ tag: 'hock', bone: 'metatarsus' + S, group: h, c: add(Hk, [0, 0.006, -0.004]), ydir: [0, 1, 0.25], lateral: lat, r: [0.031 * legK, 0.042, 0.033], k: 0.02 });
|
|
328
|
-
m.cone({ tag: 'cannon', bone: 'metatarsus' + S, group: h, a: add(Hk, [0, -0.022, 0.003]), b: add(Mt, [0, 0.01, 0.0]), ra: 0.024 * legK, rb: 0.022 * legK, k: 0.015 });
|
|
329
|
-
ellY({ tag: 'fetlock', bone: 'metatarsus' + S, group: h, c: add(Mt, [0, 0.0, -0.006]), ydir: [0, 1, 0.3], lateral: lat, r: [0.026 * legK, 0.026, 0.028], k: 0.015 });
|
|
330
|
-
sculptDigits(m, 'hpaw' + S, 'hhoof' + S, h, Mt, Ch, Tt, s, legK * 0.98);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// ---------------------------------------------------------------- TEATS (two rows along the belly)
|
|
334
|
-
const pairs = params.teats ?? 7;
|
|
335
|
-
const teatK = boar >= 0.5 ? 0.45 : piglet ? 0.5 : 0.8 + 0.6 * belly;
|
|
336
|
-
for (let i = 0; i < pairs; i++) {
|
|
337
|
-
const z = lerp([0, 0, 0.2], [0, 0, -0.34], i / Math.max(1, pairs - 1))[2];
|
|
338
|
-
const yb = 0.3 - 0.03 * belly + 0.008 * Math.abs(z + 0.08) * 4 * 0.3 + tuck;
|
|
339
|
-
const x = 0.052 + 0.01 * Math.cos(((i / (pairs - 1)) - 0.5) * 2);
|
|
340
|
-
for (const s of [1, -1]) {
|
|
341
|
-
const a = [x * s, yb + 0.02, z], b = [x * s * 1.02, yb - 0.012 * teatK, z];
|
|
342
|
-
m.cone({ tag: 'teat', bone: z > 0.05 ? 'spine3' : z < -0.2 ? 'spine1' : 'spine2', a, b, ra: 0.0085 * Math.max(0.6, teatK), rb: 0.006 * Math.max(0.6, teatK), k: 0.008 });
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// ---------------------------------------------------------------- TAIL (thin, corkscrew, a small tuft)
|
|
347
|
-
const n = TAIL_SEGS;
|
|
348
|
-
for (let i = 0; i < n; i++) {
|
|
349
|
-
const t0 = i / n, t1 = (i + 1) / n;
|
|
350
|
-
const r = (t) => 0.0115 - 0.0065 * Math.pow(t, 0.8);
|
|
351
|
-
m.cone({ tag: i >= n - 1 ? 'tailtip' : 'tail', part: 'tail', bone: 'tail' + i, a: J['tail' + i], b: J['tail' + (i + 1)], ra: r(t0), rb: r(t1), k: i === 0 ? 0.03 : 0.004, thin: i > n / 2 });
|
|
352
|
-
}
|
|
353
|
-
return m;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Cloven hoof: pastern with two dew claws behind the fetlock, then two claws (digits III and IV),
|
|
357
|
-
// each a hoof-wall half-cone, flat on the ground (carved at y = 0), the interdigital cleft between
|
|
358
|
-
// them, heel bulbs behind. Pigs walk on the tips of the claws with fairly upright pasterns.
|
|
359
|
-
function sculptDigits(m, paw, hoof, group, M, C, T, s, w) {
|
|
360
|
-
m.cone({ tag: 'pastern', bone: paw, group, a: M, b: C, ra: 0.022 * w, rb: 0.024 * w, k: 0.012 });
|
|
361
|
-
// dew claws (digits II and V): small pointed claws behind, 3-5 cm above the ground
|
|
362
|
-
for (const d of [1, -1]) {
|
|
363
|
-
const base = add(M, [0.017 * d * w, -0.012, -0.022]);
|
|
364
|
-
m.cone({ tag: 'dewclaw', bone: paw, group, a: base, b: add(base, [0.004 * d, -0.016, -0.012]), ra: 0.0075 * w, rb: 0.004 * w, k: 0.006 });
|
|
365
|
-
}
|
|
366
|
-
const zMid = (C[2] + T[2]) * 0.5;
|
|
367
|
-
const dir = Math.sign(T[2] - C[2]);
|
|
368
|
-
for (const d of [1, -1]) {
|
|
369
|
-
const off = 0.0145 * d * w;
|
|
370
|
-
const top = add(C, [off, 0.012, -0.008 * dir]);
|
|
371
|
-
const base = [C[0] + off * 1.1, 0.0, zMid - 0.003 * dir];
|
|
372
|
-
m.cone({ tag: 'hoof', bone: hoof, group, a: top, b: base, ra: 0.0145 * w, rb: 0.02 * w, k: 0.007 });
|
|
373
|
-
// the toe: a pointed front of each claw
|
|
374
|
-
m.ell({ tag: 'hoof', bone: hoof, group, c: [C[0] + off * 0.9, 0.013, T[2] - 0.016 * dir], r: [0.0135 * w, 0.0125, 0.02], axis: norm([0, -0.3, dir]), k: 0.007 });
|
|
375
|
-
m.sphere({ tag: 'heelbulb', bone: hoof, group, c: add(C, [off * 0.9, -0.015, -0.024 * dir]), rad: 0.0145 * w, k: 0.011 });
|
|
376
|
-
}
|
|
377
|
-
m.cone({ tag: 'coronet', bone: hoof, group, a: add(C, [0, 0.014, -0.011 * dir]), b: add(C, [0, 0.007, 0.011 * dir]), ra: 0.024 * w, rb: 0.024 * w, k: 0.009 });
|
|
378
|
-
// interdigital cleft: a V opening toward the front and the ground
|
|
379
|
-
m.ell({ tag: 'cleft', bone: hoof, group, c: [C[0], 0.0, T[2] - 0.002 * dir], r: [0.003, 0.026, 0.043], k: 0.0025, carve: true });
|
|
380
|
-
m.ell({ tag: 'cleft', bone: hoof, group, c: [C[0], -0.003, zMid], r: [0.0025, 0.017, 0.046], k: 0.002, carve: true });
|
|
381
|
-
m.ell({ tag: 'sole', bone: hoof, group, c: [C[0], -0.2 + 0.0015, zMid], r: [0.2, 0.2, 0.2], k: 0.003, carve: true });
|
|
382
|
-
}
|