@woosh/meep-engine 3.14.4 → 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/network/orchestrator/NetworkPeer.d.ts +56 -8
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +263 -67
- 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 +13 -7
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +103 -138
- package/src/engine/network/replication/Replicator.d.ts +29 -6
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +265 -108
- package/src/engine/network/sim/ActionLog.d.ts +2 -0
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +2 -0
- 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/SimActionExecutor.d.ts +2 -3
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +10 -11
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_scene.js +38 -37
- package/src/shade/playground/skinned_mesh_soup/README.md +39 -18
- package/src/shade/playground/skinned_mesh_soup/index.html +9 -6
- package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
- package/src/shade/playground/skinned_mesh_soup/main.js +16 -13
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +8 -2
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
- package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +23 -4
- 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/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/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/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
|
@@ -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
|
+
}
|
|
@@ -33,7 +33,7 @@ import { VM_BUILTIN, VM_OP, VM_RANDOM_MODE } from "../isa/ParticleVMISA.js";
|
|
|
33
33
|
|
|
34
34
|
const R = PARTICLE_VM_REGISTER_COUNT;
|
|
35
35
|
|
|
36
|
-
const source = /* wgsl */ `
|
|
36
|
+
const source = /* language=wgsl */ `
|
|
37
37
|
const PARTICLE_VM_REGISTER_COUNT : u32 = ${R}u;
|
|
38
38
|
const PARTICLE_VM_MAX_INSTRUCTIONS : u32 = ${PARTICLE_VM_MAX_INSTRUCTIONS}u;
|
|
39
39
|
const PARTICLE_VM_TWO_PI : f32 = 6.28318530717958647692;
|
|
@@ -28,6 +28,17 @@
|
|
|
28
28
|
* see {@link chunk_skin_blend_mesh_local} for why it goes into each
|
|
29
29
|
* matrix rather than onto the blended position.
|
|
30
30
|
*
|
|
31
|
+
* **`transform_global` on a skinned mesh is the engine's, not the
|
|
32
|
+
* asset's.** It cancels out of the rendered position, so glTF declares
|
|
33
|
+
* it meaningless — and the one meaning it does have is the frame the
|
|
34
|
+
* clone's vertices are written in, which the fold above requires to be
|
|
35
|
+
* rigid against the skin. {@link GPUAnimationManager#register_skin}
|
|
36
|
+
* therefore overwrites it, by way of
|
|
37
|
+
* {@link skin_normalize_mesh_frame}, with the skin's own bind
|
|
38
|
+
* transform. Whatever the file put there is discarded, and anything
|
|
39
|
+
* reading this expecting the file's value is reading the wrong thing.
|
|
40
|
+
* See `renderer/animation/SKINNING_FRAME_PLAN.md`.
|
|
41
|
+
*
|
|
31
42
|
* The mesh's **skin id** — a row in a GPU table — lives in
|
|
32
43
|
* {@link GPUMeshSkinningContext} and nowhere else. The CPU-side
|
|
33
44
|
* {@link Skin} it was registered with is a different thing, pure data
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkinnedMesh.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/scene/SkinnedMesh.js"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"SkinnedMesh.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/scene/SkinnedMesh.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH;IAEI;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAFU,OAAK,IAAI,CAEP;IAEZ;;OAEG;IACH,SAFa,WAAW,CAMvB;IAED;;OAEG;IACH,YAFW,WAAW,QAYrB;IA4CL;;;OAGG;IACH,wBAFU,OAAO,CAEkB;CANlC;qBA9JoB,WAAW"}
|
|
@@ -31,6 +31,17 @@ import { Mesh } from "./Mesh.js";
|
|
|
31
31
|
* see {@link chunk_skin_blend_mesh_local} for why it goes into each
|
|
32
32
|
* matrix rather than onto the blended position.
|
|
33
33
|
*
|
|
34
|
+
* **`transform_global` on a skinned mesh is the engine's, not the
|
|
35
|
+
* asset's.** It cancels out of the rendered position, so glTF declares
|
|
36
|
+
* it meaningless — and the one meaning it does have is the frame the
|
|
37
|
+
* clone's vertices are written in, which the fold above requires to be
|
|
38
|
+
* rigid against the skin. {@link GPUAnimationManager#register_skin}
|
|
39
|
+
* therefore overwrites it, by way of
|
|
40
|
+
* {@link skin_normalize_mesh_frame}, with the skin's own bind
|
|
41
|
+
* transform. Whatever the file put there is discarded, and anything
|
|
42
|
+
* reading this expecting the file's value is reading the wrong thing.
|
|
43
|
+
* See `renderer/animation/SKINNING_FRAME_PLAN.md`.
|
|
44
|
+
*
|
|
34
45
|
* The mesh's **skin id** — a row in a GPU table — lives in
|
|
35
46
|
* {@link GPUMeshSkinningContext} and nowhere else. The CPU-side
|
|
36
47
|
* {@link Skin} it was registered with is a different thing, pure data
|
package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* A rigid transform as a dual quaternion: the rotation in the real part, the translation carried in
|
|
3
|
+
* the dual part as `0.5 · t · real`.
|
|
4
|
+
*
|
|
5
|
+
* The matrix's upper 3×3 is read as a rotation and its fourth column as a translation. Anything else
|
|
6
|
+
* in the matrix — a scale, a shear — has nowhere to go, and comes back as neither itself nor a
|
|
7
|
+
* warning: see {@link m4_rigidity_defect} for the number that says so and
|
|
8
|
+
* `renderer/animation/SKINNING_FRAME_PLAN.md` for the frame arrangement that keeps a skinning
|
|
9
|
+
* matrix rigid in the first place.
|
|
10
|
+
*
|
|
11
|
+
* ## Why the rotation goes through `quat_from_m3`
|
|
12
|
+
*
|
|
13
|
+
* This used to take all four quaternion components as `sqrt(max(0, 1 ± m00 ± m11 ± m22)) · 0.5` and
|
|
14
|
+
* recover their signs from the off-diagonal differences. That is exact in exact arithmetic and
|
|
15
|
+
* badly conditioned in floating point: near the identity three of those radicands are near zero, and
|
|
16
|
+
* a square root turns an input error of `e` into an output error of `sqrt(e)`. A matrix that is the
|
|
17
|
+
* identity to `1e-6` — which is what a skin's folded joint matrices are at bind pose — yielded
|
|
18
|
+
* quaternion components off by `9e-4`, an angular error of `1.8e-3` radians, and a millimetre and a
|
|
19
|
+
* half of vertex displacement on a 1.66 m character. Measured, on `Michelle.glb`.
|
|
20
|
+
*
|
|
21
|
+
* {@link chunk_quat_from_m3} is Shoemake's branch-picking form: it computes whichever component the
|
|
22
|
+
* matrix's diagonal says is largest, and derives the other three from it by division. Every branch
|
|
23
|
+
* divides by at least 2, so the components come out **linear** in the input error rather than as its
|
|
24
|
+
* square root — the same `1e-6` matrix now gives `2.5e-7`, three and a half orders better — and the
|
|
25
|
+
* near-180° case, where the trace form is ill-conditioned for the opposite reason, is a branch of its
|
|
26
|
+
* own. One `sqrt` and a reciprocal where there were four `sqrt`s.
|
|
27
|
+
*
|
|
28
|
+
* The normalize stays, on top of that. It is a no-op for the orthonormal input this is meant to be
|
|
29
|
+
* given; what it earns its rsqrt for is the input that is not — a degenerate 3×3 leaves
|
|
30
|
+
* `quat_from_m3` on a branch whose answer has length 0.5, and this is what keeps the documented
|
|
31
|
+
* postcondition, a unit real part, true anyway.
|
|
32
|
+
*
|
|
33
|
+
* @see https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Geometry/Quaternion.h#L813
|
|
34
|
+
* @type {CodeChunk}
|
|
5
35
|
*/
|
|
6
36
|
export const chunk_dual_quat_from_m4: CodeChunk;
|
|
7
37
|
import { CodeChunk } from "../../../../compiler/CodeChunk.js";
|
package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk_dual_quat_from_m4.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"chunk_dual_quat_from_m4.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_from_m4.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,sCAFU,SAAS,CAoBlB;0BAzDyB,mCAAmC"}
|