@newkrok/three-particles 0.3.0 → 0.5.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.
- package/README.md +1 -1
- package/package.json +4 -3
- package/src/js/effects/{shaders → three-particles/shaders}/particle-system-fragment-shader.glsl.js +0 -0
- package/src/js/effects/{shaders → three-particles/shaders}/particle-system-vertex-shader.glsl.js +0 -0
- package/src/js/effects/three-particles/three-particles-bezier.js +36 -0
- package/src/js/effects/three-particles/three-particles-curves.js +1 -0
- package/src/js/effects/three-particles/three-particles-modifiers.js +66 -5
- package/src/js/effects/three-particles/three-particles-utils.js +12 -2
- package/src/js/effects/three-particles.js +208 -65
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newkrok/three-particles",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Particle system for ThreeJS",
|
|
5
5
|
"main": "src/js/three-particles.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,8 +23,9 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/NewKrok/three-particles#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
26
|
+
"easing-functions": "1.0.1",
|
|
27
|
+
"three": "0.136.0",
|
|
28
|
+
"three-noise": "^1.1.1"
|
|
28
29
|
},
|
|
29
30
|
"scripts": {
|
|
30
31
|
"test": "echo \"Error: no test specified\" && exit 1"
|
package/src/js/effects/{shaders → three-particles/shaders}/particle-system-fragment-shader.glsl.js
RENAMED
|
File without changes
|
package/src/js/effects/{shaders → three-particles/shaders}/particle-system-vertex-shader.glsl.js
RENAMED
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const nCr = (n, k) => {
|
|
2
|
+
let z = 1;
|
|
3
|
+
for (let i = 1; i <= k; i++) z *= (n + 1 - i) / i;
|
|
4
|
+
return z;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const createBezierCurveFunction = (bezierPoints) => (percentage) => {
|
|
8
|
+
if (percentage < 0) return bezierPoints[0];
|
|
9
|
+
if (percentage > 1) return bezierPoints[bezierPoints.length - 1];
|
|
10
|
+
|
|
11
|
+
let start = 0;
|
|
12
|
+
let stop = bezierPoints.length - 1;
|
|
13
|
+
|
|
14
|
+
bezierPoints.find((point, index) => {
|
|
15
|
+
const result = percentage < point.percentage;
|
|
16
|
+
if (result) stop = index;
|
|
17
|
+
else if (point.percentage !== undefined) start = index;
|
|
18
|
+
return result;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const n = stop - start;
|
|
22
|
+
const calculatedPercentage =
|
|
23
|
+
(percentage - bezierPoints[start].percentage) /
|
|
24
|
+
(bezierPoints[stop].percentage - bezierPoints[start].percentage);
|
|
25
|
+
|
|
26
|
+
let value = 0;
|
|
27
|
+
for (let i = 0; i <= n; i++) {
|
|
28
|
+
const p = bezierPoints[start + i];
|
|
29
|
+
const c =
|
|
30
|
+
nCr(n, i) *
|
|
31
|
+
Math.pow(1 - calculatedPercentage, n - i) *
|
|
32
|
+
Math.pow(calculatedPercentage, i);
|
|
33
|
+
value += c * p.y;
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import * as THREE from "three/build/three.module.js";
|
|
2
|
+
|
|
1
3
|
import { getCurveFunction } from "./three-particles-curves.js";
|
|
2
4
|
|
|
3
|
-
const
|
|
5
|
+
const noiseInput = new THREE.Vector3(0, 0, 0);
|
|
6
|
+
|
|
7
|
+
const curveModifiers = [
|
|
4
8
|
// {key:"colorOverLifetime", attributeKeys:["colorR", "colorG", "colorB"]},
|
|
5
9
|
{
|
|
6
10
|
key: "opacityOverLifetime",
|
|
@@ -15,17 +19,20 @@ const modifiers = [
|
|
|
15
19
|
];
|
|
16
20
|
|
|
17
21
|
export const applyModifiers = ({
|
|
22
|
+
delta,
|
|
23
|
+
noise,
|
|
18
24
|
startValues,
|
|
25
|
+
lifetimeValues,
|
|
19
26
|
normalizedConfig,
|
|
20
27
|
attributes,
|
|
21
28
|
particleLifetimePercentage,
|
|
22
29
|
particleIndex,
|
|
23
30
|
forceUpdate = false,
|
|
24
31
|
}) => {
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
const multiplier = getCurveFunction(
|
|
32
|
+
curveModifiers.forEach(({ key, attributeKeys, startValueKeys }) => {
|
|
33
|
+
const curveModifier = normalizedConfig[key];
|
|
34
|
+
if (curveModifier.isActive) {
|
|
35
|
+
const multiplier = getCurveFunction(curveModifier.curveFunction)(
|
|
29
36
|
particleLifetimePercentage
|
|
30
37
|
);
|
|
31
38
|
attributeKeys.forEach((attributeKey, index) => {
|
|
@@ -41,4 +48,58 @@ export const applyModifiers = ({
|
|
|
41
48
|
});
|
|
42
49
|
}
|
|
43
50
|
});
|
|
51
|
+
|
|
52
|
+
if (lifetimeValues.rotationOverLifetime) {
|
|
53
|
+
attributes.rotation.array[particleIndex] +=
|
|
54
|
+
lifetimeValues.rotationOverLifetime[particleIndex] * delta * 0.02;
|
|
55
|
+
attributes.rotation.needsUpdate = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (noise.isActive) {
|
|
59
|
+
const {
|
|
60
|
+
sampler,
|
|
61
|
+
strength,
|
|
62
|
+
offsets,
|
|
63
|
+
positionAmount,
|
|
64
|
+
rotationAmount,
|
|
65
|
+
sizeAmount,
|
|
66
|
+
} = noise;
|
|
67
|
+
const positionIndex = particleIndex * 3;
|
|
68
|
+
const positionArr = attributes.position.array;
|
|
69
|
+
let noiseOnPosition;
|
|
70
|
+
|
|
71
|
+
const noisePosition =
|
|
72
|
+
(particleLifetimePercentage + (offsets ? offsets[particleIndex] : 0)) *
|
|
73
|
+
10 *
|
|
74
|
+
strength;
|
|
75
|
+
const noisePower = 0.15 * strength;
|
|
76
|
+
|
|
77
|
+
noiseInput.set(noisePosition, 0, 0);
|
|
78
|
+
noiseOnPosition = sampler.get3(noiseInput);
|
|
79
|
+
positionArr[positionIndex] += noiseOnPosition * noisePower * positionAmount;
|
|
80
|
+
|
|
81
|
+
if (rotationAmount !== 0) {
|
|
82
|
+
attributes.rotation.array[particleIndex] +=
|
|
83
|
+
noiseOnPosition * noisePower * rotationAmount;
|
|
84
|
+
attributes.rotation.needsUpdate = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (sizeAmount !== 0) {
|
|
88
|
+
attributes.size.array[particleIndex] +=
|
|
89
|
+
noiseOnPosition * noisePower * sizeAmount;
|
|
90
|
+
attributes.size.needsUpdate = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
noiseInput.set(noisePosition, noisePosition, 0);
|
|
94
|
+
noiseOnPosition = sampler.get3(noiseInput);
|
|
95
|
+
positionArr[positionIndex + 1] +=
|
|
96
|
+
noiseOnPosition * noisePower * positionAmount;
|
|
97
|
+
|
|
98
|
+
noiseInput.set(noisePosition, noisePosition, noisePosition);
|
|
99
|
+
noiseOnPosition = sampler.get3(noiseInput);
|
|
100
|
+
positionArr[positionIndex + 2] +=
|
|
101
|
+
noiseOnPosition * noisePower * positionAmount;
|
|
102
|
+
|
|
103
|
+
attributes.position.needsUpdate = true;
|
|
104
|
+
}
|
|
44
105
|
};
|
|
@@ -8,10 +8,20 @@ export const patchObject = (
|
|
|
8
8
|
const result = {};
|
|
9
9
|
Object.keys(objectA).forEach((key) => {
|
|
10
10
|
if (!config.skippedProperties || !config.skippedProperties.includes(key)) {
|
|
11
|
-
if (
|
|
11
|
+
if (
|
|
12
|
+
typeof objectA[key] === "object" &&
|
|
13
|
+
objectA[key] &&
|
|
14
|
+
objectB[key] &&
|
|
15
|
+
!Array.isArray(objectA[key])
|
|
16
|
+
) {
|
|
12
17
|
result[key] = patchObject(objectA[key], objectB[key], config);
|
|
13
18
|
} else {
|
|
14
|
-
result[key] =
|
|
19
|
+
result[key] =
|
|
20
|
+
objectB[key] === 0
|
|
21
|
+
? 0
|
|
22
|
+
: objectB[key] === false
|
|
23
|
+
? false
|
|
24
|
+
: objectB[key] || objectA[key];
|
|
15
25
|
if (config.applyToFirstObject) objectA[key] = result[key];
|
|
16
26
|
}
|
|
17
27
|
}
|
|
@@ -9,12 +9,11 @@ import {
|
|
|
9
9
|
} from "./three-particles/three-particles-utils.js";
|
|
10
10
|
|
|
11
11
|
import { CurveFunction } from "./three-particles/three-particles-curves.js";
|
|
12
|
+
import { FBM } from "three-noise/build/three-noise.module.js";
|
|
12
13
|
import ParticleSystemFragmentShader from "./three-particles/shaders/particle-system-fragment-shader.glsl.js";
|
|
13
14
|
import ParticleSystemVertexShader from "./three-particles/shaders/particle-system-vertex-shader.glsl.js";
|
|
14
15
|
import { applyModifiers } from "./three-particles/three-particles-modifiers.js";
|
|
15
|
-
|
|
16
|
-
// Float32Array is not enough accurate when we are storing timestamp in it so we just remove unnecessary time
|
|
17
|
-
const float32Helper = 1638200000000;
|
|
16
|
+
import { createBezierCurveFunction } from "@newkrok/three-particles/src/js/effects/three-particles/three-particles-bezier";
|
|
18
17
|
|
|
19
18
|
let createdParticleSystems = [];
|
|
20
19
|
|
|
@@ -36,6 +35,14 @@ export const TimeMode = {
|
|
|
36
35
|
FPS: "FPS",
|
|
37
36
|
};
|
|
38
37
|
|
|
38
|
+
export const blendingMap = {
|
|
39
|
+
"THREE.NoBlending": THREE.NoBlending,
|
|
40
|
+
"THREE.NormalBlending": THREE.NormalBlending,
|
|
41
|
+
"THREE.AdditiveBlending": THREE.AdditiveBlending,
|
|
42
|
+
"THREE.SubtractiveBlending": THREE.SubtractiveBlending,
|
|
43
|
+
"THREE.MultiplyBlending": THREE.MultiplyBlending,
|
|
44
|
+
};
|
|
45
|
+
|
|
39
46
|
export const getDefaultParticleSystemConfig = () =>
|
|
40
47
|
JSON.parse(JSON.stringify(DEFAULT_PARTICLE_SYSTEM_CONFIG));
|
|
41
48
|
|
|
@@ -88,9 +95,32 @@ const DEFAULT_PARTICLE_SYSTEM_CONFIG = {
|
|
|
88
95
|
},
|
|
89
96
|
},
|
|
90
97
|
map: null,
|
|
98
|
+
renderer: {
|
|
99
|
+
blending: THREE.NormalBlending,
|
|
100
|
+
transparent: true,
|
|
101
|
+
depthTest: true,
|
|
102
|
+
depthWrite: false,
|
|
103
|
+
},
|
|
104
|
+
velocityOverLifetime: {
|
|
105
|
+
isActive: false,
|
|
106
|
+
linear: {
|
|
107
|
+
x: { min: 0, max: 0 },
|
|
108
|
+
y: { min: 0, max: 0 },
|
|
109
|
+
z: { min: 0, max: 0 },
|
|
110
|
+
},
|
|
111
|
+
orbital: {
|
|
112
|
+
x: { min: 0, max: 0 },
|
|
113
|
+
y: { min: 0, max: 0 },
|
|
114
|
+
z: { min: 0, max: 0 },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
91
117
|
sizeOverLifetime: {
|
|
92
118
|
isActive: false,
|
|
93
|
-
curveFunction: CurveFunction.
|
|
119
|
+
curveFunction: CurveFunction.BEZIER,
|
|
120
|
+
bezierPoints: [
|
|
121
|
+
{ x: 0, y: 0, percentage: 0 },
|
|
122
|
+
{ x: 1, y: 1, percentage: 1 },
|
|
123
|
+
],
|
|
94
124
|
},
|
|
95
125
|
/* colorOverLifetime: {
|
|
96
126
|
isActive: false,
|
|
@@ -98,7 +128,26 @@ const DEFAULT_PARTICLE_SYSTEM_CONFIG = {
|
|
|
98
128
|
}, */
|
|
99
129
|
opacityOverLifetime: {
|
|
100
130
|
isActive: false,
|
|
101
|
-
curveFunction: CurveFunction.
|
|
131
|
+
curveFunction: CurveFunction.BEZIER,
|
|
132
|
+
bezierPoints: [
|
|
133
|
+
{ x: 0, y: 0, percentage: 0 },
|
|
134
|
+
{ x: 1, y: 1, percentage: 1 },
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
rotationOverLifetime: {
|
|
138
|
+
isActive: false,
|
|
139
|
+
min: 0.0,
|
|
140
|
+
max: 0.0,
|
|
141
|
+
},
|
|
142
|
+
noise: {
|
|
143
|
+
isActive: false,
|
|
144
|
+
useRandomOffset: false,
|
|
145
|
+
strength: 1.0,
|
|
146
|
+
frequency: 0.5,
|
|
147
|
+
octaves: 1,
|
|
148
|
+
positionAmount: 1.0,
|
|
149
|
+
rotationAmount: 0.0,
|
|
150
|
+
sizeAmount: 0.0,
|
|
102
151
|
},
|
|
103
152
|
textureSheetAnimation: {
|
|
104
153
|
tiles: new THREE.Vector2(1.0, 1.0),
|
|
@@ -132,7 +181,8 @@ const calculatePositionAndVelocity = (
|
|
|
132
181
|
{ shape, sphere, cone, circle, rectangle },
|
|
133
182
|
startSpeed,
|
|
134
183
|
position,
|
|
135
|
-
velocity
|
|
184
|
+
velocity,
|
|
185
|
+
velocityOverLifetime
|
|
136
186
|
) => {
|
|
137
187
|
switch (shape) {
|
|
138
188
|
case Shape.SPHERE:
|
|
@@ -171,6 +221,21 @@ const calculatePositionAndVelocity = (
|
|
|
171
221
|
);
|
|
172
222
|
break;
|
|
173
223
|
}
|
|
224
|
+
|
|
225
|
+
if (velocityOverLifetime.isActive) {
|
|
226
|
+
velocity.x += THREE.MathUtils.randFloat(
|
|
227
|
+
velocityOverLifetime.linear.x.min,
|
|
228
|
+
velocityOverLifetime.linear.x.max
|
|
229
|
+
);
|
|
230
|
+
velocity.y += THREE.MathUtils.randFloat(
|
|
231
|
+
velocityOverLifetime.linear.y.min,
|
|
232
|
+
velocityOverLifetime.linear.y.max
|
|
233
|
+
);
|
|
234
|
+
velocity.z += THREE.MathUtils.randFloat(
|
|
235
|
+
velocityOverLifetime.linear.z.min,
|
|
236
|
+
velocityOverLifetime.linear.z.max
|
|
237
|
+
);
|
|
238
|
+
}
|
|
174
239
|
};
|
|
175
240
|
|
|
176
241
|
export const createParticleSystem = (
|
|
@@ -187,9 +252,28 @@ export const createParticleSystem = (
|
|
|
187
252
|
worldEuler: new THREE.Euler(),
|
|
188
253
|
gravityVelocity: new THREE.Vector3(0, 0, 0),
|
|
189
254
|
startValues: {},
|
|
255
|
+
lifetimeValues: {},
|
|
256
|
+
creationTimes: [],
|
|
257
|
+
noise: null,
|
|
190
258
|
};
|
|
191
259
|
|
|
192
260
|
const normalizedConfig = patchObject(DEFAULT_PARTICLE_SYSTEM_CONFIG, config);
|
|
261
|
+
|
|
262
|
+
const bezierCompatibleProperties = [
|
|
263
|
+
"sizeOverLifetime",
|
|
264
|
+
"opacityOverLifetime",
|
|
265
|
+
];
|
|
266
|
+
bezierCompatibleProperties.forEach((key) => {
|
|
267
|
+
if (
|
|
268
|
+
normalizedConfig[key].isActive &&
|
|
269
|
+
normalizedConfig[key].curveFunction === CurveFunction.BEZIER &&
|
|
270
|
+
normalizedConfig[key].bezierPoints
|
|
271
|
+
)
|
|
272
|
+
normalizedConfig[key].curveFunction = createBezierCurveFunction(
|
|
273
|
+
normalizedConfig[key].bezierPoints
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
|
|
193
277
|
const {
|
|
194
278
|
transform,
|
|
195
279
|
duration,
|
|
@@ -207,11 +291,17 @@ export const createParticleSystem = (
|
|
|
207
291
|
emission,
|
|
208
292
|
shape,
|
|
209
293
|
map,
|
|
294
|
+
renderer,
|
|
295
|
+
noise,
|
|
296
|
+
velocityOverLifetime,
|
|
210
297
|
onUpdate,
|
|
211
298
|
onComplete,
|
|
212
299
|
textureSheetAnimation,
|
|
213
300
|
} = normalizedConfig;
|
|
214
301
|
|
|
302
|
+
if (typeof renderer.blending === "string")
|
|
303
|
+
renderer.blending = blendingMap[renderer.blending];
|
|
304
|
+
|
|
215
305
|
const startPositions = Array.from(
|
|
216
306
|
{ length: maxParticles },
|
|
217
307
|
() => new THREE.Vector3()
|
|
@@ -221,6 +311,8 @@ export const createParticleSystem = (
|
|
|
221
311
|
() => new THREE.Vector3()
|
|
222
312
|
);
|
|
223
313
|
|
|
314
|
+
generalData.creationTimes = Array.from({ length: maxParticles }, () => 0);
|
|
315
|
+
|
|
224
316
|
const startValueKeys = ["startSize", "startOpacity"];
|
|
225
317
|
startValueKeys.forEach((key) => {
|
|
226
318
|
generalData.startValues[key] = Array.from({ length: maxParticles }, () =>
|
|
@@ -231,6 +323,37 @@ export const createParticleSystem = (
|
|
|
231
323
|
);
|
|
232
324
|
});
|
|
233
325
|
|
|
326
|
+
const lifetimeValueKeys = ["rotationOverLifetime"];
|
|
327
|
+
lifetimeValueKeys.forEach((key) => {
|
|
328
|
+
if (normalizedConfig[key].isActive)
|
|
329
|
+
generalData.lifetimeValues[key] = Array.from(
|
|
330
|
+
{ length: maxParticles },
|
|
331
|
+
() =>
|
|
332
|
+
THREE.MathUtils.randFloat(
|
|
333
|
+
normalizedConfig[key].min,
|
|
334
|
+
normalizedConfig[key].max
|
|
335
|
+
)
|
|
336
|
+
);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
generalData.noise = {
|
|
340
|
+
isActive: noise.isActive,
|
|
341
|
+
strength: noise.strength,
|
|
342
|
+
positionAmount: noise.positionAmount,
|
|
343
|
+
rotationAmount: noise.rotationAmount,
|
|
344
|
+
sizeAmount: noise.sizeAmount,
|
|
345
|
+
sampler: noise.isActive
|
|
346
|
+
? new FBM({
|
|
347
|
+
seed: Math.random(),
|
|
348
|
+
scale: noise.frequency,
|
|
349
|
+
octaves: noise.octaves,
|
|
350
|
+
})
|
|
351
|
+
: null,
|
|
352
|
+
offsets: noise.useRandomOffset
|
|
353
|
+
? Array.from({ length: maxParticles }, () => Math.random() * 100)
|
|
354
|
+
: null,
|
|
355
|
+
};
|
|
356
|
+
|
|
234
357
|
const material = new THREE.ShaderMaterial({
|
|
235
358
|
uniforms: {
|
|
236
359
|
elapsed: {
|
|
@@ -251,10 +374,10 @@ export const createParticleSystem = (
|
|
|
251
374
|
},
|
|
252
375
|
vertexShader: ParticleSystemVertexShader,
|
|
253
376
|
fragmentShader: ParticleSystemFragmentShader,
|
|
254
|
-
transparent:
|
|
255
|
-
blending:
|
|
256
|
-
depthTest:
|
|
257
|
-
depthWrite:
|
|
377
|
+
transparent: renderer.transparent,
|
|
378
|
+
blending: renderer.blending,
|
|
379
|
+
depthTest: renderer.depthTest,
|
|
380
|
+
depthWrite: renderer.depthWrite,
|
|
258
381
|
});
|
|
259
382
|
|
|
260
383
|
const geometry = new THREE.BufferGeometry();
|
|
@@ -264,7 +387,8 @@ export const createParticleSystem = (
|
|
|
264
387
|
shape,
|
|
265
388
|
startSpeed,
|
|
266
389
|
startPositions[i],
|
|
267
|
-
velocities[i]
|
|
390
|
+
velocities[i],
|
|
391
|
+
velocityOverLifetime
|
|
268
392
|
);
|
|
269
393
|
|
|
270
394
|
geometry.setFromPoints(
|
|
@@ -283,7 +407,6 @@ export const createParticleSystem = (
|
|
|
283
407
|
};
|
|
284
408
|
|
|
285
409
|
createFloat32AttributesRequest("isActive", false);
|
|
286
|
-
createFloat32AttributesRequest("creationTime", 0);
|
|
287
410
|
createFloat32AttributesRequest("lifetime", 0);
|
|
288
411
|
createFloat32AttributesRequest("startLifetime", () =>
|
|
289
412
|
THREE.MathUtils.randFloat(startLifetime.min, startLifetime.max)
|
|
@@ -339,8 +462,10 @@ export const createParticleSystem = (
|
|
|
339
462
|
|
|
340
463
|
const activateParticle = ({ particleIndex, activationTime }) => {
|
|
341
464
|
geometry.attributes.isActive.array[particleIndex] = true;
|
|
342
|
-
|
|
343
|
-
|
|
465
|
+
generalData.creationTimes[particleIndex] = activationTime;
|
|
466
|
+
|
|
467
|
+
if (generalData.noise.offsets)
|
|
468
|
+
generalData.noise.offsets[particleIndex] = Math.random() * 100;
|
|
344
469
|
|
|
345
470
|
const colorRandomRatio = Math.random();
|
|
346
471
|
|
|
@@ -379,6 +504,13 @@ export const createParticleSystem = (
|
|
|
379
504
|
THREE.MathUtils.randFloat(startRotation.min, startRotation.max)
|
|
380
505
|
);
|
|
381
506
|
|
|
507
|
+
if (normalizedConfig.rotationOverLifetime.isActive)
|
|
508
|
+
generalData.lifetimeValues.rotationOverLifetime[particleIndex] =
|
|
509
|
+
THREE.MathUtils.randFloat(
|
|
510
|
+
normalizedConfig.rotationOverLifetime.min,
|
|
511
|
+
normalizedConfig.rotationOverLifetime.max
|
|
512
|
+
);
|
|
513
|
+
|
|
382
514
|
geometry.attributes.rotation.needsUpdate = true;
|
|
383
515
|
geometry.attributes.colorB.needsUpdate = true;
|
|
384
516
|
|
|
@@ -386,7 +518,8 @@ export const createParticleSystem = (
|
|
|
386
518
|
shape,
|
|
387
519
|
startSpeed,
|
|
388
520
|
startPositions[particleIndex],
|
|
389
|
-
velocities[particleIndex]
|
|
521
|
+
velocities[particleIndex],
|
|
522
|
+
velocityOverLifetime
|
|
390
523
|
);
|
|
391
524
|
const positionIndex = Math.floor(particleIndex * 3);
|
|
392
525
|
geometry.attributes.position.array[positionIndex] =
|
|
@@ -395,13 +528,16 @@ export const createParticleSystem = (
|
|
|
395
528
|
startPositions[particleIndex].y;
|
|
396
529
|
geometry.attributes.position.array[positionIndex + 2] =
|
|
397
530
|
startPositions[particleIndex].z;
|
|
398
|
-
particleSystem.geometry.attributes.position.needsUpdate = true;
|
|
399
531
|
|
|
400
532
|
geometry.attributes.lifetime.array[particleIndex] = 0;
|
|
401
533
|
geometry.attributes.lifetime.needsUpdate = true;
|
|
402
534
|
|
|
403
535
|
applyModifiers({
|
|
536
|
+
delta: 0,
|
|
537
|
+
elapsed: 0,
|
|
538
|
+
noise: generalData.noise,
|
|
404
539
|
startValues: generalData.startValues,
|
|
540
|
+
lifetimeValues: generalData.lifetimeValues,
|
|
405
541
|
normalizedConfig,
|
|
406
542
|
attributes: particleSystem.geometry.attributes,
|
|
407
543
|
particleLifetimePercentage: 0,
|
|
@@ -489,12 +625,13 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
489
625
|
particleSystem.material.uniforms.elapsed.value = elapsed;
|
|
490
626
|
|
|
491
627
|
particleSystem.getWorldPosition(currentWorldPosition);
|
|
492
|
-
if (lastWorldPosition.x !== -99999)
|
|
628
|
+
if (lastWorldPosition.x !== -99999) {
|
|
493
629
|
worldPositionChange.set(
|
|
494
630
|
currentWorldPosition.x - lastWorldPosition.x,
|
|
495
631
|
currentWorldPosition.y - lastWorldPosition.y,
|
|
496
632
|
currentWorldPosition.z - lastWorldPosition.z
|
|
497
633
|
);
|
|
634
|
+
}
|
|
498
635
|
generalData.distanceFromLastEmitByDistance += worldPositionChange.length();
|
|
499
636
|
particleSystem.getWorldPosition(lastWorldPosition);
|
|
500
637
|
|
|
@@ -519,59 +656,65 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
519
656
|
particleSystem.updateMatrixWorld();
|
|
520
657
|
}
|
|
521
658
|
|
|
522
|
-
|
|
523
|
-
(
|
|
524
|
-
|
|
525
|
-
|
|
659
|
+
generalData.creationTimes.forEach((entry, index) => {
|
|
660
|
+
if (particleSystem.geometry.attributes.isActive.array[index]) {
|
|
661
|
+
const particleLifetime = now - entry;
|
|
662
|
+
if (
|
|
663
|
+
particleLifetime >
|
|
664
|
+
particleSystem.geometry.attributes.startLifetime.array[index]
|
|
665
|
+
)
|
|
666
|
+
deactivateParticle(index);
|
|
667
|
+
else {
|
|
668
|
+
const velocity = velocities[index];
|
|
669
|
+
velocity.x -= gravityVelocity.x;
|
|
670
|
+
velocity.y -= gravityVelocity.y;
|
|
671
|
+
velocity.z -= gravityVelocity.z;
|
|
672
|
+
|
|
526
673
|
if (
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
const positionIndex = index * 3;
|
|
544
|
-
const positionArr =
|
|
545
|
-
particleSystem.geometry.attributes.position.array;
|
|
546
|
-
if (simulationSpace === SimulationSpace.WORLD) {
|
|
547
|
-
positionArr[positionIndex] -= worldPositionChange.x;
|
|
548
|
-
positionArr[positionIndex + 1] -= worldPositionChange.y;
|
|
549
|
-
positionArr[positionIndex + 2] -= worldPositionChange.z;
|
|
550
|
-
}
|
|
551
|
-
positionArr[positionIndex] += velocity.x * delta;
|
|
552
|
-
positionArr[positionIndex + 1] += velocity.y * delta;
|
|
553
|
-
positionArr[positionIndex + 2] += velocity.z * delta;
|
|
554
|
-
particleSystem.geometry.attributes.position.needsUpdate = true;
|
|
674
|
+
gravity !== 0 ||
|
|
675
|
+
velocity.x !== 0 ||
|
|
676
|
+
velocity.y !== 0 ||
|
|
677
|
+
velocity.z !== 0 ||
|
|
678
|
+
worldPositionChange.x !== 0 ||
|
|
679
|
+
worldPositionChange.y !== 0 ||
|
|
680
|
+
worldPositionChange.z !== 0
|
|
681
|
+
) {
|
|
682
|
+
const positionIndex = index * 3;
|
|
683
|
+
const positionArr =
|
|
684
|
+
particleSystem.geometry.attributes.position.array;
|
|
685
|
+
|
|
686
|
+
if (simulationSpace === SimulationSpace.WORLD) {
|
|
687
|
+
positionArr[positionIndex] -= worldPositionChange.x;
|
|
688
|
+
positionArr[positionIndex + 1] -= worldPositionChange.y;
|
|
689
|
+
positionArr[positionIndex + 2] -= worldPositionChange.z;
|
|
555
690
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
particleSystem.geometry.attributes.
|
|
560
|
-
|
|
561
|
-
const particleLifetimePercentage =
|
|
562
|
-
particleLifetime /
|
|
563
|
-
particleSystem.geometry.attributes.startLifetime.array[index];
|
|
564
|
-
applyModifiers({
|
|
565
|
-
startValues: generalData.startValues,
|
|
566
|
-
normalizedConfig,
|
|
567
|
-
attributes: particleSystem.geometry.attributes,
|
|
568
|
-
particleLifetimePercentage,
|
|
569
|
-
particleIndex: index,
|
|
570
|
-
});
|
|
691
|
+
positionArr[positionIndex] += velocity.x * delta;
|
|
692
|
+
positionArr[positionIndex + 1] += velocity.y * delta;
|
|
693
|
+
positionArr[positionIndex + 2] += velocity.z * delta;
|
|
694
|
+
particleSystem.geometry.attributes.position.needsUpdate = true;
|
|
571
695
|
}
|
|
696
|
+
|
|
697
|
+
particleSystem.geometry.attributes.lifetime.array[index] =
|
|
698
|
+
particleLifetime;
|
|
699
|
+
particleSystem.geometry.attributes.lifetime.needsUpdate = true;
|
|
700
|
+
|
|
701
|
+
const particleLifetimePercentage =
|
|
702
|
+
particleLifetime /
|
|
703
|
+
particleSystem.geometry.attributes.startLifetime.array[index];
|
|
704
|
+
applyModifiers({
|
|
705
|
+
delta,
|
|
706
|
+
elapsed,
|
|
707
|
+
noise: generalData.noise,
|
|
708
|
+
startValues: generalData.startValues,
|
|
709
|
+
lifetimeValues: generalData.lifetimeValues,
|
|
710
|
+
normalizedConfig,
|
|
711
|
+
attributes: particleSystem.geometry.attributes,
|
|
712
|
+
particleLifetimePercentage,
|
|
713
|
+
particleIndex: index,
|
|
714
|
+
});
|
|
572
715
|
}
|
|
573
716
|
}
|
|
574
|
-
);
|
|
717
|
+
});
|
|
575
718
|
|
|
576
719
|
if (looping || lifetime < duration * 1000) {
|
|
577
720
|
const emissionDelta = now - lastEmissionTime;
|