@woosh/meep-engine 3.19.0 → 3.20.0

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 (123) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/editor/view/particles/effect/ParticleGraphEditorView.js +2 -2
  3. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
  4. package/editor/view/particles/effect/ParticleNodeParametersView.js +7 -48
  5. package/package.json +1 -1
  6. package/src/core/collection/array/array_group_by.d.ts.map +1 -1
  7. package/src/core/collection/array/array_group_by.js +2 -11
  8. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  9. package/src/core/geom/3d/shape/HeightMapShape3D.js +4 -9
  10. package/src/core/model/object/optional_clone.d.ts +7 -0
  11. package/src/core/model/object/optional_clone.d.ts.map +1 -0
  12. package/src/core/model/object/optional_equality.d.ts +10 -0
  13. package/src/core/model/object/optional_equality.d.ts.map +1 -0
  14. package/src/{shade/descriptor/util → core/model/object}/optional_equality.js +2 -2
  15. package/src/core/model/object/optional_hash.d.ts +9 -0
  16. package/src/core/model/object/optional_hash.d.ts.map +1 -0
  17. package/src/{shade/descriptor/util → core/model/object}/optional_hash.js +3 -3
  18. package/src/engine/asset/Asset.d.ts +1 -1
  19. package/src/engine/asset/Asset.d.ts.map +1 -1
  20. package/src/engine/asset/Asset.js +3 -1
  21. package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.d.ts.map +1 -1
  22. package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +9 -10
  23. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -1
  24. package/src/engine/graphics/ecs/particles/ParticleEffect.js +6 -22
  25. package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +1 -1
  26. package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +3 -3
  27. package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +1 -1
  28. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +1 -1
  29. package/src/shade/descriptor/pipeline/render/ColorTargetState.js +3 -3
  30. package/src/shade/descriptor/pipeline/render/FragmentState.js +1 -1
  31. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +3 -3
  32. package/src/shade/playground/particle_editor/README.md +1 -1
  33. package/src/shade/playground/particle_system/particle_prototype.d.ts +7 -9
  34. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  35. package/src/shade/playground/particle_system/particle_prototype.js +7 -9
  36. package/src/shade/playground/ssr_motion/README.md +22 -0
  37. package/src/shade/playground/ssr_motion/index.html +18 -0
  38. package/src/shade/playground/ssr_motion/main.d.ts +2 -0
  39. package/src/shade/playground/ssr_motion/main.d.ts.map +1 -0
  40. package/src/shade/playground/ssr_motion/main.js +149 -0
  41. package/src/shade/playground/ssr_variance/index.html +1 -0
  42. package/src/shade/renderer/geometry/Geometry.d.ts.map +1 -1
  43. package/src/shade/renderer/geometry/Geometry.js +4 -7
  44. package/src/shade/renderer/material/StandardShadeMaterial.js +2 -2
  45. package/src/shade/renderer/particles/DESIGN.md +9 -11
  46. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  47. package/src/shade/renderer/particles/GPUParticleSystem.js +3 -1
  48. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +1 -1
  49. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +1 -1
  50. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  51. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +9 -15
  52. package/src/shade/renderer/particles/graph/particle_group_library.d.ts.map +1 -1
  53. package/src/shade/renderer/particles/graph/particle_group_library.js +8 -3
  54. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +0 -2
  55. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
  56. package/src/shade/renderer/particles/graph/particle_node_parameters.js +0 -9
  57. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
  58. package/src/shade/renderer/particles/graph/particle_node_presentation.js +0 -10
  59. package/src/shade/renderer/particles/graph/particle_ramp.d.ts +2 -8
  60. package/src/shade/renderer/particles/graph/particle_ramp.d.ts.map +1 -1
  61. package/src/shade/renderer/particles/graph/particle_ramp.js +2 -8
  62. package/src/shade/renderer/particles/graph/validate_particle_graph.js +0 -6
  63. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  64. package/src/shade/renderer/particles/graph_particles_avboit.js +13 -4
  65. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +1 -12
  66. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
  67. package/src/shade/renderer/particles/isa/InstructionStream.js +1 -12
  68. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +54 -60
  69. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  70. package/src/shade/renderer/particles/isa/ParticleVMISA.js +9 -17
  71. package/src/shade/renderer/particles/isa/particle_assembly.d.ts +0 -1
  72. package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
  73. package/src/shade/renderer/particles/isa/particle_assembly.js +2 -16
  74. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.d.ts +1 -1
  75. package/src/shade/renderer/particles/optimizer/dag/particle_vector_graph.js +1 -1
  76. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +0 -14
  77. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +3 -17
  78. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
  79. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +15 -36
  80. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
  81. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +1 -5
  82. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.d.ts.map +1 -1
  83. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +1 -8
  84. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +2 -11
  85. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  86. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +2 -11
  87. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts.map +1 -1
  88. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js +13 -0
  89. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts +3 -6
  90. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  91. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +49 -17
  92. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  93. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +0 -2
  94. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -1
  95. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +0 -2
  96. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  97. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +1 -5
  98. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -1
  99. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +0 -2
  100. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +1 -3
  101. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  102. package/src/shade/renderer/particles/vm/ParticleVMReference.js +4 -20
  103. package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
  104. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +2 -5
  105. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts.map +1 -1
  106. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js +0 -2
  107. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts.map +1 -1
  108. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js +0 -2
  109. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts.map +1 -1
  110. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js +21 -0
  111. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  112. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -0
  113. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
  114. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +2 -1
  115. package/src/shade/renderer/scene/Mesh.js +1 -1
  116. package/src/shade/renderer/texture/ShadeTexture.js +1 -1
  117. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts +0 -19
  118. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts.map +0 -1
  119. package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js +0 -30
  120. package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.d.ts +0 -11
  121. package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.d.ts.map +0 -1
  122. package/src/shade/renderer/particles/shaders/chunk_particle_curve_disabled.js +0 -13
  123. /package/src/{shade/descriptor/util → core/model/object}/optional_clone.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"particle_program_fuzz.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/optimizer/particle_program_fuzz.js"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;GAaG;AACH,oDAXuB,MAAM;IAED,WAAW,GAA5B,MAAM;IACY,IAAI,GAAtB,OAAO;IACW,MAAM,GAAxB,OAAO;IACU,cAAc,GAA/B,MAAM;oBAqHhB;AA8ED;;;;;;;;;;;;;;;;;;GAkBG;AACH,yDALuB,MAAM;IAED,MAAM,GAAvB,MAAM;oBAmEhB"}
