reze-engine 0.68.3 → 0.68.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.
Files changed (55) hide show
  1. package/dist/_dbg-loader.mjs +1100 -0
  2. package/dist/engine.d.ts +40 -2
  3. package/dist/engine.d.ts.map +1 -1
  4. package/dist/engine.js +119 -8
  5. package/dist/graph/slots.d.ts.map +1 -1
  6. package/dist/graph/slots.js +12 -4
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/jelly-eyes.d.ts +37 -0
  10. package/dist/jelly-eyes.d.ts.map +1 -0
  11. package/dist/jelly-eyes.js +381 -0
  12. package/dist/shaders/materials/common.d.ts.map +1 -1
  13. package/dist/shaders/materials/common.js +133 -2
  14. package/package.json +1 -1
  15. package/src/engine.ts +121 -8
  16. package/src/graph/slots.ts +13 -4
  17. package/src/index.ts +1 -0
  18. package/src/jelly-eyes.ts +434 -0
  19. package/src/shaders/materials/common.ts +133 -2
  20. package/dist/graph/presets/pool_floor.d.ts +0 -3
  21. package/dist/graph/presets/pool_floor.d.ts.map +0 -1
  22. package/dist/graph/presets/pool_floor.js +0 -42
  23. package/dist/graph/presets/water.d.ts +0 -3
  24. package/dist/graph/presets/water.d.ts.map +0 -1
  25. package/dist/graph/presets/water.js +0 -31
  26. package/dist/physics/autofit.d.ts +0 -147
  27. package/dist/physics/autofit.d.ts.map +0 -1
  28. package/dist/physics/autofit.js +0 -501
  29. package/dist/shaders/agx-lut.d.ts +0 -11
  30. package/dist/shaders/agx-lut.d.ts.map +0 -1
  31. package/dist/shaders/agx-lut.js +0 -29
  32. package/dist/shaders/dfg_lut.d.ts +0 -3
  33. package/dist/shaders/dfg_lut.d.ts.map +0 -1
  34. package/dist/shaders/dfg_lut.js +0 -129
  35. package/dist/shaders/ltc_mag_lut.d.ts +0 -3
  36. package/dist/shaders/ltc_mag_lut.d.ts.map +0 -1
  37. package/dist/shaders/ltc_mag_lut.js +0 -1033
  38. package/dist/shaders/passes/field-blit.d.ts +0 -26
  39. package/dist/shaders/passes/field-blit.d.ts.map +0 -1
  40. package/dist/shaders/passes/field-blit.js +0 -65
  41. package/dist/shaders/passes/ghosts.d.ts +0 -22
  42. package/dist/shaders/passes/ghosts.d.ts.map +0 -1
  43. package/dist/shaders/passes/ghosts.js +0 -75
  44. package/dist/shaders/passes/ground-noise.d.ts +0 -7
  45. package/dist/shaders/passes/ground-noise.d.ts.map +0 -1
  46. package/dist/shaders/passes/ground-noise.js +0 -88
  47. package/dist/shaders/passes/sim.d.ts +0 -34
  48. package/dist/shaders/passes/sim.d.ts.map +0 -1
  49. package/dist/shaders/passes/sim.js +0 -169
  50. package/dist/shaders/score-api.d.ts +0 -10
  51. package/dist/shaders/score-api.d.ts.map +0 -1
  52. package/dist/shaders/score-api.js +0 -114
  53. package/dist/shaders/shadow-api.d.ts +0 -29
  54. package/dist/shaders/shadow-api.d.ts.map +0 -1
  55. package/dist/shaders/shadow-api.js +0 -112
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,qBAAqB,EACrB,8BAA8B,EAC9B,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,uBAAuB,EACvB,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,QAAQ,GACd,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACvG,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAIzC,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE/C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAIrH,OAAO,EAAE,gBAAgB,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAIhF,OAAO,EACL,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AACnE,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,WAAW,EACX,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC9H,YAAY,EACV,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAInD,OAAO,EACL,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,KAAK,EACL,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAA;AACrE,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,qBAAqB,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC5H,OAAO,EACL,GAAG,EACH,iBAAiB,EACjB,wBAAwB,EACxB,mCAAmC,GACpC,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,4BAA4B,EAAE,KAAK,cAAc,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AACzG,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAGxC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,QAAQ,GACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAI3F,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,IAAI,EACT,KAAK,SAAS,GACf,MAAM,WAAW,CAAA;AAElB;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AACnF,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD;;;;GAIG;AACH,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAC1E,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAClF,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { Model } from "./model";
2
+ export interface JellyEyeOptions {
3
+ /** How much the eyes give: 0 still, 1 the intended bounce, up to 2. Default 1. */
4
+ strength?: number;
5
+ /** The idle taps: a small bounce every few seconds while nothing else moves them.
6
+ * Default true; false leaves only what her blinks and motion set off. */
7
+ idle?: boolean;
8
+ }
9
+ export declare class JellyEyes {
10
+ strength: number;
11
+ idle: boolean;
12
+ private clock;
13
+ private taps;
14
+ private nextTap;
15
+ private readonly rest;
16
+ private readonly state;
17
+ private readonly morphs;
18
+ private readonly eyeBones;
19
+ private readonly headBone;
20
+ private fresh;
21
+ private readonly inertia;
22
+ constructor(model: Model, options: JellyEyeOptions);
23
+ /** Advance both springs by dt seconds of scene time. */
24
+ step(dt: number, model: Model): void;
25
+ /** Write jelly[0..5] into an ObjectLight copy (floats 48..71). */
26
+ write(o: Float32Array): void;
27
+ /** Where the iris sits off rest, in iris radii (right, up): the lag through
28
+ * the eye's lever, plus the inertia. */
29
+ private offset;
30
+ /** The mass on the head: semi-implicit steps toward where the head is, the
31
+ * head moving linearly across the frame. */
32
+ private stepInertia;
33
+ }
34
+ /** Zero jelly[0..5] — strength 0 is what the shader reads as off. */
35
+ export declare function clearJellyEyes(o: Float32Array): void;
36
+ export declare function clampStrength(s: number | undefined): number;
37
+ //# sourceMappingURL=jelly-eyes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jelly-eyes.d.ts","sourceRoot":"","sources":["../src/jelly-eyes.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;8EAC0E;IAC1E,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AA0HD,qBAAa,SAAS;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;IAEb,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,IAAI,CAAI;IAChB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiD;IACvE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;gBAEvF,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe;IAgBlD,wDAAwD;IACxD,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAgEpC,kEAAkE;IAClE,KAAK,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;IAe5B;6CACyC;IACzC,OAAO,CAAC,MAAM;IAad;iDAC6C;IAC7C,OAAO,CAAC,WAAW;CAkCpB;AAED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D"}
@@ -0,0 +1,381 @@
1
+ // Jelly eyes — the MMD 果冻眼 / Live2D highlight wobble, for any PMX.
2
+ //
3
+ // What every working version of the effect has in common, whether it is keyed
4
+ // by hand in MMD, a pendulum in Live2D, or a jiggle bone in Blender: an INPUT
5
+ // (a blink, a turn), something that REMEMBERS the last frame (a spring), and a
6
+ // cheap OUTPUT. Here the output is the iris's SCALE, in place: it shrinks and
7
+ // springs back as a lid moves (opening too), swells as her head turns or moves, and
8
+ // wobbles back. It never slides — tried, it read as the iris coming loose. The
9
+ // inputs are her blinks and her head, never her eyes' own turn: eye tracking
10
+ // turns the eyes after the camera, and the camera must not shake the jelly.
11
+ //
12
+ // The springs run on the CPU, stepped by the engine's frame delta — the same
13
+ // exact delta renderFrame() hands an export, so a blink bounces identically on
14
+ // screen and in the file. Their state rides in the model's ObjectLight
15
+ // (jelly[0..5], see materials/common.ts): the vertex shader scales the iris —
16
+ // the vertices the eye bones carry — about its centre, and the eye render class
17
+ // adds the gem look after its graph (glints, light through the iris, deeper
18
+ // colour), so every eye graph becomes jelly without knowing it.
19
+ // The closing morphs, by the names MMD, VRoid and the usual converters give
20
+ // them. Group morphs (a smile that closes the eyes) resolve into these through
21
+ // the effective weights, so only the leaves need naming.
22
+ const BOTH = ["まばたき", "笑い", "はぅ", "blink", "Blink", "eye_close", "Fcl_EYE_Close"];
23
+ const LEFT = ["ウィンク", "ウィンク2", "ウィンク", "ウィンク2", "wink", "Wink", "blink_L", "Fcl_EYE_Close_L"];
24
+ const RIGHT = ["ウィンク右", "ウィンク2右", "ウィンク右", "ウィンク2右", "wink_R", "Wink_R", "blink_R", "Fcl_EYE_Close_R"];
25
+ // The squash: how far a closed eye presses the picture, and the spring that
26
+ // follows it — lightly damped, so one knock ripples: the squash, a rebound past
27
+ // rest, and several smaller wobbles before it settles. One dip and done read as
28
+ // a scale, not a jelly; the ripple is the "Duang" the effect is named for.
29
+ // Only a CHANGE of closure squashes: the eye's closure less a slow follower of
30
+ // it, so a blink squeezes then bounces, while a held half-close (a smile)
31
+ // leaves the iris at rest instead of squashed for as long as she smiles.
32
+ const SQUASH_CLOSED = 0.35;
33
+ const SQUASH_HZ = 1.8;
34
+ const SQUASH_ZETA = 0.08;
35
+ const CLOSURE_FOLLOW_S = 0.35;
36
+ // The lag: the picture trails the eye's turn and catches up past it. Radians of
37
+ // lag to eye radii of offset; the head's own turn counts for a third, so a
38
+ // sudden stop of the head wobbles the eyes without a dance keeping them
39
+ // sloshing.
40
+ const LAG_HZ = 3.5;
41
+ const LAG_ZETA = 0.4;
42
+ // The lag is an angle: how far the iris trails the eye's own turn, as a share
43
+ // of the lag in look, capped at a quarter of eye tracking's default 20° reach —
44
+ // a wobble on the turn, never a second turn. It becomes iris radii through the
45
+ // eye's own lever (iris centre to eye bone), the same displacement a real turn
46
+ // of that angle gives, so it scales with whatever the rig's eyes do.
47
+ const LAG_GAIN = 0.5;
48
+ const LAG_MAX = (3 * Math.PI) / 180;
49
+ // And never past this many iris radii, whatever the lever, at strength 1.
50
+ const OFFSET_MAX = 0.2;
51
+ const HEAD_SHARE = 0.35;
52
+ // The inertia: the iris has a little mass, hung on a spring from the head, so
53
+ // her own motion — a bob, a step, a sway of the dance — leaves it behind and
54
+ // it swings back. Model units of lag to iris radii, scaled by INERTIA_GAIN.
55
+ const INERTIA_HZ = 3.0;
56
+ const INERTIA_ZETA = 0.4;
57
+ const INERTIA_GAIN = 0.04;
58
+ // The jelly's give: the iris never moves, it swells. The lag and the inertia
59
+ // are how hard it is being knocked (in iris radii, as if it could move); that
60
+ // knock grows it a little and it ripples back, as the squash does — the bounce on top
61
+ // of the blink's squash. Eased, not linear: the swell is PULSE_MAX·tanh(knock /
62
+ // PULSE_REF), so the small steady knocks of a dance still show while a jolt
63
+ // (play from a pause: the head going from still to moving at once) cannot
64
+ // swell it past the cap.
65
+ const PULSE_MAX = 0.07;
66
+ const PULSE_REF = 0.006;
67
+ // And the same knock squashes it as a blink does — nearly round, on
68
+ // the blink's spring — so her motion reads as plainly as a blink. Eased by the
69
+ // same curve, up to MOTION_SQUASH (a blink's opening gives about 0.2).
70
+ const MOTION_SQUASH = 0.18;
71
+ const PULSE_HZ = 2.0;
72
+ const PULSE_ZETA = 0.08;
73
+ // The idle taps: every few seconds, at uneven times, a small knock into the
74
+ // same springs her motion drives — the iris dips, bounces and settles, then
75
+ // rests — the way a jelly on a table is never quite still. A steady sine was
76
+ // tried, as size (a zoom) and as wider-then-taller (queasy); a settling tap is
77
+ // what reads as jelly. Velocity kicks, so the bounce keeps the springs' own
78
+ // timing; the gaps come from a hash of the tap's count, so the scene clock
79
+ // alone decides them and an export taps where the screen did.
80
+ const IDLE_SQUASH_KICK = 0.45;
81
+ const IDLE_PULSE_KICK = 0.25;
82
+ const IDLE_GAP = [1.8, 3.8];
83
+ const idleGap = (n) => {
84
+ const x = Math.sin(n * 12.9898 + 78.233) * 43758.5453;
85
+ return IDLE_GAP[0] + (x - Math.floor(x)) * (IDLE_GAP[1] - IDLE_GAP[0]);
86
+ };
87
+ // Integration step, and the jump past which a delta is a seek, not time.
88
+ const SUBSTEP = 1 / 240;
89
+ const SEEK = 0.25;
90
+ const newState = () => ({
91
+ closure: 0,
92
+ settled: 0,
93
+ squash: 0,
94
+ squashV: 0,
95
+ lag: [0, 0],
96
+ lagV: [0, 0],
97
+ look: [0, 0],
98
+ shine: 0,
99
+ pulse: 0,
100
+ pulseV: 0,
101
+ });
102
+ export class JellyEyes {
103
+ constructor(model, options) {
104
+ // Scene time stepped so far, and the idle taps: how many, and when the next.
105
+ this.clock = 0;
106
+ this.taps = 0;
107
+ this.nextTap = idleGap(0);
108
+ this.state = [newState(), newState()];
109
+ this.fresh = true;
110
+ this.inertia = { p: [0, 0, 0], v: [0, 0, 0], head: [0, 0, 0], offset: [0, 0] };
111
+ this.strength = clampStrength(options.strength);
112
+ this.idle = options.idle ?? true;
113
+ const bones = model.getSkeleton().bones;
114
+ const index = (name) => bones.findIndex((b) => b.name === name);
115
+ const both = index("両目");
116
+ const l = index("左目");
117
+ const r = index("右目");
118
+ this.eyeBones = [l >= 0 ? l : both, r >= 0 ? r : both];
119
+ this.headBone = index("頭");
120
+ const names = model.getMorphing().morphs.map((m) => m.name);
121
+ const find = (list) => list.map((n) => names.indexOf(n)).filter((i) => i >= 0);
122
+ this.morphs = [find(BOTH), find(LEFT), find(RIGHT)];
123
+ this.rest = findIrises(model, l, r, both);
124
+ }
125
+ /** Advance both springs by dt seconds of scene time. */
126
+ step(dt, model) {
127
+ const weights = model.getEffectiveMorphWeights();
128
+ const sum = (list) => list.reduce((s, i) => s + (weights[i] ?? 0), 0);
129
+ const both = sum(this.morphs[0]);
130
+ const closure = [Math.min(1, both + sum(this.morphs[1])), Math.min(1, both + sum(this.morphs[2]))];
131
+ const head = this.headBone >= 0 ? model.getBoneWorldMatrixAt(this.headBone) : null;
132
+ const seek = this.fresh || dt > SEEK || dt < 0;
133
+ if (dt > 0)
134
+ this.clock += dt;
135
+ let tap = false;
136
+ if (!seek && this.idle && this.clock >= this.nextTap) {
137
+ tap = true;
138
+ this.taps++;
139
+ this.nextTap = this.clock + idleGap(this.taps);
140
+ }
141
+ this.stepInertia(dt, head, seek);
142
+ for (let e = 0; e < 2; e++) {
143
+ const s = this.state[e];
144
+ s.closure = closure[e];
145
+ // Her HEAD's turn, not her eyes': eye tracking turns the eyes after the
146
+ // camera, so the eyes' own turn would make the camera shake the jelly.
147
+ // Only her motion — the head turning and moving (the inertia) — and her
148
+ // blinks do.
149
+ look(head, null, s.look);
150
+ if (seek)
151
+ s.settled = s.closure;
152
+ else
153
+ s.settled += (s.closure - s.settled) * Math.min(1, dt / CLOSURE_FOLLOW_S);
154
+ // Either way a lid moves squashes — opening too, which is the half of a
155
+ // blink you can see (closing, the lid hides the iris anyway).
156
+ const knock = seek ? 0 : Math.tanh(Math.hypot(...this.offset(s, e)) / PULSE_REF);
157
+ const squashTarget = SQUASH_CLOSED * Math.abs(s.closure - s.settled) + MOTION_SQUASH * knock;
158
+ if (seek) {
159
+ s.squash = squashTarget;
160
+ s.squashV = 0;
161
+ s.lag[0] = s.look[0];
162
+ s.lag[1] = s.look[1];
163
+ s.lagV[0] = s.lagV[1] = 0;
164
+ s.shine = 0;
165
+ s.pulse = s.pulseV = 0;
166
+ continue;
167
+ }
168
+ if (tap) {
169
+ s.squashV += IDLE_SQUASH_KICK;
170
+ s.pulseV -= IDLE_PULSE_KICK;
171
+ }
172
+ const steps = Math.ceil(dt / SUBSTEP);
173
+ const h = steps > 0 ? dt / steps : 0;
174
+ const pulseTarget = PULSE_MAX * knock;
175
+ for (let i = 0; i < steps; i++) {
176
+ s.pulseV += h * spring(s.pulse - pulseTarget, s.pulseV, PULSE_HZ, PULSE_ZETA);
177
+ s.pulse += h * s.pulseV;
178
+ s.squashV += h * spring(s.squash - squashTarget, s.squashV, SQUASH_HZ, SQUASH_ZETA);
179
+ s.squash += h * s.squashV;
180
+ for (let k = 0; k < 2; k++) {
181
+ s.lagV[k] += h * spring(s.lag[k] - s.look[k], s.lagV[k], LAG_HZ, LAG_ZETA);
182
+ s.lag[k] += h * s.lagV[k];
183
+ }
184
+ }
185
+ // Shine follows the motion: bright while the jelly moves, fading as it
186
+ // settles, eased so a single wobble does not strobe.
187
+ const motion = Math.min(1, 2.5 * Math.abs(s.squash - squashTarget) + 4 * Math.hypot(...this.offset(s, e)));
188
+ s.shine += (motion - s.shine) * Math.min(1, dt * 12);
189
+ }
190
+ this.fresh = false;
191
+ }
192
+ /** Write jelly[0..5] into an ObjectLight copy (floats 48..71). */
193
+ write(o) {
194
+ const [L, R] = this.rest;
195
+ o.set([L.centre[0], L.centre[1], L.centre[2], this.strength], 48);
196
+ // One scale bounce for both: the mean of the two eyes', so they swell together.
197
+ const pulse = ((this.state[0].pulse + this.state[1].pulse) / 2) * this.strength;
198
+ o.set([R.centre[0], R.centre[1], R.centre[2], pulse], 52);
199
+ for (let e = 0; e < 2; e++) {
200
+ const s = this.state[e];
201
+ const rest = this.rest[e];
202
+ o.set([rest.radius[0], rest.radius[1], s.closure, this.eyeBones[e]], 56 + e * 4);
203
+ // Offset words (65, 66) stay 0: the iris holds its place; only scale.
204
+ o.set([s.squash * this.strength, 0, 0, s.shine], 64 + e * 4);
205
+ }
206
+ }
207
+ /** Where the iris sits off rest, in iris radii (right, up): the lag through
208
+ * the eye's lever, plus the inertia. */
209
+ offset(s, e) {
210
+ const angle = (x) => Math.max(-LAG_MAX, Math.min(LAG_MAX, x * LAG_GAIN));
211
+ const rest = this.rest[e];
212
+ const r = (rest.radius[0] + rest.radius[1]) / 2;
213
+ const per = rest.lever / r;
214
+ const io = this.inertia.offset;
215
+ const x = angle(s.lag[0] - s.look[0]) * per + io[0];
216
+ const y = angle(s.lag[1] - s.look[1]) * per + io[1];
217
+ const n = Math.hypot(x, y);
218
+ const cap = n > OFFSET_MAX ? OFFSET_MAX / n : 1;
219
+ return [x * cap, y * cap];
220
+ }
221
+ /** The mass on the head: semi-implicit steps toward where the head is, the
222
+ * head moving linearly across the frame. */
223
+ stepInertia(dt, head, seek) {
224
+ const m = this.inertia;
225
+ if (!head) {
226
+ m.offset[0] = m.offset[1] = 0;
227
+ return;
228
+ }
229
+ const now = [head[12], head[13], head[14]];
230
+ if (seek) {
231
+ m.p = [...now];
232
+ m.v = [0, 0, 0];
233
+ m.head = [...now];
234
+ m.offset[0] = m.offset[1] = 0;
235
+ return;
236
+ }
237
+ const hv = [0, 1, 2].map((k) => (dt > 0 ? (now[k] - m.head[k]) / dt : 0));
238
+ const steps = Math.ceil(dt / SUBSTEP);
239
+ const h = steps > 0 ? dt / steps : 0;
240
+ for (let i = 1; i <= steps; i++) {
241
+ const t = i / steps;
242
+ for (let k = 0; k < 3; k++) {
243
+ const at = m.head[k] + (now[k] - m.head[k]) * t;
244
+ m.v[k] += h * spring(m.p[k] - at, m.v[k] - hv[k], INERTIA_HZ, INERTIA_ZETA);
245
+ m.p[k] += h * m.v[k];
246
+ }
247
+ }
248
+ m.head = now;
249
+ const u = [m.p[0] - now[0], m.p[1] - now[1], m.p[2] - now[2]];
250
+ const right = [head[0], head[1], head[2]];
251
+ const up = [head[4], head[5], head[6]];
252
+ const size = Math.max(1e-3, (this.rest[0].radius[0] + this.rest[0].radius[1] + this.rest[1].radius[0] + this.rest[1].radius[1]) / 4);
253
+ const cap = (x) => Math.max(-OFFSET_MAX, Math.min(OFFSET_MAX, x));
254
+ m.offset[0] = cap((dot(u, right) / Math.hypot(...right) / size) * INERTIA_GAIN);
255
+ m.offset[1] = cap((dot(u, up) / Math.hypot(...up) / size) * INERTIA_GAIN);
256
+ }
257
+ }
258
+ /** Zero jelly[0..5] — strength 0 is what the shader reads as off. */
259
+ export function clearJellyEyes(o) {
260
+ o.fill(0, 48, 72);
261
+ }
262
+ export function clampStrength(s) {
263
+ return Math.max(0, Math.min(2, s ?? 1));
264
+ }
265
+ /** Acceleration of a damped spring at displacement x, velocity v. */
266
+ function spring(x, v, hz, zeta) {
267
+ const w = 2 * Math.PI * hz;
268
+ return -w * w * x - 2 * zeta * w * v;
269
+ }
270
+ /**
271
+ * Where an eye looks, as (yaw, pitch) radians: the eye in the head's frame,
272
+ * plus a share of the head in the model's. Bone matrices are column-major and
273
+ * MMD rests facing −Z, so forward is the negated third column.
274
+ */
275
+ function look(eye, head, out) {
276
+ out[0] = out[1] = 0;
277
+ if (!eye)
278
+ return;
279
+ const f = [-eye[8], -eye[9], -eye[10]];
280
+ if (head && head !== eye) {
281
+ const right = [head[0], head[1], head[2]];
282
+ const up = [head[4], head[5], head[6]];
283
+ const hf = [-head[8], -head[9], -head[10]];
284
+ const fz = dot(f, hf);
285
+ out[0] = Math.atan2(dot(f, right), fz);
286
+ out[1] = Math.atan2(dot(f, up), fz);
287
+ out[0] += HEAD_SHARE * Math.atan2(hf[0], -hf[2]);
288
+ out[1] += HEAD_SHARE * Math.asin(Math.max(-1, Math.min(1, hf[1] / Math.hypot(hf[0], hf[1], hf[2]))));
289
+ }
290
+ else {
291
+ // Yaw positive toward +X, as in the head-frame branch: the shader warps
292
+ // along bind-space +X, so the two must agree.
293
+ out[0] = Math.atan2(f[0], -f[2]);
294
+ out[1] = Math.asin(Math.max(-1, Math.min(1, f[1] / Math.hypot(f[0], f[1], f[2]))));
295
+ }
296
+ }
297
+ const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
298
+ /**
299
+ * Each iris in bind space: the vertices the eye bones carry are exactly the
300
+ * part of the eye that turns to look — the iris and pupil — so their centroid
301
+ * is its centre and their spread its size. A rig that carries both eyes on
302
+ * 両目 alone is split by side. With no carried vertices at all, the eye bones'
303
+ * own heads stand in, sized from how far apart they are.
304
+ */
305
+ function findIrises(model, l, r, both) {
306
+ const bones = model.getSkeleton().bones;
307
+ const head = (i) => {
308
+ if (i < 0)
309
+ return null;
310
+ const p = [0, 0, 0];
311
+ for (let b = i; b >= 0; b = bones[b].parentIndex) {
312
+ p[0] += bones[b].bindTranslation[0];
313
+ p[1] += bones[b].bindTranslation[1];
314
+ p[2] += bones[b].bindTranslation[2];
315
+ }
316
+ return p;
317
+ };
318
+ const lHead = head(l);
319
+ const rHead = head(r);
320
+ // +X is the model's left; trust the bones when they say otherwise.
321
+ const leftSign = lHead && rHead ? Math.sign(lHead[0] - rHead[0]) || 1 : 1;
322
+ const { positions } = model.getGeometry();
323
+ const { joints, weights } = model.getSkinning();
324
+ const sets = [[], []];
325
+ const n = positions.length / 3;
326
+ for (let v = 0; v < n; v++) {
327
+ let wl = 0;
328
+ let wr = 0;
329
+ let wb = 0;
330
+ for (let k = 0; k < 4; k++) {
331
+ const j = joints[v * 4 + k];
332
+ const w = weights[v * 4 + k];
333
+ if (j === l)
334
+ wl += w;
335
+ else if (j === r)
336
+ wr += w;
337
+ else if (j === both)
338
+ wb += w;
339
+ }
340
+ if (wl >= 128)
341
+ sets[0].push(v);
342
+ else if (wr >= 128)
343
+ sets[1].push(v);
344
+ else if (wb >= 128)
345
+ sets[Math.sign(positions[v * 3]) === leftSign ? 0 : 1].push(v);
346
+ }
347
+ const apart = lHead && rHead ? Math.hypot(lHead[0] - rHead[0], lHead[1] - rHead[1]) : 0;
348
+ const fallbackRadius = apart > 0 ? apart * 0.22 : 0.3;
349
+ const rest = (set, bone, side) => {
350
+ if (set.length < 3) {
351
+ const c = bone ?? [side * fallbackRadius * 2, 0, 0];
352
+ return { centre: c, radius: [fallbackRadius, fallbackRadius], lever: fallbackRadius * 2 };
353
+ }
354
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity, z = 0;
355
+ for (const v of set) {
356
+ const x = positions[v * 3];
357
+ const y = positions[v * 3 + 1];
358
+ minX = Math.min(minX, x);
359
+ maxX = Math.max(maxX, x);
360
+ minY = Math.min(minY, y);
361
+ maxY = Math.max(maxY, y);
362
+ z += positions[v * 3 + 2];
363
+ }
364
+ // A carried set wider than the gap between the eyes is not an iris (a
365
+ // whole-face rig weighted to the eye bone): fall back rather than wobble
366
+ // half the face.
367
+ const rx = (maxX - minX) / 2;
368
+ const ry = (maxY - minY) / 2;
369
+ if (apart > 0 && (rx > apart * 0.6 || ry > apart * 0.8)) {
370
+ return { centre: bone ?? [side * fallbackRadius * 2, 0, 0], radius: [fallbackRadius, fallbackRadius], lever: fallbackRadius * 2 };
371
+ }
372
+ const centre = [(minX + maxX) / 2, (minY + maxY) / 2, z / set.length];
373
+ const radius = [Math.max(rx, 1e-3), Math.max(ry, 1e-3)];
374
+ // An eye bone sitting on the iris itself would give no lever; such a rig
375
+ // still turns its eyes visibly, so read it as a typical eyeball's.
376
+ const r = (radius[0] + radius[1]) / 2;
377
+ const lever = Math.max(bone ? Math.hypot(centre[0] - bone[0], centre[1] - bone[1], centre[2] - bone[2]) : 0, r * 1.5);
378
+ return { centre, radius, lever };
379
+ };
380
+ return [rest(sets[0], lHead, leftSign), rest(sets[1], rHead, -leftSign)];
381
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/shaders/materials/common.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,oBAAoB,QAgPhC,CAAC;AAuHF,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAGD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa,orMAgHzB,CAAA;AAQD,eAAO,MAAM,4BAA4B,QAC6H,CAAA"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/shaders/materials/common.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,oBAAoB,QAkXhC,CAAC;AAwHF,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAGD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa,orMAgHzB,CAAA;AAQD,eAAO,MAAM,4BAA4B,QAC6H,CAAA"}
@@ -213,9 +213,139 @@ fn _rzCastShadow(wp: vec3f) -> f32 {
213
213
  // sh that ambient's irradiance, folded as the world's (ibl.ts);
214
214
  // fill.rgb its fill (Engine.setModelFill), added after its graph times its
215
215
  // surface colour — zero for a model that has none.
216
- struct ObjectLight { layers: vec4u, ambient: vec4f, sh: array<vec4f, 9>, fill: vec4f }
216
+ // jelly its jelly eyes (Engine.setModelJellyEyes, jelly-eyes.ts), not
217
+ // lighting but per-model all the same, so it rides here:
218
+ // [0] left iris centre (bind space), strength — 0 is off
219
+ // [1] right iris centre, scale bounce (both eyes)
220
+ // [2] left iris half extents, closure, eye bone (−1 none)
221
+ // [3] the right's
222
+ // [4] left squash, 0, 0, shine [5] the right's
223
+ struct ObjectLight { layers: vec4u, ambient: vec4f, sh: array<vec4f, 9>, fill: vec4f, jelly: array<vec4f, 6> }
217
224
  @group(1) @binding(1) var<uniform> objectLight: ObjectLight;
218
225
 
226
+ /** What the glints need to know about a fragment of the eye render class. */
227
+ struct RzJelly {
228
+ /** Where in the iris this fragment is, in iris radii. */
229
+ src: vec2f,
230
+ /** 1 inside the iris, easing to 0 at its rim (0 everywhere when off). */
231
+ w: f32,
232
+ closure: f32,
233
+ shine: f32,
234
+ };
235
+
236
+ /**
237
+ * Where the jelly puts an iris vertex. The iris is the part of the eye the eye
238
+ * bones carry, so it is moved as a whole, in bind space before skinning:
239
+ * shrunk about its centre while a lid moves, a little more down than across,
240
+ * grown past rest as it springs back, and swelling as a turn or her motion
241
+ * knocks it — scale only, in place, inside the white, which stays where it is. Vertices take it by
242
+ * their weight on the eye bones (jelly[2].w, jelly[3].w), so nothing else on
243
+ * the face moves.
244
+ */
245
+ fn rzJellyVertex(p: vec3f, joints: vec4<u32>, nw: vec4f) -> vec3f {
246
+ let j = objectLight.jelly;
247
+ var out = p;
248
+ for (var e = 0u; e < 2u; e++) {
249
+ let bone = j[2u + e].w;
250
+ if (bone < 0.0) { continue; }
251
+ let b = u32(bone);
252
+ let w = dot(nw, select(vec4f(0.0), vec4f(1.0), joints == vec4<u32>(b)));
253
+ if (w <= 0.0) { continue; }
254
+ let c = j[e].xyz;
255
+ // A rig that carries both eyes on one bone: each vertex follows its own side.
256
+ if (j[2].w == j[3].w && e == 0u && distance(p.xy, j[1].xy) < distance(p.xy, j[0].xy)) { continue; }
257
+ if (j[2].w == j[3].w && e == 1u && distance(p.xy, j[0].xy) <= distance(p.xy, j[1].xy)) { continue; }
258
+ let st = j[4u + e];
259
+ // The squash, nearly round: it shrinks both ways, a little more down than
260
+ // across, so the iris keeps its circle and only leans oval; and the bounce
261
+ // both eyes share (jelly[1].w). Held under 1.08 so a swell cannot rise
262
+ // past the upper lid.
263
+ let k = clamp(vec2f(1.0 - 0.8 * st.x, 1.0 - st.x) + j[1].w, vec2f(0.78, 0.75), vec2f(1.08, 1.08));
264
+ let moved = c.xy + (p.xy - c.xy) * k;
265
+ out = vec3f(mix(p.xy, moved, w), p.z);
266
+ }
267
+ return out;
268
+ }
269
+
270
+ /**
271
+ * The glints' frame for an eye fragment: its place in the iris in iris radii,
272
+ * from the bind-space position, which the jelly moved the iris with — so the
273
+ * glints ride the sloshing iris. Strength 0 gives w 0, which turns them off.
274
+ */
275
+ fn rzJellyEye(rp: vec3f) -> RzJelly {
276
+ let j = objectLight.jelly;
277
+ let qL = (rp.xy - j[0].xy) / max(j[2].xy, vec2f(1e-4));
278
+ let qR = (rp.xy - j[1].xy) / max(j[3].xy, vec2f(1e-4));
279
+ let right = dot(qR, qR) < dot(qL, qL);
280
+ let a = select(qL, qR, right);
281
+ let st = select(j[4], j[5], right);
282
+ let w = (1.0 - smoothstep(0.85, 1.0, length(a))) * select(0.0, 1.0, j[0].w > 0.0);
283
+ return RzJelly(a, w, select(j[2].z, j[3].z, right), st.w);
284
+ }
285
+
286
+ /**
287
+ * The jelly shine, added after the graph: two hard glints where the light
288
+ * would catch a bead — placed by the half vector in the head's frame, so they
289
+ * hold still while the iris turns under them — and the eye brightening while
290
+ * it wobbles. Flat, cel discs rather than a gradient lobe; HDR, so bloom
291
+ * takes them. Shut eyes catch nothing.
292
+ */
293
+ fn rzJellyGlow(jj: RzJelly, tex: vec3f, alpha: f32, v: vec3f, l: vec3f, sun: vec3f, shadow: f32) -> vec3f {
294
+ let strength = objectLight.jelly[0].w;
295
+ var right = vec3f(1.0, 0.0, 0.0);
296
+ var up = vec3f(0.0, 1.0, 0.0);
297
+ var fwd = vec3f(0.0, 0.0, -1.0);
298
+ if (material.headBoneIndex >= 0.0) {
299
+ let hm = skinMats[u32(material.headBoneIndex)];
300
+ right = normalize(hm[0].xyz);
301
+ up = normalize(hm[1].xyz);
302
+ fwd = -normalize(hm[2].xyz);
303
+ }
304
+ let h = normalize(l + v);
305
+ // Held in the middle and lower iris: the top of an iris sits under the upper
306
+ // lid, and a glint there — or its bloom halo — pokes out over it.
307
+ var g = vec2f(dot(h, right), dot(h, up)) * 0.6;
308
+ g = g * min(1.0, 0.25 / max(length(g), 1e-6)) - vec2f(0.0, 0.1);
309
+ g.y = min(g.y, 0.0);
310
+ let aa = max(length(fwidth(jj.src)), 1e-4);
311
+ let glint = 1.0 - smoothstep(0.16 - aa, 0.16 + aa, distance(jj.src, g));
312
+ let second = 1.0 - smoothstep(0.07 - aa, 0.07 + aa, distance(jj.src, -0.55 * g + vec2f(0.1, -0.12)));
313
+ let facing = saturate(dot(fwd, v) * 2.0);
314
+ let key = clamp(dot(sun, vec3f(0.2126, 0.7152, 0.0722)), 0.3, 2.0);
315
+ let lit = facing * key * (0.35 + 0.65 * shadow);
316
+ // HDR, well past 1, so bloom takes them as the hard sparkle of a gem.
317
+ // Bright enough for bloom to catch, not so bright its halo spreads past the
318
+ // iris onto the lid.
319
+ let glints = (glint + 0.8 * second) * lit * (1.8 + 0.8 * jj.shine);
320
+ // Gone as the lid starts down, not only once shut: a half-closed smile puts
321
+ // the lid right over where the glint sits.
322
+ let open = 1.0 - smoothstep(0.1, 0.45, jj.closure);
323
+ // Only where the eye's own picture is (its alpha), never on the iris's top
324
+ // rim, and gone as the lid comes down.
325
+ let solid = smoothstep(0.5, 0.9, alpha);
326
+ let onEye = solid * (1.0 - smoothstep(0.05, 0.35, jj.src.y));
327
+ // Light through the jelly: the light enters where the glint is and comes out
328
+ // the far side, so the iris glows in its own colour in a crescent opposite
329
+ // the glint — the lit-from-within look of a gem, or a jelly.
330
+ let r = length(jj.src);
331
+ let away = -normalize(g + vec2f(0.0, -1e-3));
332
+ let crescent = smoothstep(0.15, 0.7, dot(jj.src, away)) * (1.0 - smoothstep(0.8, 1.0, r));
333
+ let through = tex * crescent * (2.2 + 1.0 * jj.shine) * lit;
334
+ // And the colour runs deeper: the iris's own hue pushed, never its greys.
335
+ let lum = dot(tex, vec3f(0.2126, 0.7152, 0.0722));
336
+ let vivid = max(tex - vec3f(lum), vec3f(0.0)) * 1.2;
337
+ // The glass over it: a broad soft sheen across the upper iris, under the
338
+ // lid line, the dome of a bead catching the room.
339
+ let dome = (1.0 - smoothstep(0.0, 0.5, distance(jj.src * vec2f(0.8, 1.4), vec2f(0.0, 0.2)))) * 0.45 * lit;
340
+ // The glints keep off the iris's top; the soft light (sheen, glow through,
341
+ // colour) has no halo to spill, so it only needs the eye's own picture.
342
+ let gem = (vec3f(glints) * onEye + (vec3f(dome) + through + vivid) * solid) * open * jj.w;
343
+ // The whole eye shines a little brighter, more while it wobbles — not just
344
+ // the iris, so this one is not held to it (jj.w).
345
+ let lift = tex * (0.25 + 0.35 * jj.shine) * select(0.0, 1.0, strength > 0.0);
346
+ return (gem + lift) * min(strength, 1.0);
347
+ }
348
+
219
349
  /** The light arriving at a surface of this object facing n: its own ambient
220
350
  * where loaded data gave it one (a stage's probes, a character's), else the
221
351
  * world's. The same polynomial rzWorldAmbient evaluates. */
@@ -322,10 +452,11 @@ const COMMON_VS_WGSL = /* wgsl */ `
322
452
  var output: VertexOutput;
323
453
  output.vcolor = vcolor;
324
454
  output.uv2 = uv2;
325
- let pos4 = vec4f(position, 1.0);
326
455
  let weightSum = weights0.x + weights0.y + weights0.z + weights0.w;
327
456
  let invWeightSum = select(1.0, 1.0 / weightSum, weightSum > 0.0001);
328
457
  let nw = select(vec4f(1.0, 0.0, 0.0, 0.0), weights0 * invWeightSum, weightSum > 0.0001);
458
+ var pos4 = vec4f(position, 1.0);
459
+ if (objectLight.jelly[0].w > 0.0) { pos4 = vec4f(rzJellyVertex(position, joints0, nw), 1.0); }
329
460
  var skinnedPos = vec4f(0.0);
330
461
  var skinnedNrm = vec3f(0.0);
331
462
  for (var i = 0u; i < 4u; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.68.3",
3
+ "version": "0.68.5",
4
4
  "description": "A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",