reze-engine 0.68.8 → 0.68.9

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 (59) hide show
  1. package/dist/engine.d.ts +2 -6
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +39 -41
  4. package/dist/graph/presets/pool_floor.d.ts +3 -0
  5. package/dist/graph/presets/pool_floor.d.ts.map +1 -0
  6. package/dist/graph/presets/pool_floor.js +42 -0
  7. package/dist/graph/presets/water.d.ts +3 -0
  8. package/dist/graph/presets/water.d.ts.map +1 -0
  9. package/dist/graph/presets/water.js +31 -0
  10. package/dist/graph/slots.d.ts.map +1 -1
  11. package/dist/graph/slots.js +5 -4
  12. package/dist/jelly-eyes.d.ts.map +1 -1
  13. package/dist/jelly-eyes.js +43 -17
  14. package/dist/physics/autofit.d.ts +147 -0
  15. package/dist/physics/autofit.d.ts.map +1 -0
  16. package/dist/physics/autofit.js +501 -0
  17. package/dist/shaders/agx-lut.d.ts +11 -0
  18. package/dist/shaders/agx-lut.d.ts.map +1 -0
  19. package/dist/shaders/agx-lut.js +29 -0
  20. package/dist/shaders/dfg_lut.d.ts +3 -0
  21. package/dist/shaders/dfg_lut.d.ts.map +1 -0
  22. package/dist/shaders/dfg_lut.js +129 -0
  23. package/dist/shaders/ltc_mag_lut.d.ts +3 -0
  24. package/dist/shaders/ltc_mag_lut.d.ts.map +1 -0
  25. package/dist/shaders/ltc_mag_lut.js +1033 -0
  26. package/dist/shaders/materials/common.d.ts +6 -0
  27. package/dist/shaders/materials/common.d.ts.map +1 -1
  28. package/dist/shaders/materials/common.js +67 -60
  29. package/dist/shaders/passes/depth-prepass.d.ts.map +1 -1
  30. package/dist/shaders/passes/depth-prepass.js +11 -3
  31. package/dist/shaders/passes/field-blit.d.ts +26 -0
  32. package/dist/shaders/passes/field-blit.d.ts.map +1 -0
  33. package/dist/shaders/passes/field-blit.js +65 -0
  34. package/dist/shaders/passes/ghosts.d.ts +22 -0
  35. package/dist/shaders/passes/ghosts.d.ts.map +1 -0
  36. package/dist/shaders/passes/ghosts.js +75 -0
  37. package/dist/shaders/passes/ground-noise.d.ts +7 -0
  38. package/dist/shaders/passes/ground-noise.d.ts.map +1 -0
  39. package/dist/shaders/passes/ground-noise.js +88 -0
  40. package/dist/shaders/passes/shadow.d.ts +1 -1
  41. package/dist/shaders/passes/shadow.d.ts.map +1 -1
  42. package/dist/shaders/passes/shadow.js +11 -3
  43. package/dist/shaders/passes/sim.d.ts +34 -0
  44. package/dist/shaders/passes/sim.d.ts.map +1 -0
  45. package/dist/shaders/passes/sim.js +169 -0
  46. package/dist/shaders/score-api.d.ts +10 -0
  47. package/dist/shaders/score-api.d.ts.map +1 -0
  48. package/dist/shaders/score-api.js +114 -0
  49. package/dist/shaders/shadow-api.d.ts +29 -0
  50. package/dist/shaders/shadow-api.d.ts.map +1 -0
  51. package/dist/shaders/shadow-api.js +112 -0
  52. package/package.json +1 -1
  53. package/src/engine.ts +39 -47
  54. package/src/graph/slots.ts +5 -4
  55. package/src/jelly-eyes.ts +41 -17
  56. package/src/shaders/materials/common.ts +68 -60
  57. package/src/shaders/passes/depth-prepass.ts +11 -3
  58. package/src/shaders/passes/shadow.ts +11 -3
  59. package/dist/_dbg-loader.mjs +0 -1100
