@bitefoundry/retrieviewer 0.0.3 → 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 +6 -1
- 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 +117 -59
- package/RELEASING.md +23 -12
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/linux-overlay/overlay.py +2 -2
- package/integrations/macos-overlay/overlay.jxa +8 -6
- 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/protocol.mjs +11 -7
- package/package.json +34 -13
- 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-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,339 +0,0 @@
|
|
|
1
|
-
// The grey wolf, sculpted as a signed distance field.
|
|
2
|
-
// Every primitive is attached to a bone (skinning) and a group (axial / limb / ear / jaw). The dense
|
|
3
|
-
// winter coat is partly sculpted as volume (neck ruff, cheek ruff, cape, breeches, the tail brush),
|
|
4
|
-
// with the shells adding the hair on top of it, as a wolf's silhouette is mostly fur.
|
|
5
|
-
import { HEAD_O, TAIL_SEGS, HS, hlOf } from './rig.js';
|
|
6
|
-
import { add, sub, mul, lerp, norm, cross, smoothstep } from '../../core/math/vec.js';
|
|
7
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
8
|
-
|
|
9
|
-
// Eye geometry shared by the sculpt (lids + aperture) and the eyeball shader (head-local, left eye).
|
|
10
|
-
// Axial eyeball ~23 mm (r 11.8 mm); almond fissure 22 x 10.5 mm, set obliquely (outer corner
|
|
11
|
-
// higher, 18 deg); eyes ~68 mm apart, diverging ~13 deg each; the iris fills the fissure.
|
|
12
|
-
export const EYE_BASE = { c: [0.034, 0.021, 0.036], r: 0.0118, back: 0.0025, yaw: 0.23, pitch: 0.04, lid: 0.0015, R: 0.01415, d: 0.0089, off: -0.0008, tilt: (18 * Math.PI) / 180, irisZ: 0.0072, irisR: 0.0096 };
|
|
13
|
-
// per individual: the eye moves with the head width (the muzzle stretch starts in front of it)
|
|
14
|
-
export const eyeOf = (params = {}) => ({ ...EYE_BASE, c: [EYE_BASE.c[0] * (params.headW || 1) * HS, EYE_BASE.c[1] * HS, EYE_BASE.c[2] * HS] });
|
|
15
|
-
|
|
16
|
-
const X = [1, 0, 0];
|
|
17
|
-
|
|
18
|
-
// The nose leather (head-local), two ellipsoids painted as one (coat.js): in profile a rounded wedge whose
|
|
19
|
-
// most forward point lies high, near the top, with the front face sloping back and down into the upper
|
|
20
|
-
// lip (lying1, threequarter2); from the front a broad pad with a flat top (face1, face2).
|
|
21
|
-
// - NOSE: the front lobe, flattened along its axis, which looks forward and down (~14 deg), so its lower
|
|
22
|
-
// front recedes under the tip; the nostrils open on its face. (Tilted further, 24 deg, the face and the
|
|
23
|
-
// nostrils on it turned away from a viewer above the head: face2 shows them from 20 deg above.)
|
|
24
|
-
// - NOSE_TOP: the dorsal plate, running back along the bridge line; its front end is the tip.
|
|
25
|
-
// (one ellipsoid of 27 x 31 mm in profile made a ball, and a ball focuses the key light into one dot)
|
|
26
|
-
export const NOSE = { c: [0, -0.0015, 0.1485], r: [0.0182, 0.0122, 0.0095], ax: norm([0, -0.25, 1]) };
|
|
27
|
-
export const NOSE_TOP = { c: [0, 0.0075, 0.142], r: [0.0184, 0.006, 0.017], ax: norm([0, -0.12, 1]) };
|
|
28
|
-
// The upper lip's margin (head-local, left side; x, y, z, radius): from the front of the lip ellipsoid round the
|
|
29
|
-
// corner of the muzzle and across under the nose to the midline
|
|
30
|
-
export const LIP_MARGIN = [[0.018, -0.031, 0.095, 0.0072], [0.0158, -0.0218, 0.1235, 0.0062], [0.0112, -0.0198, 0.1362, 0.0048], [0, -0.0198, 0.1418, 0.0043]];
|
|
31
|
-
// head-local point on the front lobe's surface at lateral lx and local height ly (along its tilted up axis),
|
|
32
|
-
// pushed `out` along its axis
|
|
33
|
-
export function noseAt(lx, ly, out = 0) {
|
|
34
|
-
const Z = NOSE.ax, Y = [0, Z[2], -Z[1]], [rx, ry, rz] = NOSE.r;
|
|
35
|
-
const lz = rz * Math.sqrt(Math.max(0, 1 - (lx / rx) ** 2 - (ly / ry) ** 2)) + out;
|
|
36
|
-
return [NOSE.c[0] + lx, NOSE.c[1] + Y[1] * ly + Z[1] * lz, NOSE.c[2] + Y[2] * ly + Z[2] * lz];
|
|
37
|
-
}
|
|
38
|
-
// The nostril (left side, mirrored) in the front lobe's frame (lx lateral, ly along its tilted up axis):
|
|
39
|
-
// a rounded opening in the lower half of the pad (face1: ~0.26 of the pad's width, centred a quarter of the
|
|
40
|
-
// width off the midline, two thirds of the way down, a thin rim below), and its tail, the alar groove, curving up and out
|
|
41
|
-
// round the side of the pad (lying1, threequarter2). The carve (below) gives it depth; the coat paints the
|
|
42
|
-
// same shape dark (render hint noseMarks), so it reads at every tier, whatever the mesh resolves.
|
|
43
|
-
export const NOSTRIL = { c: [0.0088, -0.0036], r: [0.0048, 0.0051], tail: [[0.0124, -0.0012], [0.0148, 0.0004], [0.0172, 0.001]], ta: 0.0015, tb: 0.0007 };
|
|
44
|
-
export function nostrilSDF(lx, ly) {
|
|
45
|
-
const x = Math.abs(lx), [cx, cy] = NOSTRIL.c, [rx, ry] = NOSTRIL.r;
|
|
46
|
-
let d = (Math.hypot((x - cx) / rx, (ly - cy) / ry) - 1) * Math.min(rx, ry);
|
|
47
|
-
const T = NOSTRIL.tail;
|
|
48
|
-
let s0 = 0, L = 0;
|
|
49
|
-
for (let i = 1; i < T.length; i++) L += Math.hypot(T[i][0] - T[i - 1][0], T[i][1] - T[i - 1][1]);
|
|
50
|
-
for (let i = 1; i < T.length; i++) {
|
|
51
|
-
const [ax, ay] = T[i - 1], ex = T[i][0] - ax, ey = T[i][1] - ay, l = Math.hypot(ex, ey);
|
|
52
|
-
const t = Math.max(0, Math.min(1, ((x - ax) * ex + (ly - ay) * ey) / (l * l)));
|
|
53
|
-
const r = NOSTRIL.ta + (NOSTRIL.tb - NOSTRIL.ta) * ((s0 + t * l) / L);
|
|
54
|
-
d = Math.min(d, Math.hypot(x - ax - t * ex, ly - ay - t * ey) - r);
|
|
55
|
-
s0 += l;
|
|
56
|
-
}
|
|
57
|
-
return d;
|
|
58
|
-
}
|
|
59
|
-
// the front lobe's frame coordinates (lx, ly) of a head-local point
|
|
60
|
-
export function noseFrame(h) {
|
|
61
|
-
const Z = NOSE.ax, d = [h[0] - NOSE.c[0], h[1] - NOSE.c[1], h[2] - NOSE.c[2]];
|
|
62
|
-
return [d[0], d[1] * Z[2] - d[2] * Z[1]];
|
|
63
|
-
}
|
|
64
|
-
// outward normal of the front lobe there (head-local)
|
|
65
|
-
export function noseNormal(lx, ly) {
|
|
66
|
-
const Z = NOSE.ax, Y = [0, Z[2], -Z[1]], [rx, ry, rz] = NOSE.r;
|
|
67
|
-
const lz = rz * Math.sqrt(Math.max(1e-4, 1 - (lx / rx) ** 2 - (ly / ry) ** 2));
|
|
68
|
-
const g = [lx / rx ** 2, ly / ry ** 2, lz / rz ** 2];
|
|
69
|
-
return norm([g[0], Y[1] * g[1] + Z[1] * g[2], Y[2] * g[1] + Z[2] * g[2]]);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function sculptWolf(m, rig, params = {}) {
|
|
73
|
-
const J = rig.J;
|
|
74
|
-
const EYE = eyeOf(params);
|
|
75
|
-
const mz = params.muzzle || 1, hw = params.headW || 1, ruff = params.ruff ?? 1, juv = params.juv || 0;
|
|
76
|
-
// head-local -> reference space: width factor, and the muzzle stretched ahead of MUZZLE_Z0
|
|
77
|
-
const hl = hlOf(mz, hw);
|
|
78
|
-
const hr = (r) => [r[0] * hw * HS, r[1] * HS, r[2] * HS]; // radii in head space
|
|
79
|
-
const eyeFrame = (s) => eyeFrameOf(EYE, HEAD_O, s);
|
|
80
|
-
|
|
81
|
-
// Ellipsoid whose local Y follows `ydir`; radii = [lateral, along ydir, third axis]
|
|
82
|
-
const ellY = (o) => {
|
|
83
|
-
const y = norm(o.ydir);
|
|
84
|
-
const lat = o.lateral || X;
|
|
85
|
-
const z = norm(cross(lat, y));
|
|
86
|
-
return m.ell({ ...o, axis: z, up: y, r: [o.r[0], o.r[1], o.r[2]] });
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// A tube along a Catmull-Rom curve through control points [[point, radius], ...] (`after`: a point beyond the last,
|
|
90
|
-
// setting its end tangent), n round cones per span after the first. The first span blends into the face with o.k;
|
|
91
|
-
// the rest are a hard union: round cones sharing their end spheres and tangents meet smoothly on the outside, while
|
|
92
|
-
// a smooth union of overlapping segments swells the tube by up to k/4 at every joint (a string of beads)
|
|
93
|
-
const tube = (pts, after, n, o) => {
|
|
94
|
-
const P = pts.map((q) => q[0]), Rr = pts.map((q) => q[1]);
|
|
95
|
-
const at = (i, t) => {
|
|
96
|
-
const p0 = P[Math.max(0, i - 1)], p1 = P[i], p2 = P[i + 1], p3 = i + 2 < P.length ? P[i + 2] : after || P[i + 1];
|
|
97
|
-
const t2 = t * t, t3 = t2 * t;
|
|
98
|
-
return [0, 1, 2].map((k) => 0.5 * (2 * p1[k] + (-p0[k] + p2[k]) * t + (2 * p0[k] - 5 * p1[k] + 4 * p2[k] - p3[k]) * t2 + (-p0[k] + 3 * p1[k] - 3 * p2[k] + p3[k]) * t3));
|
|
99
|
-
};
|
|
100
|
-
for (let i = 0; i < P.length - 1; i++) {
|
|
101
|
-
const ns = i === 0 ? 1 : n;
|
|
102
|
-
for (let j = 0; j < ns; j++) {
|
|
103
|
-
const t0 = j / ns, t1 = (j + 1) / ns;
|
|
104
|
-
m.cone({ ...o, k: i === 0 ? o.k : 0, a: at(i, t0), b: at(i, t1), ra: Rr[i] + (Rr[i + 1] - Rr[i]) * t0, rb: Rr[i] + (Rr[i + 1] - Rr[i]) * t1 });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// ---------------------------------------------------------------- TORSO
|
|
110
|
-
// deep, narrow "keeled" chest; level back; belly tucked up behind the ribs
|
|
111
|
-
m.ell({ tag: 'ribcage', bone: 'spine3', c: [0, 0.55, 0.14], r: [0.101, 0.142, 0.2], axis: norm([0, 0.12, -1]), k: 0 });
|
|
112
|
-
m.ell({ tag: 'brisket', bone: 'chest', c: [0, 0.455, 0.29], r: [0.056, 0.07, 0.1], axis: norm([0, -0.35, 1]), k: 0.06 });
|
|
113
|
-
m.ell({ tag: 'pectoral', bone: 'chest', c: [0, 0.5, 0.405], r: [0.066, 0.078, 0.06], k: 0.05 });
|
|
114
|
-
m.ell({ tag: 'withers', bone: 'chest', c: [0, 0.69, 0.26], r: [0.052, 0.055, 0.13], axis: norm([0, -0.1, 1]), k: 0.06 });
|
|
115
|
-
m.ell({ tag: 'back', bone: 'spine3', c: [0, 0.692, 0.03], r: [0.066, 0.05, 0.16], k: 0.06 });
|
|
116
|
-
m.ell({ tag: 'abdomen', bone: 'spine2', c: [0, 0.585, -0.08], r: [0.079, 0.087, 0.16], axis: norm([0, 0.33, -1]), k: 0.07 });
|
|
117
|
-
m.ell({ tag: 'loin', bone: 'spine1', c: [0, 0.68, -0.14], r: [0.06, 0.05, 0.14], k: 0.05 });
|
|
118
|
-
m.ell({ tag: 'flank', bone: 'spine1', c: [0, 0.59, -0.19], r: [0.064, 0.064, 0.09], k: 0.05 });
|
|
119
|
-
m.ell({ tag: 'pelvis', bone: 'pelvis', c: [0, 0.625, -0.28], r: [0.07, 0.085, 0.11], k: 0.06 });
|
|
120
|
-
m.ell({ tag: 'croup', bone: 'pelvis', c: [0, 0.675, -0.27], r: [0.055, 0.04, 0.1], k: 0.04 });
|
|
121
|
-
for (const s of [1, -1]) {
|
|
122
|
-
m.ell({ tag: 'rump', bone: 'pelvis', c: [0.042 * s, 0.585, -0.355], r: [0.042, 0.07, 0.05], k: 0.04 });
|
|
123
|
-
}
|
|
124
|
-
// cape: the long guard hair over the shoulders and hackles (sculpted coat volume)
|
|
125
|
-
m.ell({ tag: 'cape', bone: 'chest', c: [0, 0.675, 0.31], r: [0.09 * (0.8 + 0.2 * ruff), 0.075, 0.13], axis: norm([0, 0.25, 1]), k: 0.07 });
|
|
126
|
-
|
|
127
|
-
// ---------------------------------------------------------------- NECK (thick, wrapped in the ruff)
|
|
128
|
-
m.cone({ tag: 'neck', bone: 'neck1', a: [0, 0.58, 0.37], b: [0, 0.685, 0.455], ra: 0.088, rb: 0.07, k: 0.06 });
|
|
129
|
-
m.cone({ tag: 'neck', bone: 'neck2', a: [0, 0.685, 0.455], b: [0, 0.765, 0.51], ra: 0.07, rb: 0.058, k: 0.04 });
|
|
130
|
-
m.ell({ tag: 'nape', bone: 'neck1', c: [0, 0.745, 0.42], r: [0.046, 0.034, 0.1], axis: norm([0, 0.5, 1]), k: 0.04 });
|
|
131
|
-
m.ell({ tag: 'throat', bone: 'neck2', c: [0, 0.625, 0.5], r: [0.048, 0.06, 0.07], axis: norm([0, 0.8, 0.6]), k: 0.05 });
|
|
132
|
-
// the ruff ("mane"): a collar of long hair framing the face, fullest at the throat and the sides
|
|
133
|
-
const rf = (0.75 + 0.25 * ruff) * 1.2; // (+20 %: even a slight female keeps a ruff that frames the face)
|
|
134
|
-
m.ell({ tag: 'ruff', bone: 'neck1', c: [0, 0.64, 0.43], r: [0.082 * rf, 0.088 * rf, 0.095], axis: norm([0, 0.6, 1]), k: 0.06 });
|
|
135
|
-
m.ell({ tag: 'ruff', bone: 'neck2', c: [0, 0.67, 0.505], r: [0.062 * rf, 0.055 * rf, 0.05], axis: norm([0, 0.8, 1]), k: 0.05 });
|
|
136
|
-
|
|
137
|
-
// ---------------------------------------------------------------- HEAD (head-local coords, see HEAD_O)
|
|
138
|
-
// landmarks from profile / frontal photos (adult ~0.25 m occiput -> nose): nose tip (0,-0.012,0.155),
|
|
139
|
-
// eyes (+-0.034, 0.021, 0.036), stop ~z 0.05, chin (0,-0.058,0.125), skull top ~0.077, occiput -0.1,
|
|
140
|
-
// zygomatic width ~0.13 (+ cheek ruff); a pup has a domed skull and a short muzzle (params).
|
|
141
|
-
// Profile (lying1 / threequarter2 overlaid on the eye and the nose tip): a moderate stop in front of
|
|
142
|
-
// the eyes, the forehead rising ~0.8 mm per mm from the bridge (z 0.065 -> 0.035) to a broad, domed crown that stands
|
|
143
|
-
// ~10 mm above the eye line's old straight wedge; the midline top at z 100 / 65 / 35 / 0 is 32 / 44 / 69 / 79 mm
|
|
144
|
-
// (was 34 / 50 / 60 / 71: the bridge ran level into the crown, a small flat skull behind a long snout)
|
|
145
|
-
const H = { bone: 'head' };
|
|
146
|
-
m.ell({ ...H, tag: 'cranium', c: hl([0, 0.024 + 0.002 * juv, -0.035]), r: hr([0.053 + 0.002 * juv, 0.053 + 0.005 * juv, 0.066]), k: 0.04 });
|
|
147
|
-
// temporal muscles: a broad, domed skull between the ears (the ears sit on its corners)
|
|
148
|
-
for (const s of [1, -1]) m.ell({ ...H, tag: 'temporal', c: hl([0.03 * s, 0.041, -0.045]), r: hr([0.03, 0.026, 0.045]), k: 0.03 });
|
|
149
|
-
m.ell({ ...H, tag: 'forehead', c: hl([0, 0.043 + 0.002 * juv, 0.014]), r: hr([0.037, 0.032, 0.038]), axis: norm([0, -0.35, 1]), k: 0.025 });
|
|
150
|
-
m.ell({ ...H, tag: 'crest', c: hl([0, 0.052, -0.055]), r: hr([0.018, 0.014, 0.05]), k: 0.03 });
|
|
151
|
-
for (const s of [1, -1]) {
|
|
152
|
-
m.ell({ ...H, tag: 'brow', c: hl([0.029 * s, 0.037, 0.032]), r: hr([0.016, 0.008, 0.014]), k: 0.012 });
|
|
153
|
-
m.ell({ ...H, tag: 'zygomatic', c: hl([0.056 * s, 0.002, -0.004]), r: hr([0.016, 0.022, 0.045]), axis: norm([-0.3 * s, 0, 1]), k: 0.035 });
|
|
154
|
-
m.ell({ ...H, tag: 'cheek', c: hl([0.038 * s, -0.028, -0.006]), r: hr([0.018, 0.026, 0.038]), k: 0.035 });
|
|
155
|
-
// maxilla: the side of the face under the eye tapers into the muzzle in one plane (a wolf has no
|
|
156
|
-
// step between cheek and muzzle); converges toward the nose, deepest at the lip line
|
|
157
|
-
m.ell({ ...H, tag: 'maxilla', c: hl([0.022 * s, -0.013, 0.052]), r: hr([0.02, 0.027, 0.062]), axis: norm([-0.2 * s, -0.1, 1]), k: 0.024 });
|
|
158
|
-
// mouth corner: the upper lip runs back to the commissure under the eye and meets the cheek
|
|
159
|
-
m.ell({ ...H, tag: 'commissure', c: hl([0.031 * s, -0.036, 0.028]), r: hr([0.013, 0.012, 0.026]), k: 0.016 });
|
|
160
|
-
// cheek ruff: the hair flares sideways and back below the ears (the wide wolf face)
|
|
161
|
-
m.ell({ ...H, tag: 'cheekruff', c: hl([0.056 * s, -0.036, -0.07]), r: hr([0.03 * rf, 0.045, 0.034]), axis: norm([0.35 * s, 0, 1]), k: 0.03 });
|
|
162
|
-
m.ell({ ...H, tag: 'mastoid', c: hl([0.036 * s, -0.018, -0.062]), r: hr([0.024, 0.03, 0.03]), k: 0.03 });
|
|
163
|
-
// upper lip: from the mouth corner under the eye (the lips meet the commissure ~0.6 eye spacings off
|
|
164
|
-
// the midline, face1) forward to under the nose. Its margin, the lip line, keeps its height behind and
|
|
165
|
-
// rises toward the front to the leather's lower back: only ~6-15 mm of lip under the leather (lying1,
|
|
166
|
-
// threequarter2, face1). (Lips running level to 2 cm behind the leather hung a 3 cm white
|
|
167
|
-
// block under it, with the chin as a second lobe below: a puppy's muzzle.)
|
|
168
|
-
m.ell({ ...H, tag: 'lip', c: hl([0.0195 * s, -0.0395, 0.062]), r: hr([0.0095, 0.0108, 0.04]), axis: norm([-0.2 * s, 0.11, 1]), k: 0.014 });
|
|
169
|
-
}
|
|
170
|
-
// the front of the lip: one tube along the margin, from the side of the muzzle round its corner under the side of
|
|
171
|
-
// the nose and across under the nose to the midline, where it meets its mirror image with the same tangent; from
|
|
172
|
-
// the front its margin runs nearly level across the width of the leather before it turns back (face1, face2: a
|
|
173
|
-
// flat "w"). (Three separately blended rolls stood as two knobs either side of a crease under the nose: a pursed
|
|
174
|
-
// mouth from the front and below. Both sides come before the whisker pads, which blend into them.)
|
|
175
|
-
for (const s of [1, -1]) {
|
|
176
|
-
const C = LIP_MARGIN.map(([x, y, z, r]) => [hl([x * s, y, z]), r * HS]);
|
|
177
|
-
const [mx, my, mz2] = LIP_MARGIN[LIP_MARGIN.length - 2];
|
|
178
|
-
tube(C, hl([-mx * s, my, mz2]), 3, { ...H, tag: 'lipfront', k: 0.01 });
|
|
179
|
-
}
|
|
180
|
-
for (const s of [1, -1]) {
|
|
181
|
-
m.ell({ ...H, tag: 'whisker', c: hl([0.0115 * s, -0.0195, 0.116]), r: hr([0.009, 0.0088, 0.018]), k: 0.01 });
|
|
182
|
-
}
|
|
183
|
-
// long, fairly narrow muzzle with a straight nasal bridge and a moderate stop (the cone starts low in front of
|
|
184
|
-
// the forehead, which rises above it). The bridge ends behind
|
|
185
|
-
// the nose pad and its top line runs straight into the top of the leather (threequarter2, side3): a
|
|
186
|
-
// cone ending level with the pad capped it with a round fur dome (a bear's or pig's snout from the front)
|
|
187
|
-
m.cone({ ...H, tag: 'nasal', a: hl([0, 0.021, 0.058]), b: hl([0, 0.0084, 0.126]), ra: 0.024 * hw, rb: 0.013 * hw, k: 0.02 });
|
|
188
|
-
// the bridge: a broad, flat-topped muzzle (square in section, not a wedge), ending behind the leather
|
|
189
|
-
m.ell({ ...H, tag: 'bridge', c: hl([0, 0.009, 0.088]), r: hr([0.02, 0.012, 0.045]), axis: norm([0, -0.25, 1]), k: 0.02 });
|
|
190
|
-
m.ell({ ...H, tag: 'muzzle', c: hl([0, -0.016, 0.082]), r: hr([0.025, 0.0245, 0.05]), axis: norm([0, 0.1, 1]), k: 0.02 });
|
|
191
|
-
// the rostrum keeps the nose pad's width up to the leather (no waist behind the pad), its top under the
|
|
192
|
-
// bridge line
|
|
193
|
-
m.ell({ ...H, tag: 'rostrum', c: hl([0, -0.004, 0.13]), r: hr([0.0165, 0.012, 0.019]), k: 0.012 });
|
|
194
|
-
// the nose leather (face1: 0.55 x 0.38 eye spacings; threequarter2: it caps the whole end of the muzzle,
|
|
195
|
-
// its top running on from the bridge line and its sides reaching ~2.5 cm back)
|
|
196
|
-
m.ell({ ...H, tag: 'nose', c: hl(NOSE.c), r: hr(NOSE.r), axis: NOSE.ax, k: 0.008 });
|
|
197
|
-
m.ell({ ...H, tag: 'nosetop', c: hl(NOSE_TOP.c), r: hr(NOSE_TOP.r), axis: NOSE_TOP.ax, k: 0.006 });
|
|
198
|
-
// (no philtrum primitive: under the nose the two rostral lip rolls meet on the midline, and the groove that
|
|
199
|
-
// splits the bottom of the pad and runs down to the mouth line is painted. A small plate there, along the
|
|
200
|
-
// receding lip, caught the key light on the 5 mm cells of medium as a pale tab under the nose.)
|
|
201
|
-
// (the groove splitting the bottom of the pad is painted (coat.js): carved, it folded into a sliver on
|
|
202
|
-
// the 5 mm cells of the medium tier)
|
|
203
|
-
for (const s of [1, -1]) {
|
|
204
|
-
const ef = eyeFrame(s);
|
|
205
|
-
const at = (u, v, w) => add(add(add(ef.c, mul(ef.x, u)), mul(ef.y, v)), mul(ef.z, w));
|
|
206
|
-
// orbit: a soft hollow so brow, cheek and bridge fall away to the lids
|
|
207
|
-
ellY({ ...H, tag: 'orbit', c: at(-0.002 * s, -0.0005, 0.019), ydir: ef.y, lateral: ef.x, r: [0.018, 0.0125, 0.009], k: 0.008, carve: true });
|
|
208
|
-
m.sphere({ ...H, tag: 'eyelid', c: ef.c, rad: EYE.r + EYE.lid, k: 0.005 });
|
|
209
|
-
m.lens({ ...H, tag: 'eyesocket', c: add(ef.c, mul(ef.y, EYE.off)), x: ef.x, y: ef.y, z: ef.z, R: EYE.R, d: EYE.d, zMin: -0.002, zMax: 0.024, k: 0.0022, carve: true });
|
|
210
|
-
// nostrils: comma-shaped openings in the lower half of the pad's face (face1, face2: the darkest marks in
|
|
211
|
-
// the face): a rounded opening that looks forward, down and out, and its tail, the alar slit, running
|
|
212
|
-
// back round the side of the pad (lying1, threequarter2)
|
|
213
|
-
const [ncx, ncy] = NOSTRIL.c, nn = noseNormal(ncx * s, ncy);
|
|
214
|
-
m.ell({ ...H, tag: 'nostril', c: hl(noseAt(ncx * s, ncy, 0.0009)), r: hr([NOSTRIL.r[0], NOSTRIL.r[1], 0.005]), axis: nn, up: [0, 1, 0], k: 0.0012, carve: true });
|
|
215
|
-
const [t0, t1] = NOSTRIL.tail;
|
|
216
|
-
m.cone({ ...H, tag: 'alar', a: hl(noseAt(t0[0] * s, t0[1], 0.0003)), b: hl(noseAt(t1[0] * s, t1[1], 0.0002)), ra: 0.0014, rb: 0.001, k: 0.0008, carve: true });
|
|
217
|
-
// upper canine, hidden behind the lip and inside the closed jaw; shows when the mouth opens
|
|
218
|
-
// (4 mm further back with the front of the mouth: the lips' front ends and the lower jaw)
|
|
219
|
-
m.cone({ ...H, tag: 'canine', a: hl([0.014 * s, -0.0295, 0.1095]), b: hl([0.013 * s, -0.0362, 0.1067]), ra: 0.004, rb: 0.0012, k: 0.002 });
|
|
220
|
-
// upper incisors: three a side in an arc along the front of the upper jaw, just behind the rostral lip, their
|
|
221
|
-
// tips under the head's underside (inside the closed jaw at rest, in front of the lower incisors: a scissor
|
|
222
|
-
// bite); the open mouth shows them under the nose (the third, outer one larger)
|
|
223
|
-
for (const [x, z, ra] of [[0.0024, 0.1215, 0.0014], [0.0066, 0.1202, 0.0014], [0.0106, 0.1175, 0.0017]]) {
|
|
224
|
-
m.cone({ ...H, tag: 'tooth', a: hl([x * s, -0.027, z + 0.001]), b: hl([x * s * 1.03, -0.034, z - 0.0004]), ra, rb: 0.0008, k: 0.001 });
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// ---------------------------------------------------------------- JAW (separate surface so the mouth can open)
|
|
229
|
-
const JW = { bone: 'jaw', group: 'jaw', part: 'jaw' };
|
|
230
|
-
// The lower jaw runs forward under the rising lip line to below the back of the leather, its ventral line
|
|
231
|
-
// straight from the throat to the chin (a scissor bite: the lower incisors just behind the upper lip's
|
|
232
|
-
// front, the lower canines in front of the upper ones). (With the jaw ending 2 cm further back, a chin
|
|
233
|
-
// ellipsoid sagged below the lip line as a round lobe: a pouch from the side, a second white lobe from
|
|
234
|
-
// the front.) The front is narrower than the upper lip, so from the front little chin shows under it.
|
|
235
|
-
m.cone({ ...JW, tag: 'mandible', a: hl([0, -0.05, -0.015]), b: hl([0, -0.049, 0.095]), ra: 0.016, rb: 0.0105, k: 0 });
|
|
236
|
-
m.cone({ ...JW, tag: 'mandible', a: hl([0, -0.049, 0.095]), b: hl([0, -0.0328, 0.1142]), ra: 0.0105, rb: 0.0062, k: 0.006 });
|
|
237
|
-
for (const s of [1, -1]) {
|
|
238
|
-
m.cone({ ...JW, tag: 'mandible', a: hl([0.036 * s, -0.044, -0.03]), b: hl([0.0105 * s, -0.0315, 0.1135]), ra: 0.013, rb: 0.007, k: 0.02 });
|
|
239
|
-
}
|
|
240
|
-
// the chin: the rounded front of the jaw under the lower lip
|
|
241
|
-
m.ell({ ...JW, tag: 'chin', c: hl([0, -0.038, 0.1005]), r: hr([0.0105, 0.006, 0.008]), k: 0.01 });
|
|
242
|
-
// lower lip: the front of the jaw rises to meet the upper lip under the nose (no slit at rest)
|
|
243
|
-
m.ell({ ...JW, tag: 'lowerlip', c: hl([0, -0.0262, 0.118]), r: hr([0.0125, 0.004, 0.0075]), k: 0.01 });
|
|
244
|
-
// lower canines: at rest their tips sit inside the upper lip; they come clear as soon as the jaw drops
|
|
245
|
-
// (the snarl and the bite show fangs; the core cannot retract the lips)
|
|
246
|
-
for (const s of [1, -1]) {
|
|
247
|
-
m.cone({ ...JW, tag: 'canine', a: hl([0.0085 * s, -0.0355, 0.1112]), b: hl([0.0096 * s, -0.0212, 0.1142]), ra: 0.0036, rb: 0.0012, k: 0.002 });
|
|
248
|
-
// the rest of the lower teeth, hidden inside the upper lips at rest (the jaw's crest lies 2-13 mm inside
|
|
249
|
-
// the head there): three incisors between the canines, and the cheek teeth along the crest (P2-P4 and
|
|
250
|
-
// the carnassial), so the open mouth shows a tooth row instead of bare gum
|
|
251
|
-
for (const [x, z] of [[0.0026, 0.1197], [0.0062, 0.1182], [0.0094, 0.1158]]) m.cone({ ...JW, tag: 'tooth', a: hl([x * s, -0.0295, z]), b: hl([x * s * 1.05, -0.0225, z + 0.0012]), ra: 0.0017, rb: 0.0009, k: 0.001 });
|
|
252
|
-
for (const [x, z, y0, hgt, ra] of [[0.0128, 0.086, -0.041, 0.0045, 0.0028], [0.0137, 0.073, -0.041, 0.0055, 0.0032], [0.0146, 0.059, -0.0405, 0.006, 0.0036], [0.0149, 0.043, -0.0395, 0.0065, 0.0044]]) {
|
|
253
|
-
m.cone({ ...JW, tag: 'tooth', a: hl([x * s, y0 - 0.002, z]), b: hl([(x - 0.0006) * s, y0 + hgt, z - 0.001]), ra, rb: 0.0009, k: 0.0015 });
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// ---------------------------------------------------------------- EARS
|
|
258
|
-
// erect, triangular, set wide; broad at the base, pointed tip, cupped front (shorter than a fox's)
|
|
259
|
-
for (const S of ['L', 'R']) {
|
|
260
|
-
const s = S === 'L' ? 1 : -1;
|
|
261
|
-
const base = J['earBase' + S], tip = J['earTip' + S];
|
|
262
|
-
const up = norm(sub(tip, base));
|
|
263
|
-
const facing = norm([0.32 * s, 0.05, 1]); // (the cups face forward, a little outward: face1, face2)
|
|
264
|
-
const lat = norm(cross(up, facing));
|
|
265
|
-
const L = Math.hypot(...sub(tip, base));
|
|
266
|
-
const ear = { bone: 'ear' + S, group: 'ear' + S, thin: true };
|
|
267
|
-
const at = (t) => lerp(base, tip, t);
|
|
268
|
-
ellY({ ...ear, tag: 'ear', c: at(0.22), ydir: up, lateral: lat, r: [0.036, 0.036, 0.0095], k: 0.012 });
|
|
269
|
-
ellY({ ...ear, tag: 'ear', c: at(0.55), ydir: up, lateral: lat, r: [0.023, 0.034, 0.0068], k: 0.012 });
|
|
270
|
-
ellY({ ...ear, tag: 'ear', c: at(0.84), ydir: up, lateral: lat, r: [0.0085, 0.022, 0.0048], k: 0.01 });
|
|
271
|
-
ellY({ ...ear, tag: 'earinner', c: add(at(0.36), mul(facing, 0.0085)), ydir: up, lateral: lat, r: [0.024, 0.034, 0.0062], k: 0.004, carve: true });
|
|
272
|
-
ellY({ ...ear, tag: 'earinner', c: add(at(0.68), mul(facing, 0.0062)), ydir: up, lateral: lat, r: [0.011, 0.026, 0.0045], k: 0.003, carve: true });
|
|
273
|
-
void L;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// ---------------------------------------------------------------- LEGS
|
|
277
|
-
// long, lean legs; big feet; elbows tucked in under the narrow chest
|
|
278
|
-
for (const S of ['L', 'R']) {
|
|
279
|
-
const s = S === 'L' ? 1 : -1;
|
|
280
|
-
const lat = [s, 0, 0];
|
|
281
|
-
const sx = (v) => [v[0] * s, v[1], v[2]];
|
|
282
|
-
const g = 'F' + S;
|
|
283
|
-
const Sc = J['scapTop' + S], Sh = J['shoulder' + S], E = J['elbow' + S], W = J['wrist' + S], M = J['mcp' + S], T = J['ftoe' + S];
|
|
284
|
-
ellY({ tag: 'scapmuscle', bone: 'scapula' + S, group: g, c: add(lerp(Sc, Sh, 0.5), sx([0.008, 0, 0])), ydir: sub(Sh, Sc), lateral: lat, r: [0.026, 0.1, 0.058], k: 0.06, bias: 0.004 });
|
|
285
|
-
m.cone({ tag: 'upperarm', bone: 'humerus' + S, group: g, a: Sh, b: E, ra: 0.043, rb: 0.032, k: 0.06 });
|
|
286
|
-
ellY({ tag: 'triceps', bone: 'humerus' + S, group: g, c: add(lerp(Sh, E, 0.55), [0, 0, -0.03]), ydir: sub(E, Sh), lateral: lat, r: [0.03, 0.075, 0.036], k: 0.05 });
|
|
287
|
-
m.sphere({ tag: 'olecranon', bone: 'radius' + S, group: g, c: add(E, [0, 0.008, -0.024]), rad: 0.018, k: 0.02 });
|
|
288
|
-
m.cone({ tag: 'forearm', bone: 'radius' + S, group: g, a: E, b: W, ra: 0.032, rb: 0.019, k: 0.025 });
|
|
289
|
-
ellY({ tag: 'forearmmuscle', bone: 'radius' + S, group: g, c: add(lerp(E, W, 0.25), sx([0.003, 0, 0.004])), ydir: sub(W, E), lateral: lat, r: [0.028, 0.068, 0.032], k: 0.03 });
|
|
290
|
-
// feathering on the back of the forearm
|
|
291
|
-
ellY({ tag: 'feather', bone: 'radius' + S, group: g, c: add(lerp(E, W, 0.45), [0, 0, -0.018]), ydir: sub(W, E), lateral: lat, r: [0.016, 0.06, 0.018], k: 0.02 });
|
|
292
|
-
m.sphere({ tag: 'wrist', bone: 'metacarpus' + S, group: g, c: add(W, [0, 0, -0.003]), rad: 0.019, k: 0.012 });
|
|
293
|
-
m.sphere({ tag: 'carpalpad', bone: 'metacarpus' + S, group: g, c: add(W, [0, -0.008, -0.019]), rad: 0.009, k: 0.01 });
|
|
294
|
-
m.cone({ tag: 'pastern', bone: 'metacarpus' + S, group: g, a: W, b: M, ra: 0.018, rb: 0.018, k: 0.012 });
|
|
295
|
-
m.sphere({ tag: 'dewclaw', bone: 'metacarpus' + S, group: g, c: add(lerp(W, M, 0.3), sx([-0.016, 0, 0.002])), rad: 0.006, k: 0.005 });
|
|
296
|
-
const dp = norm(sub(T, M));
|
|
297
|
-
// big oval forefoot (print ~11 x 9.5 cm incl. claws)
|
|
298
|
-
ellY({ tag: 'paw', bone: 'fpaw' + S, group: g, c: add(add(M, mul(dp, 0.022)), [0, -0.006, 0]), ydir: dp, lateral: lat, r: [0.03, 0.04, 0.019], k: 0.014 });
|
|
299
|
-
m.sphere({ tag: 'pad', bone: 'fpaw' + S, group: g, c: add(M, [0, -0.025, 0.012]), rad: 0.013, k: 0.01 });
|
|
300
|
-
const toeX = [-0.021, -0.0072, 0.0072, 0.021], toeZ = [-0.011, 0, 0, -0.011];
|
|
301
|
-
for (let i = 0; i < 4; i++) m.sphere({ tag: 'toe', bone: 'fpaw' + S, group: g, c: [T[0] + toeX[i] * s, 0.0122, T[2] - 0.009 + toeZ[i]], rad: 0.0115, k: 0.007 });
|
|
302
|
-
for (let i = 0; i < 4; i++) m.cone({ tag: 'claw', bone: 'fpaw' + S, group: g, a: [T[0] + toeX[i] * s * 0.95, 0.011, T[2] + 0.0 + toeZ[i]], b: [T[0] + toeX[i] * s * 0.95, 0.004, T[2] + 0.011 + toeZ[i]], ra: 0.0032, rb: 0.0012, k: 0.002 });
|
|
303
|
-
|
|
304
|
-
const h = 'H' + S;
|
|
305
|
-
const Hp = J['hip' + S], K = J['knee' + S], Hk = J['hock' + S], Mt = J['mtp' + S], Tt = J['htoe' + S];
|
|
306
|
-
// broad muscular thigh with long "breeches" hair behind
|
|
307
|
-
ellY({ tag: 'thigh', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.4), sx([0.004, 0, -0.03])), ydir: sub(K, Hp), lateral: lat, r: [0.042, 0.145, 0.095], k: 0.05, bias: 0.004 });
|
|
308
|
-
m.cone({ tag: 'thighfront', bone: 'femur' + S, group: h, a: sx([0.04, 0.6, -0.15]), b: add(K, sx([-0.004, 0.055, 0.0])), ra: 0.038, rb: 0.024, k: 0.06 });
|
|
309
|
-
m.cone({ tag: 'hamstring', bone: 'femur' + S, group: h, a: sx([0.045, 0.6, -0.36]), b: add(lerp(K, Hk, 0.28), [0, 0, -0.03]), ra: 0.046, rb: 0.028, k: 0.04 });
|
|
310
|
-
ellY({ tag: 'breeches', bone: 'femur' + S, group: h, c: add(lerp(Hp, K, 0.62), sx([0.006, -0.01, -0.085])), ydir: sub(K, Hp), lateral: lat, r: [0.03, 0.08, 0.03], k: 0.035 });
|
|
311
|
-
ellY({ tag: 'flankfold', bone: 'femur' + S, group: h, c: sx([0.05, 0.48, -0.13]), ydir: [-0.03, 0.16, 0.1], lateral: lat, r: [0.02, 0.08, 0.04], k: 0.06 });
|
|
312
|
-
m.sphere({ tag: 'stifle', bone: 'tibia' + S, group: h, c: add(K, sx([0.002, 0.008, 0.006])), rad: 0.017, k: 0.04 });
|
|
313
|
-
m.cone({ tag: 'shin', bone: 'tibia' + S, group: h, a: add(lerp(K, Hk, 0.06), sx([0.0, 0.0, 0.004])), b: Hk, ra: 0.023, rb: 0.017, k: 0.03 });
|
|
314
|
-
ellY({ tag: 'calf', bone: 'tibia' + S, group: h, c: add(lerp(K, Hk, 0.3), sx([0.002, 0.01, -0.027])), ydir: sub(Hk, K), lateral: lat, r: [0.025, 0.07, 0.03], k: 0.035 });
|
|
315
|
-
m.cone({ tag: 'achilles', bone: 'tibia' + S, group: h, a: add(lerp(K, Hk, 0.5), [0, 0.01, -0.034]), b: add(Hk, [0, 0.012, -0.029]), ra: 0.012, rb: 0.011, k: 0.015 });
|
|
316
|
-
m.sphere({ tag: 'calcaneus', bone: 'metatarsus' + S, group: h, c: add(Hk, [0, 0.012, -0.025]), rad: 0.015, k: 0.012 });
|
|
317
|
-
m.sphere({ tag: 'hock', bone: 'metatarsus' + S, group: h, c: Hk, rad: 0.02, k: 0.012 });
|
|
318
|
-
m.cone({ tag: 'metatarsus', bone: 'metatarsus' + S, group: h, a: Hk, b: Mt, ra: 0.018, rb: 0.017, k: 0.012 });
|
|
319
|
-
const dh = norm(sub(Tt, Mt));
|
|
320
|
-
ellY({ tag: 'paw', bone: 'hpaw' + S, group: h, c: add(add(Mt, mul(dh, 0.02)), [0, -0.006, 0]), ydir: dh, lateral: lat, r: [0.027, 0.037, 0.018], k: 0.014 });
|
|
321
|
-
m.sphere({ tag: 'pad', bone: 'hpaw' + S, group: h, c: add(Mt, [0, -0.025, 0.01]), rad: 0.012, k: 0.01 });
|
|
322
|
-
for (let i = 0; i < 4; i++) m.sphere({ tag: 'toe', bone: 'hpaw' + S, group: h, c: [Tt[0] + toeX[i] * 0.92 * s, 0.0115, Tt[2] - 0.009 + toeZ[i]], rad: 0.0105, k: 0.007 });
|
|
323
|
-
for (let i = 0; i < 4; i++) m.cone({ tag: 'claw', bone: 'hpaw' + S, group: h, a: [Tt[0] + toeX[i] * 0.88 * s, 0.01, Tt[2] + toeZ[i]], b: [Tt[0] + toeX[i] * 0.88 * s, 0.004, Tt[2] + 0.01 + toeZ[i]], ra: 0.003, rb: 0.0011, k: 0.002 });
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// ---------------------------------------------------------------- TAIL
|
|
327
|
-
// the brush: a dense, round tail thickest at a third of its length, not tapering to a point
|
|
328
|
-
// (the long guard hair is carried partly by this volume, partly by the shells)
|
|
329
|
-
const tb = params.tailBrush ?? 1;
|
|
330
|
-
// spindle: narrow root, fullest at 50-60 % of the length, tapering to the tip
|
|
331
|
-
// (the base mesh carries the brush at coarse tiers; it tapers to a point: the tip hair is the longest)
|
|
332
|
-
const tailR = (t) => tb * (t < 0.15 ? 0.026 + 0.004 * (t / 0.15) : t < 0.55 ? 0.03 + 0.026 * smoothstep(0.15, 0.55, t) : 0.056 - 0.043 * Math.pow((t - 0.55) / 0.45, 1.6));
|
|
333
|
-
m.cone({ tag: 'tailroot', bone: 'tail0', a: [0, 0.645, -0.285], b: J.tail1, ra: 0.032, rb: tailR(0.1), k: 0.04 });
|
|
334
|
-
for (let i = 0; i < TAIL_SEGS; i++) {
|
|
335
|
-
m.cone({ tag: 'tail', bone: 'tail' + i, a: J['tail' + i], b: J['tail' + (i + 1)], ra: tailR(i / TAIL_SEGS), rb: tailR((i + 1) / TAIL_SEGS), k: 0.012, thin: i >= TAIL_SEGS - 1 });
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return m;
|
|
339
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// Web Worker entry: builds one individual (or one meshing job of it) off the main thread.
|
|
2
|
-
// Messages: { task: 'mesh', species, opts, job } -> { type: 'mesh', parts }
|
|
3
|
-
// { task: 'finish', species, opts, jobs } -> { type: 'done', data }
|
|
4
|
-
// { task: 'all', species, opts } -> { type: 'done', data }
|
|
5
|
-
import { loadSpecies } from './registry.js';
|
|
6
|
-
import { prepare, meshJob, finish, buildSync, transferables } from './core/build/pipeline.js';
|
|
7
|
-
import { regionTransferables } from './core/build/mesh.js';
|
|
8
|
-
|
|
9
|
-
self.onmessage = async (e) => {
|
|
10
|
-
const m = e.data || {};
|
|
11
|
-
try {
|
|
12
|
-
const species = await loadSpecies(m.species);
|
|
13
|
-
const t0 = performance.now();
|
|
14
|
-
const progress = (msg) => self.postMessage({ type: 'progress', msg, t: performance.now() - t0 });
|
|
15
|
-
if (m.task === 'mesh') {
|
|
16
|
-
const parts = meshJob(species, m.opts, m.job);
|
|
17
|
-
self.postMessage({ type: 'mesh', job: m.job, parts }, regionTransferables(parts));
|
|
18
|
-
} else if (m.task === 'finish') {
|
|
19
|
-
const prep = prepare(species, m.opts);
|
|
20
|
-
const out = finish(species, m.opts, m.jobs, prep, progress);
|
|
21
|
-
self.postMessage({ type: 'done', data: out }, transferables(out));
|
|
22
|
-
} else {
|
|
23
|
-
const out = buildSync(species, m.opts, progress);
|
|
24
|
-
self.postMessage({ type: 'done', data: out }, transferables(out));
|
|
25
|
-
}
|
|
26
|
-
} catch (err) {
|
|
27
|
-
self.postMessage({ type: 'error', message: String((err && err.stack) || err) });
|
|
28
|
-
}
|
|
29
|
-
};
|