reze-engine 0.50.2 → 0.50.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/engine.d.ts +294 -7
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +900 -109
  4. package/dist/shaders/cast-api.d.ts +1 -1
  5. package/dist/shaders/cast-api.d.ts.map +1 -1
  6. package/dist/shaders/cast-layout.d.ts +44 -1
  7. package/dist/shaders/cast-layout.d.ts.map +1 -1
  8. package/dist/shaders/cast-layout.js +44 -1
  9. package/dist/shaders/materials/common.d.ts.map +1 -1
  10. package/dist/shaders/materials/common.js +7 -1
  11. package/dist/shaders/materials/nodes.d.ts +1 -1
  12. package/dist/shaders/materials/nodes.d.ts.map +1 -1
  13. package/dist/shaders/materials/nodes.js +17 -9
  14. package/dist/shaders/passes/composite.d.ts +1 -1
  15. package/dist/shaders/passes/composite.d.ts.map +1 -1
  16. package/dist/shaders/passes/depth-prepass.d.ts +1 -1
  17. package/dist/shaders/passes/depth-prepass.d.ts.map +1 -1
  18. package/dist/shaders/passes/depth-prepass.js +52 -12
  19. package/dist/shaders/passes/ground.d.ts +16 -0
  20. package/dist/shaders/passes/ground.d.ts.map +1 -1
  21. package/dist/shaders/passes/ground.js +143 -49
  22. package/dist/shaders/passes/outline.d.ts +1 -1
  23. package/dist/shaders/passes/outline.d.ts.map +1 -1
  24. package/dist/shaders/passes/outline.js +12 -3
  25. package/dist/shaders/passes/particles.d.ts.map +1 -1
  26. package/dist/shaders/passes/particles.js +6 -2
  27. package/dist/shaders/passes/scene-contract.d.ts +38 -6
  28. package/dist/shaders/passes/scene-contract.d.ts.map +1 -1
  29. package/dist/shaders/passes/scene-contract.js +53 -16
  30. package/dist/shaders/passes/trails.d.ts.map +1 -1
  31. package/dist/shaders/passes/trails.js +36 -8
  32. package/package.json +2 -2
  33. package/src/engine.ts +952 -100
  34. package/src/shaders/cast-layout.ts +44 -1
  35. package/src/shaders/materials/common.ts +7 -1
  36. package/src/shaders/materials/nodes.ts +17 -9
  37. package/src/shaders/passes/depth-prepass.ts +53 -12
  38. package/src/shaders/passes/ground.ts +145 -49
  39. package/src/shaders/passes/outline.ts +14 -3
  40. package/src/shaders/passes/particles.ts +6 -2
  41. package/src/shaders/passes/scene-contract.ts +55 -16
  42. package/src/shaders/passes/trails.ts +36 -8
@@ -5,6 +5,7 @@ import { anchorAliasWgsl, ribbonSlotWgsl } from "../anchor-table";
5
5
  import { midiApi } from "../midi-api";
6
6
  import { CAST_API } from "../cast-api";
7
7
  import { clockApi, EFFECT_MATH_API, PARTICLE_STRUCT_WGSL, trailSlotsApi, viewportApi } from "./hosted-api";
