@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,66 +0,0 @@
|
|
|
1
|
-
// Meshing plan: body (incl. wing arms and legs) at 2.0 mm, head + the top of the neck at 0.9 mm
|
|
2
|
-
// (overlapping the body at the cut and cross-faded; the thin comb and wattles need the fine cells),
|
|
3
|
-
// eyelid patches at 0.4 mm, and the lower mandible as its own rigid surface so the bill can open.
|
|
4
|
-
// Cells scale with the quality tier (Q.res). Everything is computed from the individual's rig (the
|
|
5
|
-
// head sits higher on a rooster, the comb is taller).
|
|
6
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
7
|
-
import { lerp, norm, sub, smoothstep } from '../../core/math/vec.js';
|
|
8
|
-
import { NECK_SEGS } from './rig.js';
|
|
9
|
-
import { eyeFor } from './sculpt.js';
|
|
10
|
-
|
|
11
|
-
export function neckCut(J) {
|
|
12
|
-
const a = J['neck' + (NECK_SEGS - 1)];
|
|
13
|
-
const d = norm(sub(J.occiput, a));
|
|
14
|
-
const c = lerp(a, J.occiput, 0.5);
|
|
15
|
-
return { c, d, band: 0.0045 };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function eyePatch(rig, form) {
|
|
19
|
-
const E = eyeFor(form), HO = rig.headOrigin, k = form.headK ?? 1;
|
|
20
|
-
return { R: 0.011 * k, B: 0.0022 * k, h: 0.0004 * k, centres: [1, -1].map((s) => eyeFrameOf(E, HO, s).c) };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function chickenRegions(rig, params, Q) {
|
|
24
|
-
const J = rig.J, form = params.form || {};
|
|
25
|
-
const NC = neckCut(J), B = NC.band, r = Q.res;
|
|
26
|
-
const neckS = (x, y, z) => (x - NC.c[0]) * NC.d[0] + (y - NC.c[1]) * NC.d[1] + (z - NC.c[2]) * NC.d[2];
|
|
27
|
-
const EP = eyePatch(rig, form);
|
|
28
|
-
const eyeW = (x, y, z) => {
|
|
29
|
-
let dmin = 1e9;
|
|
30
|
-
for (const c of EP.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
|
|
31
|
-
return 1 - smoothstep(EP.R - EP.B, EP.R + EP.B, dmin);
|
|
32
|
-
};
|
|
33
|
-
const patches = Q.eyePatches ? EP.centres.map((c) => ({ c, R: EP.R, B: EP.B, h: EP.h * Math.max(1, r) })) : [];
|
|
34
|
-
const HO = rig.headOrigin, hk = form.headK ?? 1;
|
|
35
|
-
const juv = !!form.chick;
|
|
36
|
-
// body box: wings bound half open reach out to the side
|
|
37
|
-
const top = Math.max(J.occiput[1], J.tailTip[1]) + 0.06;
|
|
38
|
-
const hbox = {
|
|
39
|
-
min: [HO[0] - 0.034 * hk, HO[1] - 0.06 * hk * (form.wattle ?? 1) - 0.01, HO[2] - 0.075 * hk],
|
|
40
|
-
max: [HO[0] + 0.034 * hk, HO[1] + 0.058 * hk * (form.combH ?? 1), HO[2] + 0.055 * hk],
|
|
41
|
-
};
|
|
42
|
-
const male = params.sex === 'male' && !juv; // (bigger comb, wattles and hackle: slightly coarser cells keep the budgets)
|
|
43
|
-
const hBody = (juv ? 0.0024 : male ? 0.00216 : 0.0021) * r, hHead = (juv ? 0.0012 : male ? 0.00098 : 0.00092) * r;
|
|
44
|
-
return {
|
|
45
|
-
jobs: [
|
|
46
|
-
[
|
|
47
|
-
{ name: 'body', part: 'body', bmin: [-0.26, -0.004, -0.2], bmax: [0.26, top, 0.2], h: hBody, F: 4, clip: (x, y, z) => neckS(x, y, z) < B },
|
|
48
|
-
],
|
|
49
|
-
[
|
|
50
|
-
{ name: 'head', part: 'body', bmin: hbox.min, bmax: hbox.max, h: hHead, F: 6, clip: (x, y, z) => neckS(x, y, z) > -B, patches },
|
|
51
|
-
{ name: 'jaw', part: 'jaw', bmin: [HO[0] - 0.01 * hk, HO[1] - 0.016 * hk, HO[2] + 0.008 * hk], bmax: [HO[0] + 0.01 * hk, HO[1] - 0.002 * hk, HO[2] + 0.047 * hk], h: 0.0007 * r * hk, F: 6, rigidBone: 'jaw' },
|
|
52
|
-
],
|
|
53
|
-
],
|
|
54
|
-
fade(x, y, z, name, patch) {
|
|
55
|
-
const sN = neckS(x, y, z);
|
|
56
|
-
if (name === 'body') return 1 - smoothstep(-B, B, sN);
|
|
57
|
-
if (name === 'head') {
|
|
58
|
-
// (the head surface reaches 1.5 mm past the body's cut, so no see-through crack shows)
|
|
59
|
-
let f = smoothstep(-B - 0.0015, B - 0.0015, sN);
|
|
60
|
-
if (patches.length) { const ew = eyeW(x, y, z); f *= patch ? ew : 1 - ew; }
|
|
61
|
-
return f;
|
|
62
|
-
}
|
|
63
|
-
return 1;
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
// Chicken skeleton in bind pose (metres). Forward = +Z, up = +Y, the bird's left = +X; ground at y = 0,
|
|
2
|
-
// the feet under the centre of mass. Reference individual: a ~2 kg brown layer hen standing relaxed
|
|
3
|
-
// (hip height 0.21 m, back 0.27 m, crown 0.345 m, bill tip to tail tip 0.42 m). Leg bones from layer
|
|
4
|
-
// osteometry (Animals 2020: tibiotarsus 117-120 mm; femur ~0.65 and tarsometatarsus ~0.68 of it);
|
|
5
|
-
// wing bones humerus 77, ulna 70, hand 66 mm. The femur points forward and down inside the
|
|
6
|
-
// body (knee hidden in the feathers), the drumstick runs down and back to the hock at 85 mm, the
|
|
7
|
-
// scaled shank stands almost vertical.
|
|
8
|
-
//
|
|
9
|
-
// The rig adapts to the individual (params.form, see index.js): roosters stand more upright on longer
|
|
10
|
-
// legs with a longer neck and carry two sickle feathers a side; chicks have a round body, a big head
|
|
11
|
-
// on a short neck, short legs and stubby wings.
|
|
12
|
-
import { buildRig } from '../../core/rig/rig.js';
|
|
13
|
-
import { birdBones, birdLimbs, neckChain, wingJoints, featherJoints } from '../../core/rig/bird.js';
|
|
14
|
-
import { wingFor, feathersFor } from './motion.js';
|
|
15
|
-
|
|
16
|
-
export const NECK_SEGS = 4;
|
|
17
|
-
// head-local origin (between the eyes) of the reference hen
|
|
18
|
-
export const HEAD_O = [0, 0.328, 0.108];
|
|
19
|
-
|
|
20
|
-
const n2 = (y, z) => { const l = Math.hypot(y, z); return [0, y / l, z / l]; };
|
|
21
|
-
const D = Math.PI / 180;
|
|
22
|
-
|
|
23
|
-
// rotate a point about the x axis through c (pitch the torso up by a, radians)
|
|
24
|
-
const pitchAbout = (p, c, a) => {
|
|
25
|
-
const y = p[1] - c[1], z = p[2] - c[2], ca = Math.cos(a), sa = Math.sin(a);
|
|
26
|
-
return [p[0], c[1] + y * ca + z * sa, c[2] - y * sa + z * ca];
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export function headOrigin(form = {}) {
|
|
30
|
-
return form.headO || HEAD_O;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// torso transform of an individual: the reference torso lifted with the hip and pitched up about it
|
|
34
|
-
export function torsoFn(form = {}) {
|
|
35
|
-
const hipY = 0.205 * (form.hipK ?? 1), up = (form.up ?? 0) * D, dyH = hipY - 0.205;
|
|
36
|
-
const c = [0, hipY, -0.028];
|
|
37
|
-
return (p) => pitchAbout([p[0], p[1] + dyH, p[2]], c, up);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function chickenJoints(form = {}) {
|
|
41
|
-
const legK = form.legK ?? 1, neckK = form.neckK ?? 1;
|
|
42
|
-
const juv = !!form.chick;
|
|
43
|
-
// ---- legs (left), from the hip down
|
|
44
|
-
const femur = 0.078 * (form.femurK ?? legK), tib = 0.118 * legK, tar = 0.08 * (form.tarK ?? legK);
|
|
45
|
-
const hip = [0.03, 0.205 * (form.hipK ?? 1), -0.028];
|
|
46
|
-
const fa = 32 * D;
|
|
47
|
-
const knee = [0.042, hip[1] - femur * Math.sin(fa), hip[2] + femur * Math.cos(fa)];
|
|
48
|
-
const lean = 16 * D;
|
|
49
|
-
const mtpY = 0.009;
|
|
50
|
-
const ankleY = mtpY + tar * Math.cos(lean);
|
|
51
|
-
const dy = knee[1] - ankleY, dz = Math.sqrt(Math.max(1e-6, tib * tib - dy * dy));
|
|
52
|
-
const ankle = [0.034, ankleY, knee[2] - dz];
|
|
53
|
-
const mtp = [0.03, mtpY, ankle[2] + tar * Math.sin(lean)];
|
|
54
|
-
// ---- torso and head (reference hen), pitched up about the hip for an upright carriage
|
|
55
|
-
const T = torsoFn(form);
|
|
56
|
-
const J = {
|
|
57
|
-
synsacrum: T([0, 0.218, -0.04]),
|
|
58
|
-
tailBase: T([0, 0.244, -0.128]),
|
|
59
|
-
tailTip: T([0, 0.262, -0.156]),
|
|
60
|
-
neckBase: T([0, 0.25, 0.07]),
|
|
61
|
-
shoulderL: T([0.057, 0.232, 0.052]),
|
|
62
|
-
hipL: hip, kneeL: knee, ankleL: ankle, mtpL: mtp,
|
|
63
|
-
};
|
|
64
|
-
if (form.tailUp) {
|
|
65
|
-
// roosters carry the tail higher: pitch the pygostyle up about its base
|
|
66
|
-
const a = form.tailUp * D, b = J.tailBase, t = J.tailTip;
|
|
67
|
-
J.tailTip = pitchAbout(t, b, -a);
|
|
68
|
-
}
|
|
69
|
-
if (juv) {
|
|
70
|
-
// chick: round body, the tail stub barely out of the down, neck base forward
|
|
71
|
-
J.synsacrum = [0, hip[1] + 0.012, -0.03];
|
|
72
|
-
J.tailBase = [0, hip[1] + 0.02, -0.075];
|
|
73
|
-
J.tailTip = [0, hip[1] + 0.03, -0.088];
|
|
74
|
-
J.neckBase = [0, hip[1] + 0.05, 0.045];
|
|
75
|
-
// (the shoulder near the ball's surface: the folded wing lies on the ball, not inside it)
|
|
76
|
-
J.shoulderL = [0.068, hip[1] + 0.045, 0.03];
|
|
77
|
-
}
|
|
78
|
-
// head: the reference head, carried by the neck (longer neck -> higher head)
|
|
79
|
-
const HO = headOrigin(form);
|
|
80
|
-
const hk = form.headK ?? 1;
|
|
81
|
-
const occ0 = [0, HO[1] - 0.01 * hk, HO[2] - 0.02 * hk];
|
|
82
|
-
// neck: from the neck base to the occiput; its length scales with neckK (and the torso pitch)
|
|
83
|
-
const nb = J.neckBase;
|
|
84
|
-
const occ = juv ? [0, nb[1] + 0.042, nb[2] + 0.012] : [0, nb[1] + (occ0[1] - 0.25) * neckK, nb[2] + (occ0[2] - 0.07) * neckK];
|
|
85
|
-
const ho = [0, occ[1] + 0.01 * hk, occ[2] + 0.02 * hk];
|
|
86
|
-
J.occiput = occ;
|
|
87
|
-
const bk = form.billK ?? 1;
|
|
88
|
-
J.bill = [0, ho[1] - 0.007 * hk * bk, ho[2] + (0.017 + 0.027 * bk) * hk];
|
|
89
|
-
J.jawHinge = [0, ho[1] - 0.012 * hk, ho[2] - 0.007 * hk];
|
|
90
|
-
J.jawTip = [0, ho[1] - 0.012 * hk, ho[2] + (0.017 + 0.023 * bk) * hk];
|
|
91
|
-
J._headO = ho;
|
|
92
|
-
// toes: III (middle) forward, II inner, IV outer, I (hallux) back; two segments each, on the ground
|
|
93
|
-
const toe = (j, yawDeg, a, b, back = false) => {
|
|
94
|
-
const y = (yawDeg * Math.PI) / 180, m = J.mtpL;
|
|
95
|
-
const dir = back ? [Math.sin(y), 0, -Math.cos(y)] : [Math.sin(y), 0, Math.cos(y)];
|
|
96
|
-
J[`t${j}mL`] = [m[0] + dir[0] * a, 0.005, m[2] + dir[2] * a];
|
|
97
|
-
J[`t${j}tL`] = [m[0] + dir[0] * (a + b), 0.0035, m[2] + dir[2] * (a + b)];
|
|
98
|
-
};
|
|
99
|
-
const tk = form.toeK ?? 1;
|
|
100
|
-
toe(3, 3, 0.032 * tk, 0.027 * tk);
|
|
101
|
-
toe(2, -24, 0.024 * tk, 0.021 * tk);
|
|
102
|
-
toe(4, 27, 0.026 * tk, 0.022 * tk);
|
|
103
|
-
toe(1, -10, 0.013 * tk, 0.013 * tk, true);
|
|
104
|
-
const t0 = juv ? n2(1, 0.5) : n2(1, 0.62), t1 = juv ? n2(1, 0.2) : n2(1, 0.05);
|
|
105
|
-
neckChain(J, NECK_SEGS, t0, t1, 0.42);
|
|
106
|
-
const wing = wingFor(form), feathers = feathersFor(form);
|
|
107
|
-
wingJoints(J, wing);
|
|
108
|
-
featherJoints(J, wing, feathers, { bindFan: 0.2 });
|
|
109
|
-
return J;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function chickenRig(form = {}) {
|
|
113
|
-
const J = chickenJoints(form);
|
|
114
|
-
const HO = J._headO;
|
|
115
|
-
delete J._headO;
|
|
116
|
-
const F = feathersFor(form);
|
|
117
|
-
const neck = Array.from({ length: NECK_SEGS - 1 }, (_, i) => 'neck' + (NECK_SEGS - 1 - i));
|
|
118
|
-
const neckBones = Array.from({ length: NECK_SEGS }, (_, i) => 'neck' + (NECK_SEGS - 1 - i));
|
|
119
|
-
const rig = buildRig({
|
|
120
|
-
joints: J,
|
|
121
|
-
unit: 0.34,
|
|
122
|
-
headOrigin: HO,
|
|
123
|
-
bones: birdBones({ neckSegs: NECK_SEGS, jaw: true, primaries: F.primaries.length, secondaries: F.secondaries.length, rectrices: F.rectrices.length }),
|
|
124
|
-
axial: {
|
|
125
|
-
points: ['bill', 'occiput', ...neck, 'neckBase', 'synsacrum', 'tailBase', 'tailTip'],
|
|
126
|
-
bones: ['head', ...neckBones, 'chest', 'pelvis', 'tail'],
|
|
127
|
-
// wide blends along the (thick, hackled) neck: the skull's influence runs down the neck and the
|
|
128
|
-
// neck base blends far into the breast, so head-down / head-up poses bend the whole neck
|
|
129
|
-
blend: Object.fromEntries([
|
|
130
|
-
[1, [-0.22, 0.1]],
|
|
131
|
-
...Array.from({ length: NECK_SEGS - 1 }, (_, k) => [2 + k, [-0.035, 0.035]]),
|
|
132
|
-
[1 + NECK_SEGS, [-0.5, 0.035]],
|
|
133
|
-
]),
|
|
134
|
-
},
|
|
135
|
-
limbs: birdLimbs({
|
|
136
|
-
leg: { tCore: 0.95, aCore: 0.04, aBody: -0.045, midX: 0.014 },
|
|
137
|
-
wing: { tCore: 0.3, aCore: 0.06, aBody: form.chick ? -0.16 : -0.05, midX: 0.02 },
|
|
138
|
-
}),
|
|
139
|
-
appendages: [],
|
|
140
|
-
webTags: ['flankfold', 'scapular'],
|
|
141
|
-
});
|
|
142
|
-
rig.headO = HO;
|
|
143
|
-
return rig;
|
|
144
|
-
}
|
|
@@ -1,389 +0,0 @@
|
|
|
1
|
-
// The chicken sculpted as a signed distance field: the feathered silhouette (contour feathers, the
|
|
2
|
-
// fluffy underparts, hackles and saddle are part of the body shape; flight feathers and the tail are
|
|
3
|
-
// cards, see core/build/featherCards.js), the bare red head furniture (single comb, wattles,
|
|
4
|
-
// earlobes, facial skin), a short stout bill, scaled shanks and toes and, on roosters, spurs.
|
|
5
|
-
// Every primitive is attached to a bone and a group (axial / legL / wingL / jaw). Torso primitives are
|
|
6
|
-
// written for the reference hen and carried through the individual's torso transform (roosters stand
|
|
7
|
-
// more upright); head primitives are head-local (see headLocal) and scale with the head.
|
|
8
|
-
import { NECK_SEGS, torsoFn } from './rig.js';
|
|
9
|
-
import { add, sub, mul, lerp, norm, cross, dot } from '../../core/math/vec.js';
|
|
10
|
-
import { sculptEyeSocket } from '../../core/sdf/eyeSocket.js';
|
|
11
|
-
import { wingFK, makeWingFrames, degs, featherFrame, makeFeatherFrame, resolveFeathers } from '../../core/rig/bird.js';
|
|
12
|
-
import { vaneWidth } from '../../core/build/featherCards.js';
|
|
13
|
-
import { wingFor, feathersFor } from './motion.js';
|
|
14
|
-
import { shieldLayout, planFrame } from './coverts.js';
|
|
15
|
-
|
|
16
|
-
// Eye (head-local, left, reference head): lateral (yaw 66 deg), big (globe r 7 mm), round aperture
|
|
17
|
-
// ~9.5 mm, orange iris (see index.js)
|
|
18
|
-
export const EYE = { c: [0.0122, 0.0008, 0.0015], r: 0.0068, back: 0.0021, yaw: 1.15, pitch: 0.06, lid: 0.0008, R: 0.0049, d: 0.0003, off: 0.0, tilt: 0, irisZ: 0.0045, irisR: 0.0047 };
|
|
19
|
-
|
|
20
|
-
export function eyeFor(form = {}) {
|
|
21
|
-
const k = form.headK ?? 1, e = form.eyeK ?? 1;
|
|
22
|
-
return { ...EYE, c: EYE.c.map((x) => x * k), r: EYE.r * k * e, back: EYE.back * k * e, lid: EYE.lid * k, R: EYE.R * k * e, d: EYE.d * k * e, irisZ: EYE.irisZ * k * e, irisR: EYE.irisR * k * e };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function sculptChicken(m, rig, params = {}) {
|
|
26
|
-
const J = rig.J, form = params.form || {};
|
|
27
|
-
const T = torsoFn(form);
|
|
28
|
-
const HO = rig.headOrigin, hk = form.headK ?? 1;
|
|
29
|
-
const hl = (v) => [HO[0] + v[0] * hk, HO[1] + v[1] * hk, HO[2] + v[2] * hk];
|
|
30
|
-
// bill: scaled about its base (a chick's is short)
|
|
31
|
-
const bk = form.billK ?? 1;
|
|
32
|
-
const hb = (v) => hl([v[0] * bk, v[1] * bk, 0.017 + (v[2] - 0.017) * bk]);
|
|
33
|
-
const tv = (v) => { const a = T([0, 0, 0]), b = T(v); return norm(sub(b, a)); };
|
|
34
|
-
// ellipsoid whose local Y follows ydir and local X follows (roughly) xdir; r = [x, y, z]
|
|
35
|
-
const ellY = (o) => {
|
|
36
|
-
const y = norm(o.ydir);
|
|
37
|
-
let x = o.xdir || [1, 0, 0];
|
|
38
|
-
x = norm(sub(x, mul(y, dot(x, y))));
|
|
39
|
-
const z = cross(x, y);
|
|
40
|
-
return m.ell({ ...o, axis: z, up: y });
|
|
41
|
-
};
|
|
42
|
-
const A = { bone: 'chest' }, Pv = { bone: 'pelvis' };
|
|
43
|
-
const juv = !!form.chick, male = params.sex === 'male' && !juv;
|
|
44
|
-
const fl = form.fluff ?? 1; // loose-feathered breeds are bulkier underneath
|
|
45
|
-
|
|
46
|
-
if (juv) {
|
|
47
|
-
sculptChickBody(m, J, form);
|
|
48
|
-
// (its folded wing lies on the ball in a shallow bed: folded inside the ball, every wing beat brought
|
|
49
|
-
// the feathers out through its down)
|
|
50
|
-
flankUnderWing(m, J, form, FLANK_CHICK);
|
|
51
|
-
wingPocket(m, J, form);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
// ------------------------------------------------------------ TORSO (feathered)
|
|
55
|
-
const E = (o) => m.ell({ ...o, c: T(o.c), axis: tv(o.axis || [0, 0, 1]), up: tv(o.up || [0, 1, 0]) });
|
|
56
|
-
E({ ...A, tag: 'breast', c: [0, 0.184, 0.06], r: [0.066, 0.078, 0.074], axis: [0, 0.3, 1], k: 0 });
|
|
57
|
-
E({ ...A, tag: 'keel', c: [0, 0.142, 0.036], r: [0.054, 0.054, 0.064], k: 0.03 });
|
|
58
|
-
E({ ...A, tag: 'mantle', c: [0, 0.236, -0.012], r: [0.064, 0.048, 0.108], axis: [0, 0.03, 1], k: 0.03 });
|
|
59
|
-
E({ ...Pv, tag: 'belly', c: [0, 0.136 - 0.006 * (fl - 1), -0.055], r: [0.064 * fl, 0.066 * fl, 0.086], k: 0.035 });
|
|
60
|
-
E({ ...Pv, tag: 'cushion', c: [0, 0.246, -0.108], r: [0.052, 0.052, 0.062], axis: [0, 0.5, -1], k: 0.035 });
|
|
61
|
-
E({ ...Pv, tag: 'vent', c: [0, 0.165, -0.128], r: [0.052 * fl, 0.062, 0.052], k: 0.03 });
|
|
62
|
-
E({ ...A, tag: 'crop', c: [0, 0.222, 0.092], r: [0.034, 0.034, 0.03], k: 0.03 });
|
|
63
|
-
for (const s of [1, -1]) {
|
|
64
|
-
E({ ...Pv, tag: 'flankfold', c: [0.048 * s * fl, 0.15, -0.025], r: [0.03, 0.058, 0.08], k: 0.03 });
|
|
65
|
-
E({ ...A, tag: 'scapular', c: [0.04 * s, 0.25, 0.008], r: [0.026, 0.018, 0.06], axis: [0, 0.08, 1], k: 0.025 });
|
|
66
|
-
E({ ...Pv, tag: 'fluff', c: [0.034 * s * fl, 0.1, -0.062], r: [0.03 * fl, 0.034, 0.058], k: 0.03 });
|
|
67
|
-
}
|
|
68
|
-
if (male) {
|
|
69
|
-
// saddle hackles: long pointed feathers hanging from the back over the wing tips and thighs
|
|
70
|
-
for (const s of [1, -1]) E({ ...Pv, tag: 'saddle', c: [0.034 * s, 0.22, -0.09], r: [0.028, 0.052, 0.055], axis: [0, -0.6, -1], k: 0.03 });
|
|
71
|
-
}
|
|
72
|
-
flankPad(m, J, form);
|
|
73
|
-
flankUnderWing(m, J, form);
|
|
74
|
-
wingPocket(m, J, form);
|
|
75
|
-
wingBend(m, J, form);
|
|
76
|
-
// tail coverts (the base of the roof-shaped tail; the rectrices are cards)
|
|
77
|
-
const tb = J.tailBase, tt = J.tailTip;
|
|
78
|
-
const td = norm(sub(tt, tb));
|
|
79
|
-
m.ell({ bone: 'tail', tag: 'uppertail', c: add(lerp(tb, tt, 0.6), mul(td, 0.012)), r: [0.024, 0.034, 0.03], axis: td, up: [0, 1, 0], k: 0.025 });
|
|
80
|
-
m.ell({ bone: 'tail', tag: 'undertail', c: add(lerp(tb, tt, 0.3), [0, -0.022, -0.01]), r: [0.028, 0.03, 0.03], k: 0.025 });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// ---------------------------------------------------------------- NECK (hackles)
|
|
84
|
-
const nj = ['neckBase', ...Array.from({ length: NECK_SEGS - 1 }, (_, i) => 'neck' + (i + 1)), 'occiput'];
|
|
85
|
-
const r0 = (juv ? 0.03 : 0.036) * (male ? 1.08 : 1), r1 = 0.0175 * hk;
|
|
86
|
-
const nr = nj.map((_, i) => { const u = i / NECK_SEGS; return r0 + (r1 - r0) * Math.pow(u, 0.75); });
|
|
87
|
-
for (let i = 0; i < NECK_SEGS; i++) m.cone({ bone: 'neck' + i, tag: 'neck', a: J[nj[i]], b: J[nj[i + 1]], ra: nr[i], rb: nr[i + 1], k: 0.02 });
|
|
88
|
-
if (!juv) {
|
|
89
|
-
// the hackle cape: neck feathers flowing down over the shoulders (long and full on roosters)
|
|
90
|
-
const nb = J.neckBase, n1 = J.neck1, n2 = J.neck2;
|
|
91
|
-
const back = [0, 0.004, -0.018];
|
|
92
|
-
m.ell({ bone: 'neck0', tag: 'hackle', c: add(lerp(nb, n1, 0.4), back), r: [0.042 * (male ? 1.12 : 1), 0.04, 0.036], k: 0.025 });
|
|
93
|
-
m.ell({ bone: 'neck1', tag: 'hackle', c: add(lerp(n1, n2, 0.5), [0, 0, -0.01]), r: [0.03 * (male ? 1.1 : 1), 0.03, 0.028], k: 0.02 });
|
|
94
|
-
if (male) m.ell({ bone: 'neck0', tag: 'hackle', c: add(nb, [0, -0.01, -0.03]), r: [0.05, 0.04, 0.04], k: 0.03 });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ---------------------------------------------------------------- HEAD (head-local, see HO)
|
|
98
|
-
const H = { bone: 'head' };
|
|
99
|
-
m.ell({ ...H, tag: 'cranium', c: hl([0, 0.003, -0.006]), r: [0.0142 * hk, 0.0152 * hk, 0.02 * hk], k: 0.01 });
|
|
100
|
-
m.ell({ ...H, tag: 'crown', c: hl([0, 0.0095, 0.007]), r: [0.0105 * hk, 0.0078 * hk, 0.016 * hk], axis: norm([0, -0.25, 1]), k: 0.008 });
|
|
101
|
-
m.ell({ ...H, tag: 'nape', c: hl([0, -0.005, -0.017]), r: [0.0135 * hk, 0.0165 * hk, 0.016 * hk], k: 0.01 });
|
|
102
|
-
m.ell({ ...H, tag: 'chin', c: hl([0, -0.0135, 0.008]), r: [0.0085 * hk, 0.0085 * hk, 0.017 * hk], axis: norm([0, 0.2, 1]), k: 0.008 });
|
|
103
|
-
const EYEI = eyeFor(form);
|
|
104
|
-
for (const s of [1, -1]) {
|
|
105
|
-
m.ell({ ...H, tag: 'face', c: hl([0.0074 * s, -0.0058, 0.0075]), r: [0.006 * hk, 0.0092 * hk, 0.013 * hk], k: 0.007 });
|
|
106
|
-
m.ell({ ...H, tag: 'brow', c: hl([0.0095 * s, 0.0082, 0.003]), r: [0.0058 * hk, 0.0045 * hk, 0.011 * hk], k: 0.005 });
|
|
107
|
-
sculptEyeSocket(m, EYEI, HO, s, { bone: 'head' });
|
|
108
|
-
}
|
|
109
|
-
// upper mandible: stout, triangular in profile, the culmen continuing the forehead down to the tip;
|
|
110
|
-
// the lores taper the face into it
|
|
111
|
-
for (const s of [1, -1]) m.ell({ ...H, tag: 'lores', c: hl([0.0042 * s, -0.0025, 0.017]), r: [0.0048 * hk, 0.0078 * hk, 0.009 * hk], k: 0.006 });
|
|
112
|
-
m.ell({ ...H, tag: 'bill', c: hb([0, -0.0025, 0.027]), r: [0.0048 * hk * bk, 0.0068 * hk * bk, 0.0115 * hk * bk], axis: norm([0, -0.16, 1]), k: 0.005 });
|
|
113
|
-
m.cone({ ...H, tag: 'bill', a: hb([0, -0.0004, 0.031]), b: hb([0, -0.0072, 0.0452]), ra: 0.0042 * hk * bk, rb: 0.0007 * hk * bk, k: 0.004 });
|
|
114
|
-
m.cone({ ...H, tag: 'bill', a: hb([0, -0.006, 0.03]), b: hb([0, -0.0075, 0.043]), ra: 0.0035 * hk * bk, rb: 0.0008 * hk * bk, k: 0.003 });
|
|
115
|
-
for (const s of [1, -1]) m.ell({ ...H, tag: 'nostril', c: hb([0.0038 * s, 0.0006, 0.0262]), r: [0.001 * hk * bk, 0.0008 * hk * bk, 0.0022 * hk * bk], k: 0.0006, carve: true });
|
|
116
|
-
// lower mandible (own surface so the bill can open)
|
|
117
|
-
const Jw = { bone: 'jaw', part: 'jaw' };
|
|
118
|
-
m.ell({ ...Jw, tag: 'mandible', c: hb([0, -0.0082, 0.026]), r: [0.0052 * hk * bk, 0.0028 * hk * bk, 0.013 * hk * bk], axis: norm([0, 0.05, 1]), k: 0.003 });
|
|
119
|
-
m.cone({ ...Jw, tag: 'mandible', a: hb([0, -0.0082, 0.033]), b: hb([0, -0.0078, 0.0418]), ra: 0.0034 * hk * bk, rb: 0.0007 * hk * bk, k: 0.003 });
|
|
120
|
-
|
|
121
|
-
if (!juv) {
|
|
122
|
-
// single comb: a thin serrated blade along the crown from the bill base back over the nape
|
|
123
|
-
const cb = form.comb ?? 1, ch = form.combH ?? 1, flop = form.combFlop ?? 0;
|
|
124
|
-
const C = (v) => {
|
|
125
|
-
// a large hen's comb (leghorn) flops over to one side: bend the blade about the crown line
|
|
126
|
-
let [x, y, z] = v;
|
|
127
|
-
if (flop) { const a = flop * Math.max(0, y - 0.012) / 0.03; x += Math.sin(a) * (y - 0.012) * 0.9; y = 0.012 + (y - 0.012) * Math.cos(a); }
|
|
128
|
-
return hl([x, y, z]);
|
|
129
|
-
};
|
|
130
|
-
const bladeZ = [0.024 * 1, -0.016 - 0.012 * (cb - 1)];
|
|
131
|
-
const zs = (u) => bladeZ[0] + (bladeZ[1] - bladeZ[0]) * u;
|
|
132
|
-
m.ell({ ...H, tag: 'comb', thin: true, c: C([0, 0.0165, zs(0.45)]), r: [0.0021 * hk, 0.0075 * Math.sqrt(ch) * hk, 0.024 * cb * hk], axis: norm([0, 0.08, 1]), k: 0.004 });
|
|
133
|
-
// the leader: the blade continues back over the nape
|
|
134
|
-
m.ell({ ...H, tag: 'comb', thin: true, c: C([0, 0.018 + 0.004 * ch, zs(0.98)]), r: [0.0019 * hk, 0.0075 * ch * hk, 0.009 * cb * hk], axis: norm([0, 0.3, -1]), k: 0.004 });
|
|
135
|
-
const nPts = 5;
|
|
136
|
-
for (let i = 0; i < nPts; i++) {
|
|
137
|
-
const u = (i + 0.5) / nPts;
|
|
138
|
-
const h = (0.012 + 0.009 * Math.sin(Math.PI * (0.15 + 0.8 * u))) * ch;
|
|
139
|
-
const z = zs(0.08 + 0.78 * u);
|
|
140
|
-
const tilt = -0.3 + 0.6 * u; // front points lean forward, rear points back
|
|
141
|
-
m.ell({ ...H, tag: 'comb', thin: true, c: C([0, 0.021 + h * 0.52, z]), r: [0.0019 * hk, h * 0.6 * hk, 0.0036 * cb * hk], axis: norm([0, tilt, 1]), up: norm([0, 1, -tilt]), k: 0.0016 });
|
|
142
|
-
}
|
|
143
|
-
// wattles: two rounded lobes hanging under the bill
|
|
144
|
-
const wl = form.wattle ?? 1;
|
|
145
|
-
for (const s of [1, -1]) {
|
|
146
|
-
m.ell({ ...H, tag: 'wattle', thin: true, c: hl([0.0024 * s, -0.0145 - 0.0068 * wl, 0.0225]), r: [0.0022 * hk, 0.0082 * wl * hk, 0.0096 * Math.sqrt(wl) * hk], axis: norm([0, 0.15, 1]), k: 0.005 });
|
|
147
|
-
}
|
|
148
|
-
// earlobes: flat ovals below and behind the eye
|
|
149
|
-
const el = form.earlobe ?? 1;
|
|
150
|
-
for (const s of [1, -1]) {
|
|
151
|
-
m.ell({ ...H, tag: 'earlobe', c: hl([0.0118 * s, -0.0105 - 0.002 * (el - 1), -0.009]), r: [0.0024 * hk, 0.0052 * el * hk, 0.0042 * el * hk], axis: norm([0, 0.3, 1]), k: 0.0025 });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ---------------------------------------------------------------- LEGS
|
|
156
|
-
for (const s of [1, -1]) {
|
|
157
|
-
const S = s > 0 ? 'L' : 'R', g = 'leg' + S;
|
|
158
|
-
const j = (n) => J[n + S];
|
|
159
|
-
const kn = j('knee'), an = j('ankle'), mt = j('mtp');
|
|
160
|
-
// drumstick: feathered almost to the hock, blended into the belly fluff
|
|
161
|
-
ellY({ bone: 'tibia' + S, group: g, tag: 'thigh', c: lerp(kn, an, 0.22), ydir: sub(an, kn), r: [0.026 * fl, 0.046, 0.03 * fl], k: 0.03 });
|
|
162
|
-
m.cone({ bone: 'tibia' + S, group: g, tag: 'trousers', a: lerp(kn, an, 0.3), b: lerp(kn, an, 0.84), ra: 0.02 * fl, rb: 0.0095, k: 0.014 });
|
|
163
|
-
m.cone({ bone: 'tibia' + S, group: g, tag: 'shank', a: lerp(kn, an, 0.78), b: an, ra: 0.0068, rb: 0.0064, k: 0.004 });
|
|
164
|
-
m.sphere({ bone: 'tarsus' + S, group: g, tag: 'hock', c: add(an, [0, 0, -0.0012]), rad: 0.0074, k: 0.004 });
|
|
165
|
-
// shank: oval (deeper front to back), scaled
|
|
166
|
-
m.cone({ bone: 'tarsus' + S, group: g, tag: 'tarsus', a: an, b: mt, ra: 0.0062, rb: 0.0056, k: 0.003 });
|
|
167
|
-
m.sphere({ bone: 'tarsus' + S, group: g, tag: 'pad', c: add(mt, [0, -0.0004, 0.001]), rad: 0.0052, k: 0.003 });
|
|
168
|
-
// spur: on the inner rear of the shank, a third of the way up, curving up and back
|
|
169
|
-
const sp = form.spur ?? 0;
|
|
170
|
-
if (sp > 0) {
|
|
171
|
-
const base = lerp(mt, an, 0.3);
|
|
172
|
-
const dir = norm([-0.45 * s, 0.25, -1]);
|
|
173
|
-
const tip = add(add(base, mul(dir, 0.02 * sp)), [0, 0.004 * sp, 0]);
|
|
174
|
-
m.cone({ bone: 'tarsus' + S, group: g, tag: 'spur', a: add(base, mul(dir, 0.003)), b: tip, ra: 0.0036 * Math.min(1.2, sp + 0.3), rb: 0.0009, k: 0.0025 });
|
|
175
|
-
}
|
|
176
|
-
for (const t of [1, 2, 3, 4]) {
|
|
177
|
-
const a = mt, b = J[`t${t}m${S}`], c = J[`t${t}t${S}`];
|
|
178
|
-
const tk = form.toeR ?? 1;
|
|
179
|
-
const r0 = (t === 1 ? 0.0038 : 0.0044) * tk;
|
|
180
|
-
m.cone({ bone: `toe${t}a${S}`, group: g, tag: 'toe', a, b, ra: r0, rb: 0.0036 * tk, k: 0.003 });
|
|
181
|
-
m.cone({ bone: `toe${t}b${S}`, group: g, tag: 'toe', a: b, b: lerp(b, c, 0.7), ra: 0.0036 * tk, rb: 0.0027 * tk, k: 0.0025 });
|
|
182
|
-
m.cone({ bone: `toe${t}b${S}`, group: g, tag: 'claw', a: lerp(b, c, 0.62), b: add(c, [0, -0.0012, 0]), ra: 0.0021 * tk, rb: 0.0005, k: 0.0012 });
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ---------------------------------------------------------------- WINGS (arm; flight feathers are cards)
|
|
187
|
-
const wk = form.wingK ?? 1;
|
|
188
|
-
// the arm's flesh hangs below the bones (ventral) and is thin above them, so the coverts lie on its
|
|
189
|
-
// dorsal side (a 9-12 mm arm above the bone line buried the covert cards: they cut out through it)
|
|
190
|
-
// (a chick's arm hangs further below its bones and blends into the ball over less: the folded pin
|
|
191
|
-
// feathers lie on it with the ball close under it, and a wider web stretched as the wing beat)
|
|
192
|
-
const AV = form.chick ? 1.4 : 0.8, AT = 0.75;
|
|
193
|
-
for (const s of [1, -1]) {
|
|
194
|
-
const S = s > 0 ? 'L' : 'R', g = 'wing' + S;
|
|
195
|
-
const sh = J['shoulder' + S], el = J['elbow' + S], wr = J['wrist' + S], tp = J['handTip' + S];
|
|
196
|
-
let n = norm(cross(sub(el, sh), sub(wr, el)));
|
|
197
|
-
if (n[1] < 0) n = mul(n, -1);
|
|
198
|
-
const seg = (a, b, bone, thick, chord, back, tag, k = 0.01) => {
|
|
199
|
-
const d = norm(sub(b, a));
|
|
200
|
-
const t = mul(norm(cross(n, d)), s); // trailing side
|
|
201
|
-
const c = add(add(lerp(a, b, 0.5), mul(t, back)), mul(n, -thick * AV));
|
|
202
|
-
return ellY({ bone, group: g, tag, c, ydir: d, xdir: n, r: [thick, Math.hypot(...sub(b, a)) * 0.58, chord], k });
|
|
203
|
-
};
|
|
204
|
-
seg(sh, el, 'humerus' + S, 0.012 * wk * AT, 0.02 * wk, 0.005 * wk, 'arm', form.chick ? 0.006 : 0.014);
|
|
205
|
-
seg(el, wr, 'ulna' + S, 0.009 * wk * AT, 0.018 * wk, 0.006 * wk, 'arm');
|
|
206
|
-
seg(wr, tp, 'hand' + S, 0.0065 * wk, 0.016 * wk, 0.005 * wk, 'hand', 0.007);
|
|
207
|
-
// the bend of the wing: one rounded, feathered knob from the patagium to the wrist that the covert
|
|
208
|
-
// roots grow from (the feather stack stands ~1 cm above the bones there; a thin knob left a hollow
|
|
209
|
-
// ringed by the coverts' roots)
|
|
210
|
-
const pa = lerp(sh, el, 0.3);
|
|
211
|
-
ellY({ bone: 'ulna' + S, group: g, tag: 'patagium', c: add(lerp(pa, wr, 0.55), mul(n, 0.0005 * wk)), ydir: sub(wr, pa), xdir: n, r: [0.0085 * wk, Math.hypot(...sub(wr, pa)) * 0.62 + 0.004 * wk, 0.0085 * wk], k: 0.009 });
|
|
212
|
-
m.sphere({ bone: 'hand' + S, group: g, tag: 'wrist', c: wr, rad: 0.0085 * wk, k: 0.007 });
|
|
213
|
-
coverts(m, J, form, s);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// The wing's coverts as skin: the folded wing's shield on the forearm (coverts.js: its outline, its top
|
|
218
|
-
// fitted just above the flight-feather stack, the row of greater covert cards along its rim, the lid over
|
|
219
|
-
// its upper rear corner). A chick has none: its arm is down-covered skin and its pin feathers leave it at
|
|
220
|
-
// their roots (its old covert plate stood up through its folded feathers once the wing lay on the ball).
|
|
221
|
-
function coverts(m, J, form, s) {
|
|
222
|
-
if (form.chick) return;
|
|
223
|
-
const S = s > 0 ? 'L' : 'R';
|
|
224
|
-
const F = planFrame(J, s);
|
|
225
|
-
// the shield: a slab whose top is the fitted plane (plan mm, heights mm), reaching below the wing plane
|
|
226
|
-
const L = shieldLayout(form).core, [h0, hx, hy] = L.plane;
|
|
227
|
-
const q0 = F.Q(0, 0, h0);
|
|
228
|
-
const U = norm(sub(F.Q(1, 0, h0 + hx), q0));
|
|
229
|
-
let V = sub(F.Q(0, 1, h0 + hy), q0);
|
|
230
|
-
V = norm(sub(V, mul(U, dot(V, U))));
|
|
231
|
-
let Np = cross(U, V);
|
|
232
|
-
if (dot(Np, F.n) < 0) Np = mul(Np, -1);
|
|
233
|
-
const th = L.t * 0.001;
|
|
234
|
-
const o = add(q0, mul(Np, -th / 2));
|
|
235
|
-
const poly = L.poly.map(([x, y]) => { const q = sub(F.Q(x, y, h0 + hx * x + hy * y), q0); return [dot(q, U), dot(q, V)]; });
|
|
236
|
-
m.fin({ bone: 'ulna' + S, group: 'wing' + S, tag: 'coverts', o, u: U, v: V, poly, t: th, round: Math.min(th / 2, L.round * 0.001), k: 0.003, bias: 0.008 });
|
|
237
|
-
const Ld = shieldLayout(form).lid;
|
|
238
|
-
if (Ld) {
|
|
239
|
-
// the lid over the upper rear corner: a plate whose underside is its fitted plane (above the stack)
|
|
240
|
-
const [l0, lx, ly] = Ld.plane;
|
|
241
|
-
const r0 = F.Q(0, 0, l0);
|
|
242
|
-
const LU = norm(sub(F.Q(1, 0, l0 + lx), r0));
|
|
243
|
-
let LV = sub(F.Q(0, 1, l0 + ly), r0);
|
|
244
|
-
LV = norm(sub(LV, mul(LU, dot(LV, LU))));
|
|
245
|
-
let LN = cross(LU, LV);
|
|
246
|
-
if (dot(LN, F.n) < 0) LN = mul(LN, -1);
|
|
247
|
-
const lt = Ld.t * 0.001;
|
|
248
|
-
const lpoly = Ld.poly.map(([x, y]) => { const q = sub(F.Q(x, y, l0 + lx * x + ly * y), r0); return [dot(q, LU), dot(q, LV)]; });
|
|
249
|
-
m.fin({ bone: 'ulna' + S, group: 'wing' + S, tag: 'coverts', o: add(r0, mul(LN, lt / 2)), u: LU, v: LV, poly: lpoly, t: lt, round: Math.min(lt / 2, Ld.round * 0.001), k: Ld.k, bias: 0.008 });
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
// chick: a round ball of down with a big head on a short neck (reference space of a scaled-up chick)
|
|
253
|
-
function sculptChickBody(m, J, form) {
|
|
254
|
-
const A = { bone: 'chest' }, Pv = { bone: 'pelvis' };
|
|
255
|
-
const hy = J.hipL[1];
|
|
256
|
-
m.ell({ ...A, tag: 'breast', c: [0, hy + 0.03, 0.03], r: [0.07, 0.07, 0.07], k: 0 });
|
|
257
|
-
m.ell({ ...Pv, tag: 'belly', c: [0, hy - 0.005, -0.025], r: [0.072, 0.065, 0.08], k: 0.04 });
|
|
258
|
-
m.ell({ ...Pv, tag: 'cushion', c: [0, hy + 0.035, -0.06], r: [0.055, 0.05, 0.05], k: 0.04 });
|
|
259
|
-
m.ell({ bone: 'tail', tag: 'uppertail', c: lerp(J.tailBase, J.tailTip, 0.6), r: [0.02, 0.02, 0.02], k: 0.03 });
|
|
260
|
-
for (const s of [1, -1]) {
|
|
261
|
-
m.ell({ ...Pv, tag: 'flankfold', c: [0.05 * s, hy - 0.01, -0.02], r: [0.03, 0.05, 0.06], k: 0.035 });
|
|
262
|
-
m.ell({ ...A, tag: 'scapular', c: [0.045 * s, hy + 0.045, 0.01], r: [0.028, 0.022, 0.045], k: 0.03 });
|
|
263
|
-
m.ell({ ...Pv, tag: 'fluff', c: [0.035 * s, hy - 0.045, -0.035], r: [0.03, 0.03, 0.045], k: 0.03 });
|
|
264
|
-
}
|
|
265
|
-
void form;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// The flank under the folded wing is flatter than the barrel of the body around it (the folded wing
|
|
269
|
-
// makes the side of a resting bird flat, photos): one broad, soft carver whose inner face is the folded
|
|
270
|
-
// wing's plane under its stack (the bottom of the folded primaries), so the body narrows smoothly under
|
|
271
|
-
// the wing and the slab bed below (wingPocket) only takes the last few millimetres. Smooth everywhere:
|
|
272
|
-
// in flight the flank under the open wing is flattened, not dented. FLANK: centre in the wing's plan
|
|
273
|
-
// frame (mm, as coverts.js), radii (along, across, depth, mm), the bed's depth under the wing plane
|
|
274
|
-
// (mm) and the blend (m).
|
|
275
|
-
export const FLANK = { c: [90, 22], r: [100, 50, 30], under: 1, fluff: 35, k: 0.02 };
|
|
276
|
-
// a chick's bed: broad and shallow on its round ball
|
|
277
|
-
export const FLANK_CHICK = { c: [80, 8], r: [140, 120, 30], under: 2.5, fluff: 0, k: 0.008 };
|
|
278
|
-
function flankUnderWing(m, J, form, C = FLANK) {
|
|
279
|
-
const W = wingFor(form), wk = form.wingK ?? 1;
|
|
280
|
-
const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
|
|
281
|
-
const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
|
|
282
|
-
const sh = J.shoulderL;
|
|
283
|
-
const V = (o) => [o.x, o.y, o.z];
|
|
284
|
-
const wr = add(sh, V(fr.wrist)), d = V(fr.dU), n = V(fr.nU), t = norm(cross(n, d));
|
|
285
|
-
const k = 0.001 * wk;
|
|
286
|
-
// (loose-feathered breeds bulge more under the wing: the flank flattens deeper with the fluff)
|
|
287
|
-
const under = C.under + C.fluff * Math.max(0, (form.fluff ?? 1) - 1);
|
|
288
|
-
const c0 = add(add(add(wr, mul(d, -C.c[0] * k)), mul(t, C.c[1] * k)), mul(n, (C.r[2] - under) * k));
|
|
289
|
-
for (const s of [1, -1]) {
|
|
290
|
-
const mr = (p) => [p[0] * s, p[1], p[2]];
|
|
291
|
-
m.ell({ bone: 'chest', tag: 'flankFlat', carve: true, c: mr(c0), r: [C.r[1] * k, C.r[2] * k, C.r[0] * k], axis: mr(mul(d, -1)), up: mr(n), k: C.k * wk });
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// The flank under the front of the folded wing filled out to its bed (the barrel curves in under the
|
|
296
|
-
// wing's front and the stack's lower edge stood off it over a dark hollow, deepest on an upright rooster);
|
|
297
|
-
// carved to the bed by flankUnderWing / wingPocket after it. PAD: centre in the wing's plan (mm), radii
|
|
298
|
-
// (along, across, depth), the centre's height above the wing plane (mm), blend (m).
|
|
299
|
-
export const PAD = { c: [10, 20], r: [45, 22, 14], h: -11, k: 0.016 };
|
|
300
|
-
function flankPad(m, J, form) {
|
|
301
|
-
const W = wingFor(form), wk = form.wingK ?? 1, C = PAD;
|
|
302
|
-
const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
|
|
303
|
-
const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
|
|
304
|
-
const V = (o) => [o.x, o.y, o.z];
|
|
305
|
-
const wr = add(J.shoulderL, V(fr.wrist)), d = V(fr.dU), n = V(fr.nU), t = norm(cross(n, d));
|
|
306
|
-
const c0 = add(add(add(wr, mul(d, -C.c[0] * 0.001 * wk)), mul(t, C.c[1] * 0.001 * wk)), mul(n, C.h * 0.001));
|
|
307
|
-
for (const s of [1, -1]) {
|
|
308
|
-
const mr = (p) => [p[0] * s, p[1], p[2]];
|
|
309
|
-
m.ell({ bone: 'chest', tag: 'flankPad', c: mr(c0), r: [C.r[1] * 0.001 * wk, C.r[2] * 0.001, C.r[0] * 0.001 * wk], axis: mr(mul(d, -1)), up: mr(n), k: C.k });
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// The bend of the folded wing tucks under the breast and shoulder feathers (photos: the wrist does not
|
|
314
|
-
// show; the front of the folded wing disappears into the side of the breast): a soft mound of the body
|
|
315
|
-
// over the folded wrist and the front of the covert shield, from the folded wing's pose (plan mm as
|
|
316
|
-
// coverts.js: centre, radii along x / y / the wing's normal, the centre's height above the wing plane).
|
|
317
|
-
export const BEND = { c: [-9, -3], r: [19, 20, 14], h: -1.5, k: 0.014 };
|
|
318
|
-
function wingBend(m, J, form) {
|
|
319
|
-
const W = wingFor(form), wk = form.wingK ?? 1, C = BEND;
|
|
320
|
-
const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
|
|
321
|
-
const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
|
|
322
|
-
const V = (o) => [o.x, o.y, o.z];
|
|
323
|
-
const wr = add(J.shoulderL, V(fr.wrist)), d = V(fr.dU), n = V(fr.nU), t = norm(cross(n, d));
|
|
324
|
-
const c0 = add(add(add(wr, mul(d, -C.c[0] * 0.001 * wk)), mul(t, C.c[1] * 0.001 * wk)), mul(n, C.h * 0.001));
|
|
325
|
-
for (const s of [1, -1]) {
|
|
326
|
-
const mr = (p) => [p[0] * s, p[1], p[2]];
|
|
327
|
-
m.ell({ bone: 'chest', tag: 'wingBend', c: mr(c0), r: [C.r[1] * 0.001 * wk, C.r[2] * 0.001, C.r[0] * 0.001 * wk], axis: mr(mul(d, -1)), up: mr(n), k: C.k });
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// The wing pocket: the folded wing lies ON the flank (photos: the wing is a shield on the side of the
|
|
332
|
-
// body, its flight feathers stacked on the contour feathers), so the flank under it is carved to a bed
|
|
333
|
-
// just under the folded stack: one flat slab carver per folded card (primaries, secondaries and their
|
|
334
|
-
// coverts: exact planar-polygon distance, the card's own outline inset a little), whose inner face is
|
|
335
|
-
// the card's underside less a gap (2 mm: lying, the pelvis turns against the chest and the bed came up to the
|
|
336
|
-
// lowest primary). The union of the slabs is the stack's underside, so the bed
|
|
337
|
-
// follows its outline: no hollow is carved beyond the cards (a single ellipsoid left a trench around
|
|
338
|
-
// the wing), and where the folded wing lies on the barrel of the flank the carve fades to nothing at
|
|
339
|
-
// its edges. The folded wing comes from motion.js (wing.fold through the rig's shoulder), so the bed
|
|
340
|
-
// follows every individual (a rooster's pitched torso, a fluffy breed's wider flanks, short chick
|
|
341
|
-
// wings). Carvers only cut what was sculpted before them: the torso, not the wing's own arm, the legs,
|
|
342
|
-
// neck or tail coverts.
|
|
343
|
-
export function wingPocket(m, J, form = {}) {
|
|
344
|
-
const W = wingFor(form), F = resolveFeathers(feathersFor(form)), cov = F.coverts;
|
|
345
|
-
const L = { h: W.lengths[0], u: W.lengths[1], m: W.lengths[2] };
|
|
346
|
-
const fr = wingFK(makeWingFrames(), 1, L, degs(W.fold));
|
|
347
|
-
const sh = J.shoulderL;
|
|
348
|
-
const P0 = { x: sh[0] + fr.wrist.x, y: sh[1] + fr.wrist.y, z: sh[2] + fr.wrist.z };
|
|
349
|
-
const ff = makeFeatherFrame();
|
|
350
|
-
const g = 0.002, T = 0.03, inset = 0.004, k = 0.008;
|
|
351
|
-
const V = (o) => [o.x, o.y, o.z];
|
|
352
|
-
const slab = (f, o = {}) => {
|
|
353
|
-
const A = V(ff.axis), N = V(ff.normal), Tv = norm(cross(N, A));
|
|
354
|
-
const fo = o.shape ? { ...f, ...o.shape } : f;
|
|
355
|
-
const len = f.len * (o.lenK || 1), w = f.width * (o.widthK || 1);
|
|
356
|
-
const root = add(add(V(ff.root), mul(N, o.lift || 0)), mul(A, o.shift || 0));
|
|
357
|
-
const arch = fo.arch ?? 0.12;
|
|
358
|
-
// the card in pieces along its length (more where it droops more), each slab as low as the piece's lowest point (the
|
|
359
|
-
// droop at its outer end, the vane edges, half the card's thickness)
|
|
360
|
-
const nS = Math.max(2, Math.min(7, Math.ceil((fo.droop || 0) * len / 0.002)));
|
|
361
|
-
const SEG = Array.from({ length: nS + 1 }, (_, j) => 0.04 + 0.96 * Math.sqrt(j / nS));
|
|
362
|
-
for (let q = 0; q < nS; q++) {
|
|
363
|
-
const t0 = SEG[q], t1 = SEG[q + 1];
|
|
364
|
-
const drop = (fo.droop || 0) * len * t1 * t1 + arch * w * 0.66 + 0.00025;
|
|
365
|
-
const poly = [], back = [];
|
|
366
|
-
for (let i = 0; i <= 4; i++) {
|
|
367
|
-
const t = t0 + (t1 - t0) * i / 4, [wo, wi] = vaneWidth(fo, Math.min(t, 0.99), w), cu = (fo.curve || 0) * len * t * t;
|
|
368
|
-
poly.push([t * len, cu + Math.max(0, wi - inset)]);
|
|
369
|
-
back.push([t * len, cu - Math.max(0, wo - inset)]);
|
|
370
|
-
}
|
|
371
|
-
const pts = poly.concat(back.reverse());
|
|
372
|
-
for (const s of [1, -1]) {
|
|
373
|
-
const mr = (p) => [p[0] * s, p[1], p[2]];
|
|
374
|
-
const o0 = add(root, mul(N, T / 2 - g - drop));
|
|
375
|
-
m.fin({ bone: 'chest', tag: 'wingPocket', carve: true, o: mr(o0), u: mr(A), v: mr(Tv), poly: pts, t: T, round: 0.006, k });
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
for (const f of F.primaries) {
|
|
380
|
-
featherFrame(ff, P0, fr.dM, fr.nM, L.m, 1, f, f.fold, false);
|
|
381
|
-
slab(f);
|
|
382
|
-
slab(f, { lenK: cov.primary * (1 - 0.25 * f.i / Math.max(1, f.n - 1)), widthK: 1.05, lift: 0.0022, shift: -0.004, shape: { emarg: 0, tipRound: 0.6, outer: 0.45, curve: 0.02 } });
|
|
383
|
-
}
|
|
384
|
-
for (const f of F.secondaries) {
|
|
385
|
-
featherFrame(ff, P0, fr.dU, fr.nU, L.u, 1, f, f.fold, true);
|
|
386
|
-
slab(f);
|
|
387
|
-
if (!f.cov?.skip) slab(f, { lenK: cov.secondary, widthK: 1.15, lift: 0.0028, shift: -0.006, shape: { tipRound: 0.65, outer: 0.45, curve: 0.02 } });
|
|
388
|
-
}
|
|
389
|
-
}
|