1
+ {"version":3,"file":"particle_program_fuzz.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/optimizer/particle_program_fuzz.js"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;GAaG;AACH,oDAXuB,MAAM;IAED,WAAW,GAA5B,MAAM;IACY,IAAI,GAAtB,OAAO;IACW,MAAM,GAAxB,OAAO;IACU,cAAc,GAA/B,MAAM;oBAqHhB;AAuED;;;;;;;;;;;;;;;;;;GAkBG;AACH,yDALuB,MAAM;IAED,MAAM,GAAvB,MAAM;oBAmEhB"}
@@ -41,7 +41,7 @@ const FUZZ_OPS = [
41
41
  VM_OP.SMOOTHSTEP, VM_OP.RSQRT, VM_OP.TAN, VM_OP.ASIN, VM_OP.ACOS, VM_OP.ATAN2,
42
42
  VM_OP.DOT, VM_OP.CROSS, VM_OP.LENGTH, VM_OP.NORMALIZE, VM_OP.DISTANCE,
43
43
  VM_OP.CMP_LT, VM_OP.CMP_LE, VM_OP.CMP_GT, VM_OP.CMP_GE, VM_OP.CMP_EQ,
44
- VM_OP.SELECT, VM_OP.RANDOM, VM_OP.CURVE, VM_OP.LOAD_CONST, VM_OP.LOAD_ATTR, VM_OP.LOAD_BUILTIN,
44
+ VM_OP.SELECT, VM_OP.RANDOM, VM_OP.LOAD_CONST, VM_OP.LOAD_ATTR, VM_OP.LOAD_BUILTIN,
45
45
  VM_OP.NOP,
46
46
  ];
47
47
 
@@ -222,13 +222,6 @@ function emit_random_instruction(stream, assembler, rand, pool) {
222
222
  return;
223
223
  }
224
224
 
225
- case VM_OP.CURVE: {
226
- const handle = Math.floor(rand() * 4);
227
-
228
- stream.curve(dst, handle, source(group), width);
229
- return;
230
- }
231
-
232
225
  default: {
233
226
  // A `SELECT` whose condition is a constant is the shape the folding pass exists for, and
234
227
  // random registers hold one about never — so it is worth steering into deliberately.
@@ -13,7 +13,7 @@ export function vm_semantics_of(op: number): ParticleOpSemantics;
13
13
  * it — whether it can be deleted when its result is unread, narrowed when its high lanes are dead,
14
14
  * evaluated at compile time, or recognised as a recomputation of something already in a register.
15
15
  * Those are four different questions and an opcode can answer them differently: `LOAD_ATTR` is
16
- * removable but not shareable across a store, `RANDOM` is neither, and `CURVE` is both.
16
+ * removable but not shareable across a store, `RANDOM` is neither, and `LOAD_BUILTIN` is both.
17
17
  *
18
18
  * Every opcode has to appear in {@link VM_SEMANTICS} — the spec asserts it — because the safe
19
19
  * default for a new one is "assume nothing", and a table that silently omitted it would instead have
@@ -22,7 +22,7 @@ export function vm_semantics_of(op: number): ParticleOpSemantics;
22
22
  * Which lane of a source feeds which lane of the result is not a property of the opcode any more:
23
23
  * every register operand carries a swizzle, and `vm_operand_slot` in the ISA answers it per operand.
24
24
  * What is left here is per-opcode: whether lane `i` of the result depends on lane `i` of the
25
- * sources alone (`lanewise`), and whether every lane of the result is the same value (`broadcasts`).
25
+ * sources alone (`lanewise`).
26
26
  */
27
27
  /**
28
28
  * @typedef {object} ParticleOpSemantics
@@ -37,9 +37,6 @@ export function vm_semantics_of(op: number): ParticleOpSemantics;
37
37
  * @property {boolean} shareable two executions with equal operand values produce equal results, so a
38
38
  * second one can read the first one's register instead. False for anything reading the record or
39
39
  * the RNG.
40
- * @property {boolean} broadcasts every lane of the destination holds the same value, by construction
41
- * rather than by what the operands happen to be. Lane `i` is then a copy of lane 0 and may be read
42
- * as one.
43
40
  * @property {boolean} foldable the JS reference and the WGSL interpreter are both obliged to produce
44
41
  * the *same bits* for this operation, so evaluating it here and baking a constant changes nothing
45
42
  * on either. Correctly-rounded IEEE arithmetic qualifies; a transcendental does not — JS
@@ -79,12 +76,6 @@ export type ParticleOpSemantics = {
79
76
  * the RNG.
80
77
  */
81
78
  shareable: boolean;
82
- /**
83
- * every lane of the destination holds the same value, by construction
84
- * rather than by what the operands happen to be. Lane `i` is then a copy of lane 0 and may be read
85
- * as one.
86
- */
87
- broadcasts: boolean;
88
79
  /**
89
80
  * the JS reference and the WGSL interpreter are both obliged to produce
90
81
  * the *same bits* for this operation, so evaluating it here and baking a constant changes nothing
@@ -1 +1 @@
1
- {"version":3,"file":"particle_vm_semantics.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/optimizer/particle_vm_semantics.js"],"names":[],"mappings":"AAoJA;;;;;;GAMG;AACH,oCAHW,MAAM,GACJ,mBAAmB,CAY/B;AAnKD;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,+CAA+C;AAC/C,2BADW,IAAI,MAAM,EAAE,mBAAmB,CAAC,CACL;;;;;;;kBA7BxB,OAAO;;;;;cAGP,OAAO;;;;;;gBAEP,OAAO;;;;;;eAGP,OAAO;;;;;;gBAGP,OAAO;;;;;;;;cAGP,OAAO;;;;;;;;;;sBAKP,OAAO"}
1
+ {"version":3,"file":"particle_vm_semantics.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/optimizer/particle_vm_semantics.js"],"names":[],"mappings":"AA4IA;;;;;;GAMG;AACH,oCAHW,MAAM,GACJ,mBAAmB,CAW/B;AA1JD;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,+CAA+C;AAC/C,2BADW,IAAI,MAAM,EAAE,mBAAmB,CAAC,CACL;;;;;;;kBA1BxB,OAAO;;;;;cAGP,OAAO;;;;;;gBAEP,OAAO;;;;;;eAGP,OAAO;;;;;;;;cAGP,OAAO;;;;;;;;;;sBAKP,OAAO"}
@@ -7,7 +7,7 @@ import { VM_OP } from "../isa/ParticleVMISA.js";
7
7
  * it — whether it can be deleted when its result is unread, narrowed when its high lanes are dead,
8
8
  * evaluated at compile time, or recognised as a recomputation of something already in a register.
9
9
  * Those are four different questions and an opcode can answer them differently: `LOAD_ATTR` is
10
- * removable but not shareable across a store, `RANDOM` is neither, and `CURVE` is both.
10
+ * removable but not shareable across a store, `RANDOM` is neither, and `LOAD_BUILTIN` is both.
11
11
  *
12
12
  * Every opcode has to appear in {@link VM_SEMANTICS} — the spec asserts it — because the safe
13
13
  * default for a new one is "assume nothing", and a table that silently omitted it would instead have
@@ -16,7 +16,7 @@ import { VM_OP } from "../isa/ParticleVMISA.js";
16
16
  * Which lane of a source feeds which lane of the result is not a property of the opcode any more:
17
17
  * every register operand carries a swizzle, and `vm_operand_slot` in the ISA answers it per operand.
18
18
  * What is left here is per-opcode: whether lane `i` of the result depends on lane `i` of the
19
- * sources alone (`lanewise`), and whether every lane of the result is the same value (`broadcasts`).
19
+ * sources alone (`lanewise`).
20
20
  */
21
21
 
22
22
  /**
@@ -32,9 +32,6 @@ import { VM_OP } from "../isa/ParticleVMISA.js";
32
32
  * @property {boolean} shareable two executions with equal operand values produce equal results, so a
33
33
  * second one can read the first one's register instead. False for anything reading the record or
34
34
  * the RNG.
35
- * @property {boolean} broadcasts every lane of the destination holds the same value, by construction
36
- * rather than by what the operands happen to be. Lane `i` is then a copy of lane 0 and may be read
37
- * as one.
38
35
  * @property {boolean} foldable the JS reference and the WGSL interpreter are both obliged to produce
39
36
  * the *same bits* for this operation, so evaluating it here and baking a constant changes nothing
40
37
  * on either. Correctly-rounded IEEE arithmetic qualifies; a transcendental does not — JS
@@ -62,7 +59,6 @@ function semantics(op, flags) {
62
59
  lanewise: false,
63
60
  narrowable: false,
64
61
  shareable: false,
65
- broadcasts: false,
66
62
  foldable: false,
67
63
  foldable_inexact: false,
68
64
  ...flags,
@@ -141,10 +137,6 @@ semantics(VM_OP.SELECT, EXACT);
141
137
  // Ordered and side-effecting: it advances the shared RNG, and its width IS the number of draws it
142
138
  // takes. Removing, duplicating, reordering or narrowing one moves every value drawn after it.
143
139
  semantics(VM_OP.RANDOM, { side_effects: true });
144
- // An external WGSL symbol, but a pure function of (handle, t) — so a dead one goes and a repeated
145
- // one is shared. Every lane of the result is the same sample, which is what makes it narrowable —
146
- // and what makes it a broadcast, so a consumer reading it wide is a consumer that wants `.xxxx`.
147
- semantics(VM_OP.CURVE, { lanewise: true, narrowable: true, shareable: true, broadcasts: true });
148
140
 
149
141
  /**
150
142
  * What may be assumed about an opcode. An unknown one is assumed to do everything, so a new opcode
@@ -159,7 +151,6 @@ export function vm_semantics_of(op) {
159
151
  lanewise: false,
160
152
  narrowable: false,
161
153
  shareable: false,
162
- broadcasts: false,
163
154
  foldable: false,
164
155
  foldable_inexact: false,
165
156
  };
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_particle_avboit_contribution.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,iDAFU,SAAS,CA0Dc;0BA1EP,oCAAoC"}
1
+ {"version":3,"file":"chunk_particle_avboit_contribution.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,iDAFU,SAAS,CAuEc;0BAvFP,oCAAoC"}
@@ -24,6 +24,19 @@ struct ParticleAVBOITContribution {
24
24
  emission : vec4<f32>,
25
25
  }
26
26
 
27
+ // Black covering fragments still contribute extinction; zero-alpha premultiplied RGB still emits.
28
+ fn particle_avboit_is_empty(color : vec4<f32>, blend : u32) -> bool {
29
+ return all(particle_premultiply(color, blend) == vec4<f32>(0.0));
30
+ }
31
+
32
+ // The atlas is unorm, so non-negative straight alpha cannot produce emission. Signed alpha and
33
+ // premultiplied sprites keep all four outputs: either can emit without positive coverage.
34
+ fn particle_avboit_draw_blend(color : vec4<f32>, blend : u32) -> u32 {
35
+ if (blend == PARTICLE_BLEND_ADDITIVE) { return PARTICLE_BLEND_ADDITIVE; }
36
+ if (blend == PARTICLE_BLEND_ALPHA && color.a >= 0.0) { return PARTICLE_BLEND_ALPHA; }
37
+ return PARTICLE_BLEND_PREMULTIPLIED;
38
+ }
39
+
27
40
  fn particle_avboit_contribution(
28
41
  shaded : vec4<f32>,
29
42
  blend : u32,
@@ -1,9 +1,6 @@
1
- /**
2
- * The draw pipeline: the four additive accumulators, reverse-Z depth test against the scene, no
3
- * depth write.
4
- * @type {RenderPipelineDescriptor}
5
- */
6
- export const PARTICLE_AVBOIT_DRAW_PIPELINE: RenderPipelineDescriptor;
1
+ export const PARTICLE_AVBOIT_DRAW_ALPHA_PIPELINE: RenderPipelineDescriptor;
2
+ export const PARTICLE_AVBOIT_DRAW_ADDITIVE_PIPELINE: RenderPipelineDescriptor;
3
+ export const PARTICLE_AVBOIT_DRAW_GENERAL_PIPELINE: RenderPipelineDescriptor;
7
4
  /** The draw shader's resource set, for building its bind group. */
8
5
  export const PARTICLE_AVBOIT_DRAW_RESOURCES: ShaderResourceSetDescriptor;
9
6
  /** The assembled shader, for the validity tier. */
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_avboit_draw.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js"],"names":[],"mappings":"AAkIA;;;;GAIG;AACH,4CAFU,wBAAwB,CAa/B;AAEH,mEAAmE;AACnE,yEAAwD;AAExD,mDAAmD;AACnD,2DAAsD;yCAxJb,iEAAiE;4CAW9D,sDAAsD;iCAFjE,kCAAkC"}
1
+ {"version":3,"file":"shader_particle_avboit_draw.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js"],"names":[],"mappings":"AAgLA,2EAAsI;AACtI,8EAA2I;AAC3I,6EAA8I;AAE9I,mEAAmE;AACnE,yEAAwD;AAExD,mDAAmD;AACnD,2DAAsD;yCAxLb,iEAAiE;4CAW9D,sDAAsD;iCAFjE,kCAAkC"}
@@ -77,9 +77,28 @@ struct ParticleAVBOITDrawOutput {
77
77
  @location(3) emission : vec4<f32>,
78
78
  }
79
79
 
80
+ // Each draw uses the same GPU-owned alive list. Clip the other modes before rasterization.
81
+ fn particle_avboit_vertex(vi : u32, ii : u32, blend : u32) -> ParticleVertexOut {
82
+ var out = particle_billboard_vertex(vi, ii);
83
+ if (particle_avboit_draw_blend(out.color, out.blend) != blend) {
84
+ out.clip = vec4<f32>(2.0, 2.0, 2.0, 1.0);
85
+ }
86
+ return out;
87
+ }
88
+
80
89
  @vertex
81
- fn vs_main(@builtin(vertex_index) vi : u32, @builtin(instance_index) ii : u32) -> ParticleVertexOut {
82
- return particle_billboard_vertex(vi, ii);
90
+ fn vs_alpha(@builtin(vertex_index) vi : u32, @builtin(instance_index) ii : u32) -> ParticleVertexOut {
91
+ return particle_avboit_vertex(vi, ii, PARTICLE_BLEND_ALPHA);
92
+ }
93
+
94
+ @vertex
95
+ fn vs_additive(@builtin(vertex_index) vi : u32, @builtin(instance_index) ii : u32) -> ParticleVertexOut {
96
+ return particle_avboit_vertex(vi, ii, PARTICLE_BLEND_ADDITIVE);
97
+ }
98
+
99
+ @vertex
100
+ fn vs_general(@builtin(vertex_index) vi : u32, @builtin(instance_index) ii : u32) -> ParticleVertexOut {
101
+ return particle_avboit_vertex(vi, ii, PARTICLE_BLEND_PREMULTIPLIED);
83
102
  }
84
103
 
85
104
  @fragment
@@ -104,6 +123,10 @@ fn fs_main(in : ParticleVertexOut) -> ParticleAVBOITDrawOutput {
104
123
  color = particle_apply_lighting(color, in.world_position, normalize(in.normal));
105
124
  }
106
125
 
126
+ if (particle_avboit_is_empty(color, in.blend)) {
127
+ discard;
128
+ }
129
+
107
130
  let volumetrics = sample_volumetrics(in.view_depth, screen_uv, in.clip.xy);
108
131
 
109
132
  let contribution = particle_avboit_contribution(color, in.blend, transmittance, volumetrics);
@@ -129,22 +152,31 @@ fn fs_main(in : ParticleVertexOut) -> ParticleAVBOITDrawOutput {
129
152
  const descriptor = ShaderDescriptor.from({ label: "Particle AVBOIT Draw", body, resources });
130
153
 
131
154
  /**
132
- * The draw pipeline: the four additive accumulators, reverse-Z depth test against the scene, no
133
- * depth write.
134
- * @type {RenderPipelineDescriptor}
155
+ * The variants share WGSL, bindings and attachments; only the vertex entry point and target writes
156
+ * differ. Disabling unused targets avoids blending zeros over every billboard pixel.
157
+ * @param {string} label
158
+ * @param {string} entryPoint
159
+ * @param {number[]} writeMasks
160
+ * @returns {RenderPipelineDescriptor}
135
161
  */
136
- export const PARTICLE_AVBOIT_DRAW_PIPELINE = RenderPipelineDescriptor.from({
137
- label: "Particle AVBOIT Draw",
138
- layout: resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT),
139
- vertex: { module: { code: descriptor.source }, entryPoint: "vs_main" },
140
- fragment: {
141
- module: { code: descriptor.source },
142
- entryPoint: "fs_main",
143
- targets: AVBOIT_DRAW_TARGETS,
144
- },
145
- depthStencil: DepthStencilState.from({ format: "depth32float", depthWriteEnabled: false, depthCompare: "greater" }),
146
- primitive: { topology: "triangle-list", cullMode: "none" },
147
- });
162
+ function create_draw_pipeline(label, entryPoint, writeMasks) {
163
+ return RenderPipelineDescriptor.from({
164
+ label,
165
+ layout: resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT),
166
+ vertex: { module: { code: descriptor.source }, entryPoint },
167
+ fragment: {
168
+ module: { code: descriptor.source },
169
+ entryPoint: "fs_main",
170
+ targets: AVBOIT_DRAW_TARGETS.map((target, i) => ({ ...target, writeMask: writeMasks[i] })),
171
+ },
172
+ depthStencil: DepthStencilState.from({ format: "depth32float", depthWriteEnabled: false, depthCompare: "greater" }),
173
+ primitive: { topology: "triangle-list", cullMode: "none" },
174
+ });
175
+ }
176
+
177
+ export const PARTICLE_AVBOIT_DRAW_ALPHA_PIPELINE = create_draw_pipeline("Particle AVBOIT Draw Alpha", "vs_alpha", [0xF, 0xF, 0xF, 0]);
178
+ export const PARTICLE_AVBOIT_DRAW_ADDITIVE_PIPELINE = create_draw_pipeline("Particle AVBOIT Draw Additive", "vs_additive", [0, 0, 0, 0xF]);
179
+ export const PARTICLE_AVBOIT_DRAW_GENERAL_PIPELINE = create_draw_pipeline("Particle AVBOIT Draw General", "vs_general", [0xF, 0xF, 0xF, 0xF]);
148
180
 
149
181
  /** The draw shader's resource set, for building its bind group. */
150
182
  export const PARTICLE_AVBOIT_DRAW_RESOURCES = resources;
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_emit.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH,kDAA8E;AAE9E;;;;;;;;GAQG;AACH,4BAFU,YAAY,CAOK;AAqD3B,iDAIG;6BA1G0B,mCAAmC;8BAGlC,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_emit.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH,kDAA8E;AAE9E;;;;;;;;GAQG;AACH,4BAFU,YAAY,CAOK;AAoD3B,iDAIG;6BAxG0B,mCAAmC;8BAGlC,+BAA+B"}
@@ -8,7 +8,6 @@ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
8
8
  import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
9
9
  import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
10
10
  import { chunk_particle_vm_registers_fast } from "../vm/chunk_particle_vm_registers_fast.js";
11
- import { chunk_particle_curve_disabled } from "./chunk_particle_curve_disabled.js";
12
11
  import { chunk_particle_emit_step } from "./chunk_particle_emit_step.js";
13
12
 
14
13
  /**
@@ -99,7 +98,6 @@ fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
99
98
  `, [
100
99
  chunk_particle_emit_step,
101
100
  chunk_particle_vm_registers_fast,
102
- chunk_particle_curve_disabled,
103
101
  ]);
104
102
 
105
103
  export const shader_particle_emit = ComputeShader.from({
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_emit_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit_wide.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;GAIG;AACH,iDAFU,MAAM,CAGiD;AAiEjE,sDAIG;8BA9G2B,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_emit_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit_wide.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;GAIG;AACH,iDAFU,MAAM,CAGiD;AAgEjE,sDAIG;8BA5G2B,+BAA+B"}
@@ -7,7 +7,6 @@ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourc
7
7
  import { PARTICLE_VM_WIDE_LAUNCH_LANES } from "../ParticleConstants.js";
8
8
  import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
9
9
  import { chunk_particle_vm_registers_wide } from "../vm/chunk_particle_vm_registers_wide.js";
10
- import { chunk_particle_curve_disabled } from "./chunk_particle_curve_disabled.js";
11
10
  import { chunk_particle_emit_step } from "./chunk_particle_emit_step.js";
12
11
  import { EMIT_SETTINGS, PARTICLE_EMIT_WORKGROUP_SIZE } from "./shader_particle_emit.js";
13
12
 
@@ -104,7 +103,6 @@ fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
104
103
  `, [
105
104
  chunk_particle_emit_step,
106
105
  chunk_particle_vm_registers_wide,
107
- chunk_particle_curve_disabled,
108
106
  ]);
109
107
 
110
108
  export const shader_particle_emit_wide = ComputeShader.from({
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_simulate.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate.js"],"names":[],"mappings":";AA0DA;;;;;GAKG;AACH,gCAFU,YAAY,CAMS;AAuD/B,qDAIG;iDAxH8C,yBAAyB;6BAJ7C,mCAAmC;8BAClC,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_simulate.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate.js"],"names":[],"mappings":";AAuDA;;;;;GAKG;AACH,gCAFU,YAAY,CAMS;AAsD/B,qDAIG;iDApH8C,yBAAyB;6BAJ7C,mCAAmC;8BAClC,+BAA+B"}
@@ -8,7 +8,6 @@ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourc
8
8
  import { PARTICLE_SIMULATE_WORKGROUP_SIZE } from "../ParticleConstants.js";
9
9
  import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
10
10
  import { chunk_particle_vm_registers_fast } from "../vm/chunk_particle_vm_registers_fast.js";
11
- import { chunk_particle_curve_disabled } from "./chunk_particle_curve_disabled.js";
12
11
  import { chunk_particle_simulate_step } from "./chunk_particle_simulate_step.js";
13
12
 
14
13
  /**
@@ -47,9 +46,7 @@ import { chunk_particle_simulate_step } from "./chunk_particle_simulate_step.js"
47
46
  * frame from that same value, so thread count and bound agree by construction — and, because the
48
47
  * padded length is a whole number of workgroups, agree exactly.
49
48
  *
50
- * All structured reads go through `array<u32>` for emulator-testability. Curve sampling uses the
51
- * pluggable `particle_vm_sample_curve` — here the no-op provider; the feature swaps in the
52
- * animation-database-backed one.
49
+ * All structured reads go through `array<u32>` for emulator-testability.
53
50
  *
54
51
  * @type {ComputeShader}
55
52
  */
@@ -116,7 +113,6 @@ fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
116
113
  `, [
117
114
  chunk_particle_simulate_step,
118
115
  chunk_particle_vm_registers_fast,
119
- chunk_particle_curve_disabled,
120
116
  ]);
121
117
 
122
118
  body.addExtension(WebGPUExtensionType.Subgroups);
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_simulate_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;GAGG;AACH,qDAFU,MAAM,CAGqD;AA8DrE,0DAIG;8BAvH2B,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_simulate_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;GAGG;AACH,qDAFU,MAAM,CAGqD;AA6DrE,0DAIG;8BArH2B,+BAA+B"}
@@ -7,7 +7,6 @@ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourc
7
7
  import { PARTICLE_SIMULATE_WORKGROUP_SIZE, PARTICLE_VM_WIDE_LAUNCH_LANES } from "../ParticleConstants.js";
8
8
  import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
9
9
  import { chunk_particle_vm_registers_wide } from "../vm/chunk_particle_vm_registers_wide.js";
10
- import { chunk_particle_curve_disabled } from "./chunk_particle_curve_disabled.js";
11
10
  import { chunk_particle_simulate_step } from "./chunk_particle_simulate_step.js";
12
11
  import { SIMULATE_SETTINGS } from "./shader_particle_simulate.js";
13
12
 
@@ -111,7 +110,6 @@ fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
111
110
  `, [
112
111
  chunk_particle_simulate_step,
113
112
  chunk_particle_vm_registers_wide,
114
- chunk_particle_curve_disabled,
115
113
  ]);