8
+ import { sceneIdFieldWgsl, sceneIdPadWgsl } from "./scene-contract";
8
9
  /**
9
10
  * Sub-segments drawn between each pair of recorded samples.
10
11
  *
@@ -74,7 +75,14 @@ struct CameraU {
74
75
  }
75
76
  struct TrailU {
76
77
  time: f32,
77
- _pad0: f32,
78
+ // How many subjects the cast ACTUALLY holds this frame, not the four the
79
+ // layout has room for. The instance count is sized by this on the CPU and
80
+ // decoded by it here, and the two must use the same number or the flattened
81
+ // [ribbon][subject][segment] index lands on the wrong ribbon. It is a uniform
82
+ // rather than the RZ_SUBJECTS constant precisely because it changes when a
83
+ // model is added or removed, and recompiling every trail shader for that
84
+ // would be absurd.
85
+ subjects: f32,
78
86
  _pad1: f32,
79
87
  _pad2: f32,
80
88
  }
@@ -195,11 +203,14 @@ fn vs(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> VSOut
195
203
  let rest = ii / subs;
196
204
  let seg = k / SUB;
197
205
  let sub = k % SUB;
198
- let subject = i32(rest % u32(RZ_SUBJECTS));
206
+ // The LIVE subject count, floored at one so a cast that is momentarily empty
207
+ // divides by something. See TrailU.subjects.
208
+ let live = max(1u, u32(tu.subjects));
209
+ let subject = i32(rest % live);
199
210
  // Instance index counts RIBBONS; the cast buffer is addressed by anchor slot.
200
211
  // One ribbon per trailed anchor, so these are the same number only when every
201
212
  // anchor is trailed — _rzRibbonSlot is what bridges them.
202
- let ribbon = i32(rest / u32(RZ_SUBJECTS));
213
+ let ribbon = i32(rest / live);
203
214
  let slot = _rzRibbonSlot(ribbon);
204
215
 
205
216
  let n = rzTrailCount(subject, slot);
@@ -293,9 +304,23 @@ fn vs(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> VSOut
293
304
  if (dot(perpA, perpB) < 0.0) { perpB = -perpB; }
294
305
  let clipP = select(clipA, clipB, atEnd);
295
306
  let perp = select(perpA, perpB, atEnd);
296
- // trailWidth speaks PIXELS, like the original's constants; rzViewportHeight()
297
- // lets the effect scale them to the frame.
298
- let wPx = max(0.0, trailWidth(u, age));
307
+ // trailWidth speaks WORLD UNITS the model's units, not the screen's.
308
+ //
309
+ // It spoke pixels, like the fullscreen original's constants, and that made
310
+ // the ribbon a screen ornament: zoom out and it grew relative to the hand
311
+ // that drew it, zoom in and it thinned to a thread. A ribbon is a thing in
312
+ // the scene, so its width belongs in the scene's units and should foreshorten
313
+ // like everything else.
314
+ //
315
+ // The EXTRUSION stays in 2D pixel space untouched — every 3D-extrusion
316
+ // artefact this ribbon ever had (fold-over wedges, bowties, twisted quads) is
317
+ // recorded above, and none of it comes back. Only the width's SOURCE changes:
318
+ // a world length L perpendicular to view at depth w projects to
319
+ // L * proj[1][1] / w in NDC y, so half the frame height converts it to the
320
+ // pixels the 2D offset wants. Per vertex, so a ribbon receding along its own
321
+ // length tapers with distance exactly as geometry would.
322
+ let wWorld = max(0.0, trailWidth(u, age));
323
+ let wPx = wWorld * cam.proj[1][1] * (H * 0.5) / max(clipP.w, 0.01);
299
324
  let ndc = clipP.xy / clipP.w + perp * (c.y * wPx) / toPx;
300
325
  out.clip = vec4f(ndc * clipP.w, clipP.z, clipP.w);
301
326
  out.slot = u32(slot);
@@ -315,7 +340,10 @@ struct TrailFSOut {
315
340
  // The scene's aux target: (bloom mask, coverage). Writing mask 1 is what
316
341
  // makes a ribbon BLOOM — it is light, and the gate is what says so.
317
342
  @location(1) aux: vec4f,
318
- }
343
+ // Declared whenever the pass carries the attachment, and padded rather than
344
+ // written: a ribbon is not a thing you would address by id, so its pipeline
345
+ // takes this target at writeMask 0. Declared anyway — see sceneFsOutWgsl.
346
+ ${sceneIdFieldWgsl()}}
319
347
 
320
348
  @fragment
321
349
  fn fs(in: VSOut) -> TrailFSOut {
@@ -334,7 +362,7 @@ fn fs(in: VSOut) -> TrailFSOut {
334
362
  // mapper is what keeps the sum from clipping.
335
363
  o.color = vec4f(c.rgb, c.a);
336
364
  o.aux = vec4f(${src.bloom ? "1.0" : "0.0"}, 1.0, 0.0, c.a);
337
- return o;
365
+ ${sceneIdPadWgsl("o")} return o;
338
366
  }
339
367
  `);
340
368
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.50.2",
3
+ "version": "0.50.4",
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",
@@ -41,4 +41,4 @@
41
41
  "@types/node": "^20",
42
42
  "typescript": "^5"
43
43
  }
44
- }
44
+ }