@@ -102,13 +102,14 @@ function prelude(renderClass: RenderClass, alphaMode: AlphaMode, blend: StyleBle
102
102
  // camera-averted fragments change (front surfaces have dot(n,v) > 0 and are
103
103
  // untouched), unlike a front_facing test, which PMX's clockwise winding
104
104
  // inverts. Fixes inner skirt linings (裙子白1-style flipped-normal copies)
105
- // shading near-black through sheer outer layers. Eye is exempt: it FRONT-culls
106
- // by design, so its visible fragments are back faces with intended normals.
105
+ // shading near-black through sheer outer layers. Eye is exempt: its normals
106
+ // shade as authored.
107
107
  const flip =
108
108
  renderClass === "eye" ? "" : "\n n = select(-n, n, dot(n, v) >= 0.0);"
109
109
  return `@fragment fn fs(input: VertexOutput) -> FSOut {
110
- ${PLAIN_SAMPLE} // MMD alpha semantics: material alpha × texture alpha.
111
- let alpha = material.alpha * tex_s.a;
110
+ ${PLAIN_SAMPLE} // MMD alpha semantics: material alpha × texture alpha, capped at 1 as MMD
111
+ // does (a PMX can author alpha above 1; blended, it burns the material white).
112
+ let alpha = saturate(material.alpha * tex_s.a);
112
113
  ${discard}
113
114
 
114
115
  // ── Dissolve ──
package/src/jelly-eyes.ts CHANGED
@@ -90,23 +90,23 @@ const HL_SCALE_MIN = 0.85
90
90
  const HL_SCALE_MAX = 1.2
91
91
  // The roll: while a closing expression holds, the iris turns about its eye
92
92
  // bone's X axis (左目/右目, the eyeball's centre), rolling down with the lid —
93
- // the angle at weight 1, and simultaneous expressions add. And it comes
94
- // forward a little (iris radii) with the expression and with the spring, so
95
- // the roll does not sink it into the white. The MME rolls with the lid
96
- // exactly, which the lid hides; here the roll follows on a spring of the same
97
- // pace and decay as the blink's, so as the eye opens the iris swings up past
98
- // rest and wobbles back, where it can be seen.
93
+ // the angle at weight 1, and simultaneous expressions add. It comes forward
94
+ // only with the spring (iris radii): pushed with the expression as well, a
95
+ // shut eye's iris came through a lid set close in front of it (白里黑子). The MME rolls with the lid
96
+ // exactly, which the lid hides; here the roll follows on a spring twice the
97
+ // blink's pace with its decay, so as the eye opens the iris swings up past rest
98
+ // and wobbles back, where it can be seen. At the blink's own pace it trailed
99
+ // the opening lid and swung a third of an iris past centre: a jump.
99
100
  const ROLL: Record<string, number> = {
100
101
  まばたき: -15, blink: -15, Blink: -15, eye_close: -15, Fcl_EYE_Close: -15, はぅ: -15, 笑い: -5,
101
102
  ウィンク: -5, ウィンク: -5, wink: -5, Wink: -5, ウィンク2: -15, ウィンク2: -15, blink_L: -15, Fcl_EYE_Close_L: -15,
102
103
  ウィンク右: -5, ウィンク右: -5, wink_R: -5, Wink_R: -5, ウィンク2右: -15, ウィンク2右: -15, blink_R: -15, Fcl_EYE_Close_R: -15,
103
104
  }
104
- const ROLL_HZ = SPRING_HZ
105
- const ROLL_ZETA = Math.LN2 / HALF_LIFE / (2 * Math.PI * SPRING_HZ)
106
- // How much of the spring's swing about the expression angle shows: the whole
107
- // of it carried the iris up most of its radius after a blink.
108
- const ROLL_SWING = 0.4
109
- const PUSH_EXPRESSION = 0.15
105
+ const ROLL_HZ = 6
106
+ const ROLL_ZETA = Math.LN2 / HALF_LIFE / (2 * Math.PI * ROLL_HZ)
107
+ // How much of the spring's swing about the expression angle shows: a
108
+ // twenty-fifth of an iris radius past centre after a blink.
109
+ const ROLL_SWING = 0.25
110
110
  const PUSH_ELASTIC = 0.04
111
111
  // A highlight sheet by name, for rigs that keep it on its own material.
112
112
  const HIGHLIGHT = /ハイライト|ハイライト|高光|highlight|hilight|(^|[^a-z])hl([^a-z]|$)/i
@@ -288,10 +288,23 @@ export class JellyEyes {
288
288
  const l = index("左目")
289
289
  const r = index("右目")
290
290
  this.headBone = index("頭")
291
- const names = model.getMorphing().morphs.map((m) => m.name)
292
- const find = (list: string[]) => list.map((n) => names.indexOf(n)).filter((i) => i >= 0)
291
+ const all = model.getMorphing().morphs
292
+ const names = all.map((m) => m.name)
293
+ // The weights read are resolved, so a group whose every target is named
294
+ // (Reze's まばたき is ウィンク2 + ウィンク2右) arrives through its
295
+ // leaves; counted as well, a blink rolled the iris twice as far.
296
+ const known = new Set([...BOTH, ...LEFT, ...RIGHT])
297
+ const resolved = (i: number) => {
298
+ const refs = all[i].groupReferences
299
+ return !!refs?.length && refs.every((r) => known.has(names[r.morphIndex]))
300
+ }
301
+ const morphIndex = (n: string) => {
302
+ const i = names.indexOf(n)
303
+ return i >= 0 && !resolved(i) ? i : -1
304
+ }
305
+ const find = (list: string[]) => list.map(morphIndex).filter((i) => i >= 0)
293
306
  this.morphs = [find(BOTH), find(LEFT), find(RIGHT)]
294
- const rolls = (list: string[]) => list.map((n) => ({ morph: names.indexOf(n), deg: ROLL[n] ?? 0 })).filter((r) => r.morph >= 0 && r.deg !== 0)
307
+ const rolls = (list: string[]) => list.map((n) => ({ morph: morphIndex(n), deg: ROLL[n] ?? 0 })).filter((r) => r.morph >= 0 && r.deg !== 0)
295
308
  this.rolls = [rolls([...BOTH, ...LEFT]), rolls([...BOTH, ...RIGHT])]
296
309
  this.rest = findIrises(model, l, r, both)
297
310
  // The bone that carries each iris, which may be under the eye bone.
@@ -423,7 +436,7 @@ export class JellyEyes {
423
436
  const pivot = rest.pivot
424
437
  o.set(pivot ? [pivot[0], pivot[1], pivot[2], (this.roll[e] + (s.roll - this.roll[e]) * ROLL_SWING) * DEG * g] : [0, 0, 0, 0], 80 + e * 4)
425
438
  const hs = (k: 0 | 1) => Math.max(HL_SCALE_MIN, Math.min(HL_SCALE_MAX, 1 + x * HL_SCALE[k] * g))
426
- o.set([hs(0), hs(1), (s.closure * PUSH_EXPRESSION + Math.min(Math.abs(x), SPRING_LIMIT) * PUSH_ELASTIC) * r * g, 0], 88 + e * 4)
439
+ o.set([hs(0), hs(1), Math.min(Math.abs(x), SPRING_LIMIT) * PUSH_ELASTIC * r * g, 0], 88 + e * 4)
427
440
  }
428
441
  }
429
442
 
@@ -550,6 +563,11 @@ function blink(s: EyeState, dt: number): void {
550
563
  * As draw ids (1-based over the materials that draw, as the engine numbers
551
564
  * MaterialUniforms.materialId), at most two. A rig whose highlight is painted
552
565
  * into the iris has none, and only the iris moves.
566
+ *
567
+ * A layer drawn on vertices an earlier layer already uses is a copy of that
568
+ * layer (白里黑子's ☆ and ❤ are star and heart irises on the iris's own
569
+ * vertices), so it moves with it. Slid as a highlight, a copy of the dome sits
570
+ * in front of the iris on one half, flipping sides with the tremble.
553
571
  */
554
572
  function findHighlights(model: Model, rest: [EyeRest, EyeRest]): number[] {
555
573
  const materials = model.getMaterials?.() ?? []
@@ -557,6 +575,7 @@ function findHighlights(model: Model, rest: [EyeRest, EyeRest]): number[] {
557
575
  const iris = new Set([...rest[0].verts, ...rest[1].verts])
558
576
  if (!materials.length || !indices.length || !iris.size) return []
559
577
  const layers: { id: number; name: string; minX: number; maxX: number; minY: number; maxY: number }[] = []
578
+ const used = new Set<number>()
560
579
  let start = 0
561
580
  let id = 0
562
581
  for (const m of materials) {
@@ -564,16 +583,21 @@ function findHighlights(model: Model, rest: [EyeRest, EyeRest]): number[] {
564
583
  if (count === 0) continue
565
584
  id++
566
585
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity
586
+ let copy = true
587
+ const mine: number[] = []
567
588
  for (let k = start; k < start + count; k++) {
568
589
  const v = indices[k]
569
590
  if (!iris.has(v)) continue
591
+ if (!used.has(v)) copy = false
592
+ mine.push(v)
570
593
  minX = Math.min(minX, positions[v * 3])
571
594
  maxX = Math.max(maxX, positions[v * 3])
572
595
  minY = Math.min(minY, positions[v * 3 + 1])
573
596
  maxY = Math.max(maxY, positions[v * 3 + 1])
574
597
  }
575
598
  start += count
576
- if (minX <= maxX) layers.push({ id, name: m.name, minX, maxX, minY, maxY })
599
+ for (const v of mine) used.add(v)
600
+ if (minX <= maxX && !copy) layers.push({ id, name: m.name, minX, maxX, minY, maxY })
577
601
  }
578
602
  const out: number[] = []
579
603
  layers.forEach((l, i) => {
@@ -26,6 +26,73 @@ import { WORLD_AMBIENT_WGSL } from "../lights"
26
26
  // group(1): per-model skinning
27
27
  // group(2): per-material (diffuse texture + material uniforms)
28
28
 
29
+ /** The jelly eyes' vertex move (jelly-eyes.ts). Every pass that places model
30
+ * vertices takes it, or a pass that skips it draws the iris where it was —
31
+ * the shadow map then shades half the moved iris with its own unmoved copy.
32
+ * Reads `objectLight.jelly` and `material.materialId`, which the including
33
+ * module declares. */
34
+ export const JELLY_VERTEX_WGSL = /* wgsl */ `
35
+ fn _rzJellyTurn(q: vec2f, a: f32) -> vec2f {
36
+ let c = cos(a);
37
+ let s = sin(a);
38
+ return vec2f(c * q.x - s * q.y, s * q.x + c * q.y);
39
+ }
40
+
41
+ /**
42
+ * Where the jelly puts an iris vertex. The iris is the part of the eye the eye
43
+ * bones carry, so it is moved as a whole, in bind space before skinning:
44
+ * scaled about its centre (the CPU composes the blink's spring, the lid's
45
+ * press and her motion's knock into one scale), turned and drifted a hair on
46
+ * the spring, brought forward a hair, and rolled about the eye bone with a
47
+ * closing expression — inside the white, which stays where it is. A highlight
48
+ * layer (this draw's material is one of jelly[1].w's) takes the iris's move,
49
+ * then its own scale, turn and tremble, before the roll. Vertices take it by their weight on the eye bones
50
+ * (jelly[2].w, jelly[3].w), so nothing else on the face moves.
51
+ */
52
+ fn rzJellyVertex(p: vec3f, joints: vec4<u32>, nw: vec4f) -> vec3f {
53
+ let j = objectLight.jelly;
54
+ let ids = u32(j[1].w);
55
+ let mid = u32(material.materialId);
56
+ let hl = mid > 0u && (mid == (ids & 4095u) || mid == (ids >> 12u));
57
+ var out = p;
58
+ for (var e = 0u; e < 2u; e++) {
59
+ let bone = j[2u + e].w;
60
+ if (bone < 0.0) { continue; }
61
+ let b = u32(bone);
62
+ let w = dot(nw, select(vec4f(0.0), vec4f(1.0), joints == vec4<u32>(b)));
63
+ if (w <= 0.0) { continue; }
64
+ let c = j[e].xyz;
65
+ // A rig that carries both eyes on one bone: each vertex follows its own side.
66
+ if (j[2].w == j[3].w && e == 0u && distance(p.xy, j[1].xy) < distance(p.xy, j[0].xy)) { continue; }
67
+ if (j[2].w == j[3].w && e == 1u && distance(p.xy, j[0].xy) <= distance(p.xy, j[1].xy)) { continue; }
68
+ let t = j[4u + e];
69
+ let m = j[6u + e];
70
+ let h = j[10u + e];
71
+ var q = _rzJellyTurn((p.xy - c.xy) * t.xy, t.z) + m.xy;
72
+ // Forward is −Z (MMD faces −Z).
73
+ var push = h.z;
74
+ if (hl) {
75
+ // Sliding over the iris's dome on its own, a highlight sheet a hair in
76
+ // front of it would sink into it where the dome bulges more and the two
77
+ // fight for depth; so it comes forward by as far as it slid — a slope of
78
+ // one, steeper than the dome anywhere it draws.
79
+ let before = q;
80
+ q = _rzJellyTurn(q * h.xy, t.w) + m.zw;
81
+ push += length(q - before);
82
+ }
83
+ var moved = vec3f(c.xy + q, p.z - push);
84
+ let roll = j[8u + e];
85
+ if (roll.w != 0.0) {
86
+ let d = moved - roll.xyz;
87
+ let rd = _rzJellyTurn(d.yz, roll.w);
88
+ moved = roll.xyz + vec3f(d.x, rd.x, rd.y);
89
+ }
90
+ out = mix(p, moved, w);
91
+ }
92
+ return out;
93
+ }
94
+ `
95
+
29
96
  export const COMMON_BINDINGS_WGSL = /* wgsl */ `
30
97
 
31
98
  struct CameraUniforms {
@@ -234,66 +301,7 @@ fn _rzCastShadow(wp: vec3f) -> f32 {
234
301
  struct ObjectLight { layers: vec4u, ambient: vec4f, sh: array<vec4f, 9>, fill: vec4f, jelly: array<vec4f, 12> }
235
302
  @group(1) @binding(1) var<uniform> objectLight: ObjectLight;
236
303
 
237
- fn _rzJellyTurn(q: vec2f, a: f32) -> vec2f {
238
- let c = cos(a);
239
- let s = sin(a);
240
- return vec2f(c * q.x - s * q.y, s * q.x + c * q.y);
241
- }
242
-
243
- /**
244
- * Where the jelly puts an iris vertex. The iris is the part of the eye the eye
245
- * bones carry, so it is moved as a whole, in bind space before skinning:
246
- * scaled about its centre (the CPU composes the blink's spring, the lid's
247
- * press and her motion's knock into one scale), turned and drifted a hair on
248
- * the spring, brought forward a hair, and rolled about the eye bone with a
249
- * closing expression — inside the white, which stays where it is. A highlight
250
- * layer (this draw's material is one of jelly[1].w's) takes the iris's move,
251
- * then its own scale, turn and tremble, before the roll. Vertices take it by their weight on the eye bones
252
- * (jelly[2].w, jelly[3].w), so nothing else on the face moves.
253
- */
254
- fn rzJellyVertex(p: vec3f, joints: vec4<u32>, nw: vec4f) -> vec3f {
255
- let j = objectLight.jelly;
256
- let ids = u32(j[1].w);
257
- let mid = u32(material.materialId);
258
- let hl = mid > 0u && (mid == (ids & 4095u) || mid == (ids >> 12u));
259
- var out = p;
260
- for (var e = 0u; e < 2u; e++) {
261
- let bone = j[2u + e].w;
262
- if (bone < 0.0) { continue; }
263
- let b = u32(bone);
264
- let w = dot(nw, select(vec4f(0.0), vec4f(1.0), joints == vec4<u32>(b)));
265
- if (w <= 0.0) { continue; }
266
- let c = j[e].xyz;
267
- // A rig that carries both eyes on one bone: each vertex follows its own side.
268
- if (j[2].w == j[3].w && e == 0u && distance(p.xy, j[1].xy) < distance(p.xy, j[0].xy)) { continue; }
269
- if (j[2].w == j[3].w && e == 1u && distance(p.xy, j[0].xy) <= distance(p.xy, j[1].xy)) { continue; }
270
- let t = j[4u + e];
271
- let m = j[6u + e];
272
- let h = j[10u + e];
273
- var q = _rzJellyTurn((p.xy - c.xy) * t.xy, t.z) + m.xy;
274
- // Forward is −Z (MMD faces −Z).
275
- var push = h.z;
276
- if (hl) {
277
- // Sliding over the iris's dome on its own, a highlight sheet a hair in
278
- // front of it would sink into it where the dome bulges more and the two
279
- // fight for depth; so it comes forward by as far as it slid — a slope of
280
- // one, steeper than the dome anywhere it draws.
281
- let before = q;
282
- q = _rzJellyTurn(q * h.xy, t.w) + m.zw;
283
- push += length(q - before);
284
- }
285
- var moved = vec3f(c.xy + q, p.z - push);
286
- let roll = j[8u + e];
287
- if (roll.w != 0.0) {
288
- let d = moved - roll.xyz;
289
- let rd = _rzJellyTurn(d.yz, roll.w);
290
- moved = roll.xyz + vec3f(d.x, rd.x, rd.y);
291
- }
292
- out = mix(p, moved, w);
293
- }
294
- return out;
295
- }
296
-
304
+ ${JELLY_VERTEX_WGSL}
297
305
  /** The light arriving at a surface of this object facing n: its own ambient
298
306
  * where loaded data gave it one (a stage's probes, a character's), else the
299
307
  * world's. The same polynomial rzWorldAmbient evaluates. */
@@ -27,7 +27,7 @@
27
27
  // attachment, and that answer does not exist at import time. The constant could
28
28
  // not have taken the outputs at all, which is most of why it did not have them.
29
29
 
30
- import { DISSOLVE_WGSL } from "../materials/common"
30
+ import { DISSOLVE_WGSL, JELLY_VERTEX_WGSL } from "../materials/common"
31
31
  import { sceneFsOutWgsl, sceneIdPadWgsl } from "./scene-contract"
32
32
 
33
33
  export function transparentDepthPrepassWgsl(): string {
@@ -44,13 +44,20 @@ struct MaterialUniforms {
44
44
  alpha: f32,
45
45
  _skip0: vec4f,
46
46
  _skip1: vec4f,
47
- _skip2: vec3f,
47
+ _skip2: f32,
48
+ materialId: f32,
49
+ _skip3: f32,
48
50
  dissolve: f32,
49
51
  };
50
52
 
51
53
  @group(0) @binding(0) var<uniform> camera: CameraUniforms;
52
54
  @group(0) @binding(2) var diffuseSampler: sampler;
53
55
  @group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
56
+ // The model's ObjectLight, for its jelly eyes: depth goes down where the colour
57
+ // pass will draw the iris.
58
+ struct ObjectLight { layers: vec4u, ambient: vec4f, sh: array<vec4f, 9>, fill: vec4f, jelly: array<vec4f, 12> }
59
+ @group(1) @binding(1) var<uniform> objectLight: ObjectLight;
60
+ ${JELLY_VERTEX_WGSL}
54
61
  @group(2) @binding(0) var diffuseTexture: texture_2d<f32>;
55
62
  @group(2) @binding(1) var<uniform> material: MaterialUniforms;
56
63
 
@@ -74,10 +81,11 @@ struct VSOut {
74
81
  @location(3) joints0: vec4<u32>,
75
82
  @location(4) weights0: vec4<f32>,
76
83
  ) -> VSOut {
77
- let pos4 = vec4f(position, 1.0);
78
84
  let weightSum = weights0.x + weights0.y + weights0.z + weights0.w;
79
85
  let invWeightSum = select(1.0, 1.0 / weightSum, weightSum > 0.0001);
80
86
  let w = select(vec4f(1.0, 0.0, 0.0, 0.0), weights0 * invWeightSum, weightSum > 0.0001);
87
+ var pos4 = vec4f(position, 1.0);
88
+ if (objectLight.jelly[0].w > 0.0) { pos4 = vec4f(rzJellyVertex(position, joints0, w), 1.0); }
81
89
  var skinned = vec4f(0.0);
82
90
  for (var i = 0u; i < 4u; i++) {
83
91
  skinned += (skinMats[joints0[i]] * pos4) * w[i];
@@ -1,4 +1,4 @@
1
- import { DISSOLVE_WGSL } from "../materials/common"
1
+ import { DISSOLVE_WGSL, JELLY_VERTEX_WGSL } from "../materials/common"
2
2
 
3
3
  // Shadow map depth pass. Skinned VS + alpha-test FS (depth-only attachment, no
4
4
  // color targets): texels where diffuse-texture alpha × material alpha fall below
@@ -21,10 +21,17 @@ struct MaterialDiffuse {
21
21
  diffuse: vec4f,
22
22
  _skip0: vec4f,
23
23
  _skip1: vec4f,
24
- _skip2: vec3f,
24
+ _skip2: f32,
25
+ materialId: f32,
26
+ _skip3: f32,
25
27
  dissolve: f32,
26
28
  };
27
29
  @group(1) @binding(1) var<uniform> material: MaterialDiffuse;
30
+ // The model's ObjectLight, for its jelly eyes: the map must hold the iris where
31
+ // the colour pass draws it.
32
+ struct ObjectLight { layers: vec4u, ambient: vec4f, sh: array<vec4f, 9>, fill: vec4f, jelly: array<vec4f, 12> }
33
+ @group(0) @binding(3) var<uniform> objectLight: ObjectLight;
34
+ ${JELLY_VERTEX_WGSL}
28
35
 
29
36
  struct VSOut {
30
37
  @builtin(position) position: vec4f,
@@ -38,10 +45,11 @@ struct VSOut {
38
45
 
39
46
  @vertex fn vs(@location(0) position: vec3f, @location(1) normal: vec3f, @location(2) uv: vec2f,
40
47
  @location(3) joints0: vec4<u32>, @location(4) weights0: vec4<f32>) -> VSOut {
41
- let pos4 = vec4f(position, 1.0);
42
48
  let ws = weights0.x + weights0.y + weights0.z + weights0.w;
43
49
  let inv = select(1.0, 1.0 / ws, ws > 0.0001);
44
50
  let nw = select(vec4f(1.0,0.0,0.0,0.0), weights0 * inv, ws > 0.0001);
51
+ var pos4 = vec4f(position, 1.0);
52
+ if (objectLight.jelly[0].w > 0.0) { pos4 = vec4f(rzJellyVertex(position, joints0, nw), 1.0); }
45
53
  var sp = vec4f(0.0);
46
54
  for (var i = 0u; i < 4u; i++) { sp += (skinMats[joints0[i]] * pos4) * nw[i]; }
47
55
  var out: VSOut;