116
114
 
117
115
  body.addExtension(WebGPUExtensionType.Subgroups);
@@ -36,17 +36,15 @@ export function u32_to_unit_f32(u: number): number;
36
36
  * @param {Uint32Array} params.record particle record words (mutated in place); attributes are f32 bits
37
37
  * @param {number[][]} [params.builtins] builtin values indexed by {@link VM_BUILTIN} id, each a 4-array
38
38
  * @param {number} [params.rng_state] initial RNG state (u32)
39
- * @param {(handle: number, t: number) => number} [params.sampleCurve] curve evaluator for the CURVE op
40
39
  * @returns {{ killed: boolean, rng_state: number }}
41
40
  */
42
- export function execute_particle_vm({ words, constants, register_count, record, builtins, rng_state, sampleCurve, }: {
41
+ export function execute_particle_vm({ words, constants, register_count, record, builtins, rng_state, }: {
43
42
  words: Uint32Array;
44
43
  constants: Float32Array;
45
44
  register_count: number;
46
45
  record: Uint32Array;
47
46
  builtins?: number[][];
48
47
  rng_state?: number;
49
- sampleCurve?: (handle: number, t: number) => number;
50
48
  }): {
51
49
  killed: boolean;
52
50
  rng_state: number;
@@ -1 +1 @@
1
- {"version":3,"file":"ParticleVMReference.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/vm/ParticleVMReference.js"],"names":[],"mappings":"AA0BA;;;;;;;GAOG;AACH,gCAHW,MAAM;WACK,MAAM;WAAS,MAAM;EAW1C;AAED;;;;;GAKG;AACH,mCAHW,MAAM,GACJ,MAAM,CAIlB;AAqED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;WATW,WAAW;eACX,YAAY;oBACZ,MAAM;YACN,WAAW;eACX,MAAM,EAAE,EAAE;gBACV,MAAM;2BACG,MAAM,KAAK,MAAM,KAAK,MAAM;;YACzB,OAAO;eAAa,MAAM;EA+RhD"}
1
+ {"version":3,"file":"ParticleVMReference.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/vm/ParticleVMReference.js"],"names":[],"mappings":"AA0BA;;;;;;;GAOG;AACH,gCAHW,MAAM;WACK,MAAM;WAAS,MAAM;EAW1C;AAED;;;;;GAKG;AACH,mCAHW,MAAM,GACJ,MAAM,CAIlB;AA8DD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAR+B,KAAK,EAAzB,WAAW;IACU,SAAS,EAA9B,YAAY;IACG,cAAc,EAA7B,MAAM;IACc,MAAM,EAA1B,WAAW;IACS,QAAQ,GAA5B,MAAM,EAAE,EAAE;IACM,SAAS,GAAzB,MAAM;;YACM,OAAO;eAAa,MAAM;EAuRhD"}
@@ -72,17 +72,10 @@ const OP_WIDTH = new Int8Array(OP_COUNT);
72
72
  /** The lanes the opcode always writes, or `-1` for as many as it operates on. @type {Int8Array} */
73
73
  const OP_DEST = new Int8Array(OP_COUNT);
74
74
 
75
- /** Bit `n` set where source slot `n` is read one lane whatever the width. @type {Uint8Array} */
76
- const OP_SCALAR = new Uint8Array(OP_COUNT);
77
-
78
75
  for (const [op, meta] of VM_ISA) {
79
76
  OP_DEFINED[op] = 1;
80
77
  OP_WIDTH[op] = meta.width === VM_WIDTH.VARIABLE ? -1 : vm_operation_width(op, 0);
81
78
  OP_DEST[op] = meta.dest === VM_DEST.WIDTH ? -1 : vm_dest_width(op, 0);
82
-
83
- for (const slot of meta.scalar_operands) {
84
- OP_SCALAR[op] |= 1 << slot;
85
- }
86
79
  }
87
80
 
88
81
  // --- module-local copies of what the loop reads per instruction ----------------------------------
@@ -92,7 +85,7 @@ for (const [op, meta] of VM_ISA) {
92
85
  // constants to the JIT, and the opcode switch can be a jump table.
93
86
 
94
87
  const {
95
- ABS, ACOS, ADD, ASIN, ATAN2, CLAMP, CMP_EQ, CMP_GE, CMP_GT, CMP_LE, CMP_LT, COS, CROSS, CURVE,
88
+ ABS, ACOS, ADD, ASIN, ATAN2, CLAMP, CMP_EQ, CMP_GE, CMP_GT, CMP_LE, CMP_LT, COS, CROSS,
96
89
  DISTANCE, DIV, DOT, EXP, FLOOR, FRACT, HALT, KILL, LENGTH, LOAD_ATTR, LOAD_BUILTIN, LOAD_CONST,
97
90
  LOG, MAD, MAX, MIN, MIX, MOV, MUL, NEG, NOP, NORMALIZE, POW, RANDOM, RSQRT, SELECT, SIN,
98
91
  SMOOTHSTEP, SQRT, STEP, STORE_ATTR, SUB, TAN,
@@ -139,7 +132,6 @@ const LITERAL_U32 = new Uint32Array(LITERAL_F32.buffer);
139
132
  * @param {Uint32Array} params.record particle record words (mutated in place); attributes are f32 bits
140
133
  * @param {number[][]} [params.builtins] builtin values indexed by {@link VM_BUILTIN} id, each a 4-array
141
134
  * @param {number} [params.rng_state] initial RNG state (u32)
142
- * @param {(handle: number, t: number) => number} [params.sampleCurve] curve evaluator for the CURVE op
143
135
  * @returns {{ killed: boolean, rng_state: number }}
144
136
  */
145
137
  export function execute_particle_vm({
@@ -149,7 +141,6 @@ export function execute_particle_vm({
149
141
  record,
150
142
  builtins = [],
151
143
  rng_state = 0,
152
- sampleCurve = () => 0,
153
144
  }) {
154
145
  // Register file: one f32 per slot. A value of width w occupies w consecutive slots.
155
146
  const reg = new Float32Array(register_count);
@@ -217,14 +208,13 @@ export function execute_particle_vm({
217
208
  const w = fixed_width < 0 ? (word0 >>> WIDTH_SHIFT) & WIDTH_MASK : fixed_width;
218
209
  const dst = (word0 >>> DST_SHIFT) & DST_MASK;
219
210
  const kinds = word0 >>> KIND_SHIFT;
220
- const scalar = OP_SCALAR[op];
221
211
  const s0 = words[base + 1];
222
212
  const s1 = words[base + 2];
223
213
  const s2 = words[base + 3];
224
214
 
225
- gather(a, kinds & KIND_MASK, s0, (scalar & 1) !== 0 ? 1 : w);
226
- gather(b, (kinds >>> KIND_BITS) & KIND_MASK, s1, (scalar & 2) !== 0 ? 1 : w);
227
- gather(c, (kinds >>> (2 * KIND_BITS)) & KIND_MASK, s2, (scalar & 4) !== 0 ? 1 : w);
215
+ gather(a, kinds & KIND_MASK, s0, w);
216
+ gather(b, (kinds >>> KIND_BITS) & KIND_MASK, s1, w);
217
+ gather(c, (kinds >>> (2 * KIND_BITS)) & KIND_MASK, s2, w);
228
218
 
229
219
  switch (op) {
230
220
  case HALT:
@@ -408,12 +398,6 @@ export function execute_particle_vm({
408
398
  for (let i = 0; i < w; i++) d[i] = draw_unit();
409
399
  break;
410
400
 
411
- case CURVE: {
412
- const v = sampleCurve(s0, b[0]);
413
- for (let i = 0; i < w; i++) d[i] = v;
414
- break;
415
- }
416
-
417
401
  default:
418
402
  throw new Error(`ParticleVMReference: unhandled opcode ${op} at pc ${pc}`);
419
403
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_particle_vm.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/vm/chunk_particle_vm.js"],"names":[],"mappings":"AA6UA;;;GAGG;AACH,gCAFU,SAAS,CAEmG;0BAhV5F,oCAAoC"}
1
+ {"version":3,"file":"chunk_particle_vm.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/vm/chunk_particle_vm.js"],"names":[],"mappings":"AA0UA;;;GAGG;AACH,gCAFU,SAAS,CAEmG;0BA7U5F,oCAAoC"}
@@ -66,8 +66,8 @@ import { PARTICLE_VM_CONTEXT_STRUCT } from "./PARTICLE_VM_CONTEXT_STRUCT.js";
66
66
  * VGPRs on RDNA2 and held the shader to 10 waves against a cap of 16.
67
67
  *
68
68
  * Where those slots LIVE is not this chunk's business. The interpreter reads and writes them through
69
- * `vm_reg_read` and `vm_reg_write`, which a backing chunk supplies — the same external-symbol seam
70
- * `particle_vm_sample_curve` uses. There are two backings and they are the two interpreters:
69
+ * `vm_reg_read` and `vm_reg_write`, which a backing chunk supplies. There are two backings and they
70
+ * are the two interpreters:
71
71
  *
72
72
  * - {@link ./chunk_particle_vm_registers_fast.js} — a `var<private>` array of
73
73
  * {@link ../ParticleConstants.js PARTICLE_VM_FAST_REGISTER_SLOTS}. Dynamically indexed, so it
@@ -128,8 +128,6 @@ import { PARTICLE_VM_CONTEXT_STRUCT } from "./PARTICLE_VM_CONTEXT_STRUCT.js";
128
128
  * driver then fetches the instruction words through the scalar unit, branches the switch on a
129
129
  * scalar and indexes `vm_reg` through M0 without the per-lane waterfall. Emit cannot: its waves
130
130
  * span emitters.
131
- * - The `CURVE` opcode calls the external symbol `particle_vm_sample_curve(handle: u32, t: f32) ->
132
- * f32`. The enclosing shader must define it (production: animation-curve backed; tests: a stub).
133
131
  */
134
132
 
135
133
  const source = /* language=wgsl */ `
@@ -318,7 +316,6 @@ fn particle_vm_execute(
318
316
  if (w > 2u) { d.z = random(); }
319
317
  if (w > 3u) { d.w = random(); }
320
318
  }
321
- case ${VM_OP.CURVE}u: { d = vec4<f32>(particle_vm_sample_curve(s0, b.x)); }
322
319
 
323
320
  default: { lanes = 0u; }
324
321
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_warmup_advance.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,sCAFU,YAAY,CAMc;AAgBpC;;;;GAIG;AACH,kCAFU,MAAM,CA6Bd;AAEF,2DAeG;;6BAvG0B,mCAAmC;8BAClC,+BAA+B;gDAQb,6BAA6B"}
1
+ {"version":3,"file":"shader_particle_warmup_advance.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,sCAFU,YAAY,CAMc;AAgBpC;;;;GAIG;AACH,kCAFU,MAAM,CA6Bd;AAEF,2DAcG;;6BArG0B,mCAAmC;8BAClC,+BAA+B;gDAOb,6BAA6B"}
@@ -6,7 +6,6 @@ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
6
6
  import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
7
7
  import { PARTICLE_WARMUP_LAUNCH_LANES, PARTICLE_WARMUP_WORKGROUP_SIZE } from "../ParticleConstants.js";
8
8
  import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
9
- import { chunk_particle_curve_disabled } from "../shaders/chunk_particle_curve_disabled.js";
10
9
  import { chunk_particle_vm_registers_fast } from "../vm/chunk_particle_vm_registers_fast.js";
11
10
  import { chunk_particle_warmup_step } from "./chunk_particle_warmup_step.js";
12
11
  import { PARTICLE_WARMUP_WORKGROUP_COUNT } from "./shader_particle_warmup.js";
@@ -101,7 +100,6 @@ fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
101
100
  `, [
102
101
  chunk_particle_warmup_step,
103
102
  chunk_particle_vm_registers_fast,
104
- chunk_particle_curve_disabled,
105
103
  ]),
106
104
  });
107
105
 
@@ -1 +1 @@
1
- {"version":3,"file":"shader_particle_warmup_advance_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js"],"names":[],"mappings":"AAkDA,gEAmBG;8BAlE2B,+BAA+B"}
1
+ {"version":3,"file":"shader_particle_warmup_advance_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js"],"names":[],"mappings":"AAiDA,gEAkBG;8BAhE2B,+BAA+B"}
@@ -9,7 +9,6 @@ import {
9
9
  PARTICLE_WARMUP_LAUNCH_LANES,
10
10
  PARTICLE_WARMUP_WORKGROUP_SIZE,
11
11
  } from "../ParticleConstants.js";
12
- import { chunk_particle_curve_disabled } from "../shaders/chunk_particle_curve_disabled.js";
13
12
  import { chunk_particle_vm_registers_wide } from "../vm/chunk_particle_vm_registers_wide.js";
14
13
  import { chunk_particle_warmup_step } from "./chunk_particle_warmup_step.js";
15
14
  import { WARMUP_ADVANCE_BODY, WARMUP_ADVANCE_SETTINGS } from "./shader_particle_warmup_advance.js";
@@ -65,6 +64,5 @@ fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
65
64
  `, [
66
65
  chunk_particle_warmup_step,
67
66
  chunk_particle_vm_registers_wide,
68
- chunk_particle_curve_disabled,
69
67
  ]),
70
68
  });
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_ssr_reprojection.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js"],"names":[],"mappings":"AAIA,+CAmBuC;0BAvBb,uCAAuC"}
1
+ {"version":3,"file":"chunk_ssr_reprojection.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js"],"names":[],"mappings":"AAIA,+CAwCuC;0BA5Cb,uCAAuC"}
@@ -21,4 +21,25 @@ fn ssr_surface_history_uv(pixel: vec2f, velocity: vec2f, jitter_delta: vec2f, si
21
21
  return (pixel - velocity + jitter_delta) / size;
22
22
  }
23
23
 
24
+ // Surface motion does not include reflection parallax. Bound the expected lag of
25
+ // an exponential history to one internal pixel when this correspondence is used.
26
+ // Rotation and raster jitter cancel between the two projections; translation does not.
27
+ fn ssr_surface_parallax_confidence(camera_position: vec3f, position: vec3f, distance: f32,
28
+ previous_view_projection: mat4x4f, size: vec2f) -> f32 {
29
+ let surface_uv = ssr_history_uv(position, previous_view_projection);
30
+ var reflected_uv: vec2f;
31
+ if (is_finite(distance) && distance > 0.0) {
32
+ reflected_uv = ssr_history_uv(ssr_virtual_position(camera_position,position,distance),previous_view_projection);
33
+ } else {
34
+ // A miss has no finite reflected depth. Infinity bounds the parallax of
35
+ // a stale finite reflection that can still be present in this history.
36
+ let clip = previous_view_projection * vec4f(position-camera_position,0.0);
37
+ if (!is_finite(clip.w) || clip.w <= 1e-6) { return 0.0; }
38
+ reflected_uv = ndc_to_uv(clip.xy/clip.w);
39
+ }
40
+ let displacement = length((reflected_uv-surface_uv)*size);
41
+ if (!is_finite(displacement)) { return 0.0; }
42
+ return 1.0/(1.0+displacement);
43
+ }
44
+
24
45
  `, [chunk_ndc_to_uv, chunk_is_finite]);
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_ssr_temporal_accumulate.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js"],"names":[],"mappings":"AAUA,gGAAgG;AAChG,sDAyHuH;0BApI7F,uCAAuC"}
1
+ {"version":3,"file":"chunk_ssr_temporal_accumulate.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js"],"names":[],"mappings":"AAUA,gGAAgG;AAChG,sDA6HuH;0BAxI7F,uCAAuC"}
@@ -119,6 +119,10 @@ fn ssr_temporal_accumulate(current: vec4f, previous: vec4f, previous_age: f32,
119
119
  // well-supported long-term estimate. Do not leave it pinned to a clipped edge.
120
120
  let rectified = any(abs(previous.rgb-clipped) > vec3f(1e-5));
121
121
  if (rectified) { age = min(age, 2.0); }
122
+ // Confidence can force a much larger current contribution than 1/age.
123
+ // Carry that actual update rate into the age/variance pair too; otherwise a
124
+ // half-current blend can claim the uncertainty of a 65-frame accumulation.
125
+ age = min(age, 1.0 / max(1e-6, 1.0-saturate(confidence)));
122
126
  let weight = min(saturate(confidence), 1.0 - 1.0/age);
123
127
  let color = mix(current.rgb, clipped, weight);
124
128
  var result: SSRAccumulation;
@@ -1 +1 @@
1
- {"version":3,"file":"ssr_reproject_shader.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js"],"names":[],"mappings":"AAoGA,+CAGG;4BAjGyB,6BAA6B"}
1
+ {"version":3,"file":"ssr_reproject_shader.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js"],"names":[],"mappings":"AAqGA,+CAGG;4BAlGyB,6BAA6B"}
@@ -65,7 +65,7 @@ fn main(@builtin(position) coord: vec4f) -> SSRTemporalOutput {
65
65
  var confidence = 0.0;
66
66
  var motion_confidence = 1.0;
67
67
  var history_uv = vec2f(0.0);
68
- let virtual_eligible = settings.reprojection_mode != 1u && metadata.y >= 0.75 && metadata.x > 0.0 && is_finite(metadata.x) && roughness <= 0.2;
68
+ let virtual_eligible = settings.reprojection_mode != 1u && metadata.y >= 0.5 && metadata.x > 0.0 && is_finite(metadata.x) && roughness <= 0.2;
69
69
  if (virtual_eligible) {
70
70
  let uv = ssr_history_uv(virtual_position, camera_previous.view_projection_matrix);
71
71
  history_uv = uv;
@@ -81,6 +81,7 @@ fn main(@builtin(position) coord: vec4f) -> SSRTemporalOutput {
81
81
  history_uv = uv;
82
82
  history = ssr_sample_history(uv, position, normal, roughness, metadata, virtual_position, false, plane_tolerance);
83
83
  confidence = history.confidence * surface_confidence;
84
+ confidence *= ssr_surface_parallax_confidence(camera_position,position,metadata.x,camera_previous.view_projection_matrix,size);
84
85
  // Surface correspondence alone cannot justify a long history for a smooth finite reflection.
85
86
  if (virtual_eligible) { confidence *= 0.25; }
86
87
  }