@bitefoundry/retrieviewer 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ASSET-PROVENANCE.md +11 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +95 -0
- package/DESKTOP-PLATFORMS.md +6 -1
- package/INSTALLING.md +4 -0
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +116 -0
- package/README.md +121 -59
- package/RELEASING.md +33 -13
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/linux-overlay/overlay.py +8 -2
- package/integrations/macos-overlay/overlay.jxa +9 -7
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +7 -6
- package/integrations/windows-overlay/desktop.mjs +2 -1
- package/integrations/windows-overlay/protocol.mjs +13 -7
- package/integrations/windows-overlay/worker.mjs +1 -1
- package/package.json +34 -13
- package/puppy-comfort-sprites.mjs +33 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +140 -0
- package/puppy-companion-life.mjs +58 -18
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-companion-sprites.mjs +4 -2
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-actions.mjs +4 -2
- package/puppy-paper-behaviors.mjs +1 -1
- package/puppy-paper-contact.mjs +4 -2
- package/puppy-paper-seat.mjs +4 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +79 -21
- package/retrieviewer-cli.mjs +8 -6
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +12 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- package/vendor/procedural-animals/src/worker.js +0 -29
|
@@ -1,676 +0,0 @@
|
|
|
1
|
-
// Eyes: eyeball meshes with a purpose-built shader and a small behaviour model, driven by the packed
|
|
2
|
-
// `data.eyes[i] = { side, bone, c, x, y, z, scale, spec, look }`.
|
|
3
|
-
// * cornea: clear coat with scene reflections and sharp light catchlights (MeshPhysicalMaterial,
|
|
4
|
-
// so every scene light, shadow, environment and fog applies);
|
|
5
|
-
// * iris: procedural stroma (radial fibres, collarette, crypts, pupillary ruff, dark limbal ring)
|
|
6
|
-
// seen THROUGH the cornea: the view ray is refracted at the corneal surface and traced to the
|
|
7
|
-
// recessed iris plane, so the iris shifts with the viewing angle like a real eye;
|
|
8
|
-
// * pupil (look.pupil): 'round', 'slit' (vertical: cats, foxes, snakes) or 'bar' (horizontal
|
|
9
|
-
// rounded rectangle: goats, sheep, deer, horses, cattle, frogs); its size follows the light
|
|
10
|
-
// (elevation of the scene's main directional light) and arousal within look.pupilSize [min, max];
|
|
11
|
-
// * lids (look.lids): 'mammal' (almond aperture, lid-margin shading, blinking upper lid),
|
|
12
|
-
// 'bird' (a nictitating membrane sweeps across from the front corner; the lower lid rises for
|
|
13
|
-
// sleep), 'none' (fish, snakes: no blinks, glossy spectacle), 'simple' (spiders: glossy black
|
|
14
|
-
// domes, any number and size of eyes);
|
|
15
|
-
// * behaviour: fixations with quick saccades, blinks every few seconds (sometimes double), gaze that
|
|
16
|
-
// leads the head toward motion.state.lookTarget / input.look, motion.state.eyelid (0 open .. 1
|
|
17
|
-
// shut) for sleep, half-lidded and still in death. Optional state: motion.state.eyeRoll (0..1, the
|
|
18
|
-
// eyeball rolls back and shows its sclera: white shark biting), motion.state.nictitate (0..1, the
|
|
19
|
-
// nictitating membrane closes: carcharhinid sharks); look.blink === false turns automatic blinks off.
|
|
20
|
-
// * look.cornea (optional, default 1): strength of the cornea's clear coat. Under a bright sky the clear coat's
|
|
21
|
-
// reflection can swamp a dark iris (a brown bear's eyes read pale blue-grey in the showcase); a species with
|
|
22
|
-
// small, dark, deep-set eyes lowers it (bear 0.2) and keeps a small wet catchlight.
|
|
23
|
-
// * look.envSpecular (optional, default 1): scale of the eyeball's environment (indirect) specular. three.js
|
|
24
|
-
// replaces a standard material's envMapIntensity with scene.environmentIntensity whenever the scene has an
|
|
25
|
-
// environment and the material has no env map of its own (WebGLRenderer), so the material's 0.28 below does not
|
|
26
|
-
// apply in such scenes and a bright sky's sheen covers a dark iris (bear 0.2).
|
|
27
|
-
import * as THREE from 'three';
|
|
28
|
-
|
|
29
|
-
const PUPIL = { round: 0, slit: 1, bar: 2 };
|
|
30
|
-
const LIDS = { mammal: 0, bird: 1, none: 2, simple: 3 };
|
|
31
|
-
const PUPIL_SIZE = { round: [0.3, 0.5], slit: [0.07, 0.7], bar: [0.07, 0.42] };
|
|
32
|
-
const DEFAULT_IRIS = { inner: [0.2, 0.06, 0.007], mid: [0.54, 0.2, 0.022], hi: [0.78, 0.38, 0.055], outer: [0.26, 0.075, 0.009] };
|
|
33
|
-
|
|
34
|
-
const PARS = /* glsl */ `
|
|
35
|
-
uniform float uIrisZ, uIrisR, uPupil, uLensR, uLensD, uLensOff, uBlink, uLower, uNict, uLidTravel, uFront, uEnvSpec;
|
|
36
|
-
uniform float uRimShade, uLidShade, uLimbus, uLidSpec, uLidFur, uGlaze, uAmbient, uLidHair, uIrisLight, uEyeFill, uLidFlat, uLidSeam, uLidClump, uLidFill, uIrisTex, uLidMeet;
|
|
37
|
-
float gLidWrap = 0.0; // (look.lidFill) the coat's wrapped diffuse on a closing lid, set per fragment
|
|
38
|
-
uniform mat4 uSocketInv;
|
|
39
|
-
uniform vec3 uLidColor, uIrisIn, uIrisMid, uIrisHi, uIrisOut, uSclera;
|
|
40
|
-
varying vec3 vEyeObj; varying vec3 vCamObj; varying vec3 vEyeWorld; varying vec3 vIrisN;
|
|
41
|
-
float eh3(vec3 p) { p = fract(p * 0.1031); p += dot(p, p.zyx + 31.32); return fract((p.x + p.y) * p.z); }
|
|
42
|
-
float evn3(vec3 p) {
|
|
43
|
-
vec3 i = floor(p), f = fract(p); f = f * f * (3.0 - 2.0 * f);
|
|
44
|
-
return mix(mix(mix(eh3(i), eh3(i + vec3(1, 0, 0)), f.x), mix(eh3(i + vec3(0, 1, 0)), eh3(i + vec3(1, 1, 0)), f.x), f.y),
|
|
45
|
-
mix(mix(eh3(i + vec3(0, 0, 1)), eh3(i + vec3(1, 0, 1)), f.x), mix(eh3(i + vec3(0, 1, 1)), eh3(i + vec3(1, 1, 1)), f.x), f.y), f.z);
|
|
46
|
-
}
|
|
47
|
-
// noise sampled on circles around the pupil: periodic in angle, stretched along the radius
|
|
48
|
-
float irisN(float a, float r, float k, float kr, float o) { return evn3(vec3(cos(a) * k + o, sin(a) * k - o, r * kr)); }
|
|
49
|
-
// signed distance to the pupil edge in iris radii (< 0 inside)
|
|
50
|
-
float pupilSD(vec2 qn) {
|
|
51
|
-
#if PUPIL_TYPE == 1
|
|
52
|
-
// vertical slit: a narrow lens pointed at top and bottom
|
|
53
|
-
float w = uPupil, hh = 0.93;
|
|
54
|
-
float R = (hh * hh + w * w) / (2.0 * w);
|
|
55
|
-
vec2 p = abs(qn);
|
|
56
|
-
return length(vec2(p.x + R - w, p.y)) - R;
|
|
57
|
-
#elif PUPIL_TYPE == 2
|
|
58
|
-
// horizontal bar: rounded rectangle
|
|
59
|
-
vec2 ext = vec2(0.58, uPupil);
|
|
60
|
-
float rr = uPupil * 0.9;
|
|
61
|
-
vec2 d = abs(qn) - ext + rr;
|
|
62
|
-
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - rr;
|
|
63
|
-
#else
|
|
64
|
-
return length(qn) - uPupil;
|
|
65
|
-
#endif
|
|
66
|
-
}
|
|
67
|
-
vec3 irisColor(vec2 q) {
|
|
68
|
-
vec2 qn = q / uIrisR;
|
|
69
|
-
float r = length(qn);
|
|
70
|
-
float a = atan(q.y, q.x);
|
|
71
|
-
float pd = pupilSD(qn);
|
|
72
|
-
// radial fibre bundles at three scales
|
|
73
|
-
float f1 = irisN(a, r, 24.0, 2.5, 0.0);
|
|
74
|
-
float f2 = irisN(a, r, 9.0, 1.2, 7.3);
|
|
75
|
-
float f3 = irisN(a, r, 55.0, 5.0, 3.1);
|
|
76
|
-
float fib = f1 * 0.5 + f2 * 0.3 + f3 * 0.2;
|
|
77
|
-
// wavy collarette ring and dark crypts in the mid stroma
|
|
78
|
-
float cr = 0.53 + 0.06 * (irisN(a, 0.0, 3.0, 0.0, 1.7) - 0.5);
|
|
79
|
-
float coll = smoothstep(0.045, 0.0, abs(r - cr));
|
|
80
|
-
float crypt = smoothstep(0.64, 0.8, irisN(a, r, 14.0, 7.0, 9.1)) * smoothstep(0.5, 0.62, r) * (1.0 - smoothstep(0.84, 0.93, r));
|
|
81
|
-
vec3 col = mix(uIrisIn, uIrisMid, smoothstep(0.36, 0.62, r));
|
|
82
|
-
col = mix(col, uIrisHi, fib * 0.65 * smoothstep(0.42, 0.66, r) * (1.0 - smoothstep(0.8, 0.94, r)));
|
|
83
|
-
col = mix(col, uIrisOut, smoothstep(0.78, 0.96, r));
|
|
84
|
-
col *= mix(1.0, 0.72 + 0.56 * fib, uIrisTex); // (look.irisTexture: the contrast of the radial fibres and crypts)
|
|
85
|
-
col = mix(col, col * 1.3 + 0.015, coll * 0.55);
|
|
86
|
-
col *= 1.0 - crypt * 0.5 * uIrisTex;
|
|
87
|
-
col *= mix(1.0, uLimbus, smoothstep(0.9, 1.0, r)); // limbal ring
|
|
88
|
-
col = mix(col, uIrisIn * 0.3 + 0.004, smoothstep(0.08, 0.01, pd)); // pupillary ruff
|
|
89
|
-
float pw = fwidth(pd) + 0.004;
|
|
90
|
-
col = mix(col, vec3(0.0025), smoothstep(pw, -pw, pd)); // pupil
|
|
91
|
-
return col;
|
|
92
|
-
}
|
|
93
|
-
float lensSD(vec2 p, float dUp, float dLo) { return max(length(p + vec2(0.0, dUp)) - uLensR, length(p - vec2(0.0, dLo)) - uLensR); }
|
|
94
|
-
`;
|
|
95
|
-
|
|
96
|
-
const MAP = /* glsl */ `
|
|
97
|
-
// ---- iris seen through the cornea
|
|
98
|
-
vec3 Pe = vEyeObj;
|
|
99
|
-
vec3 Ne = normalize(Pe);
|
|
100
|
-
vec3 Ve = normalize(Pe - vCamObj);
|
|
101
|
-
float lidCover = 0.0, lidMargin = 0.0, eyeAO = 1.0, eyeLightOcc = 1.0, nictCover = 0.0;
|
|
102
|
-
vec3 Sk = (uSocketInv * vec4(vEyeWorld, 1.0)).xyz;
|
|
103
|
-
Sk.y -= uLensOff;
|
|
104
|
-
#if LID_TYPE == 3
|
|
105
|
-
// simple glossy dome (spiders)
|
|
106
|
-
diffuseColor.rgb = uIrisOut * 0.06 + 0.003;
|
|
107
|
-
#else
|
|
108
|
-
float onCornea = smoothstep(uIrisZ - 0.00035, uIrisZ + 0.00035, Pe.z);
|
|
109
|
-
vec3 Rr = refract(Ve, Ne, 1.0 / 1.376);
|
|
110
|
-
float tI = (uIrisZ - Pe.z) / min(Rr.z, -0.05);
|
|
111
|
-
vec2 qI = Pe.xy + Rr.xy * max(tI, 0.0);
|
|
112
|
-
vec3 irisC = irisColor(qI);
|
|
113
|
-
vec3 scl = uSclera * (0.55 + 0.45 * smoothstep(-0.002, 0.006, Pe.z));
|
|
114
|
-
diffuseColor.rgb = mix(scl, irisC, onCornea);
|
|
115
|
-
#endif
|
|
116
|
-
#if LID_TYPE == 0 || LID_TYPE == 1
|
|
117
|
-
// ---- lids: aperture in the socket frame (fixed to the head, not to the moving eyeball)
|
|
118
|
-
#if LID_TYPE == 0
|
|
119
|
-
float dUp = uLensD + uBlink * uLidTravel * 0.85, dLo = uLensD + uBlink * uLidTravel * 0.15;
|
|
120
|
-
#else
|
|
121
|
-
float dUp = uLensD + uBlink * uLidTravel * 0.12, dLo = uLensD + uBlink * uLidTravel * 0.88;
|
|
122
|
-
#endif
|
|
123
|
-
#if LID_TYPE == 0 && LID_ARC == 1
|
|
124
|
-
// (look.lidArc) the corners stay put: the upper lid's edge descends as an arc from corner to corner and meets
|
|
125
|
-
// the lower lid (which rises a little) along the whole fissure, so a shut eye shows its lid margins as one
|
|
126
|
-
// curved seam; the two-circle lens below closes to a single point in the middle of the eye
|
|
127
|
-
float hw = sqrt(max(uLensR * uLensR - uLensD * uLensD, 1e-10));
|
|
128
|
-
float ax = min(abs(Sk.x), hw * 0.9999);
|
|
129
|
-
float sq = sqrt(max(uLensR * uLensR - ax * ax, 1e-10));
|
|
130
|
-
float yA = sq - uLensD, s0 = ax / sq; // the open upper edge (the lower is -yA), |slope|
|
|
131
|
-
// (look.lidMeet: the lids meet at -lidMeet yA when shut, 0.7 by default; the upper lid travels 1 + lidMeet of yA)
|
|
132
|
-
float kUp = 1.0 - (1.0 + uLidMeet) * uBlink, kLo = 1.0 - (1.0 - uLidMeet) * uBlink;
|
|
133
|
-
float yUp = yA * kUp, yLo = -yA * kLo;
|
|
134
|
-
float sdUp = (Sk.y - yUp) / sqrt(1.0 + kUp * kUp * s0 * s0);
|
|
135
|
-
float sdLo = (yLo - Sk.y) / sqrt(1.0 + kLo * kLo * s0 * s0);
|
|
136
|
-
float sdB = max(max(sdUp, sdLo), abs(Sk.x) - hw);
|
|
137
|
-
#else
|
|
138
|
-
float sdB = lensSD(Sk.xy, dUp, dLo);
|
|
139
|
-
float sdUp = length(Sk.xy + vec2(0.0, dUp)) - uLensR;
|
|
140
|
-
#endif
|
|
141
|
-
lidCover = smoothstep(-0.00015, 0.00015, sdB);
|
|
142
|
-
// (look.lidSeam > 0: the dark lid margin narrows as the lids close, to a seam of about that half-width when shut:
|
|
143
|
-
// the open eye's 0.3-1.4 mm margin fade on both lids drew a shut eye's seam as a ~3 mm dark band)
|
|
144
|
-
float mA = 0.0003, mB = 0.0014;
|
|
145
|
-
if (uLidSeam > 0.0) { mA = mix(mA, 0.3 * uLidSeam, uBlink); mB = mix(mB, uLidSeam, uBlink); }
|
|
146
|
-
lidMargin = 1.0 - smoothstep(mA, mB, sdB);
|
|
147
|
-
float aoRim = smoothstep(0.0, -0.003, sdB);
|
|
148
|
-
float shadowUp = smoothstep(-0.0075, -0.0004, sdUp);
|
|
149
|
-
eyeAO = mix(1.0 - 0.7 * uRimShade, 1.0, aoRim) * (1.0 - 0.6 * uLidShade * shadowUp);
|
|
150
|
-
eyeLightOcc = mix(1.0 - 0.45 * uRimShade, 1.0, aoRim) * (1.0 - 0.7 * uLidShade * shadowUp);
|
|
151
|
-
#if LID_TYPE == 1
|
|
152
|
-
// nictitating membrane: sweeps from the front corner across the eye
|
|
153
|
-
float halfW = sqrt(max(uLensR * uLensR - uLensD * uLensD, 1e-10));
|
|
154
|
-
float edgeX = mix(halfW * 1.1, -halfW * 1.1, uNict);
|
|
155
|
-
nictCover = smoothstep(edgeX - 0.0004, edgeX + 0.0004, Sk.x * uFront) * step(0.001, uNict);
|
|
156
|
-
// a milky, translucent sheet: the iris shows through, veiled and cooled
|
|
157
|
-
diffuseColor.rgb = mix(diffuseColor.rgb, vec3(0.5, 0.55, 0.6), nictCover * 0.6);
|
|
158
|
-
#endif
|
|
159
|
-
// short hairs / fine skin lying along the lid, a slightly darker fold near the brow, dark margin
|
|
160
|
-
float hairs = 0.8 + 0.4 * evn3(vec3(Sk.x * 2600.0, Sk.y * 650.0, 3.7)) * evn3(vec3(Sk.x * 900.0, Sk.y * 260.0, 9.1));
|
|
161
|
-
// (look.lidHair: a furred lid, strands lying along the lid from the nasal corner toward the temple and tufts
|
|
162
|
-
// of them, at the contrast of the coat's own base streaks; faded out where they get smaller than a pixel)
|
|
163
|
-
if (uLidHair > 0.0) {
|
|
164
|
-
vec2 hq = vec2(Sk.x * uFront, Sk.y + 0.2 * Sk.x * uFront);
|
|
165
|
-
float fdH = 1.0 - smoothstep(0.35, 0.9, length(fwidth(hq)) * 5200.0);
|
|
166
|
-
float st1 = evn3(vec3(hq.x * 900.0, hq.y * 6000.0, 1.3)), st2 = evn3(vec3(hq.x * 450.0, hq.y * 2600.0, 7.9));
|
|
167
|
-
float furH = mix(1.0, (0.62 + 0.76 * st1) * (0.84 + 0.32 * st2), fdH);
|
|
168
|
-
hairs = mix(hairs, furH, uLidHair);
|
|
169
|
-
}
|
|
170
|
-
// (look.lidClump: the coat's tufts at a normal viewing distance, where the strands above fade out: tone variation
|
|
171
|
-
// at the clump scale (~2-3 mm, drawn out along the lid hair), so a shut eye's lids read as fur, not a smooth disc)
|
|
172
|
-
if (uLidClump > 0.0) {
|
|
173
|
-
vec2 cq = vec2(Sk.x * uFront, Sk.y + 0.2 * Sk.x * uFront);
|
|
174
|
-
float c1 = evn3(vec3(cq.x * 380.0, cq.y * 900.0, 5.3)), c2 = evn3(vec3(cq.x * 170.0, cq.y * 420.0, 2.1));
|
|
175
|
-
float fdC = 1.0 - smoothstep(0.35, 0.9, length(fwidth(cq)) * 1300.0);
|
|
176
|
-
hairs *= mix(1.0, (0.55 + 0.9 * c1) * (0.8 + 0.4 * c2), uLidClump * fdC);
|
|
177
|
-
}
|
|
178
|
-
float fold = 1.0 - 0.25 * smoothstep(0.0, 0.004, Sk.y);
|
|
179
|
-
vec3 lidAlb = uLidColor * hairs * fold * mix(1.0, 0.06, lidMargin);
|
|
180
|
-
diffuseColor.rgb = mix(diffuseColor.rgb, lidAlb, lidCover);
|
|
181
|
-
gLidWrap = uLidFill * uLidFur * lidCover;
|
|
182
|
-
eyeAO = mix(eyeAO, 1.0, lidCover);
|
|
183
|
-
eyeLightOcc = mix(eyeLightOcc, 1.0, lidCover);
|
|
184
|
-
#endif
|
|
185
|
-
`;
|
|
186
|
-
|
|
187
|
-
// (look.lidFill) a furred closing lid takes the direct light like the coat round it: the coat's wrapped diffuse,
|
|
188
|
-
// (N.L + 0.4) / 1.4 (coatMaterial.js shadeLight), which lights fur well past the terminator where a Lambert lid went dark
|
|
189
|
-
const DIRECT = /* glsl */ `
|
|
190
|
-
#include <lights_physical_pars_fragment>
|
|
191
|
-
void RE_Direct_Eye(const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {
|
|
192
|
-
RE_Direct_Physical(directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight);
|
|
193
|
-
if (gLidWrap > 0.0) {
|
|
194
|
-
float ndl = dot(geometryNormal, directLight.direction);
|
|
195
|
-
float extra = max(clamp((ndl + 0.4) / 1.4, 0.0, 1.0) - max(ndl, 0.0), 0.0);
|
|
196
|
-
reflectedLight.directDiffuse += gLidWrap * extra * directLight.color * BRDF_Lambert(material.diffuseContribution);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
#undef RE_Direct
|
|
200
|
-
#define RE_Direct RE_Direct_Eye
|
|
201
|
-
`;
|
|
202
|
-
|
|
203
|
-
const MATERIAL = /* glsl */ `
|
|
204
|
-
#include <lights_physical_fragment>
|
|
205
|
-
// lids are skin, not cornea (look.lidSpec < 1: a furred lid, without the smooth ball's sky sheen)
|
|
206
|
-
material.roughness = mix(material.roughness, 0.78, lidCover);
|
|
207
|
-
float lidSpecK = mix(1.0, uLidSpec, lidCover);
|
|
208
|
-
material.specularColor *= lidSpecK;
|
|
209
|
-
material.specularColorBlended *= lidSpecK;
|
|
210
|
-
material.specularF90 *= lidSpecK;
|
|
211
|
-
#ifdef USE_CLEARCOAT
|
|
212
|
-
material.clearcoat *= 1.0 - lidCover;
|
|
213
|
-
material.clearcoatRoughness = mix(material.clearcoatRoughness, 0.12, nictCover);
|
|
214
|
-
#endif
|
|
215
|
-
`;
|
|
216
|
-
|
|
217
|
-
const NORMALS = /* glsl */ `
|
|
218
|
-
#include <normal_fragment_maps>
|
|
219
|
-
#if LID_TYPE != 3
|
|
220
|
-
{
|
|
221
|
-
// (look.irisLight) the iris and the pupil are a flat disc behind the cornea, lit through it: shaded with the disc's
|
|
222
|
-
// own normal (the eye's axis) instead of the cornea's sphere. Seen from below or from the side, the part of the
|
|
223
|
-
// cornea in view faces away from a high light, and the iris behind it went black while the face round it was lit.
|
|
224
|
-
// The clear coat (the cornea's reflection) keeps the sphere's normal.
|
|
225
|
-
float irisK = uIrisLight * onCornea * (1.0 - lidCover);
|
|
226
|
-
if (irisK > 0.0) normal = normalize(mix(normal, normalize(vIrisN), irisK));
|
|
227
|
-
// (look.lidFlat) a closing lid lies in the face: shaded with the socket's axis (the face's normal round the eye)
|
|
228
|
-
// rather than as a lit dome with a hard terminator across it
|
|
229
|
-
if (uLidFlat > 0.0 && lidCover > 0.0) {
|
|
230
|
-
vec3 sockZ = normalize((viewMatrix * vec4(uSocketInv[0][2], uSocketInv[1][2], uSocketInv[2][2], 0.0)).xyz);
|
|
231
|
-
normal = normalize(mix(normal, sockZ, uLidFlat * lidCover));
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
#endif
|
|
235
|
-
`;
|
|
236
|
-
|
|
237
|
-
const MOD = /* glsl */ `
|
|
238
|
-
#include <aomap_fragment>
|
|
239
|
-
// (look.lidFur > 0: a furred closing lid is lit like the coat round it, by the scene's lights only: the coat
|
|
240
|
-
// shader takes no environment map, so a lid that took the sky's light read paler than the fur outdoors and
|
|
241
|
-
// darker indoors. look.glaze < 1: less of the base layer's broad sheen over the open eye; the clear coat's
|
|
242
|
-
// sharp corneal reflection stays)
|
|
243
|
-
float lidFurK = lidCover * uLidFur;
|
|
244
|
-
// (look.ambient: the whole eye's indirect diffuse from the scene's ambient lights, as the coat is lit, not the
|
|
245
|
-
// environment map's irradiance: a sky map poured blue light into an orange iris and greyed it)
|
|
246
|
-
reflectedLight.indirectDiffuse = mix(reflectedLight.indirectDiffuse, irradiance * BRDF_Lambert(material.diffuseColor), max(lidFurK, uAmbient));
|
|
247
|
-
// (look.fill: a fill light on the eye where the direct light does not reach, fading out where it does, as the
|
|
248
|
-
// coat's camera-side fill lifts the fur round the eye: the sky in front of the eye (the environment map's
|
|
249
|
-
// irradiance), or without an environment map the coat's own fill from the ambient lights. With the eye lit by the
|
|
250
|
-
// weak ambient lights alone (look.ambient), an iris or a closed lid in shade went 4-10x darker than the fur, which
|
|
251
|
-
// also takes light scattered through it; the sky map's full irradiance on the other hand bleached a sunlit iris)
|
|
252
|
-
if (uEyeFill > 0.0) {
|
|
253
|
-
// the coat's own fill (coatMaterial.js: the ambient and hemisphere lights' camera-side fill at its uFill 0.45)
|
|
254
|
-
vec3 coatFill = ambientLightColor * 2.0;
|
|
255
|
-
#if NUM_HEMI_LIGHTS > 0
|
|
256
|
-
for (int i = 0; i < NUM_HEMI_LIGHTS; i++) coatFill += hemisphereLights[i].skyColor + hemisphereLights[i].groundColor;
|
|
257
|
-
#endif
|
|
258
|
-
coatFill *= 0.45 * clamp(dot(normal, geometryViewDir) * 0.6 + 0.4, 0.0, 1.0);
|
|
259
|
-
#if defined( USE_ENVMAP ) && defined( ENVMAP_TYPE_CUBE_UV )
|
|
260
|
-
// (look.lidFill: a furred closing lid takes the coat's fill like the fur round it, not the sky map's irradiance,
|
|
261
|
-
// which lit a shut eye in shade 2-7x brighter than the fur: pale discs)
|
|
262
|
-
vec3 fillIrr = mix(iblIrradiance, coatFill, uLidFill * lidFurK);
|
|
263
|
-
#else
|
|
264
|
-
vec3 fillIrr = coatFill;
|
|
265
|
-
#endif
|
|
266
|
-
vec3 dirC = vec3(0.0);
|
|
267
|
-
#if NUM_DIR_LIGHTS > 0
|
|
268
|
-
for (int i = 0; i < NUM_DIR_LIGHTS; i++) dirC += directionalLights[i].color;
|
|
269
|
-
#endif
|
|
270
|
-
#if NUM_SUN_LIGHTS > 0
|
|
271
|
-
for (int i = 0; i < NUM_SUN_LIGHTS; i++) dirC += sunLights[i].color;
|
|
272
|
-
#endif
|
|
273
|
-
vec3 lam = BRDF_Lambert(material.diffuseColor);
|
|
274
|
-
float litFrac = clamp(dot(reflectedLight.directDiffuse, vec3(1.0)) / max(dot(dirC * lam, vec3(1.0)), 1e-9), 0.0, 1.0);
|
|
275
|
-
// (a furred lid with look.lidFill: the coat's full fill; the iris: look.fill's share of it)
|
|
276
|
-
reflectedLight.indirectDiffuse += fillIrr * (mix(uEyeFill, 1.0, uLidFill * lidFurK) * (1.0 - litFrac)) * lam;
|
|
277
|
-
}
|
|
278
|
-
// (look.lidFill: the light a furred lid scatters toward the viewer from a sun behind it, as the coat's fur glows
|
|
279
|
-
// against the light (coatMaterial.js back-scatter, (albedo + 0.04): a black coat's fur glows too), at about the
|
|
280
|
-
// coat's level round the eye: backlit, the fur round a shut eye glowed while the lid went black)
|
|
281
|
-
#if NUM_DIR_LIGHTS > 0
|
|
282
|
-
if (uLidFill > 0.0 && lidFurK > 0.0) {
|
|
283
|
-
for (int i = 0; i < NUM_DIR_LIGHTS; i++) {
|
|
284
|
-
float bl = pow(clamp(dot(-directionalLights[i].direction, geometryViewDir), 0.0, 1.0), 2.5);
|
|
285
|
-
reflectedLight.directDiffuse += (uLidFill * lidFurK * 0.15 * bl) * directionalLights[i].color * BRDF_Lambert(material.diffuseColor + 0.04);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
#endif
|
|
289
|
-
reflectedLight.indirectSpecular *= (1.0 - lidFurK) * mix(uGlaze, 1.0, lidCover);
|
|
290
|
-
reflectedLight.directSpecular *= mix(uGlaze, 1.0, lidCover);
|
|
291
|
-
reflectedLight.directDiffuse *= eyeLightOcc;
|
|
292
|
-
reflectedLight.directSpecular *= eyeLightOcc;
|
|
293
|
-
reflectedLight.indirectDiffuse *= eyeAO;
|
|
294
|
-
reflectedLight.indirectSpecular *= eyeAO * uEnvSpec;
|
|
295
|
-
#ifdef USE_CLEARCOAT
|
|
296
|
-
clearcoatSpecularDirect *= eyeLightOcc;
|
|
297
|
-
clearcoatSpecularIndirect *= eyeAO;
|
|
298
|
-
#endif
|
|
299
|
-
`;
|
|
300
|
-
|
|
301
|
-
const smooth01 = (t) => { t = Math.min(1, Math.max(0, t)); return t * t * (3 - 2 * t); };
|
|
302
|
-
const col3 = (c, d) => new THREE.Color(...(c || d));
|
|
303
|
-
|
|
304
|
-
// Resolves a species look into complete parameters (defaults = cheetah).
|
|
305
|
-
export function resolveLook(look = {}) {
|
|
306
|
-
const pupil = PUPIL[look.pupil] !== undefined ? look.pupil : 'round';
|
|
307
|
-
const lids = LIDS[look.lids] !== undefined ? look.lids : 'mammal';
|
|
308
|
-
return {
|
|
309
|
-
pupil, lids,
|
|
310
|
-
pupilSize: look.pupilSize || PUPIL_SIZE[pupil],
|
|
311
|
-
iris: { ...DEFAULT_IRIS, ...(look.iris || {}) },
|
|
312
|
-
sclera: { color: [0.2, 0.15, 0.11], visible: false, ...(look.sclera || {}) },
|
|
313
|
-
lidColor: look.lidColor || [0.5, 0.31, 0.15],
|
|
314
|
-
// shading of the eyeball by its lids (1 = the default: a deep-set eye; a flat face with prominent
|
|
315
|
-
// eyes, the cat, shades less) and the darkening of the limbal ring (iris colour x limbus at its edge)
|
|
316
|
-
shade: { rim: 1, lid: 1, ...(look.shade || {}) },
|
|
317
|
-
limbus: look.limbus ?? 0.2,
|
|
318
|
-
// specular of a closing lid (1 = the default smooth skin; a lid covered in short fur, the cat's, has
|
|
319
|
-
// almost none: on a dark coat the smooth lid mirrored the sky and read as a glossy open eye)
|
|
320
|
-
lidSpec: look.lidSpec ?? 1,
|
|
321
|
-
// (0..1) a closing lid lit like fur: by the scene's lights only, no environment map (0 = the default: the
|
|
322
|
-
// lid takes the environment like the eyeball it is painted on)
|
|
323
|
-
lidFur: look.lidFur ?? 0,
|
|
324
|
-
// (0..1) the base layer's broad specular sheen over the open eye (1 = the default); the clear coat (the
|
|
325
|
-
// cornea's sharp reflection) is kept either way
|
|
326
|
-
glaze: look.glaze ?? 1,
|
|
327
|
-
// (0..1) the eye's indirect diffuse from the scene's ambient lights instead of the environment map (as the
|
|
328
|
-
// coat shader is lit; 0 = the default)
|
|
329
|
-
ambient: look.ambient ?? 0,
|
|
330
|
-
// (0..1) a closing lid textured like fur (strands and tufts along the lid) instead of fine smooth skin
|
|
331
|
-
lidHair: look.lidHair ?? 0,
|
|
332
|
-
// (0..1) the iris and pupil shaded with the iris disc's normal (the eye's axis) instead of the cornea's sphere
|
|
333
|
-
// (0 = the default: the sphere's, which darkens the iris seen from below or aside under a high light)
|
|
334
|
-
irisLight: look.irisLight ?? 0,
|
|
335
|
-
// (0..1) the coat shader's camera-side fill light on the eye (iris and lids) where the direct light does not
|
|
336
|
-
// reach, as on the fur round it (0 = the default: none)
|
|
337
|
-
fill: look.fill ?? 0,
|
|
338
|
-
// (0..1) a closing lid shaded with the socket's axis, as the face round it, instead of as a dome (0 = the default)
|
|
339
|
-
lidFlat: look.lidFlat ?? 0,
|
|
340
|
-
// (m) the half-width the dark lid margin narrows to as the lids shut (0 = the default: the open eye's 0.3-1.4 mm
|
|
341
|
-
// margin fade at every stage, a ~3 mm dark band along a shut eye's seam)
|
|
342
|
-
lidSeam: look.lidSeam ?? 0,
|
|
343
|
-
// (0..1) tone variation of a closing lid at the coat's clump scale (0 = the default: none)
|
|
344
|
-
lidClump: look.lidClump ?? 0,
|
|
345
|
-
// (0..1) the contrast of the iris's radial fibre bundles and dark crypts (1 = the default; a cat's even iris
|
|
346
|
-
// with its crypts at full contrast read as the ticks of a clock face)
|
|
347
|
-
irisTexture: look.irisTexture ?? 1,
|
|
348
|
-
// (0..1, with fill and lidFur) a furred closing lid is lit like the coat round it: the coat's full ambient fill
|
|
349
|
-
// instead of the environment map's irradiance, and the coat's wrapped diffuse (0 = the default)
|
|
350
|
-
lidFill: look.lidFill ?? 0,
|
|
351
|
-
// (mammal lids) true: the corners stay put and the lids meet along the whole fissure when they shut (a
|
|
352
|
-
// curved seam); false (the default): the two-circle lens, which closes to a point
|
|
353
|
-
lidArc: !!look.lidArc,
|
|
354
|
-
// (with lidArc) where the shut lids meet, in units of the open aperture's half-height below its centre (0.7 = the
|
|
355
|
-
// default; nearer 1 the upper lid does all the closing and the lower lid shows as a thinner band under the seam)
|
|
356
|
-
lidMeet: look.lidMeet ?? 0.7,
|
|
357
|
-
// (0..1) the cornea's clear coat strength (1 = the default; see the header: bear 0.2)
|
|
358
|
-
cornea: look.cornea ?? 1,
|
|
359
|
-
// (0..) scale of the eyeball's environment specular (1 = the default; see the header: bear 0.2). It multiplies
|
|
360
|
-
// whatever glaze / lidFur leave of it, so the options compose
|
|
361
|
-
envSpecular: look.envSpecular ?? 1,
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function applyLook(eyes, shared, look) {
|
|
366
|
-
const L = resolveLook(look);
|
|
367
|
-
shared.uIrisIn.value.setRGB(...L.iris.inner);
|
|
368
|
-
shared.uIrisMid.value.setRGB(...L.iris.mid);
|
|
369
|
-
shared.uIrisHi.value.setRGB(...L.iris.hi);
|
|
370
|
-
shared.uIrisOut.value.setRGB(...L.iris.outer);
|
|
371
|
-
const sc = L.sclera.visible ? L.sclera.color : L.sclera.color.map((c) => c * 0.6);
|
|
372
|
-
shared.uSclera.value.setRGB(...sc);
|
|
373
|
-
shared.uLidColor.value.setRGB(...L.lidColor);
|
|
374
|
-
shared.uRimShade.value = L.shade.rim;
|
|
375
|
-
shared.uLidShade.value = L.shade.lid;
|
|
376
|
-
shared.uLimbus.value = L.limbus;
|
|
377
|
-
shared.uLidSpec.value = L.lidSpec;
|
|
378
|
-
shared.uLidFur.value = L.lidFur;
|
|
379
|
-
shared.uGlaze.value = L.glaze;
|
|
380
|
-
shared.uAmbient.value = L.ambient;
|
|
381
|
-
shared.uLidHair.value = L.lidHair;
|
|
382
|
-
shared.uIrisLight.value = L.irisLight;
|
|
383
|
-
shared.uEyeFill.value = L.fill;
|
|
384
|
-
shared.uLidFlat.value = L.lidFlat;
|
|
385
|
-
shared.uLidSeam.value = L.lidSeam;
|
|
386
|
-
shared.uLidClump.value = L.lidClump;
|
|
387
|
-
shared.uLidFill.value = L.lidFill;
|
|
388
|
-
shared.uIrisTex.value = L.irisTexture;
|
|
389
|
-
shared.uLidMeet.value = L.lidMeet;
|
|
390
|
-
shared.uEnvSpec.value = L.envSpecular;
|
|
391
|
-
for (const e of eyes) {
|
|
392
|
-
const m = e.material;
|
|
393
|
-
m.defines = { PUPIL_TYPE: PUPIL[L.pupil], LID_TYPE: LIDS[L.lids], LID_ARC: L.lidArc ? 1 : 0 };
|
|
394
|
-
m.roughness = L.lids === 'simple' ? 0.25 : 0.6;
|
|
395
|
-
m.clearcoatRoughness = L.lids === 'none' || L.lids === 'simple' ? 0.02 : 0.03;
|
|
396
|
-
m.clearcoat = L.cornea;
|
|
397
|
-
m.needsUpdate = true;
|
|
398
|
-
}
|
|
399
|
-
return L;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export function createEyes(eyeData) {
|
|
403
|
-
eyeData = eyeData || [];
|
|
404
|
-
const shared = {
|
|
405
|
-
uPupil: { value: 0.36 },
|
|
406
|
-
uBlink: { value: 0 },
|
|
407
|
-
uNict: { value: 0 },
|
|
408
|
-
uLower: { value: 0 },
|
|
409
|
-
uLidColor: { value: new THREE.Color() },
|
|
410
|
-
uIrisIn: { value: new THREE.Color() },
|
|
411
|
-
uIrisMid: { value: new THREE.Color() },
|
|
412
|
-
uIrisHi: { value: new THREE.Color() },
|
|
413
|
-
uIrisOut: { value: new THREE.Color() },
|
|
414
|
-
uSclera: { value: new THREE.Color() },
|
|
415
|
-
uRimShade: { value: 1 },
|
|
416
|
-
uLidShade: { value: 1 },
|
|
417
|
-
uLimbus: { value: 0.2 },
|
|
418
|
-
uLidSpec: { value: 1 },
|
|
419
|
-
uLidFur: { value: 0 },
|
|
420
|
-
uGlaze: { value: 1 },
|
|
421
|
-
uAmbient: { value: 0 },
|
|
422
|
-
uLidHair: { value: 0 },
|
|
423
|
-
uIrisLight: { value: 0 },
|
|
424
|
-
uEyeFill: { value: 0 },
|
|
425
|
-
uLidFlat: { value: 0 },
|
|
426
|
-
uLidSeam: { value: 0 },
|
|
427
|
-
uLidClump: { value: 0 },
|
|
428
|
-
uLidFill: { value: 0 },
|
|
429
|
-
uIrisTex: { value: 1 },
|
|
430
|
-
uLidMeet: { value: 0.7 },
|
|
431
|
-
uEnvSpec: { value: 1 },
|
|
432
|
-
};
|
|
433
|
-
const geos = new Map();
|
|
434
|
-
// 'simple' eyes (spiders: up to eight still domes on one bone) are merged into one mesh built in
|
|
435
|
-
// bind space, so they cost a single draw call
|
|
436
|
-
const L0 = resolveLook(eyeData[0]?.look);
|
|
437
|
-
if (L0.lids === 'simple' && eyeData.length > 1 && eyeData.every((ed) => (ed.bone || 'head') === (eyeData[0].bone || 'head'))) {
|
|
438
|
-
const pos = [], nrm = [], idx = [];
|
|
439
|
-
const m = new THREE.Matrix4(), q = new THREE.Quaternion(), sc = new THREE.Vector3();
|
|
440
|
-
for (const ed of eyeData) {
|
|
441
|
-
const E = ed.spec, g = new THREE.SphereGeometry(E.r, 28, 18);
|
|
442
|
-
g.rotateX(Math.PI / 2);
|
|
443
|
-
const x = new THREE.Vector3(...ed.x), y = new THREE.Vector3(...ed.y), z = new THREE.Vector3(...ed.z);
|
|
444
|
-
q.setFromRotationMatrix(new THREE.Matrix4().makeBasis(x, y, z));
|
|
445
|
-
g.applyMatrix4(m.compose(new THREE.Vector3(...ed.c), q, sc.setScalar(ed.scale || 1)));
|
|
446
|
-
const o = pos.length / 3;
|
|
447
|
-
for (const v of g.attributes.position.array) pos.push(v);
|
|
448
|
-
for (const v of g.attributes.normal.array) nrm.push(v);
|
|
449
|
-
for (const k of g.index.array) idx.push(k + o);
|
|
450
|
-
g.dispose();
|
|
451
|
-
}
|
|
452
|
-
const geo = new THREE.BufferGeometry();
|
|
453
|
-
geo.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3));
|
|
454
|
-
geo.setAttribute('normal', new THREE.Float32BufferAttribute(nrm, 3));
|
|
455
|
-
geo.setIndex(idx);
|
|
456
|
-
geos.set('merged', geo);
|
|
457
|
-
eyeData = [{ ...eyeData[0], c: [0, 0, 0], x: [1, 0, 0], y: [0, 1, 0], z: [0, 0, 1], scale: 1, side: 1, spec: { ...eyeData[0].spec, tilt: 0 }, merged: geo }];
|
|
458
|
-
}
|
|
459
|
-
const eyes = eyeData.map((ed, i) => {
|
|
460
|
-
const E = ed.spec;
|
|
461
|
-
const own = {
|
|
462
|
-
uSocketInv: { value: new THREE.Matrix4() },
|
|
463
|
-
uIrisZ: { value: E.irisZ ?? E.r * 0.6 },
|
|
464
|
-
uIrisR: { value: E.irisR ?? E.r * 0.8 },
|
|
465
|
-
uLensR: { value: E.R ?? E.r * 1.15 },
|
|
466
|
-
uLensD: { value: E.d ?? E.r * 0.7 },
|
|
467
|
-
uLensOff: { value: E.off || 0 },
|
|
468
|
-
uLidTravel: { value: 2 * ((E.R ?? E.r * 1.15) - (E.d ?? E.r * 0.7)) },
|
|
469
|
-
uFront: { value: 1 },
|
|
470
|
-
};
|
|
471
|
-
let geo = ed.merged || geos.get(E.r);
|
|
472
|
-
if (!geo) {
|
|
473
|
-
geo = new THREE.SphereGeometry(E.r, 64, 40);
|
|
474
|
-
geo.rotateX(Math.PI / 2); // pole -> +Z (forward)
|
|
475
|
-
geos.set(E.r, geo);
|
|
476
|
-
}
|
|
477
|
-
const mat = new THREE.MeshPhysicalMaterial({ color: 0xffffff, roughness: 0.6, metalness: 0, clearcoat: 1, clearcoatRoughness: 0.03, specularIntensity: 0.2, envMapIntensity: 0.28 });
|
|
478
|
-
mat.onBeforeCompile = (sh) => {
|
|
479
|
-
Object.assign(sh.uniforms, shared, own);
|
|
480
|
-
sh.vertexShader = sh.vertexShader
|
|
481
|
-
.replace('#include <common>', '#include <common>\nvarying vec3 vEyeObj; varying vec3 vCamObj; varying vec3 vEyeWorld; varying vec3 vIrisN;')
|
|
482
|
-
.replace('#include <begin_vertex>', '#include <begin_vertex>\n vEyeObj = position;\n vEyeWorld = (modelMatrix * vec4(position, 1.0)).xyz;\n vCamObj = (inverse(modelMatrix) * vec4(cameraPosition, 1.0)).xyz;\n vIrisN = normalize(normalMatrix * vec3(0.0, 0.0, 1.0));');
|
|
483
|
-
sh.fragmentShader = sh.fragmentShader
|
|
484
|
-
.replace('#include <common>', '#include <common>\n' + PARS)
|
|
485
|
-
.replace('#include <map_fragment>', MAP)
|
|
486
|
-
.replace('#include <normal_fragment_maps>', NORMALS)
|
|
487
|
-
.replace('#include <lights_physical_pars_fragment>', DIRECT)
|
|
488
|
-
.replace('#include <lights_physical_fragment>', MATERIAL)
|
|
489
|
-
.replace('#include <aomap_fragment>', MOD);
|
|
490
|
-
};
|
|
491
|
-
mat.customProgramCacheKey = () => 'pa-eye-' + (mat.defines ? mat.defines.PUPIL_TYPE + '-' + mat.defines.LID_TYPE + (mat.defines.LID_ARC ? '-arc' : '') : '');
|
|
492
|
-
const e = new THREE.Mesh(geo, mat);
|
|
493
|
-
e.name = 'eye' + i;
|
|
494
|
-
e.matrixAutoUpdate = false;
|
|
495
|
-
e.frustumCulled = false;
|
|
496
|
-
e.receiveShadow = true;
|
|
497
|
-
// bind-space frames: the socket (aperture, tilted) and the eyeball at rest (upright pupil)
|
|
498
|
-
const x = new THREE.Vector3(...ed.x), y = new THREE.Vector3(...ed.y), z = new THREE.Vector3(...ed.z);
|
|
499
|
-
const socketQ = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(x, y, z));
|
|
500
|
-
const ph = (E.tilt || 0) * ed.side;
|
|
501
|
-
const x0 = x.clone().multiplyScalar(Math.cos(ph)).addScaledVector(y, -Math.sin(ph));
|
|
502
|
-
const y0 = x.clone().multiplyScalar(Math.sin(ph)).addScaledVector(y, Math.cos(ph));
|
|
503
|
-
const ballQ = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(x0, y0, z));
|
|
504
|
-
// the front (nasal) corner: +x or -x of the socket frame, whichever points forward
|
|
505
|
-
own.uFront.value = x.z >= 0 ? 1 : -1;
|
|
506
|
-
e.userData = { side: ed.side, bone: ed.bone || 'head', c: new THREE.Vector3(...ed.c), socketQ, ballQ, own, scale: ed.scale || 1, r: E.r };
|
|
507
|
-
return e;
|
|
508
|
-
});
|
|
509
|
-
const look = applyLook(eyes, shared, eyeData[0]?.look);
|
|
510
|
-
return { eyes, uniforms: shared, look, geometries: [...geos.values()] };
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// Places the eyes on their bone every frame and runs saccades, blinks, lids and pupils.
|
|
514
|
-
export class EyeRig {
|
|
515
|
-
constructor(eyes, uniforms, skeleton, look) {
|
|
516
|
-
this.eyes = eyes;
|
|
517
|
-
this.u = uniforms;
|
|
518
|
-
this.sk = skeleton;
|
|
519
|
-
this.setLook(look);
|
|
520
|
-
this.gaze = { yaw: 0, pitch: 0, tYaw: 0, tPitch: 0, next: 0.6, lookYaw: 0, lookPitch: 0 };
|
|
521
|
-
this.blinkWait = 1.5 + Math.random() * 3;
|
|
522
|
-
this.blinkAge = -1;
|
|
523
|
-
this.pendingDouble = false;
|
|
524
|
-
this.pupil = 0.4;
|
|
525
|
-
this.lidState = 0;
|
|
526
|
-
// test / cinematic overrides (null = automatic): blink 0..1, dilation 0..1, pupil size, gaze [yaw, pitch], eyelid 0..1
|
|
527
|
-
this.override = { blink: null, dilation: null, pupil: null, gaze: null, eyelid: null };
|
|
528
|
-
this._light = null; this._lightAge = 1e9;
|
|
529
|
-
this._qb = new THREE.Quaternion(); this._pb = new THREE.Vector3(); this._sb = new THREE.Vector3();
|
|
530
|
-
this._q = new THREE.Quaternion(); this._q2 = new THREE.Quaternion(); this._qe = new THREE.Quaternion();
|
|
531
|
-
this._p = new THREE.Vector3(); this._t = new THREE.Vector3(); this._s = new THREE.Vector3(1, 1, 1);
|
|
532
|
-
this._Y = new THREE.Vector3(0, 1, 0); this._X = new THREE.Vector3(1, 0, 0);
|
|
533
|
-
this._bindQinv = new Map(); this._bindP = new Map();
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
setLook(look) {
|
|
537
|
-
this.look = look;
|
|
538
|
-
this.canBlink = (look.lids === 'mammal' || look.lids === 'bird') && look.blink !== false;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
_boneRel(name) {
|
|
542
|
-
const i = this.sk.index[name] ?? this.sk.index.head ?? 0;
|
|
543
|
-
if (!this._bindQinv.has(i)) {
|
|
544
|
-
const q = new THREE.Quaternion(), p = new THREE.Vector3(), s = new THREE.Vector3();
|
|
545
|
-
this.sk.bind[i].decompose(p, q, s);
|
|
546
|
-
this._bindQinv.set(i, q.invert());
|
|
547
|
-
this._bindP.set(i, p);
|
|
548
|
-
}
|
|
549
|
-
this.sk.bones[i].matrixWorld.decompose(this._pb, this._qb, this._sb);
|
|
550
|
-
this._qb.multiply(this._bindQinv.get(i)); // rigid rotation: world * bind^-1
|
|
551
|
-
this._t.copy(this._bindP.get(i)).applyQuaternion(this._qb).negate().add(this._pb);
|
|
552
|
-
return { q: this._qb, t: this._t };
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// the scene's main directional light (the shadow caster, else the brightest), refreshed now and then
|
|
556
|
-
_mainLight(root, dt) {
|
|
557
|
-
this._lightAge += dt;
|
|
558
|
-
if (root && (this._lightAge > 1 || root !== this._root || (this._light && !this._light.parent))) {
|
|
559
|
-
this._root = root;
|
|
560
|
-
this._lightAge = 0;
|
|
561
|
-
let best = null, score = -1;
|
|
562
|
-
root.traverse((o) => {
|
|
563
|
-
if (!o.isDirectionalLight || !o.visible) return;
|
|
564
|
-
const s = o.intensity * (o.castShadow ? 10 : 1);
|
|
565
|
-
if (s > score) { score = s; best = o; }
|
|
566
|
-
});
|
|
567
|
-
this._light = best;
|
|
568
|
-
}
|
|
569
|
-
return this._light;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
update(dt, { root = null, state = {}, look = null } = {}) {
|
|
573
|
-
const dead = state.action === 'death' || state.dead === true;
|
|
574
|
-
const lid = this.override.eyelid ?? Math.max(state.eyelid || 0, dead ? 0.5 : 0);
|
|
575
|
-
const g = this.gaze;
|
|
576
|
-
// fixations and quick saccades (smaller and rarer at speed, when the gaze locks forward)
|
|
577
|
-
const run = Math.min(1, (state.speed || 0) / 10);
|
|
578
|
-
g.next -= dt;
|
|
579
|
-
if (g.next <= 0 && !dead) {
|
|
580
|
-
g.next = (0.5 + Math.random() * 2.3) * (1 + run * 2);
|
|
581
|
-
g.tYaw = (Math.random() - 0.5) * 0.18 * (1 - 0.7 * run);
|
|
582
|
-
g.tPitch = (Math.random() - 0.5) * 0.08 * (1 - 0.7 * run);
|
|
583
|
-
}
|
|
584
|
-
// the eyes lead the head toward a look target (then recentre as the head catches up)
|
|
585
|
-
let lyaw = 0, lpitch = 0;
|
|
586
|
-
const target = state.lookTarget || look;
|
|
587
|
-
if (target && !dead && this.eyes.length) {
|
|
588
|
-
const e = this.eyes[0], rel = this._boneRel(e.userData.bone);
|
|
589
|
-
let ay = 0, ap = 0;
|
|
590
|
-
for (const ey of this.eyes) {
|
|
591
|
-
const d = ey.userData;
|
|
592
|
-
this._p.copy(d.c).applyQuaternion(rel.q).add(rel.t);
|
|
593
|
-
this._q.copy(rel.q).multiply(d.ballQ).invert();
|
|
594
|
-
const v = this._p.subVectors(target, this._p).applyQuaternion(this._q);
|
|
595
|
-
ay += Math.atan2(v.x, v.z); ap += Math.atan2(v.y, Math.hypot(v.x, v.z));
|
|
596
|
-
}
|
|
597
|
-
const n = this.eyes.length;
|
|
598
|
-
lyaw = THREE.MathUtils.clamp(ay / n, -0.35, 0.35);
|
|
599
|
-
lpitch = THREE.MathUtils.clamp(ap / n, -0.25, 0.25);
|
|
600
|
-
}
|
|
601
|
-
const kl = 1 - Math.exp(-dt / 0.03);
|
|
602
|
-
g.lookYaw += (lyaw - g.lookYaw) * kl;
|
|
603
|
-
g.lookPitch += (lpitch - g.lookPitch) * kl;
|
|
604
|
-
const k = 1 - Math.exp(-dt / 0.022);
|
|
605
|
-
g.yaw += (g.tYaw - g.yaw) * k;
|
|
606
|
-
g.pitch += (g.tPitch - g.pitch) * k;
|
|
607
|
-
// blinks: ~70 ms close, 35 ms hold, 130 ms open; sometimes a double blink. Birds blink with
|
|
608
|
-
// the nictitating membrane (a bit slower sweep).
|
|
609
|
-
let b = 0;
|
|
610
|
-
if (this.canBlink && !dead && lid < 0.95) {
|
|
611
|
-
this.blinkWait -= dt;
|
|
612
|
-
if (this.blinkAge < 0 && this.blinkWait <= 0) {
|
|
613
|
-
this.blinkAge = 0;
|
|
614
|
-
this.pendingDouble = !this.pendingDouble && Math.random() < 0.15;
|
|
615
|
-
this.blinkWait = this.pendingDouble ? 0.1 : 2.5 + Math.random() * 5.5;
|
|
616
|
-
}
|
|
617
|
-
if (this.blinkAge >= 0) {
|
|
618
|
-
this.blinkAge += dt;
|
|
619
|
-
const bird = this.look.lids === 'bird';
|
|
620
|
-
const t = this.blinkAge, c = bird ? 0.09 : 0.07, h = bird ? 0.05 : 0.035, o = bird ? 0.12 : 0.13;
|
|
621
|
-
if (t < c) b = smooth01(t / c);
|
|
622
|
-
else if (t < c + h) b = 1;
|
|
623
|
-
else if (t < c + h + o) b = 1 - smooth01((t - c - h) / o);
|
|
624
|
-
else { b = 0; this.blinkAge = -1; }
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
if (state.nictitate > 0 && this.look.lids === 'bird') b = Math.max(b, state.nictitate);
|
|
628
|
-
if (this.override.blink !== null) b = this.override.blink;
|
|
629
|
-
this.lidState += (lid - this.lidState) * (1 - Math.exp(-dt / 0.15));
|
|
630
|
-
if (dt === 0) this.lidState = lid;
|
|
631
|
-
if (this.look.lids === 'bird') { this.u.uNict.value = b; this.u.uBlink.value = this.lidState; }
|
|
632
|
-
else if (this.look.lids === 'mammal') { this.u.uNict.value = 0; this.u.uBlink.value = Math.max(b, this.lidState); }
|
|
633
|
-
else { this.u.uNict.value = 0; this.u.uBlink.value = 0; }
|
|
634
|
-
// pupil: small in bright sun, wide when the sun is low or the animal is aroused
|
|
635
|
-
let dil = 0.35;
|
|
636
|
-
const L = this._mainLight(root, dt);
|
|
637
|
-
if (L) {
|
|
638
|
-
L.updateMatrixWorld();
|
|
639
|
-
this._p.setFromMatrixPosition(L.matrixWorld);
|
|
640
|
-
if (L.target) { L.target.updateMatrixWorld(); this._p.sub(this._t.setFromMatrixPosition(L.target.matrixWorld)); }
|
|
641
|
-
const elev = this._p.normalize().y;
|
|
642
|
-
this.lightElevation = elev;
|
|
643
|
-
dil = 1 - Math.min(1, Math.max(0, (elev - 0.05) / 0.35));
|
|
644
|
-
dil = dil * 0.85 + 0.15 * (1 - Math.min(1, L.intensity / 3));
|
|
645
|
-
}
|
|
646
|
-
if (state.action === 'attack' || state.speed > 8) dil = Math.min(1, dil + 0.3);
|
|
647
|
-
if (dead) dil = 0.9;
|
|
648
|
-
if (this.override.dilation !== null) dil = this.override.dilation;
|
|
649
|
-
const kp = dt > 0 ? 1 - Math.exp(-dt / 0.4) : 1;
|
|
650
|
-
this.pupil += (dil - this.pupil) * kp;
|
|
651
|
-
const ps = this.look.pupilSize;
|
|
652
|
-
this.u.uPupil.value = this.override.pupil ?? THREE.MathUtils.lerp(ps[0], ps[1], this.pupil);
|
|
653
|
-
// place each eye: socket frame (aperture) and eyeball (rest * gaze)
|
|
654
|
-
const gy = this.override.gaze ? this.override.gaze[0] : g.yaw + g.lookYaw;
|
|
655
|
-
let gp = this.override.gaze ? this.override.gaze[1] : g.pitch + g.lookPitch;
|
|
656
|
-
// ocular rotation: the eyeball rolls back and down (the white shark protects its eye on the bite)
|
|
657
|
-
const roll = state.eyeRoll || 0;
|
|
658
|
-
if (roll > 0 && !this.override.gaze) gp -= roll * 1.25;
|
|
659
|
-
for (const e of this.eyes) {
|
|
660
|
-
const d = e.userData;
|
|
661
|
-
const rel = this._boneRel(d.bone);
|
|
662
|
-
this._p.copy(d.c).applyQuaternion(rel.q).add(rel.t);
|
|
663
|
-
this._s.setScalar(d.scale);
|
|
664
|
-
this._q.copy(rel.q).multiply(d.socketQ);
|
|
665
|
-
d.own.uSocketInv.value.compose(this._p, this._q, this._s).invert();
|
|
666
|
-
const still = this.look.lids === 'simple';
|
|
667
|
-
this._qe.copy(rel.q).multiply(d.ballQ);
|
|
668
|
-
if (!still) this._qe.multiply(this._q2.setFromAxisAngle(this._Y, gy)).multiply(this._q2.setFromAxisAngle(this._X, -gp));
|
|
669
|
-
e.matrix.compose(this._p, this._qe, this._s);
|
|
670
|
-
e.matrixWorld.copy(e.matrix);
|
|
671
|
-
if (e.parent) e.matrixWorld.premultiply(e.parent.matrixWorld);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
export { applyLook as setEyeLook };
|