@woosh/meep-engine 3.14.3 → 3.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts +30 -0
- package/src/core/geom/3d/mat4/m4_rigidity_defect.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_rigidity_defect.js +71 -0
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +733 -726
- package/src/engine/network/NetworkSession.d.ts +24 -4
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +28 -4
- package/src/engine/network/orchestrator/NetworkPeer.d.ts +96 -7
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +392 -68
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +6 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +6 -0
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +105 -13
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +306 -59
- package/src/engine/network/replication/Replicator.d.ts +43 -7
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +309 -111
- package/src/engine/network/sim/ActionLog.d.ts +23 -3
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +26 -3
- package/src/engine/network/sim/ActionRecordCursor.d.ts +82 -0
- package/src/engine/network/sim/ActionRecordCursor.d.ts.map +1 -0
- package/src/engine/network/sim/ActionRecordCursor.js +120 -0
- package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
- package/src/engine/network/sim/RewindEngine.js +13 -29
- package/src/engine/network/sim/SimAction.d.ts +15 -0
- package/src/engine/network/sim/SimAction.d.ts.map +1 -1
- package/src/engine/network/sim/SimAction.js +15 -0
- package/src/engine/network/sim/SimActionExecutor.d.ts +51 -2
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +74 -7
- package/src/engine/network/transport/Channel.d.ts +1 -1
- package/src/engine/network/transport/Channel.js +1 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/simulation/Ticker.d.ts.map +1 -1
- package/src/engine/simulation/Ticker.js +4 -1
- package/src/engine/ui/GUIEngine.d.ts.map +1 -1
- package/src/engine/ui/GUIEngine.js +6 -0
- package/src/shade/playground/particle_system/README.md +98 -0
- package/src/shade/playground/particle_system/index.html +124 -0
- package/src/shade/playground/particle_system/main.d.ts +2 -0
- package/src/shade/playground/particle_system/main.d.ts.map +1 -0
- package/src/shade/playground/particle_system/main.js +180 -0
- package/src/shade/playground/particle_system/particle_scene.d.ts +52 -0
- package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -0
- package/src/shade/playground/particle_system/particle_scene.js +553 -0
- package/src/shade/playground/skinned_mesh_soup/README.md +143 -0
- package/src/shade/playground/skinned_mesh_soup/index.html +202 -0
- package/src/shade/playground/skinned_mesh_soup/main.d.ts +7 -0
- package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -0
- package/src/shade/playground/skinned_mesh_soup/main.js +567 -0
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +29 -0
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -0
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +428 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +1958 -1796
- package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +357 -0
- package/src/shade/renderer/animation/skin_bind_transform.d.ts +25 -0
- package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_bind_transform.js +33 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts +67 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_clip_scale_conflicts.js +199 -0
- package/src/shade/renderer/animation/skin_frame_defect.d.ts +34 -0
- package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_frame_defect.js +132 -0
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts +24 -0
- package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_joint_matrix.js +46 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +70 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_normalize_mesh_frame.js +216 -0
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts +86 -0
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +1 -0
- package/src/shade/renderer/animation/skin_test_fixtures.js +250 -0
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts +18 -4
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +18 -4
- package/src/shade/renderer/particles/DESIGN.md +5 -5
- package/src/shade/renderer/particles/cull/chunk_particle_cull.d.ts.map +1 -1
- package/src/shade/renderer/particles/cull/chunk_particle_cull.js +3 -1
- package/src/shade/renderer/particles/data/chunk_particle_emitter.js +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +43 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +44 -0
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +33 -59
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +185 -118
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +15 -10
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/compile_particle_graph.js +205 -170
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +44 -0
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -0
- package/src/shade/renderer/particles/graph/particle_graph_authoring.js +108 -0
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts +89 -0
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -0
- package/src/shade/renderer/particles/isa/InstructionStream.js +162 -0
- package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts +1 -48
- package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleAssembler.js +25 -114
- package/src/shade/renderer/particles/particle_prototype.d.ts.map +1 -1
- package/src/shade/renderer/particles/particle_prototype.js +181 -180
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +4 -4
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/create_particle_effect.js +19 -19
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js +4 -2
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +4 -4
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +7 -5
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +3 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +3 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +5 -2
- package/src/shade/renderer/particles/shaders/shader_particle_render.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_render.js +9 -2
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -1
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +1 -1
- package/src/shade/renderer/scene/SkinnedMesh.d.ts +11 -0
- package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
- package/src/shade/renderer/scene/SkinnedMesh.js +11 -0
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts +33 -3
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js +58 -37
- package/src/shade/renderer/particles/graph/ParticleGraph.d.ts +0 -54
- package/src/shade/renderer/particles/graph/ParticleGraph.d.ts.map +0 -1
- package/src/shade/renderer/particles/graph/ParticleGraph.js +0 -99
- package/src/shade/renderer/particles/prototypeParticleSystem.d.ts +0 -2
- package/src/shade/renderer/particles/prototypeParticleSystem.d.ts.map +0 -1
- package/src/shade/renderer/particles/prototypeParticleSystem.js +0 -448
|
@@ -1,180 +1,181 @@
|
|
|
1
|
-
import { EMITTER_BLEND, EMITTER_PROJECTION } from "./data/PARTICLE_EMITTER_LAYOUT.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* @param {
|
|
25
|
-
* @param {number} [options.
|
|
26
|
-
* @param {number} [options.
|
|
27
|
-
* @
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{ name: "
|
|
33
|
-
{ name: "
|
|
34
|
-
{ name: "
|
|
35
|
-
{ name: "
|
|
36
|
-
{ name: "
|
|
37
|
-
{ name: "
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
spawn
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
spawn
|
|
65
|
-
spawn
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
update
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
update
|
|
109
|
-
update
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* system.
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* @param {
|
|
168
|
-
* @param {object} [options
|
|
169
|
-
* @
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
system.attachToNode(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
1
|
+
import { EMITTER_BLEND, EMITTER_PROJECTION } from "./data/PARTICLE_EMITTER_LAYOUT.js";
|
|
2
|
+
import { NodeGraph } from "../../../core/model/node-graph/NodeGraph.js";
|
|
3
|
+
import { particle_node, particle_wire } from "./graph/particle_graph_authoring.js";
|
|
4
|
+
import { VM_BUILTIN, VM_RANDOM_MODE } from "./isa/ParticleVMISA.js";
|
|
5
|
+
import { ParticleLayout } from "./layout/ParticleLayout.js";
|
|
6
|
+
import { create_particle_effect } from "./runtime/create_particle_effect.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Worked examples of authoring particle effects with the node graph + wiring them into a
|
|
10
|
+
* {@link GPUParticleSystem}. Demonstrates: distinct per-particle lifecycle (no built-in age — the
|
|
11
|
+
* effect declares it), AnimationCurve sampling over life, flipbook frames, random emission,
|
|
12
|
+
* additive vs alpha blending, projection modes, soft depth and lighting toggles.
|
|
13
|
+
*
|
|
14
|
+
* `curves` is a `GPUAnimationManager` (or anything with `register_curve(AnimationCurve) -> handle`);
|
|
15
|
+
* `size_curve` / `alpha_curve` are meep `AnimationCurve`s. Both are optional — passing `undefined`
|
|
16
|
+
* yields effects that use constant size/alpha instead (curve handle 0, evaluated as 0 by the
|
|
17
|
+
* disabled provider), which is handy for the headless tests.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A fire effect: buoyant, turbulent, additive-blended camera-facing sprites whose size and opacity
|
|
22
|
+
* follow curves over their lifetime and whose flipbook advances with age.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} [options]
|
|
25
|
+
* @param {number} [options.size_curve] curve handle for size(normalizedAge)
|
|
26
|
+
* @param {number} [options.alpha_curve] curve handle for alpha(normalizedAge)
|
|
27
|
+
* @param {number} [options.flipbook_frames]
|
|
28
|
+
* @returns {{layout: ParticleLayout, effect: object, emitter: object}}
|
|
29
|
+
*/
|
|
30
|
+
export function fire_effect({ size_curve, alpha_curve, flipbook_frames = 16 } = {}) {
|
|
31
|
+
const layout = new ParticleLayout([
|
|
32
|
+
{ name: "position", components: 3 },
|
|
33
|
+
{ name: "velocity", components: 3 },
|
|
34
|
+
{ name: "age", components: 1 },
|
|
35
|
+
{ name: "lifetime", components: 1 },
|
|
36
|
+
{ name: "size", components: 1 },
|
|
37
|
+
{ name: "color", components: 4 },
|
|
38
|
+
{ name: "frame", components: 1 },
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// --- SPAWN: seed each particle's state ---
|
|
42
|
+
const spawn = new NodeGraph();
|
|
43
|
+
{
|
|
44
|
+
// position = emitter position + a small disk of jitter on the ground
|
|
45
|
+
const ep = particle_node(spawn, "builtin", { id: VM_BUILTIN.EMITTER_POSITION });
|
|
46
|
+
const disk = particle_node(spawn, "random", { mode: VM_RANDOM_MODE.UNIT_DISK });
|
|
47
|
+
const jitter = particle_node(spawn, "scale"); particle_wire(spawn, jitter, "v", disk); particle_wire(spawn, jitter, "s", [0.2]);
|
|
48
|
+
const p0 = particle_node(spawn, "add"); particle_wire(spawn, p0, "a", ep); particle_wire(spawn, p0, "b", jitter);
|
|
49
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "position" }), "value", p0);
|
|
50
|
+
|
|
51
|
+
// velocity = upward buoyancy + signed turbulence
|
|
52
|
+
const up = particle_node(spawn, "const", { value: [0, 2.0, 0, 0] });
|
|
53
|
+
const turb = particle_node(spawn, "random", { mode: VM_RANDOM_MODE.UNIFORM_SIGNED });
|
|
54
|
+
const turbS = particle_node(spawn, "scale"); particle_wire(spawn, turbS, "v", turb); particle_wire(spawn, turbS, "s", [0.5]);
|
|
55
|
+
const v0 = particle_node(spawn, "add"); particle_wire(spawn, v0, "a", up); particle_wire(spawn, v0, "b", turbS);
|
|
56
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "velocity" }), "value", v0);
|
|
57
|
+
|
|
58
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "age" }), "value", [0]);
|
|
59
|
+
// lifetime 1.2..1.8s
|
|
60
|
+
const lr = particle_node(spawn, "random", { mode: VM_RANDOM_MODE.UNIFORM });
|
|
61
|
+
const ls = particle_node(spawn, "mad"); particle_wire(spawn, ls, "a", lr); particle_wire(spawn, ls, "b", [0.6]); particle_wire(spawn, ls, "c", [1.2]);
|
|
62
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "lifetime" }), "value", ls);
|
|
63
|
+
|
|
64
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "size" }), "value", [0.4]);
|
|
65
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "color" }), "value", [1.0, 0.6, 0.2, 1.0]);
|
|
66
|
+
particle_wire(spawn, particle_node(spawn, "setAttribute", { name: "frame" }), "value", [0]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- UPDATE: advance + destroy ---
|
|
70
|
+
const update = new NodeGraph();
|
|
71
|
+
{
|
|
72
|
+
const dt = particle_node(update, "builtin", { id: VM_BUILTIN.DELTA_TIME });
|
|
73
|
+
|
|
74
|
+
// age += dt
|
|
75
|
+
const age = particle_node(update, "attribute", { name: "age" });
|
|
76
|
+
const newAge = particle_node(update, "add"); particle_wire(update, newAge, "a", age); particle_wire(update, newAge, "b", dt);
|
|
77
|
+
particle_wire(update, particle_node(update, "setAttribute", { name: "age" }), "value", newAge);
|
|
78
|
+
|
|
79
|
+
// normalizedAge = age / lifetime
|
|
80
|
+
const lifetime = particle_node(update, "attribute", { name: "lifetime" });
|
|
81
|
+
const nAge = particle_node(update, "div"); particle_wire(update, nAge, "a", newAge); particle_wire(update, nAge, "b", lifetime);
|
|
82
|
+
|
|
83
|
+
// kill when normalizedAge >= 1
|
|
84
|
+
const dead = particle_node(update, "compare", { op: "ge" }); particle_wire(update, dead, "a", nAge); particle_wire(update, dead, "b", [1]);
|
|
85
|
+
particle_wire(update, particle_node(update, "kill"), "condition", dead);
|
|
86
|
+
|
|
87
|
+
// buoyant rise + drift: velocity += (0, 1, 0)*dt ; position += velocity*dt
|
|
88
|
+
const vel = particle_node(update, "attribute", { name: "velocity" });
|
|
89
|
+
const buoy = particle_node(update, "const", { value: [0, 1.0, 0, 0] });
|
|
90
|
+
const buoyDt = particle_node(update, "scale"); particle_wire(update, buoyDt, "v", buoy); particle_wire(update, buoyDt, "s", dt);
|
|
91
|
+
const nVel = particle_node(update, "add"); particle_wire(update, nVel, "a", vel); particle_wire(update, nVel, "b", buoyDt);
|
|
92
|
+
particle_wire(update, particle_node(update, "setAttribute", { name: "velocity" }), "value", nVel);
|
|
93
|
+
const pos = particle_node(update, "attribute", { name: "position" });
|
|
94
|
+
const velDt = particle_node(update, "scale"); particle_wire(update, velDt, "v", nVel); particle_wire(update, velDt, "s", dt);
|
|
95
|
+
const nPos = particle_node(update, "add"); particle_wire(update, nPos, "a", pos); particle_wire(update, nPos, "b", velDt);
|
|
96
|
+
particle_wire(update, particle_node(update, "setAttribute", { name: "position" }), "value", nPos);
|
|
97
|
+
|
|
98
|
+
// size + alpha from curves over life (or constants if no curve provided)
|
|
99
|
+
if (size_curve !== undefined) {
|
|
100
|
+
const sc = particle_node(update, "curve", { handle: size_curve }); particle_wire(update, sc, "t", nAge);
|
|
101
|
+
particle_wire(update, particle_node(update, "setAttribute", { name: "size" }), "value", sc);
|
|
102
|
+
}
|
|
103
|
+
const color = particle_node(update, "attribute", { name: "color" });
|
|
104
|
+
if (alpha_curve !== undefined) {
|
|
105
|
+
const ac = particle_node(update, "curve", { handle: alpha_curve }); particle_wire(update, ac, "t", nAge);
|
|
106
|
+
// color.rgb unchanged, color.a = ac : rebuild via select on a swizzle mask is overkill;
|
|
107
|
+
// simplest: multiply color by (1,1,1,ac_normalized) — approximate by scaling alpha only.
|
|
108
|
+
const alphaVec = particle_node(update, "mul");
|
|
109
|
+
particle_wire(update, alphaVec, "a", color);
|
|
110
|
+
particle_wire(update, alphaVec, "b", ac); // broadcasts ac to all lanes (rgb also fades — a warm ember look)
|
|
111
|
+
particle_wire(update, particle_node(update, "setAttribute", { name: "color" }), "value", alphaVec);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// flipbook frame = floor(normalizedAge * frames)
|
|
115
|
+
const framesN = particle_node(update, "const", { value: [flipbook_frames, 0, 0, 0] });
|
|
116
|
+
const fscaled = particle_node(update, "mul"); particle_wire(update, fscaled, "a", nAge); particle_wire(update, fscaled, "b", framesN);
|
|
117
|
+
const fframe = particle_node(update, "floor"); particle_wire(update, fframe, "x", fscaled);
|
|
118
|
+
particle_wire(update, particle_node(update, "setAttribute", { name: "frame" }), "value", fframe);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const effect = create_particle_effect({ layout, spawn, update });
|
|
122
|
+
|
|
123
|
+
const emitter = {
|
|
124
|
+
effect,
|
|
125
|
+
spawn_rate: 120,
|
|
126
|
+
flags: { blend: EMITTER_BLEND.ADDITIVE, projection: EMITTER_PROJECTION.BILLBOARD },
|
|
127
|
+
render: { position: "position", size: "size", color: "color", frame: "frame" },
|
|
128
|
+
bounds: { center: [0, 1.5, 0], radius: 2.5 },
|
|
129
|
+
// A 4x4 flipbook packed as the whole atlas here; a real atlas would use a sub-rect.
|
|
130
|
+
atlas_region: [0, 0, 1, 1],
|
|
131
|
+
flipbook: [4, 4],
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
return { layout, effect, emitter };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* A smoke effect: slow, expanding, alpha-blended, lit, soft-depth billboards. Same authoring
|
|
139
|
+
* surface as fire; the differences are all data (blend/lighting/soft flags, rates, colours).
|
|
140
|
+
* @returns {{layout: ParticleLayout, effect: object, emitter: object}}
|
|
141
|
+
*/
|
|
142
|
+
export function smoke_effect() {
|
|
143
|
+
const { layout, effect } = fire_effect({ flipbook_frames: 8 });
|
|
144
|
+
const emitter = {
|
|
145
|
+
effect,
|
|
146
|
+
spawn_rate: 25,
|
|
147
|
+
flags: { blend: EMITTER_BLEND.ALPHA, projection: EMITTER_PROJECTION.BILLBOARD, soft_depth: true, lighting: true, sort: true },
|
|
148
|
+
render: { position: "position", size: "size", color: "color", frame: "frame" },
|
|
149
|
+
bounds: { center: [0, 3, 0], radius: 5 },
|
|
150
|
+
atlas_region: [0, 0, 1, 1],
|
|
151
|
+
flipbook: [1, 1],
|
|
152
|
+
};
|
|
153
|
+
return { layout, effect, emitter };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Register a fire + smoke plume on a particle system, optionally attaching the fire to a bone.
|
|
158
|
+
*
|
|
159
|
+
* The per-frame loop the integrator runs:
|
|
160
|
+
* ```js
|
|
161
|
+
* const spawn_requests = system.update(dt, { is_visible }); // CPU: bone transforms + spawn counts
|
|
162
|
+
* system.uploadFrame(spawn_requests); // upload emitters (if dirty) + requests
|
|
163
|
+
* graph_particles({ graph, gpu: system.gpuHandles(), frame }); // reset -> emit -> simulate -> indirect
|
|
164
|
+
* // caller appends the depth sort + billboard render into its own graph
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @param {import("./GPUParticleSystem.js").GPUParticleSystem} system
|
|
168
|
+
* @param {object} [options]
|
|
169
|
+
* @param {object} [options.bone] a Node3D to attach the fire emitter to
|
|
170
|
+
* @returns {{fire: number, smoke: number}} emitter indices
|
|
171
|
+
*/
|
|
172
|
+
export function register_campfire(system, { bone } = {}) {
|
|
173
|
+
const fire = system.addEmitter(fire_effect().emitter);
|
|
174
|
+
const smoke = system.addEmitter(smoke_effect().emitter);
|
|
175
|
+
if (bone !== undefined) {
|
|
176
|
+
system.attachToNode(fire, bone);
|
|
177
|
+
system.attachToNode(smoke, bone);
|
|
178
|
+
}
|
|
179
|
+
system.buildEmitterData();
|
|
180
|
+
return { fire, smoke };
|
|
181
|
+
}
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @param {object} params
|
|
9
9
|
* @param {import("../layout/ParticleLayout.js").ParticleLayout} params.layout
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {
|
|
10
|
+
* @param {NodeGraph} [params.spawn]
|
|
11
|
+
* @param {NodeGraph} [params.update]
|
|
12
12
|
* @returns {{ layout: import("../layout/ParticleLayout.js").ParticleLayout, program: import("../isa/ParticleProgram.js").ParticleProgram }}
|
|
13
13
|
*/
|
|
14
14
|
export function create_particle_effect({ layout, spawn, update }: {
|
|
15
15
|
layout: import("../layout/ParticleLayout.js").ParticleLayout;
|
|
16
|
-
spawn?:
|
|
17
|
-
update?:
|
|
16
|
+
spawn?: NodeGraph;
|
|
17
|
+
update?: NodeGraph;
|
|
18
18
|
}): {
|
|
19
19
|
layout: import("../layout/ParticleLayout.js").ParticleLayout;
|
|
20
20
|
program: import("../isa/ParticleProgram.js").ParticleProgram;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_particle_effect.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/create_particle_effect.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH;IALwE,MAAM,EAAnE,OAAO,6BAA6B,EAAE,cAAc;
|
|
1
|
+
{"version":3,"file":"create_particle_effect.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/runtime/create_particle_effect.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH;IALwE,MAAM,EAAnE,OAAO,6BAA6B,EAAE,cAAc;IACjC,KAAK;IACL,MAAM;;YACb,OAAO,6BAA6B,EAAE,cAAc;aAAW,OAAO,2BAA2B,EAAE,eAAe;EAKxI"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { compile_particle_effect } from "../graph/compile_particle_graph.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Compile a particle effect: a per-particle attribute {@link ../layout/ParticleLayout.js} plus SPAWN
|
|
5
|
-
* and UPDATE node graphs, lowered to VM bytecode.
|
|
6
|
-
*
|
|
7
|
-
* The returned value bundles the layout with the compiled program so the {@link ./EmitterRegistry.js}
|
|
8
|
-
* can resolve render-attribute names to record offsets and pack the program into the arena.
|
|
9
|
-
*
|
|
10
|
-
* @param {object} params
|
|
11
|
-
* @param {import("../layout/ParticleLayout.js").ParticleLayout} params.layout
|
|
12
|
-
* @param {
|
|
13
|
-
* @param {
|
|
14
|
-
* @returns {{ layout: import("../layout/ParticleLayout.js").ParticleLayout, program: import("../isa/ParticleProgram.js").ParticleProgram }}
|
|
15
|
-
*/
|
|
16
|
-
export function create_particle_effect({ layout, spawn, update }) {
|
|
17
|
-
const program = compile_particle_effect({ spawn, update, layout });
|
|
18
|
-
return { layout, program };
|
|
19
|
-
}
|
|
1
|
+
import { compile_particle_effect } from "../graph/compile_particle_graph.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compile a particle effect: a per-particle attribute {@link ../layout/ParticleLayout.js} plus SPAWN
|
|
5
|
+
* and UPDATE node graphs, lowered to VM bytecode.
|
|
6
|
+
*
|
|
7
|
+
* The returned value bundles the layout with the compiled program so the {@link ./EmitterRegistry.js}
|
|
8
|
+
* can resolve render-attribute names to record offsets and pack the program into the arena.
|
|
9
|
+
*
|
|
10
|
+
* @param {object} params
|
|
11
|
+
* @param {import("../layout/ParticleLayout.js").ParticleLayout} params.layout
|
|
12
|
+
* @param {NodeGraph} [params.spawn]
|
|
13
|
+
* @param {NodeGraph} [params.update]
|
|
14
|
+
* @returns {{ layout: import("../layout/ParticleLayout.js").ParticleLayout, program: import("../isa/ParticleProgram.js").ParticleProgram }}
|
|
15
|
+
*/
|
|
16
|
+
export function create_particle_effect({ layout, spawn, update }) {
|
|
17
|
+
const program = compile_particle_effect({ spawn, update, layout });
|
|
18
|
+
return { layout, program };
|
|
19
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk_particle_curve_animation.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,6CAFU,SAAS,
|
|
1
|
+
{"version":3,"file":"chunk_particle_curve_animation.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_curve_animation.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,6CAFU,SAAS,CAS0C;0BA5BnC,oCAAoC"}
|
|
@@ -21,9 +21,11 @@ const CURVE_TABLE = ANIMATION_DATABASE_SPEC.get("animation_curves");
|
|
|
21
21
|
*
|
|
22
22
|
* @type {CodeChunk}
|
|
23
23
|
*/
|
|
24
|
-
export const chunk_particle_curve_animation = CodeChunk.from(
|
|
24
|
+
export const chunk_particle_curve_animation = CodeChunk.from(
|
|
25
|
+
/* language=wgsl */
|
|
26
|
+
`
|
|
25
27
|
fn particle_vm_sample_curve(handle : u32, t : f32) -> f32 {
|
|
26
28
|
let header = ${CURVE_TABLE.marshalling_method_read}(&particle_curve_database, handle);
|
|
27
29
|
return animation_curve_evaluate(t, &particle_curve_database, header);
|
|
28
30
|
}
|
|
29
|
-
`, [CURVE_TABLE.chunk_read, chunk_animation_curve_evaluate]);
|
|
31
|
+
`, [CURVE_TABLE.chunk_read, chunk_animation_curve_evaluate]);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pluggable lighting hook for the billboard fragment shader. `particle_apply_lighting(color, world,
|
|
3
|
-
*
|
|
2
|
+
* Pluggable lighting hook for the billboard fragment shader. `particle_apply_lighting(color, world, normal)`
|
|
3
|
+
* returns the lit colour; the default is a pass-through (unlit / emissive).
|
|
4
4
|
*
|
|
5
|
-
* The production feature swaps this for a chunk that binds
|
|
6
|
-
* ../../deferred/SHADING_LIGHT_RESOURCE_GROUP.js} and calls `shade_standard_material_direct` + IBL —
|
|
5
|
+
* The production feature swaps this for a chunk that binds
|
|
6
|
+
* {@link ../../deferred/SHADING_LIGHT_RESOURCE_GROUP.js} and calls `shade_standard_material_direct` + IBL —
|
|
7
7
|
* i.e. billboards reuse the exact same lighting path as opaque surfaces when an emitter opts in via
|
|
8
8
|
* its `lighting` flag. Keeping it a hook means unlit emitters compile without pulling in the whole
|
|
9
9
|
* clustered-lighting resource group.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk_particle_lighting.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_lighting.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,4CAFU,SAAS,
|
|
1
|
+
{"version":3,"file":"chunk_particle_lighting.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_lighting.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,4CAFU,SAAS,CAQhB;0BApBuB,oCAAoC"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Pluggable lighting hook for the billboard fragment shader. `particle_apply_lighting(color, world,
|
|
5
|
-
*
|
|
4
|
+
* Pluggable lighting hook for the billboard fragment shader. `particle_apply_lighting(color, world, normal)`
|
|
5
|
+
* returns the lit colour; the default is a pass-through (unlit / emissive).
|
|
6
6
|
*
|
|
7
|
-
* The production feature swaps this for a chunk that binds
|
|
8
|
-
* ../../deferred/SHADING_LIGHT_RESOURCE_GROUP.js} and calls `shade_standard_material_direct` + IBL —
|
|
7
|
+
* The production feature swaps this for a chunk that binds
|
|
8
|
+
* {@link ../../deferred/SHADING_LIGHT_RESOURCE_GROUP.js} and calls `shade_standard_material_direct` + IBL —
|
|
9
9
|
* i.e. billboards reuse the exact same lighting path as opaque surfaces when an emitter opts in via
|
|
10
10
|
* its `lighting` flag. Keeping it a hook means unlit emitters compile without pulling in the whole
|
|
11
11
|
* clustered-lighting resource group.
|
|
12
12
|
*
|
|
13
13
|
* @type {CodeChunk}
|
|
14
14
|
*/
|
|
15
|
-
export const chunk_particle_lighting_unlit = CodeChunk.from(
|
|
15
|
+
export const chunk_particle_lighting_unlit = CodeChunk.from(
|
|
16
|
+
/* language=wgsl */
|
|
17
|
+
`
|
|
16
18
|
fn particle_apply_lighting(color : vec4<f32>, world_position : vec3<f32>, normal : vec3<f32>) -> vec4<f32> {
|
|
17
19
|
return color;
|
|
18
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk_particle_render_math.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_render_math.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,yCAFU,SAAS,
|
|
1
|
+
{"version":3,"file":"chunk_particle_render_math.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/chunk_particle_render_math.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,yCAFU,SAAS,CA2FhB;0BA3GuB,oCAAoC"}
|
|
@@ -16,7 +16,9 @@ import { EMITTER_BLEND, EMITTER_PROJECTION } from "../data/PARTICLE_EMITTER_LAYO
|
|
|
16
16
|
*
|
|
17
17
|
* @type {CodeChunk}
|
|
18
18
|
*/
|
|
19
|
-
export const chunk_particle_render_math = CodeChunk.from(
|
|
19
|
+
export const chunk_particle_render_math = CodeChunk.from(
|
|
20
|
+
/* language=wgsl */
|
|
21
|
+
`
|
|
20
22
|
const PARTICLE_PROJ_BILLBOARD : u32 = ${EMITTER_PROJECTION.BILLBOARD}u;
|
|
21
23
|
const PARTICLE_PROJ_STRETCHED : u32 = ${EMITTER_PROJECTION.STRETCHED}u;
|
|
22
24
|
const PARTICLE_PROJ_HORIZONTAL : u32 = ${EMITTER_PROJECTION.HORIZONTAL}u;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_particle_emit.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;GAYG;AAEH,2CAHU,aAAa,CAGwB;
|
|
1
|
+
{"version":3,"file":"shader_particle_emit.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_emit.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;GAYG;AAEH,2CAHU,aAAa,CAGwB;AA+F/C,iDAIG;8BAlI2B,+BAA+B"}
|
|
@@ -64,7 +64,9 @@ resources.createGroup()
|
|
|
64
64
|
.addStorageBuffer("alive_out", WebGPUArray.u32, true)
|
|
65
65
|
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
66
66
|
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
67
|
-
const body = CodeChunk.from(
|
|
67
|
+
const body = CodeChunk.from(
|
|
68
|
+
/* language=wgsl */
|
|
69
|
+
`
|
|
68
70
|
const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
69
71
|
const PARTICLE_USER_WORD_START : u32 = ${PARTICLE_RECORD_USER_WORD_START}u;
|
|
70
72
|
const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_particle_finalize.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_finalize.js"],"names":[],"mappings":"AA4BA,
|
|
1
|
+
{"version":3,"file":"shader_particle_finalize.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_finalize.js"],"names":[],"mappings":"AA4BA,2DAYG;AAaH,2DA0BG;;8BA7E2B,+BAA+B;iDAIZ,+BAA+B"}
|
|
@@ -29,7 +29,8 @@ reset_resources.createGroup().addStorageBuffer("counters", WebGPUArray.from(atom
|
|
|
29
29
|
export const shader_particle_reset_counters = ComputeShader.from({
|
|
30
30
|
label: "Particle Reset Counters",
|
|
31
31
|
resources: reset_resources,
|
|
32
|
-
body: CodeChunk.from(
|
|
32
|
+
body: CodeChunk.from(
|
|
33
|
+
/* language=wgsl */ `
|
|
33
34
|
@compute @workgroup_size(1, 1, 1)
|
|
34
35
|
fn main() {
|
|
35
36
|
atomicStore(&counters[${PARTICLE_COUNTER.ALIVE}u], 0u);
|
|
@@ -53,7 +54,9 @@ indirect_resources.createGroup()
|
|
|
53
54
|
export const shader_particle_build_indirect = ComputeShader.from({
|
|
54
55
|
label: "Particle Build Indirect",
|
|
55
56
|
resources: indirect_resources,
|
|
56
|
-
body: CodeChunk.from(
|
|
57
|
+
body: CodeChunk.from(
|
|
58
|
+
/* language=wgsl */
|
|
59
|
+
`
|
|
57
60
|
@compute @workgroup_size(1, 1, 1)
|
|
58
61
|
fn main() {
|
|
59
62
|
let alive = atomicLoad(&counters[${PARTICLE_COUNTER.ALIVE}u]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_particle_render.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_render.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shader_particle_render.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_render.js"],"names":[],"mappings":"AA8JA;;;;;;;;;GASG;AACH;IAP4B,YAAY,GAA7B,MAAM;IACgB,YAAY,GAAlC,MAAM,GAAC,IAAI;IAEkB,aAAa;IAExC,wBAAwB,CA2BpC;;;;;;;;;;;;;;;;AAED,yFAAyF;AACzF,uEAAsD;yCApMb,iEAAiE;4CAO9D,sDAAsD"}
|