@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,341 +0,0 @@
|
|
|
1
|
-
// The brown rat's coat: coarse agouti fur (grey base, buff band, black tip; long sparse dark guard
|
|
2
|
-
// hairs on the back), countershaded to a grey-buff belly with a fairly sharp flank line; short sleek
|
|
3
|
-
// fur on the face; nearly bare pink-brown ears (skin with a haze of fine hair); pink feet (bare skin,
|
|
4
|
-
// sparse pale hair on top, keratin claws); the long tail as ring scales (material 6 scutes across the
|
|
5
|
-
// tail axis), dark above, paler below; pink nose leather; yellow-orange incisors.
|
|
6
|
-
// Colour variants: agouti (wild), dark (urban melanic), albino (white, pink skin), hooded (black hood
|
|
7
|
-
// over head and shoulders plus a dorsal stripe on white, grown as a pattern SDF on the surface).
|
|
8
|
-
// Works in the reference space of rig.js; colours sampled from the reference photos.
|
|
9
|
-
import { HEAD_O, HK } from './rig.js';
|
|
10
|
-
import { neckS } from './regions.js';
|
|
11
|
-
import { SDFModel } from '../../core/sdf/sdf.js';
|
|
12
|
-
import { norm, sub, dot, cross, len, add, mul, smoothstep, clamp, mix, fbm3 } from '../../core/math/vec.js';
|
|
13
|
-
import { srgb, mix3, MAT } from '../../core/build/coatKit.js';
|
|
14
|
-
|
|
15
|
-
// palette per colour variant (sRGB hex, literature + photo samples)
|
|
16
|
-
const PALETTES = {
|
|
17
|
-
agouti: {
|
|
18
|
-
back: 0x615446, flank: 0x5a4f45, low: 0x756b61, belly: 0xa39a8c, head: 0x605244, cheek: 0x6b5e50,
|
|
19
|
-
muzzle: 0x716558, earSkin: 0xa07c6e, earIn: 0xb88c80, feet: 0xcfaea2, tailTop: 0x4a3e38, tailUnder: 0x7e6e66,
|
|
20
|
-
nose: 0xb9868a, claw: 0xd8c8b4, agouti: 0.95, undercoat: 0.55,
|
|
21
|
-
},
|
|
22
|
-
dark: {
|
|
23
|
-
back: 0x3e3833, flank: 0x3a3430, low: 0x4a433d, belly: 0x7a746c, head: 0x3c3632, cheek: 0x423b36,
|
|
24
|
-
muzzle: 0x4a423c, earSkin: 0x6e5a56, earIn: 0x86706a, feet: 0xb89a92, tailTop: 0x36302c, tailUnder: 0x5a504a,
|
|
25
|
-
nose: 0x9a7276, claw: 0xc8b8a8, agouti: 0.45, undercoat: 0.35,
|
|
26
|
-
},
|
|
27
|
-
albino: {
|
|
28
|
-
back: 0xf0ece4, flank: 0xf2eee6, low: 0xf2eee8, belly: 0xf5f2ec, head: 0xf2eee6, cheek: 0xf4f0ea,
|
|
29
|
-
muzzle: 0xf4efe8, earSkin: 0xe8b9b0, earIn: 0xeab4ac, feet: 0xebbfb6, tailTop: 0xe4b8ae, tailUnder: 0xe8c2b8,
|
|
30
|
-
nose: 0xeaafaf, claw: 0xf0e6dc, agouti: 0.0, undercoat: 0.1,
|
|
31
|
-
},
|
|
32
|
-
hooded: {
|
|
33
|
-
// base white; the hood / stripe colour is the pattern colour
|
|
34
|
-
back: 0xf0ede6, flank: 0xf0ede6, low: 0xf2efe8, belly: 0xf2efe8, head: 0xf0ede6, cheek: 0xf0ede6,
|
|
35
|
-
muzzle: 0xf2eee8, earSkin: 0xa88480, earIn: 0xc49a94, feet: 0xebbfb6, tailTop: 0x8a7872, tailUnder: 0xd8b4aa,
|
|
36
|
-
nose: 0xd89a9a, claw: 0xf0e6dc, agouti: 0.0, undercoat: 0.15,
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
const HOOD = 0x221e1e;
|
|
40
|
-
|
|
41
|
-
function coatColours(p) {
|
|
42
|
-
const base = PALETTES[p.colour] || PALETTES.agouti;
|
|
43
|
-
const k = p.coatWarmth || 0, l = p.coatLightness || 0;
|
|
44
|
-
const fixed = ['belly', 'earSkin', 'earIn', 'feet', 'nose', 'claw', 'tailUnder'];
|
|
45
|
-
const tweak = (h) => { const c = srgb(h); return [c[0] * (1 + 0.12 * k + l), c[1] * (1 + 0.03 * k + l), c[2] * (1 - 0.12 * k + l)]; };
|
|
46
|
-
const C = {};
|
|
47
|
-
for (const [key, v] of Object.entries(base)) {
|
|
48
|
-
if (key === 'agouti' || key === 'undercoat') C[key] = v;
|
|
49
|
-
else C[key] = p.colour === 'albino' || p.colour === 'hooded' || fixed.includes(key) ? srgb(v) : tweak(v);
|
|
50
|
-
}
|
|
51
|
-
// juveniles: softer, greyer (less rufous) fur
|
|
52
|
-
if (p.juv && p.colour !== 'albino' && p.colour !== 'hooded') for (const key of ['back', 'flank', 'low', 'head', 'cheek']) { const c = C[key], g = (c[0] + c[1] + c[2]) / 3; C[key] = mix3(c, [g, g, g * 1.03], 0.35); }
|
|
53
|
-
return C;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function ratCoat(ctx) {
|
|
57
|
-
const { model, rig, pos, nrm, regionOf: partOf, regionNames, weights, nV, params } = ctx;
|
|
58
|
-
const { BONES, AXIAL } = rig;
|
|
59
|
-
const COL = coatColours(params);
|
|
60
|
-
const { dominant, axialS, skinIndex, skinWeight, limbMember } = weights;
|
|
61
|
-
const AX = weights.axialLengths;
|
|
62
|
-
const P = (v) => [pos[v * 3], pos[v * 3 + 1], pos[v * 3 + 2]];
|
|
63
|
-
const N = (v) => [nrm[v * 3], nrm[v * 3 + 1], nrm[v * 3 + 2]];
|
|
64
|
-
const sOcc = AX[1], sNeckBase = AX[3], sTailBase = AX[8];
|
|
65
|
-
const isLimb = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw|femur|tibia|metatarsus|hpaw)/.test(b.name));
|
|
66
|
-
const isFoot = BONES.map((b) => /^(fpaw|hpaw|metacarpus|metatarsus)/.test(b.name));
|
|
67
|
-
const eyePrims = model.prims.filter((p) => p.tag === 'eyesocket');
|
|
68
|
-
const nosePrim = model.prims.find((p) => p.tag === 'nose');
|
|
69
|
-
const cleftPrim = model.prims.find((p) => p.tag === 'lipcleft');
|
|
70
|
-
const earPrims = model.prims.filter((p) => p.tag === 'ear');
|
|
71
|
-
const clawPrims = model.prims.filter((p) => p.tag === 'claw');
|
|
72
|
-
const jawPrims = model.forPart('jaw');
|
|
73
|
-
const headPrims = model.forPart('body').filter((p) => (p.bone === 'head' || p.bone === 'snout') && !p.carve);
|
|
74
|
-
const hooded = params.colour === 'hooded';
|
|
75
|
-
const albino = params.colour === 'albino';
|
|
76
|
-
const teethPart = regionNames.map((n) => n === 'uteeth' || n === 'lteeth');
|
|
77
|
-
const jawPart = regionNames.map((n) => n === 'jaw');
|
|
78
|
-
const headPart = regionNames.map((n) => n === 'head');
|
|
79
|
-
|
|
80
|
-
const region = new Uint8Array(nV); // 0 torso, 1 neck, 2 head, 3 teeth, 4 tail, 5 ear, 6 jaw, 7 snout
|
|
81
|
-
const legness = new Float32Array(nV);
|
|
82
|
-
const legBone = new Int16Array(nV).fill(-1);
|
|
83
|
-
for (let v = 0; v < nV; v++) {
|
|
84
|
-
const bn = BONES[dominant[v]].name;
|
|
85
|
-
const p = P(v);
|
|
86
|
-
let lb = -1, lw = 0;
|
|
87
|
-
for (let k = 0; k < 4; k++) {
|
|
88
|
-
const b = skinIndex[v * 4 + k], w = skinWeight[v * 4 + k];
|
|
89
|
-
if (isLimb[b] && w > lw) { lw = w; lb = b; }
|
|
90
|
-
}
|
|
91
|
-
legBone[v] = lb;
|
|
92
|
-
legness[v] = lb >= 0 ? smoothstep(0.15, 0.85, limbMember[v]) : 0;
|
|
93
|
-
if (teethPart[partOf[v]]) region[v] = 3;
|
|
94
|
-
else if (jawPart[partOf[v]]) region[v] = 6;
|
|
95
|
-
else if (bn.startsWith('ear')) region[v] = 5;
|
|
96
|
-
else if (bn === 'snout') region[v] = 7;
|
|
97
|
-
else if (axialS[v] > sTailBase + 0.003 && bn.startsWith('tail')) region[v] = 4;
|
|
98
|
-
else if (axialS[v] < sOcc + 0.002 || (headPart[partOf[v]] && neckS(p[0], p[1], p[2]) > 0.006)) region[v] = 2;
|
|
99
|
-
else if (axialS[v] < sNeckBase) region[v] = 1;
|
|
100
|
-
else region[v] = 0;
|
|
101
|
-
if (region[v] === 2 || region[v] >= 3) legness[v] = 0;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// hooded pattern: signed distance (m, < 0 = coloured) of the hood (head, neck, shoulders and chest
|
|
105
|
-
// down to the elbows) and the dorsal stripe to the tail root
|
|
106
|
-
const hoodSDF = (p, n, r, v) => {
|
|
107
|
-
if (r === 2 || r === 5 || r === 6 || r === 7) {
|
|
108
|
-
// an optional blaze: a white wedge up the face from the nose (the berkshire / blazed fancy)
|
|
109
|
-
if (params.blaze) {
|
|
110
|
-
const h = mul(sub(p, HEAD_O), 1 / HK);
|
|
111
|
-
const b = Math.abs(h[0]) - (0.0012 + 0.16 * Math.max(0, h[2] + 0.012)) * params.blaze;
|
|
112
|
-
if (h[1] > -0.02) return clamp(-b, -0.004, 0.004) * (h[2] > -0.014 ? 1 : -1) - (h[2] > -0.014 ? 0 : 0.004);
|
|
113
|
-
}
|
|
114
|
-
return -0.006;
|
|
115
|
-
}
|
|
116
|
-
if (r === 4) return 0.006;
|
|
117
|
-
// hood: behind the ears to the shoulders, slanting back over the withers
|
|
118
|
-
const zc = 0.004 + 0.3 * (p[1] - 0.04) + 0.0012 * Math.sin(p[0] * 700);
|
|
119
|
-
let d = zc - p[2];
|
|
120
|
-
// the forelegs below the elbow stay white
|
|
121
|
-
if (legness[v] > 0.5 && legBone[v] >= 0 && /radius|metacarpus|fpaw/.test(BONES[legBone[v]].name)) d = Math.max(d, 0.003);
|
|
122
|
-
// the belly behind the chest stays white
|
|
123
|
-
if (n[1] < -0.3) d = Math.max(d, -0.002 + (0.03 - p[1]) * 0.4);
|
|
124
|
-
// dorsal stripe: ~16 mm wide down the back to the tail root, a little ragged
|
|
125
|
-
const w = 0.0085 * (1 + 0.15 * Math.sin(p[2] * 180)) * smoothstep(-0.095, -0.075, p[2]) + 0.002;
|
|
126
|
-
const up = smoothstep(0.1, 0.5, n[1]);
|
|
127
|
-
const stripe = up > 0 ? Math.abs(p[0]) - w * up : 0.01;
|
|
128
|
-
d = Math.min(d, stripe);
|
|
129
|
-
return clamp(d, -0.006, 0.006);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const comb = new Float32Array(nV * 3);
|
|
133
|
-
const tint = new Float32Array(nV * 4);
|
|
134
|
-
const furLen = new Float32Array(nV);
|
|
135
|
-
const markSDF = new Float32Array(nV).fill(1);
|
|
136
|
-
const pattern = new Float32Array(nV).fill(1);
|
|
137
|
-
const patternColor = new Float32Array(nV * 4);
|
|
138
|
-
const surf = new Float32Array(nV * 4);
|
|
139
|
-
const hoodC = srgb(params.hoodColour || HOOD);
|
|
140
|
-
const tooth = srgb(0xd4a050), toothTip = srgb(0xeed8a8);
|
|
141
|
-
const juvK = params.juv ? 0.75 : 1;
|
|
142
|
-
|
|
143
|
-
for (let v = 0; v < nV; v++) {
|
|
144
|
-
const p = P(v), n = N(v), r = region[v];
|
|
145
|
-
const h = mul(sub(p, HEAD_O), 1 / HK);
|
|
146
|
-
const bone = BONES[dominant[v]];
|
|
147
|
-
const L = legness[v];
|
|
148
|
-
let col, fl, mat = MAT.FUR, mark = 1, ag = COL.agouti, uc = COL.undercoat, gloss = 0, feat = 0, sz = 0;
|
|
149
|
-
|
|
150
|
-
// ---- comb
|
|
151
|
-
let d;
|
|
152
|
-
if (r === 5) d = norm(sub(bone.tail, bone.head));
|
|
153
|
-
else if (r === 2 || r === 6 || r === 7 || r === 3) d = norm(add(norm(sub(h, [0, -0.008, 0.026])), [0, -0.1, -0.5]));
|
|
154
|
-
else if (r === 4) d = norm(sub(bone.tail, bone.head));
|
|
155
|
-
else {
|
|
156
|
-
const seg = weights.segT[v * 2] | 0;
|
|
157
|
-
const a = AXIAL.points[seg], b = AXIAL.points[Math.min(seg + 1, AXIAL.points.length - 1)];
|
|
158
|
-
d = norm(add(norm(sub(b, a)), [0, -0.5 * Math.abs(n[0]), 0]));
|
|
159
|
-
if (L > 0 && legBone[v] >= 0) {
|
|
160
|
-
const lbn = BONES[legBone[v]];
|
|
161
|
-
let dl = norm(sub(lbn.tail, lbn.head));
|
|
162
|
-
if (isFoot[legBone[v]]) dl = norm(add(dl, [0, 0, 0.4]));
|
|
163
|
-
else dl = norm(add(dl, [0, -0.3, -0.2]));
|
|
164
|
-
d = norm(add(mul(d, 1 - L), mul(dl, L)));
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
let t = sub(d, mul(n, dot(d, n)));
|
|
168
|
-
if (len(t) < 1e-4) t = cross(n, [1, 0, 0]);
|
|
169
|
-
t = norm(t);
|
|
170
|
-
comb[v * 3] = t[0]; comb[v * 3 + 1] = t[1]; comb[v * 3 + 2] = t[2];
|
|
171
|
-
|
|
172
|
-
// ---- colour, fur length, marks
|
|
173
|
-
if (r === 3) {
|
|
174
|
-
// incisors: orange-yellow enamel on the front face, paler toward the chisel tip
|
|
175
|
-
mat = MAT.KERATIN; fl = 0; gloss = 0.8;
|
|
176
|
-
const tipK = partOf[v] >= 0 && regionNames[partOf[v]] === 'uteeth' ? smoothstep(-0.016, -0.019, h[1]) : smoothstep(-0.019, -0.0165, h[1]);
|
|
177
|
-
col = albino ? mix3(tooth, toothTip, 0.5) : mix3(tooth, toothTip, tipK * 0.6);
|
|
178
|
-
} else if (r === 0 || r === 1) {
|
|
179
|
-
const up = clamp(n[1], -1, 1);
|
|
180
|
-
col = mix3(COL.low, COL.flank, smoothstep(-0.35, 0.2, up));
|
|
181
|
-
col = mix3(col, COL.back, smoothstep(0.25, 0.85, up));
|
|
182
|
-
// belly: grey-buff, a fairly sharp flank line (blended by normal and height)
|
|
183
|
-
const ventral = smoothstep(-0.2, -0.55, n[1]) * smoothstep(0.045, 0.02, p[1]);
|
|
184
|
-
const chest = smoothstep(0.0, 0.03, p[2]) * smoothstep(0.2, 0.6, n[2]) * smoothstep(0.045, 0.02, p[1]);
|
|
185
|
-
col = mix3(col, COL.belly, clamp(Math.max(ventral, chest * 0.8, smoothstep(0.4, 0.8, -n[1])), 0, 1));
|
|
186
|
-
// coarse coat: long dorsal guard hairs, shorter on the flanks, dense short belly fur
|
|
187
|
-
fl = mix(0.0068, 0.0095, smoothstep(-0.4, 0.3, n[1]));
|
|
188
|
-
fl = Math.max(fl, 0.0115 * smoothstep(0.5, 0.95, n[1]) * smoothstep(0.02, -0.02, p[2]) + 0.0098 * smoothstep(0.5, 0.95, n[1]) * smoothstep(-0.02, 0.02, p[2])); // longest over the loins
|
|
189
|
-
fl = mix(fl, 0.0055, smoothstep(-0.3, -0.8, n[1]));
|
|
190
|
-
ag *= 1 - smoothstep(0.1, 0.6, -n[1]);
|
|
191
|
-
if (L > 0) {
|
|
192
|
-
const lb = legBone[v] >= 0 ? BONES[legBone[v]].name : '';
|
|
193
|
-
let lc = mix3(COL.flank, COL.belly, smoothstep(0.0, -0.8, n[0] * Math.sign(p[0] || 1)) * 0.6), lf = mix(0.003, 0.006, smoothstep(0.01, 0.04, p[1]));
|
|
194
|
-
if (isFoot[legBone[v]] && p[1] < 0.013) {
|
|
195
|
-
// pink feet: bare skin, sparse short pale hair on the top of the foot
|
|
196
|
-
lc = COL.feet; lf = 0; mat = MAT.SKIN; gloss = 0.25;
|
|
197
|
-
} else if (/radius|tibia/.test(lb)) {
|
|
198
|
-
// lower legs: short fur, pinkish skin showing near the wrist and the heel
|
|
199
|
-
const sk = smoothstep(0.016, 0.006, p[1]);
|
|
200
|
-
lc = mix3(mix3(COL.flank, COL.belly, 0.35), COL.feet, sk * 0.6); lf = mix(0.0035, 0.0016, sk);
|
|
201
|
-
}
|
|
202
|
-
if (/femur/.test(lb)) { lc = mix3(col, lc, smoothstep(0.035, 0.015, p[1])); lf = mix(fl, lf, 0.4); }
|
|
203
|
-
col = mix3(col, lc, L);
|
|
204
|
-
fl = mix(fl, lf, L);
|
|
205
|
-
if (mat === MAT.SKIN) { col = COL.feet; fl = lf; }
|
|
206
|
-
ag *= 1 - 0.8 * L * (/radius|tibia|metacarpus|fpaw|metatarsus|hpaw/.test(lb) ? 1 : 0);
|
|
207
|
-
// claws: pale keratin
|
|
208
|
-
for (const c of clawPrims) if (SDFModel.dist(c, p[0], p[1], p[2]) < 0.00025) { mat = MAT.KERATIN; col = COL.claw; fl = 0; gloss = 0.7; }
|
|
209
|
-
// soles: the bare pads, a little darker and glossier
|
|
210
|
-
if (mat === MAT.SKIN && n[1] < -0.5) { col = mix3(col, [col[0] * 0.85, col[1] * 0.78, col[2] * 0.78], 0.6); fl = 0; gloss = 0.4; }
|
|
211
|
-
}
|
|
212
|
-
// the anus / scrotum region: short sparse hair
|
|
213
|
-
if (p[2] < -0.078 && p[1] < 0.045 && n[2] < -0.3) fl = Math.min(fl, 0.004);
|
|
214
|
-
} else if (r === 4) {
|
|
215
|
-
// tail: ring scales (scutes across the tail axis, ~1 mm), dark above, paler below, a little
|
|
216
|
-
// paler toward the tip; sparse short bristles are the scute relief
|
|
217
|
-
const bb = BONES[dominant[v]];
|
|
218
|
-
const ax = norm(sub(bb.tail, bb.head));
|
|
219
|
-
const dorsal = norm(cross([1, 0, 0], ax));
|
|
220
|
-
const top = dot(n, dorsal);
|
|
221
|
-
const along = clamp((axialS[v] - sTailBase) / Math.max(1e-4, AX[AX.length - 1] - sTailBase), 0, 1);
|
|
222
|
-
col = mix3(COL.tailUnder, COL.tailTop, smoothstep(-0.45, 0.35, top));
|
|
223
|
-
col = mix3(col, COL.tailUnder, 0.25 * along);
|
|
224
|
-
mat = MAT.SCALES; fl = 0; gloss = 0.3;
|
|
225
|
-
sz = 0.00095 * (1 - 0.35 * along) * juvK;
|
|
226
|
-
feat = -1; // scutes: rings across the comb
|
|
227
|
-
// the fur of the rump runs a little way onto the tail root
|
|
228
|
-
if (axialS[v] < sTailBase + 0.009) { mat = MAT.FUR; col = mix3(COL.flank, COL.tailTop, 0.4); fl = 0.004; sz = 0; feat = 0; }
|
|
229
|
-
} else if (r === 5) {
|
|
230
|
-
// ears: thin, nearly bare skin (fine short hair haze), pinker in the cup, a darker rim
|
|
231
|
-
const side = p[0] >= 0 ? 0 : 1;
|
|
232
|
-
const ep = earPrims[side];
|
|
233
|
-
const face = [ep.P[9], ep.P[10], ep.P[11]];
|
|
234
|
-
const upE = [ep.P[6], ep.P[7], ep.P[8]], latE = [ep.P[3], ep.P[4], ep.P[5]];
|
|
235
|
-
const c = [ep.P[0], ep.P[1], ep.P[2]];
|
|
236
|
-
const q = sub(p, c);
|
|
237
|
-
const along = dot(q, upE) / ep.P[13], across = dot(q, latE) / ep.P[12];
|
|
238
|
-
const rim = 1 - Math.hypot(along, across);
|
|
239
|
-
const inner = smoothstep(0.0, 0.4, dot(n, face)) * smoothstep(0.02, 0.12, rim);
|
|
240
|
-
col = mix3(COL.earSkin, COL.earIn, inner);
|
|
241
|
-
mat = MAT.FUR; gloss = 0;
|
|
242
|
-
fl = 0.0004;
|
|
243
|
-
// the ear root is furred like the head
|
|
244
|
-
const root = smoothstep(-0.2, -0.75, along);
|
|
245
|
-
if (root > 0) { col = mix3(col, COL.head, root); fl = mix(fl, 0.003, root); }
|
|
246
|
-
ag = 0; uc = 0.6;
|
|
247
|
-
} else {
|
|
248
|
-
// head, snout and jaw: short sleek fur, paler on the lips and chin
|
|
249
|
-
col = COL.head;
|
|
250
|
-
const g3 = (cc, rr) => Math.exp(-(((Math.abs(h[0]) - cc[0]) / rr[0]) ** 2 + ((h[1] - cc[1]) / rr[1]) ** 2 + ((h[2] - cc[2]) / rr[2]) ** 2));
|
|
251
|
-
col = mix3(col, COL.cheek, g3([0.009, -0.01, -0.006], [0.005, 0.006, 0.01]));
|
|
252
|
-
col = mix3(col, COL.muzzle, smoothstep(0.004, 0.018, h[2]) * 0.8);
|
|
253
|
-
const chinW = r === 6 ? 0.7 : smoothstep(-0.015, -0.019, h[1]) * smoothstep(-0.2, -0.7, n[1]);
|
|
254
|
-
col = mix3(col, COL.belly, clamp(chinW, 0, 1) * 0.8);
|
|
255
|
-
fl = mix(0.0045, 0.0018, smoothstep(-0.01, 0.02, h[2]));
|
|
256
|
-
if (Math.abs(h[0]) > 0.008 && h[1] < -0.004 && h[2] < 0.004) fl = Math.max(fl, 0.0048); // cheek fur
|
|
257
|
-
if (h[2] < -0.02) fl = mix(fl, 0.0068, smoothstep(-0.02, -0.03, h[2])); // nape
|
|
258
|
-
ag *= 0.75;
|
|
259
|
-
// eye rims: dark bare lid margin
|
|
260
|
-
for (const e of eyePrims) {
|
|
261
|
-
const de = SDFModel.dist(e, p[0], p[1], p[2]);
|
|
262
|
-
if (Math.abs(de) < 0.0008) mark = Math.min(mark, Math.abs(de) - 0.0003);
|
|
263
|
-
if (Math.abs(de) < 0.0003) { mat = MAT.DARK_SKIN; fl = 0; }
|
|
264
|
-
else fl = Math.min(fl, mix(0.0004, fl, smoothstep(0.0009, 0.0045, Math.abs(de))));
|
|
265
|
-
}
|
|
266
|
-
// nose leather (pink rhinarium) and the split upper lip
|
|
267
|
-
if (nosePrim && SDFModel.dist(nosePrim, p[0], p[1], p[2]) < 0.00035 && h[2] > 0.0205 && h[1] > -0.0145) { mat = MAT.SKIN; col = COL.nose; fl = 0; gloss = 0.65; }
|
|
268
|
-
if (cleftPrim) {
|
|
269
|
-
const dc = SDFModel.dist(cleftPrim, p[0], p[1], p[2]);
|
|
270
|
-
if (dc < 0.0005) { mark = Math.min(mark, dc - 0.0003); fl = Math.min(fl, 0.0004); }
|
|
271
|
-
}
|
|
272
|
-
if (r === 7) fl = Math.min(fl, 0.0022); // whisker pads: short dense fur
|
|
273
|
-
// lips / mouth lining: head vertices touching the jaw surface, jaw vertices inside the head
|
|
274
|
-
if (partOf[v] >= 0 && !jawPart[partOf[v]]) {
|
|
275
|
-
const dj = SDFModel.evalList(jawPrims, p[0], p[1], p[2]);
|
|
276
|
-
if (dj < 0.00025) { mat = MAT.MOUTH; col = [0.3, 0.12, 0.12]; fl = 0; }
|
|
277
|
-
} else {
|
|
278
|
-
const dh = SDFModel.evalList(headPrims, p[0], p[1], p[2]);
|
|
279
|
-
if (dh < 0.0) { mat = MAT.MOUTH; col = [0.3, 0.12, 0.12]; fl = 0; }
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (params.juv && mat === MAT.FUR) fl *= 0.8;
|
|
283
|
-
|
|
284
|
-
// ---- hooded: hood and dorsal stripe (pattern SDF, crisp but hair-ragged edges)
|
|
285
|
-
if (hooded && (mat === MAT.FUR || mat === MAT.DARK_SKIN)) pattern[v] = hoodSDF(p, n, r, v);
|
|
286
|
-
|
|
287
|
-
// low-frequency colour variation
|
|
288
|
-
const cv = fbm3(p[0] * 90, p[1] * 90, p[2] * 90, 3) - 0.5;
|
|
289
|
-
if (mat === MAT.FUR) col = [col[0] * (1 + 0.16 * cv), col[1] * (1 + 0.13 * cv), col[2] * (1 + 0.1 * cv)];
|
|
290
|
-
|
|
291
|
-
tint[v * 4] = col[0]; tint[v * 4 + 1] = col[1]; tint[v * 4 + 2] = col[2]; tint[v * 4 + 3] = mat;
|
|
292
|
-
furLen[v] = mat === MAT.FUR || mat === MAT.SKIN ? fl : 0;
|
|
293
|
-
markSDF[v] = mark;
|
|
294
|
-
patternColor[v * 4] = hoodC[0]; patternColor[v * 4 + 1] = hoodC[1]; patternColor[v * 4 + 2] = hoodC[2]; patternColor[v * 4 + 3] = hooded ? 1 : 0;
|
|
295
|
-
if (mat === MAT.SCALES) { surf[v * 4] = gloss; surf[v * 4 + 1] = sz; surf[v * 4 + 2] = feat; surf[v * 4 + 3] = -0.4; }
|
|
296
|
-
else { surf[v * 4] = gloss; surf[v * 4 + 1] = 0; surf[v * 4 + 2] = mat === MAT.FUR ? clamp(ag, 0, 1) : 0; surf[v * 4 + 3] = mat === MAT.FUR ? uc : 0; }
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// smooth fur length, agouti banding and colour across the fur so region boundaries (head / neck,
|
|
300
|
-
// body / legs) never show as a line in the coat
|
|
301
|
-
const nb = weights.neighbors;
|
|
302
|
-
const tmp = new Float32Array(nV), tmpA = new Float32Array(nV), tmpC = new Float32Array(nV * 3);
|
|
303
|
-
for (let it = 0; it < 8; it++) {
|
|
304
|
-
for (let v = 0; v < nV; v++) {
|
|
305
|
-
const ns = nb[v];
|
|
306
|
-
tmp[v] = furLen[v]; tmpA[v] = surf[v * 4 + 2];
|
|
307
|
-
tmpC[v * 3] = tint[v * 4]; tmpC[v * 3 + 1] = tint[v * 4 + 1]; tmpC[v * 3 + 2] = tint[v * 4 + 2];
|
|
308
|
-
if (!ns || !ns.length || tint[v * 4 + 3] !== MAT.FUR) continue;
|
|
309
|
-
let a = 0, g = 0, n = 0, c0 = 0, c1 = 0, c2 = 0;
|
|
310
|
-
for (const q of ns) {
|
|
311
|
-
if (tint[q * 4 + 3] !== MAT.FUR) continue;
|
|
312
|
-
a += furLen[q]; g += surf[q * 4 + 2]; c0 += tint[q * 4]; c1 += tint[q * 4 + 1]; c2 += tint[q * 4 + 2]; n++;
|
|
313
|
-
}
|
|
314
|
-
if (!n) continue;
|
|
315
|
-
tmp[v] = 0.5 * furLen[v] + (0.5 * a) / n;
|
|
316
|
-
tmpA[v] = 0.5 * surf[v * 4 + 2] + (0.5 * g) / n;
|
|
317
|
-
if (it < 3) { tmpC[v * 3] = 0.5 * tint[v * 4] + 0.5 * c0 / n; tmpC[v * 3 + 1] = 0.5 * tint[v * 4 + 1] + 0.5 * c1 / n; tmpC[v * 3 + 2] = 0.5 * tint[v * 4 + 2] + 0.5 * c2 / n; }
|
|
318
|
-
}
|
|
319
|
-
furLen.set(tmp);
|
|
320
|
-
for (let v = 0; v < nV; v++) { surf[v * 4 + 2] = tmpA[v]; tint[v * 4] = tmpC[v * 3]; tint[v * 4 + 1] = tmpC[v * 3 + 1]; tint[v * 4 + 2] = tmpC[v * 3 + 2]; }
|
|
321
|
-
}
|
|
322
|
-
// smooth the hair flow (the axial segment directions change at the joints: no seams in the coat)
|
|
323
|
-
const cb = new Float32Array(nV * 3);
|
|
324
|
-
for (let it = 0; it < 6; it++) {
|
|
325
|
-
for (let v = 0; v < nV; v++) {
|
|
326
|
-
const ns = nb[v];
|
|
327
|
-
let x = comb[v * 3], y = comb[v * 3 + 1], z = comb[v * 3 + 2];
|
|
328
|
-
if (ns && ns.length && tint[v * 4 + 3] === MAT.FUR && region[v] !== 5) {
|
|
329
|
-
for (const q of ns) { if ((region[q] <= 1 ? 0 : region[q]) !== (region[v] <= 1 ? 0 : region[v])) continue; x += comb[q * 3]; y += comb[q * 3 + 1]; z += comb[q * 3 + 2]; }
|
|
330
|
-
const nx = nrm[v * 3], ny = nrm[v * 3 + 1], nz = nrm[v * 3 + 2];
|
|
331
|
-
const dn = x * nx + y * ny + z * nz;
|
|
332
|
-
x -= dn * nx; y -= dn * ny; z -= dn * nz;
|
|
333
|
-
const l = Math.hypot(x, y, z) || 1;
|
|
334
|
-
x /= l; y /= l; z /= l;
|
|
335
|
-
}
|
|
336
|
-
cb[v * 3] = x; cb[v * 3 + 1] = y; cb[v * 3 + 2] = z;
|
|
337
|
-
}
|
|
338
|
-
comb.set(cb);
|
|
339
|
-
}
|
|
340
|
-
return { comb, tint, pattern, mark: markSDF, furLen, patternColor, surf, region };
|
|
341
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
// Brown rat (Rattus norvegicus). A small plantigrade quadruped on the rabbit / bear templates: a
|
|
2
|
-
// hunched pear-shaped body, pointed snout with whiskers (real geometry) and yellow incisors, dark
|
|
3
|
-
// bulging eyes, thin rounded ears, pink hands and feet with separate toes, and a long scaly tail.
|
|
4
|
-
// Colours are variants (createAnimal('rat', { variant: 'hooded' })): 'wild' (default: agouti, ~15 %
|
|
5
|
-
// of seeds the dark urban form), 'agouti', 'dark', 'albino' (white, pink skin, red eyes), 'hooded'
|
|
6
|
-
// (fancy: black hood and dorsal stripe on white, sometimes a blaze); pups with { age: 'juvenile' }.
|
|
7
|
-
import { ratRig, HEAD_O, hl } from './rig.js';
|
|
8
|
-
import { sculptRat, eyeOf } from './sculpt.js';
|
|
9
|
-
import { ratRegions } from './regions.js';
|
|
10
|
-
import { ratCoat } from './coat.js';
|
|
11
|
-
import { ratWhiskers } from './whiskers.js';
|
|
12
|
-
import { motion } from './motion.js';
|
|
13
|
-
import { rng } from '../../core/math/vec.js';
|
|
14
|
-
|
|
15
|
-
const VARIANTS = [
|
|
16
|
-
['wild', 'Wild brown rat'],
|
|
17
|
-
['agouti', 'Agouti'],
|
|
18
|
-
['dark', 'Dark (urban)'],
|
|
19
|
-
['albino', 'Albino (PEW)'],
|
|
20
|
-
['hooded', 'Hooded (fancy)'],
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
// Seeded individual. Size: males 350-500 g, females 250-350 g (length ~ mass^1/3 against the
|
|
24
|
-
// ~330 g reference); juveniles (~4-5 weeks, ~70 g): 0.6 x, big head, eyes, ears and feet, shorter
|
|
25
|
-
// tail. Proportions per seed: legs, body length, girth, head width, muzzle, ears, tail length.
|
|
26
|
-
function variation(R, o) {
|
|
27
|
-
const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
|
|
28
|
-
// the coat from its own hashed stream so consecutive seeds do not correlate
|
|
29
|
-
const M = rng(Math.imul((o.seed ?? 1) + 0x5bd1e995, 0x297a2d39) ^ 0x1b873593);
|
|
30
|
-
for (let i = 0; i < 3; i++) M();
|
|
31
|
-
let variant = o.variant && VARIANTS.some((v) => v[0] === o.variant) ? o.variant : 'wild';
|
|
32
|
-
const colour = variant === 'wild' ? (M() < 0.15 ? 'dark' : 'agouti') : variant;
|
|
33
|
-
const sex = o.sex || (R() < 0.5 ? 'male' : 'female');
|
|
34
|
-
const age = o.age || 'adult';
|
|
35
|
-
const juv = age === 'juvenile' ? 1 : 0;
|
|
36
|
-
const male = sex === 'male' ? 1 : 0;
|
|
37
|
-
const fancy = colour === 'albino' || colour === 'hooded';
|
|
38
|
-
const size = (male ? 1.07 : 0.965) * (1 + 0.045 * g()) * (juv ? 0.6 : 1);
|
|
39
|
-
const head = (male ? 1.03 : 0.99) * (1 + 0.025 * g()) * (juv ? 1.22 : 1);
|
|
40
|
-
const params = {
|
|
41
|
-
sex, age, size, variant, colour, juv,
|
|
42
|
-
tail: (1 + 0.05 * g()) * (juv ? 0.86 : 1),
|
|
43
|
-
tailThick: (1 + 0.06 * g()) * (male ? 1.05 : 1) * (juv ? 0.9 : 1),
|
|
44
|
-
ear: (1 + 0.06 * g()) * (juv ? 1.14 : 1) * (fancy ? 1.04 : 1),
|
|
45
|
-
earWidth: 1 + 0.05 * g(),
|
|
46
|
-
headWidth: (male ? 1.05 : 1) * (1 + 0.03 * g()),
|
|
47
|
-
muzzle: (1 + 0.04 * g()) * (juv ? 0.86 : 1) * (fancy ? 0.97 : 1),
|
|
48
|
-
whisker: (1 + 0.06 * g()) * (juv ? 0.8 : 1),
|
|
49
|
-
blaze: colour === 'hooded' && M() < 0.35 ? 0.7 + 0.5 * M() : 0,
|
|
50
|
-
coatWarmth: colour === 'agouti' ? 0.9 * g() : 0.3 * g(),
|
|
51
|
-
coatLightness: 0.09 * g(),
|
|
52
|
-
coatSeed: Math.floor(R() * 1e6),
|
|
53
|
-
minThick: 0.0005,
|
|
54
|
-
warps: [
|
|
55
|
-
{ type: 'legs', k: 1 + 0.035 * g() - 0.04 * juv, top: 0.03 },
|
|
56
|
-
{ type: 'length', k: 1 + 0.03 * g() - 0.07 * juv + 0.01 * male, z0: -0.07, z1: 0.03 },
|
|
57
|
-
{ type: 'girth', k: 1 + 0.06 * g() + 0.03 * male - 0.04 * juv + (fancy ? 0.02 : 0), cy: 0.05, z0: -0.085, z1: 0.04, fade: 0.012 },
|
|
58
|
-
{ type: 'scaleAbout', c: HEAD_O, k: head, r0: 0.016, r1: 0.034 },
|
|
59
|
-
// pups: big feet
|
|
60
|
-
...(juv ? [[0.019, 0.037], [-0.019, 0.037], [0.024, -0.028], [-0.024, -0.028]].map(([x, z]) => ({ type: 'scaleAbout', c: [x, 0.003, z], k: 1.15, r0: 0.006, r1: 0.014 })) : []),
|
|
61
|
-
],
|
|
62
|
-
};
|
|
63
|
-
return params;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export default {
|
|
67
|
-
id: 'rat',
|
|
68
|
-
name: 'Brown rat',
|
|
69
|
-
latin: 'Rattus norvegicus',
|
|
70
|
-
group: 'paws',
|
|
71
|
-
plan: 'quadruped',
|
|
72
|
-
covering: 'fur',
|
|
73
|
-
variants: VARIANTS.map(([id, name]) => ({ id, name, latin: 'Rattus norvegicus' })),
|
|
74
|
-
variation,
|
|
75
|
-
rig: (params) => ratRig(params),
|
|
76
|
-
sculpt: (m, rig, params) => sculptRat(m, rig, params),
|
|
77
|
-
regions: ratRegions,
|
|
78
|
-
coat: ratCoat,
|
|
79
|
-
surfaces: ratWhiskers,
|
|
80
|
-
eyeSpecs: (params) => [1, -1].map((side) => ({ side, spec: eyeOf(params), headOrigin: HEAD_O, bone: 'head', look: params.colour === 'albino' ? EYE_ALBINO : EYE_LOOK })),
|
|
81
|
-
motion,
|
|
82
|
-
render: (params = {}) => ({
|
|
83
|
-
markColor: params.colour === 'albino' ? [0.5, 0.25, 0.25] : [0.02, 0.015, 0.013],
|
|
84
|
-
strandDensity: 2600,
|
|
85
|
-
clumpDensity: 2.2,
|
|
86
|
-
shellScale: 1,
|
|
87
|
-
// (no silhouette fins: on this short coat their inset edge drew a dark line along the outline)
|
|
88
|
-
fins: false,
|
|
89
|
-
raiseLen: [0.004, 0.009],
|
|
90
|
-
}),
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// Wild type: a glossy near-black bead (very dark brown iris, the round pupil barely distinguishable)
|
|
94
|
-
export const EYE_LOOK = {
|
|
95
|
-
pupil: 'round',
|
|
96
|
-
lids: 'mammal',
|
|
97
|
-
iris: { inner: [0.006, 0.003, 0.0025], mid: [0.011, 0.006, 0.005], hi: [0.03, 0.017, 0.012], outer: [0.004, 0.0025, 0.002] },
|
|
98
|
-
sclera: { color: [0.01, 0.007, 0.006], visible: false },
|
|
99
|
-
lidColor: [0.03, 0.02, 0.018],
|
|
100
|
-
pupilSize: [0.55, 0.7],
|
|
101
|
-
};
|
|
102
|
-
// Albino: red (the fundus through an unpigmented iris), a pale pink tinge at the rim
|
|
103
|
-
export const EYE_ALBINO = {
|
|
104
|
-
pupil: 'round',
|
|
105
|
-
lids: 'mammal',
|
|
106
|
-
iris: { inner: [0.35, 0.02, 0.03], mid: [0.45, 0.04, 0.05], hi: [0.7, 0.3, 0.3], outer: [0.3, 0.05, 0.06] },
|
|
107
|
-
sclera: { color: [0.4, 0.1, 0.1], visible: false },
|
|
108
|
-
lidColor: [0.7, 0.42, 0.4],
|
|
109
|
-
pupilSize: [0.45, 0.6],
|
|
110
|
-
};
|
|
111
|
-
void hl;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// Brown rat motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
|
|
2
|
-
// Numbers are for the reference individual (params.size = 1, ~330 g, hip joint ~56 mm); the engine
|
|
3
|
-
// scales them by dynamic similarity for pups and big males.
|
|
4
|
-
//
|
|
5
|
-
// Gaits (overground runway data for intact rats, Górska et al. / Koopmans et al.;
|
|
6
|
-
// hindlimb kinematics, Sci. Rep. 2022): an exploratory walk (lateral-sequence "alternate" pattern,
|
|
7
|
-
// LF ~0.3 after LH, duty 0.64-0.75, 1.5-2.5 Hz), a fast walk (4 Hz, duty 0.52), the trot (4.5 Hz,
|
|
8
|
-
// duty 0.43, diagonal pairs), a transverse gallop (5.1 Hz), the half-bound (5.6 Hz: the hind feet
|
|
9
|
-
// land almost together, the forefeet staggered) and the bound (5.7 Hz, pairs synchronous), mean duty
|
|
10
|
-
// 0.40 when running; bursts to ~3 m/s. Offsets [FL, FR, HL, HR] relative to HL touchdown.
|
|
11
|
-
import { hooks } from './behaviour.js';
|
|
12
|
-
|
|
13
|
-
const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
|
|
14
|
-
const WALK = [0.3, 0.8, 0.0, 0.5];
|
|
15
|
-
const TROT = [0.5, 0.02, 0.0, 0.5];
|
|
16
|
-
const GALLOP = [0.46, 0.58, 0.0, 0.12];
|
|
17
|
-
const HALFB = [0.6, 0.48, 0.0, 0.06];
|
|
18
|
-
const BOUND = [0.5, 0.52, 0.0, 0.02];
|
|
19
|
-
|
|
20
|
-
export const motion = {
|
|
21
|
-
maxSpeed: 3.0,
|
|
22
|
-
accel: [7, 12],
|
|
23
|
-
decel: 6,
|
|
24
|
-
turnRate: 5,
|
|
25
|
-
latAccelMax: 6,
|
|
26
|
-
gears: { walk: 0.3, trot: 0.95, gallop: 1.25, halfbound: 1.45, bound: 1.75 },
|
|
27
|
-
gallopBlend: [1.1, 1.8],
|
|
28
|
-
flexBlend: [1.0, 1.7],
|
|
29
|
-
hooks,
|
|
30
|
-
gaits: [
|
|
31
|
-
G('walk', 0.0, 1.6, 0.74, WALK, { liftF: 0.006, liftH: 0.007, bobF: 0.0012, bobH: 0.0015, flex: 0.0, lat: 0.07, fold: 0.5, heel: 25, tail: 0, drop: 0 }),
|
|
32
|
-
G('walk', 0.3, 2.5, 0.64, WALK, { liftF: 0.007, liftH: 0.008, bobF: 0.0015, bobH: 0.002, flex: 0.0, lat: 0.08, fold: 0.55, heel: 35, tail: 0.1, drop: 0 }),
|
|
33
|
-
G('walk', 0.7, 4.0, 0.52, WALK, { liftF: 0.008, liftH: 0.009, bobF: 0.002, bobH: 0.0025, flex: 0.02, lat: 0.06, fold: 0.6, heel: 45, tail: 0.2, drop: 0.001 }),
|
|
34
|
-
G('trot', 0.9, 4.5, 0.43, TROT, { liftF: 0.009, liftH: 0.01, bobF: 0.0025, bobH: 0.003, flex: 0.03, lat: 0.03, fold: 0.7, heel: 55, tail: 0.3, drop: 0.002 }),
|
|
35
|
-
G('trot', 1.05, 4.6, 0.43, TROT, { liftF: 0.009, liftH: 0.01, bobF: 0.0025, bobH: 0.003, flex: 0.04, lat: 0.03, fold: 0.7, heel: 55, tail: 0.3, drop: 0.002 }),
|
|
36
|
-
G('gallop', 1.15, 5.0, 0.4, GALLOP, { liftF: 0.011, liftH: 0.012, bobF: 0.003, bobH: 0.004, flex: 0.14, lat: 0, fold: 0.8, heel: 60, tail: 0.5, drop: 0.003 }),
|
|
37
|
-
G('gallop', 1.3, 5.2, 0.39, GALLOP, { liftF: 0.011, liftH: 0.012, bobF: 0.003, bobH: 0.004, flex: 0.16, lat: 0, fold: 0.8, heel: 60, tail: 0.5, drop: 0.003 }),
|
|
38
|
-
G('halfbound', 1.4, 5.6, 0.38, HALFB, { liftF: 0.012, liftH: 0.013, bobF: 0.0035, bobH: 0.0045, flex: 0.2, lat: 0, fold: 0.85, heel: 62, tail: 0.6, drop: 0.003 }),
|
|
39
|
-
G('halfbound', 1.6, 5.65, 0.36, HALFB, { liftF: 0.012, liftH: 0.013, bobF: 0.0035, bobH: 0.0045, flex: 0.22, lat: 0, fold: 0.85, heel: 62, tail: 0.6, drop: 0.003 }),
|
|
40
|
-
G('bound', 1.75, 5.7, 0.34, BOUND, { liftF: 0.013, liftH: 0.014, bobF: 0.004, bobH: 0.005, flex: 0.25, lat: 0, fold: 0.72, heel: 64, tail: 0.7, drop: 0.004 }),
|
|
41
|
-
G('bound', 3.0, 6.2, 0.28, BOUND, { liftF: 0.014, liftH: 0.015, bobF: 0.0045, bobH: 0.0055, flex: 0.28, lat: 0, fold: 0.75, heel: 66, tail: 0.8, drop: 0.004 }),
|
|
42
|
-
],
|
|
43
|
-
feet: {
|
|
44
|
-
// plantigrade: the palm and the whole hind sole flat in stance, the heel lifting first
|
|
45
|
-
front: { type: 'plantigrade', curl: 20, heelStrike: 0, flex: 6, couple: 0.6, toeOut: 0.12, elbowDown: 0, retract: 0.5, liftBehind: 0.4 },
|
|
46
|
-
hind: { type: 'plantigrade', curl: 35, heelStrike: 0, lead: 0.35, toeOut: 0.22, retract: 0.35, liftBehind: 0.3 },
|
|
47
|
-
},
|
|
48
|
-
stance: { width: 1, gallopWidth: 0.85, sprawl: 0, crouch: 0, scuff: [2, 3, 0] },
|
|
49
|
-
body: {
|
|
50
|
-
// sections of the bind mesh at the girdles, fur included (measured on the bind mesh: chest bottom
|
|
51
|
-
// ~25 mm, belly ~22 mm (the sections reach a little lower, to 19-22 mm: with the measured 23 mm a
|
|
52
|
-
// curled sleeping rat pushed a forearm into the ground), the rump over the tail root ~21 mm above the ground; the back
|
|
53
|
-
// (long and low) ~91 mm over the withers, ~96 mm over the loins, ~85 mm over the tail root)
|
|
54
|
-
chest: { y: 0.0565, hh: 0.0345, hw: 0.033 },
|
|
55
|
-
pelvis: { y: 0.059, hh: 0.037, hw: 0.047 },
|
|
56
|
-
mid: { y: 0.0575, hh: 0.0385, hw: 0.048 },
|
|
57
|
-
rump: { z: -0.08, y: 0.0545, hh: 0.038, hw: 0.029 },
|
|
58
|
-
back: 0.024,
|
|
59
|
-
},
|
|
60
|
-
head: {
|
|
61
|
-
// [speed, raise (m), reach (m), pitch (rad, + = nose down)]: nose low, sniffing the ground
|
|
62
|
-
carriage: [[0, -0.002, 0.002, 0.18], [0.3, -0.004, 0.004, 0.2], [1.0, -0.004, 0.006, 0.12], [2, -0.004, 0.008, 0.08]],
|
|
63
|
-
stab: [[0, 0], [0.3, 0.15], [1, 0.25], [2, 0.35]],
|
|
64
|
-
neckBend: 35, neckPivot: 0.5, yaw: 0.9, pitchUp: 0.6, pitchDown: 0.6,
|
|
65
|
-
},
|
|
66
|
-
tail: {
|
|
67
|
-
// slopes down from the rump and trails along the ground at rest; carried straight out behind,
|
|
68
|
-
// just off the ground, when running
|
|
69
|
-
carriage: [
|
|
70
|
-
[0.0, [-38, -30, -20, -12, -6, -3, -1, 0, 0, 0, 0, 0]],
|
|
71
|
-
[0.5, [-30, -22, -14, -8, -4, -2, 0, 0, 0, 0, 0, 0]],
|
|
72
|
-
[1.3, [-18, -10, -5, -2, 0, 0, 1, 1, 1, 1, 1, 1]],
|
|
73
|
-
[3.0, [-12, -5, -1, 1, 2, 2, 2, 2, 2, 2, 2, 2]],
|
|
74
|
-
],
|
|
75
|
-
stiffness: 1.1, sway: 6, flick: 0, wag: 0, swish: 0, curl: 0, balance: 0.4,
|
|
76
|
-
radius: [0.0065, 0.0014],
|
|
77
|
-
},
|
|
78
|
-
ears: { mobility: 0.5, speedFlatten: 0.5, flattenSpeeds: [1.2, 3], twitch: 1.2, prick: 0.3 },
|
|
79
|
-
breath: { rate: 1.4, amp: 0.02, pant: false, heatSpeed: 3 },
|
|
80
|
-
actions: {
|
|
81
|
-
attack: { style: 'bite-lunge' },
|
|
82
|
-
eat: { style: 'graze', dropF: 0.1, dropH: 0.0 },
|
|
83
|
-
drink: { dropF: 0.12, dropH: 0.0 },
|
|
84
|
-
jump: { height: 0.25, distance: 0.45 },
|
|
85
|
-
idle: { shift: 0.5 },
|
|
86
|
-
sit: {},
|
|
87
|
-
lie: {},
|
|
88
|
-
sleep: { style: 'curl' },
|
|
89
|
-
},
|
|
90
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// Meshing plan: body at 1 mm, the thin tail at 0.7 mm, head (with the thin ears) at 0.6 mm overlapping across the nape and
|
|
2
|
-
// cross-faded, the four feet (separate toes, ~1.7 mm thick) at 0.5 mm cross-faded above the wrist and
|
|
3
|
-
// the heel, eyelid patches at 0.2 mm, the lower jaw as its own rigid surface, and the incisors as
|
|
4
|
-
// rigid parts (hero .. medium; sub-pixel below).
|
|
5
|
-
import { ratJoints, HEAD_O } from './rig.js';
|
|
6
|
-
import { EYE } from './sculpt.js';
|
|
7
|
-
import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
|
|
8
|
-
import { lerp, norm, sub, smoothstep } from '../../core/math/vec.js';
|
|
9
|
-
|
|
10
|
-
const J0 = ratJoints();
|
|
11
|
-
export const NECK_CUT = (() => {
|
|
12
|
-
const d = norm(sub(J0.occiput, J0.neckBase));
|
|
13
|
-
const c = lerp(J0.neckMid, J0.occiput, 0.5);
|
|
14
|
-
return { c, d, band: 0.003 };
|
|
15
|
-
})();
|
|
16
|
-
export const neckS = (x, y, z) => (x - NECK_CUT.c[0]) * NECK_CUT.d[0] + (y - NECK_CUT.c[1]) * NECK_CUT.d[1] + (z - NECK_CUT.c[2]) * NECK_CUT.d[2];
|
|
17
|
-
|
|
18
|
-
// feet: below this height (and inside the foot boxes) the fine foot mesh takes over
|
|
19
|
-
// tail: behind this plane the tail region takes over
|
|
20
|
-
export const TAIL_Z = -0.104, TAIL_B = 0.002;
|
|
21
|
-
export const FOOT_Y = 0.0105, FOOT_B = 0.0018;
|
|
22
|
-
const FOOT_BOX = {
|
|
23
|
-
F: { x0: 0.006, x1: 0.036, z0: 0.012, z1: 0.058 },
|
|
24
|
-
H: { x0: 0.006, x1: 0.04, z0: -0.058, z1: 0.01 },
|
|
25
|
-
};
|
|
26
|
-
export const inFoot = (x, z) => {
|
|
27
|
-
const ax = Math.abs(x);
|
|
28
|
-
for (const b of Object.values(FOOT_BOX)) if (ax > b.x0 && ax < b.x1 && z > b.z0 && z < b.z1) return true;
|
|
29
|
-
return false;
|
|
30
|
-
};
|
|
31
|
-
// > 0 inside the foot region (signed height below the cut)
|
|
32
|
-
const footS = (x, y, z) => (inFoot(x, z) ? FOOT_Y - y : -1);
|
|
33
|
-
|
|
34
|
-
export const EYE_PATCH = { R: 0.0056, B: 0.0008, h: 0.0002, centres: [1, -1].map((c) => eyeFrameOf(EYE, HEAD_O, c).c) };
|
|
35
|
-
export function eyePatchWeight(x, y, z) {
|
|
36
|
-
let dmin = 1e9;
|
|
37
|
-
for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
|
|
38
|
-
return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function ratRegions(rig, params, Q) {
|
|
42
|
-
// (the crowd tier's ~4 mm body cells need a wider overlap across the nape, or a slit opens there)
|
|
43
|
-
const r = Q.res, B = NECK_CUT.band * Math.max(1, r / 2.6);
|
|
44
|
-
const patches = Q.eyePatches ? EYE_PATCH.centres.map((c) => ({ c, R: EYE_PATCH.R, B: EYE_PATCH.B, h: EYE_PATCH.h * Math.max(1, r) })) : [];
|
|
45
|
-
const feet = r < 2.5; // low / crowd: the feet stay in the body mesh
|
|
46
|
-
const fine = r < 2.5; // the thin tail in its own finer region (hero .. medium)
|
|
47
|
-
const jobs = [
|
|
48
|
-
[{ name: 'body', part: 'body', bmin: [-0.055, -0.006, -0.3], bmax: [0.055, 0.15, 0.08], h: 0.00103 * r, F: 4, clip: (x, y, z) => neckS(x, y, z) < B && (!feet || footS(x, y, z) < FOOT_B) && (!fine || z > TAIL_Z - TAIL_B) }],
|
|
49
|
-
[
|
|
50
|
-
{ name: 'head', part: 'body', bmin: [-0.04, 0.026, 0.035], bmax: [0.04, 0.108, 0.114], h: 0.00062 * r, F: 6, clip: (x, y, z) => neckS(x, y, z) > -B, patches },
|
|
51
|
-
{ name: 'jaw', part: 'jaw', bmin: [-0.013, 0.032, 0.053], bmax: [0.013, 0.062, 0.106], h: 0.00055 * r, F: 6, rigidBone: 'jaw' },
|
|
52
|
-
],
|
|
53
|
-
];
|
|
54
|
-
if (feet) {
|
|
55
|
-
const fj = [];
|
|
56
|
-
for (const [k, b] of Object.entries(FOOT_BOX)) {
|
|
57
|
-
for (const s of [1, -1]) {
|
|
58
|
-
const x0 = s > 0 ? b.x0 : -b.x1, x1 = s > 0 ? b.x1 : -b.x0;
|
|
59
|
-
fj.push({ name: 'foot' + k + (s > 0 ? 'L' : 'R'), part: 'body', bmin: [x0, -0.004, b.z0], bmax: [x1, FOOT_Y + 0.004, b.z1], h: 0.0005 * r, F: 6, clip: (x, y, z) => footS(x, y, z) > -FOOT_B });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
jobs.push(fj);
|
|
63
|
-
}
|
|
64
|
-
if (fine) jobs[0].push({ name: 'tail', part: 'body', bmin: [-0.02, -0.004, -0.32], bmax: [0.02, 0.05, TAIL_Z + 0.004], h: 0.0007 * r, F: 4, clip: (x, y, z) => z < TAIL_Z + TAIL_B });
|
|
65
|
-
if (r < 2.5) {
|
|
66
|
-
const ht = 0.00022 * Math.min(r, 1.6);
|
|
67
|
-
jobs.push([
|
|
68
|
-
{ name: 'uteeth', part: 'uteeth', bmin: [-0.004, 0.042, 0.09], bmax: [0.004, 0.056, 0.106], h: ht, F: 4, rigidBone: 'head' },
|
|
69
|
-
{ name: 'lteeth', part: 'lteeth', bmin: [-0.004, 0.04, 0.088], bmax: [0.004, 0.052, 0.104], h: ht, F: 4, rigidBone: 'jaw' },
|
|
70
|
-
]);
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
jobs,
|
|
74
|
-
fade(x, y, z, name, patch) {
|
|
75
|
-
const sN = neckS(x, y, z);
|
|
76
|
-
if (name === 'body') {
|
|
77
|
-
let f = 1 - smoothstep(-B, B, sN);
|
|
78
|
-
if (feet && inFoot(x, z)) f *= 1 - smoothstep(-FOOT_B, FOOT_B, FOOT_Y - y);
|
|
79
|
-
if (fine) f *= smoothstep(TAIL_Z - TAIL_B, TAIL_Z + TAIL_B, z);
|
|
80
|
-
return f;
|
|
81
|
-
}
|
|
82
|
-
if (name === 'head') {
|
|
83
|
-
let f = smoothstep(-B, B, sN);
|
|
84
|
-
if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
|
|
85
|
-
return f;
|
|
86
|
-
}
|
|
87
|
-
if (name === 'tail') return 1 - smoothstep(TAIL_Z - TAIL_B, TAIL_Z + TAIL_B, z);
|
|
88
|
-
if (name.startsWith('foot')) return smoothstep(-FOOT_B, FOOT_B, FOOT_Y - y);
|
|
89
|
-
return 1;
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}
|