@newkrok/three-particles 0.6.2 → 0.8.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 +2 -1
- package/package.json +4 -3
- package/src/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.js +5 -0
- package/src/js/effects/three-particles/three-particles-modifiers.js +28 -0
- package/src/js/effects/three-particles/three-particles-utils.js +20 -29
- package/src/js/effects/three-particles.js +132 -25
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Particle system for ThreeJS
|
|
|
7
7
|
You can create your own particle effects with it's editor https://github.com/NewKrok/three-particles-editor
|
|
8
8
|
|
|
9
9
|
# Video
|
|
10
|
+
|
|
10
11
|
- Projectiles: https://youtu.be/Q352JuxON04
|
|
11
12
|
- First preview: https://youtu.be/dtN_bndvoGU
|
|
12
13
|
|
|
@@ -22,4 +23,4 @@ Install with npm
|
|
|
22
23
|
`npm i @newkrok/three-particles`
|
|
23
24
|
|
|
24
25
|
Add as a package.json dependency
|
|
25
|
-
`"dependencies": { ... "@newkrok/three-particles": "0.
|
|
26
|
+
`"dependencies": { ... "@newkrok/three-particles": "0.7.0" ... }, `
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newkrok/three-particles",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Particle system for ThreeJS",
|
|
5
5
|
"main": "src/js/three-particles.js",
|
|
6
6
|
"bin": {
|
|
@@ -27,8 +27,9 @@
|
|
|
27
27
|
"homepage": "https://github.com/NewKrok/three-particles#readme",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"easing-functions": "1.0.1",
|
|
30
|
-
"three": "0.
|
|
31
|
-
"three-noise": "
|
|
30
|
+
"three": "0.140.0",
|
|
31
|
+
"three-noise": "1.1.2",
|
|
32
|
+
"@newkrok/three-utils": "0.1.0"
|
|
32
33
|
},
|
|
33
34
|
"scripts": {
|
|
34
35
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -4,6 +4,9 @@ const ParticleSystemFragmentShader = `
|
|
|
4
4
|
uniform float fps;
|
|
5
5
|
uniform bool useFPSForFrameIndex;
|
|
6
6
|
uniform vec2 tiles;
|
|
7
|
+
uniform bool discardBackgroundColor;
|
|
8
|
+
uniform vec3 backgroundColor;
|
|
9
|
+
uniform float backgroundColorTolerance;
|
|
7
10
|
|
|
8
11
|
varying vec4 vColor;
|
|
9
12
|
varying float vLifetime;
|
|
@@ -56,6 +59,8 @@ const ParticleSystemFragmentShader = `
|
|
|
56
59
|
vec4 rotatedTexture = texture2D(map, uvPoint);
|
|
57
60
|
|
|
58
61
|
gl_FragColor = gl_FragColor * rotatedTexture;
|
|
62
|
+
|
|
63
|
+
if (discardBackgroundColor && abs(length(rotatedTexture.rgb - backgroundColor.rgb)) < backgroundColorTolerance ) discard;
|
|
59
64
|
}
|
|
60
65
|
`;
|
|
61
66
|
|
|
@@ -2,7 +2,9 @@ import * as THREE from "three";
|
|
|
2
2
|
|
|
3
3
|
import { getCurveFunction } from "./three-particles-curves.js";
|
|
4
4
|
|
|
5
|
+
const ROTATION_CONVERTER = THREE.MathUtils.radToDeg(1);
|
|
5
6
|
const noiseInput = new THREE.Vector3(0, 0, 0);
|
|
7
|
+
const orbitalEuler = new THREE.Euler();
|
|
6
8
|
|
|
7
9
|
const curveModifiers = [
|
|
8
10
|
// {key:"colorOverLifetime", attributeKeys:["colorR", "colorG", "colorB"]},
|
|
@@ -23,12 +25,38 @@ export const applyModifiers = ({
|
|
|
23
25
|
noise,
|
|
24
26
|
startValues,
|
|
25
27
|
lifetimeValues,
|
|
28
|
+
hasOrbitalVelocity,
|
|
29
|
+
orbitalVelocityData,
|
|
26
30
|
normalizedConfig,
|
|
27
31
|
attributes,
|
|
32
|
+
particleLifetime,
|
|
28
33
|
particleLifetimePercentage,
|
|
29
34
|
particleIndex,
|
|
30
35
|
forceUpdate = false,
|
|
31
36
|
}) => {
|
|
37
|
+
if (hasOrbitalVelocity) {
|
|
38
|
+
const positionIndex = particleIndex * 3;
|
|
39
|
+
const positionArr = attributes.position.array;
|
|
40
|
+
const { speed, positionOffset } = orbitalVelocityData[particleIndex];
|
|
41
|
+
|
|
42
|
+
positionArr[positionIndex] -= positionOffset.x;
|
|
43
|
+
positionArr[positionIndex + 1] -= positionOffset.y;
|
|
44
|
+
positionArr[positionIndex + 2] -= positionOffset.z;
|
|
45
|
+
|
|
46
|
+
orbitalEuler.set(
|
|
47
|
+
speed.x * ROTATION_CONVERTER * delta,
|
|
48
|
+
speed.z * ROTATION_CONVERTER * delta,
|
|
49
|
+
speed.y * ROTATION_CONVERTER * delta
|
|
50
|
+
);
|
|
51
|
+
positionOffset.applyEuler(orbitalEuler);
|
|
52
|
+
|
|
53
|
+
positionArr[positionIndex] += positionOffset.x;
|
|
54
|
+
positionArr[positionIndex + 1] += positionOffset.y;
|
|
55
|
+
positionArr[positionIndex + 2] += positionOffset.z;
|
|
56
|
+
|
|
57
|
+
attributes.position.needsUpdate = true;
|
|
58
|
+
}
|
|
59
|
+
|
|
32
60
|
curveModifiers.forEach(({ key, attributeKeys, startValueKeys }) => {
|
|
33
61
|
const curveModifier = normalizedConfig[key];
|
|
34
62
|
if (curveModifier.isActive) {
|
|
@@ -2,37 +2,9 @@ import * as THREE from "three";
|
|
|
2
2
|
|
|
3
3
|
import { EmitFrom } from "../three-particles.js";
|
|
4
4
|
|
|
5
|
-
export const patchObject = (
|
|
6
|
-
objectA,
|
|
7
|
-
objectB,
|
|
8
|
-
config = { skippedProperties: [], applyToFirstObject: false }
|
|
9
|
-
) => {
|
|
10
|
-
const result = {};
|
|
11
|
-
Object.keys(objectA).forEach((key) => {
|
|
12
|
-
if (!config.skippedProperties || !config.skippedProperties.includes(key)) {
|
|
13
|
-
if (
|
|
14
|
-
typeof objectA[key] === "object" &&
|
|
15
|
-
objectA[key] &&
|
|
16
|
-
objectB[key] &&
|
|
17
|
-
!Array.isArray(objectA[key])
|
|
18
|
-
) {
|
|
19
|
-
result[key] = patchObject(objectA[key], objectB[key], config);
|
|
20
|
-
} else {
|
|
21
|
-
result[key] =
|
|
22
|
-
objectB[key] === 0
|
|
23
|
-
? 0
|
|
24
|
-
: objectB[key] === false
|
|
25
|
-
? false
|
|
26
|
-
: objectB[key] || objectA[key];
|
|
27
|
-
if (config.applyToFirstObject) objectA[key] = result[key];
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return result;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
5
|
export const calculateRandomPositionAndVelocityOnSphere = (
|
|
35
6
|
position,
|
|
7
|
+
quaternion,
|
|
36
8
|
velocity,
|
|
37
9
|
startSpeed,
|
|
38
10
|
{ radius, radiusThickness, arc }
|
|
@@ -59,6 +31,8 @@ export const calculateRandomPositionAndVelocityOnSphere = (
|
|
|
59
31
|
radius * normalizedThickness * zDirection +
|
|
60
32
|
radius * radiusThickness * randomizedDistanceRatio * zDirection;
|
|
61
33
|
|
|
34
|
+
position.applyQuaternion(quaternion);
|
|
35
|
+
|
|
62
36
|
const randomizedSpeed = THREE.MathUtils.randFloat(
|
|
63
37
|
startSpeed.min,
|
|
64
38
|
startSpeed.max
|
|
@@ -69,10 +43,12 @@ export const calculateRandomPositionAndVelocityOnSphere = (
|
|
|
69
43
|
position.y * speedMultiplierByPosition * randomizedSpeed,
|
|
70
44
|
position.z * speedMultiplierByPosition * randomizedSpeed
|
|
71
45
|
);
|
|
46
|
+
velocity.applyQuaternion(quaternion);
|
|
72
47
|
};
|
|
73
48
|
|
|
74
49
|
export const calculateRandomPositionAndVelocityOnCone = (
|
|
75
50
|
position,
|
|
51
|
+
quaternion,
|
|
76
52
|
velocity,
|
|
77
53
|
startSpeed,
|
|
78
54
|
{ radius, radiusThickness, arc, angle = 90 }
|
|
@@ -92,6 +68,8 @@ export const calculateRandomPositionAndVelocityOnCone = (
|
|
|
92
68
|
radius * radiusThickness * randomizedDistanceRatio * yDirection;
|
|
93
69
|
position.z = 0;
|
|
94
70
|
|
|
71
|
+
position.applyQuaternion(quaternion);
|
|
72
|
+
|
|
95
73
|
const positionLength = position.length();
|
|
96
74
|
const normalizedAngle = Math.abs(
|
|
97
75
|
(positionLength / radius) * THREE.Math.degToRad(angle)
|
|
@@ -114,10 +92,12 @@ export const calculateRandomPositionAndVelocityOnCone = (
|
|
|
114
92
|
randomizedSpeed,
|
|
115
93
|
Math.cos(normalizedAngle) * randomizedSpeed
|
|
116
94
|
);
|
|
95
|
+
velocity.applyQuaternion(quaternion);
|
|
117
96
|
};
|
|
118
97
|
|
|
119
98
|
export const calculateRandomPositionAndVelocityOnBox = (
|
|
120
99
|
position,
|
|
100
|
+
quaternion,
|
|
121
101
|
velocity,
|
|
122
102
|
startSpeed,
|
|
123
103
|
{ scale, emitFrom }
|
|
@@ -157,15 +137,19 @@ export const calculateRandomPositionAndVelocityOnBox = (
|
|
|
157
137
|
break;
|
|
158
138
|
}
|
|
159
139
|
|
|
140
|
+
position.applyQuaternion(quaternion);
|
|
141
|
+
|
|
160
142
|
const randomizedSpeed = THREE.MathUtils.randFloat(
|
|
161
143
|
startSpeed.min,
|
|
162
144
|
startSpeed.max
|
|
163
145
|
);
|
|
164
146
|
velocity.set(0, 0, randomizedSpeed);
|
|
147
|
+
velocity.applyQuaternion(quaternion);
|
|
165
148
|
};
|
|
166
149
|
|
|
167
150
|
export const calculateRandomPositionAndVelocityOnCircle = (
|
|
168
151
|
position,
|
|
152
|
+
quaternion,
|
|
169
153
|
velocity,
|
|
170
154
|
startSpeed,
|
|
171
155
|
{ radius, radiusThickness, arc }
|
|
@@ -185,6 +169,8 @@ export const calculateRandomPositionAndVelocityOnCircle = (
|
|
|
185
169
|
radius * radiusThickness * randomizedDistanceRatio * yDirection;
|
|
186
170
|
position.z = 0;
|
|
187
171
|
|
|
172
|
+
position.applyQuaternion(quaternion);
|
|
173
|
+
|
|
188
174
|
const randomizedSpeed = THREE.MathUtils.randFloat(
|
|
189
175
|
startSpeed.min,
|
|
190
176
|
startSpeed.max
|
|
@@ -197,10 +183,12 @@ export const calculateRandomPositionAndVelocityOnCircle = (
|
|
|
197
183
|
position.y * speedMultiplierByPosition * randomizedSpeed,
|
|
198
184
|
0
|
|
199
185
|
);
|
|
186
|
+
velocity.applyQuaternion(quaternion);
|
|
200
187
|
};
|
|
201
188
|
|
|
202
189
|
export const calculateRandomPositionAndVelocityOnRectangle = (
|
|
203
190
|
position,
|
|
191
|
+
quaternion,
|
|
204
192
|
velocity,
|
|
205
193
|
startSpeed,
|
|
206
194
|
{ rotation, scale }
|
|
@@ -213,9 +201,12 @@ export const calculateRandomPositionAndVelocityOnRectangle = (
|
|
|
213
201
|
position.y = yOffset * Math.cos(rotationX);
|
|
214
202
|
position.z = xOffset * Math.sin(rotationY) - yOffset * Math.sin(rotationX);
|
|
215
203
|
|
|
204
|
+
position.applyQuaternion(quaternion);
|
|
205
|
+
|
|
216
206
|
const randomizedSpeed = THREE.MathUtils.randFloat(
|
|
217
207
|
startSpeed.min,
|
|
218
208
|
startSpeed.max
|
|
219
209
|
);
|
|
220
210
|
velocity.set(0, 0, randomizedSpeed);
|
|
211
|
+
velocity.applyQuaternion(quaternion);
|
|
221
212
|
};
|
|
@@ -6,15 +6,16 @@ import {
|
|
|
6
6
|
calculateRandomPositionAndVelocityOnCone,
|
|
7
7
|
calculateRandomPositionAndVelocityOnRectangle,
|
|
8
8
|
calculateRandomPositionAndVelocityOnSphere,
|
|
9
|
-
patchObject,
|
|
10
9
|
} from "./three-particles/three-particles-utils.js";
|
|
11
10
|
|
|
12
11
|
import { CurveFunction } from "./three-particles/three-particles-curves.js";
|
|
13
12
|
import { FBM } from "three-noise/build/three-noise.module.js";
|
|
13
|
+
import { Gyroscope } from "three/examples/jsm/misc/Gyroscope";
|
|
14
14
|
import ParticleSystemFragmentShader from "./three-particles/shaders/particle-system-fragment-shader.glsl.js";
|
|
15
15
|
import ParticleSystemVertexShader from "./three-particles/shaders/particle-system-vertex-shader.glsl.js";
|
|
16
16
|
import { applyModifiers } from "./three-particles/three-particles-modifiers.js";
|
|
17
17
|
import { createBezierCurveFunction } from "./three-particles/three-particles-bezier";
|
|
18
|
+
import { patchObject } from "@newkrok/three-utils/src/js/newkrok/three-utils/object-utils.js";
|
|
18
19
|
|
|
19
20
|
let createdParticleSystems = [];
|
|
20
21
|
|
|
@@ -108,6 +109,9 @@ const DEFAULT_PARTICLE_SYSTEM_CONFIG = {
|
|
|
108
109
|
map: null,
|
|
109
110
|
renderer: {
|
|
110
111
|
blending: THREE.NormalBlending,
|
|
112
|
+
discardBackgroundColor: false,
|
|
113
|
+
backgroundColorTolerance: 1.0,
|
|
114
|
+
backgroundColor: { r: 1.0, g: 1.0, b: 1.0 },
|
|
111
115
|
transparent: true,
|
|
112
116
|
depthTest: true,
|
|
113
117
|
depthWrite: false,
|
|
@@ -192,6 +196,7 @@ const calculatePositionAndVelocity = (
|
|
|
192
196
|
{ shape, sphere, cone, circle, rectangle, box },
|
|
193
197
|
startSpeed,
|
|
194
198
|
position,
|
|
199
|
+
quaternion,
|
|
195
200
|
velocity,
|
|
196
201
|
velocityOverLifetime
|
|
197
202
|
) => {
|
|
@@ -199,6 +204,7 @@ const calculatePositionAndVelocity = (
|
|
|
199
204
|
case Shape.SPHERE:
|
|
200
205
|
calculateRandomPositionAndVelocityOnSphere(
|
|
201
206
|
position,
|
|
207
|
+
quaternion,
|
|
202
208
|
velocity,
|
|
203
209
|
startSpeed,
|
|
204
210
|
sphere
|
|
@@ -208,6 +214,7 @@ const calculatePositionAndVelocity = (
|
|
|
208
214
|
case Shape.CONE:
|
|
209
215
|
calculateRandomPositionAndVelocityOnCone(
|
|
210
216
|
position,
|
|
217
|
+
quaternion,
|
|
211
218
|
velocity,
|
|
212
219
|
startSpeed,
|
|
213
220
|
cone
|
|
@@ -217,6 +224,7 @@ const calculatePositionAndVelocity = (
|
|
|
217
224
|
case Shape.CIRCLE:
|
|
218
225
|
calculateRandomPositionAndVelocityOnCircle(
|
|
219
226
|
position,
|
|
227
|
+
quaternion,
|
|
220
228
|
velocity,
|
|
221
229
|
startSpeed,
|
|
222
230
|
circle
|
|
@@ -226,6 +234,7 @@ const calculatePositionAndVelocity = (
|
|
|
226
234
|
case Shape.RECTANGLE:
|
|
227
235
|
calculateRandomPositionAndVelocityOnRectangle(
|
|
228
236
|
position,
|
|
237
|
+
quaternion,
|
|
229
238
|
velocity,
|
|
230
239
|
startSpeed,
|
|
231
240
|
rectangle
|
|
@@ -235,6 +244,7 @@ const calculatePositionAndVelocity = (
|
|
|
235
244
|
case Shape.BOX:
|
|
236
245
|
calculateRandomPositionAndVelocityOnBox(
|
|
237
246
|
position,
|
|
247
|
+
quaternion,
|
|
238
248
|
velocity,
|
|
239
249
|
startSpeed,
|
|
240
250
|
box
|
|
@@ -243,18 +253,33 @@ const calculatePositionAndVelocity = (
|
|
|
243
253
|
}
|
|
244
254
|
|
|
245
255
|
if (velocityOverLifetime.isActive) {
|
|
246
|
-
|
|
247
|
-
velocityOverLifetime.linear.x.min
|
|
248
|
-
velocityOverLifetime.linear.x.max
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
velocityOverLifetime.linear.
|
|
257
|
-
|
|
256
|
+
if (
|
|
257
|
+
velocityOverLifetime.linear.x.min !== 0 ||
|
|
258
|
+
velocityOverLifetime.linear.x.max !== 0
|
|
259
|
+
) {
|
|
260
|
+
velocity.x += THREE.MathUtils.randFloat(
|
|
261
|
+
velocityOverLifetime.linear.x.min,
|
|
262
|
+
velocityOverLifetime.linear.x.max
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
if (
|
|
266
|
+
velocityOverLifetime.linear.y.min !== 0 ||
|
|
267
|
+
velocityOverLifetime.linear.y.max !== 0
|
|
268
|
+
) {
|
|
269
|
+
velocity.y += THREE.MathUtils.randFloat(
|
|
270
|
+
velocityOverLifetime.linear.y.min,
|
|
271
|
+
velocityOverLifetime.linear.y.max
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (
|
|
275
|
+
velocityOverLifetime.linear.z.min !== 0 ||
|
|
276
|
+
velocityOverLifetime.linear.z.max !== 0
|
|
277
|
+
) {
|
|
278
|
+
velocity.z += THREE.MathUtils.randFloat(
|
|
279
|
+
velocityOverLifetime.linear.z.min,
|
|
280
|
+
velocityOverLifetime.linear.z.max
|
|
281
|
+
);
|
|
282
|
+
}
|
|
258
283
|
}
|
|
259
284
|
};
|
|
260
285
|
|
|
@@ -268,10 +293,13 @@ export const createParticleSystem = (
|
|
|
268
293
|
currentWorldPosition: new THREE.Vector3(-99999),
|
|
269
294
|
worldPositionChange: new THREE.Vector3(),
|
|
270
295
|
worldQuaternion: new THREE.Quaternion(),
|
|
296
|
+
wrapperQuaternion: new THREE.Quaternion(),
|
|
271
297
|
lastWorldQuaternion: new THREE.Quaternion(-99999),
|
|
272
298
|
worldEuler: new THREE.Euler(),
|
|
273
299
|
gravityVelocity: new THREE.Vector3(0, 0, 0),
|
|
274
300
|
startValues: {},
|
|
301
|
+
hasOrbitalVelocity: false,
|
|
302
|
+
orbitalVelocityData: [],
|
|
275
303
|
lifetimeValues: {},
|
|
276
304
|
creationTimes: [],
|
|
277
305
|
noise: null,
|
|
@@ -332,6 +360,24 @@ export const createParticleSystem = (
|
|
|
332
360
|
);
|
|
333
361
|
|
|
334
362
|
generalData.creationTimes = Array.from({ length: maxParticles }, () => 0);
|
|
363
|
+
generalData.hasOrbitalVelocity =
|
|
364
|
+
normalizedConfig.velocityOverLifetime.isActive &&
|
|
365
|
+
(normalizedConfig.velocityOverLifetime.orbital.x.min !== 0 ||
|
|
366
|
+
normalizedConfig.velocityOverLifetime.orbital.x.max !== 0 ||
|
|
367
|
+
normalizedConfig.velocityOverLifetime.orbital.y.min !== 0 ||
|
|
368
|
+
normalizedConfig.velocityOverLifetime.orbital.y.max !== 0 ||
|
|
369
|
+
normalizedConfig.velocityOverLifetime.orbital.z.min !== 0 ||
|
|
370
|
+
normalizedConfig.velocityOverLifetime.orbital.z.max !== 0);
|
|
371
|
+
|
|
372
|
+
if (generalData.hasOrbitalVelocity) {
|
|
373
|
+
generalData.orbitalVelocityData = Array.from(
|
|
374
|
+
{ length: maxParticles },
|
|
375
|
+
() => ({
|
|
376
|
+
speed: new THREE.Vector3(),
|
|
377
|
+
positionOffset: new THREE.Vector3(),
|
|
378
|
+
})
|
|
379
|
+
);
|
|
380
|
+
}
|
|
335
381
|
|
|
336
382
|
const startValueKeys = ["startSize", "startOpacity"];
|
|
337
383
|
startValueKeys.forEach((key) => {
|
|
@@ -391,6 +437,15 @@ export const createParticleSystem = (
|
|
|
391
437
|
useFPSForFrameIndex: {
|
|
392
438
|
value: textureSheetAnimation.timeMode === TimeMode.FPS,
|
|
393
439
|
},
|
|
440
|
+
backgroundColor: {
|
|
441
|
+
value: renderer.backgroundColor,
|
|
442
|
+
},
|
|
443
|
+
discardBackgroundColor: {
|
|
444
|
+
value: renderer.discardBackgroundColor,
|
|
445
|
+
},
|
|
446
|
+
backgroundColorTolerance: {
|
|
447
|
+
value: renderer.backgroundColorTolerance,
|
|
448
|
+
},
|
|
394
449
|
},
|
|
395
450
|
vertexShader: ParticleSystemVertexShader,
|
|
396
451
|
fragmentShader: ParticleSystemFragmentShader,
|
|
@@ -407,6 +462,7 @@ export const createParticleSystem = (
|
|
|
407
462
|
shape,
|
|
408
463
|
startSpeed,
|
|
409
464
|
startPositions[i],
|
|
465
|
+
generalData.wrapperQuaternion,
|
|
410
466
|
velocities[i],
|
|
411
467
|
velocityOverLifetime
|
|
412
468
|
);
|
|
@@ -538,6 +594,7 @@ export const createParticleSystem = (
|
|
|
538
594
|
shape,
|
|
539
595
|
startSpeed,
|
|
540
596
|
startPositions[particleIndex],
|
|
597
|
+
generalData.wrapperQuaternion,
|
|
541
598
|
velocities[particleIndex],
|
|
542
599
|
velocityOverLifetime
|
|
543
600
|
);
|
|
@@ -550,6 +607,31 @@ export const createParticleSystem = (
|
|
|
550
607
|
(position ? position.z : 0) + startPositions[particleIndex].z;
|
|
551
608
|
geometry.attributes.position.needsUpdate = true;
|
|
552
609
|
|
|
610
|
+
if (generalData.hasOrbitalVelocity) {
|
|
611
|
+
generalData.orbitalVelocityData[particleIndex].speed.set(
|
|
612
|
+
THREE.MathUtils.randFloat(
|
|
613
|
+
normalizedConfig.velocityOverLifetime.orbital.x.min,
|
|
614
|
+
normalizedConfig.velocityOverLifetime.orbital.x.max
|
|
615
|
+
) *
|
|
616
|
+
(Math.PI / 180),
|
|
617
|
+
THREE.MathUtils.randFloat(
|
|
618
|
+
normalizedConfig.velocityOverLifetime.orbital.y.min,
|
|
619
|
+
normalizedConfig.velocityOverLifetime.orbital.y.max
|
|
620
|
+
) *
|
|
621
|
+
(Math.PI / 180),
|
|
622
|
+
THREE.MathUtils.randFloat(
|
|
623
|
+
normalizedConfig.velocityOverLifetime.orbital.z.min,
|
|
624
|
+
normalizedConfig.velocityOverLifetime.orbital.z.max
|
|
625
|
+
) *
|
|
626
|
+
(Math.PI / 180)
|
|
627
|
+
);
|
|
628
|
+
generalData.orbitalVelocityData[particleIndex].positionOffset.set(
|
|
629
|
+
startPositions[particleIndex].x,
|
|
630
|
+
startPositions[particleIndex].y,
|
|
631
|
+
startPositions[particleIndex].z
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
|
|
553
635
|
geometry.attributes.lifetime.array[particleIndex] = 0;
|
|
554
636
|
geometry.attributes.lifetime.needsUpdate = true;
|
|
555
637
|
|
|
@@ -559,15 +641,18 @@ export const createParticleSystem = (
|
|
|
559
641
|
noise: generalData.noise,
|
|
560
642
|
startValues: generalData.startValues,
|
|
561
643
|
lifetimeValues: generalData.lifetimeValues,
|
|
644
|
+
hasOrbitalVelocity: generalData.hasOrbitalVelocity,
|
|
645
|
+
orbitalVelocityData: generalData.orbitalVelocityData,
|
|
562
646
|
normalizedConfig,
|
|
563
647
|
attributes: particleSystem.geometry.attributes,
|
|
648
|
+
particleLifetime: 0,
|
|
564
649
|
particleLifetimePercentage: 0,
|
|
565
650
|
particleIndex,
|
|
566
651
|
forceUpdate: true,
|
|
567
652
|
});
|
|
568
653
|
};
|
|
569
654
|
|
|
570
|
-
|
|
655
|
+
let particleSystem = new THREE.Points(geometry, material);
|
|
571
656
|
particleSystem.sortParticles = true;
|
|
572
657
|
|
|
573
658
|
particleSystem.position.copy(transform.position);
|
|
@@ -579,8 +664,15 @@ export const createParticleSystem = (
|
|
|
579
664
|
const calculatedCreationTime =
|
|
580
665
|
now + THREE.MathUtils.randFloat(startDelay.min, startDelay.max) * 1000;
|
|
581
666
|
|
|
667
|
+
let wrapper;
|
|
668
|
+
if (normalizedConfig.simulationSpace === SimulationSpace.WORLD) {
|
|
669
|
+
wrapper = new Gyroscope();
|
|
670
|
+
wrapper.add(particleSystem);
|
|
671
|
+
}
|
|
672
|
+
|
|
582
673
|
createdParticleSystems.push({
|
|
583
674
|
particleSystem,
|
|
675
|
+
wrapper,
|
|
584
676
|
generalData,
|
|
585
677
|
onUpdate,
|
|
586
678
|
onComplete,
|
|
@@ -597,18 +689,26 @@ export const createParticleSystem = (
|
|
|
597
689
|
deactivateParticle,
|
|
598
690
|
activateParticle,
|
|
599
691
|
});
|
|
600
|
-
|
|
692
|
+
|
|
693
|
+
return wrapper || particleSystem;
|
|
601
694
|
};
|
|
602
695
|
|
|
603
696
|
export const destroyParticleSystem = (particleSystem) => {
|
|
604
697
|
createdParticleSystems = createdParticleSystems.filter(
|
|
605
|
-
({ particleSystem: savedParticleSystem }) =>
|
|
606
|
-
|
|
607
|
-
|
|
698
|
+
({ particleSystem: savedParticleSystem, wrapper }) => {
|
|
699
|
+
if (
|
|
700
|
+
savedParticleSystem !== particleSystem &&
|
|
701
|
+
wrapper !== particleSystem
|
|
702
|
+
) {
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
608
705
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
706
|
+
savedParticleSystem.geometry.dispose();
|
|
707
|
+
savedParticleSystem.material.dispose();
|
|
708
|
+
savedParticleSystem.parent.remove(savedParticleSystem);
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
);
|
|
612
712
|
};
|
|
613
713
|
|
|
614
714
|
export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
@@ -618,6 +718,7 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
618
718
|
generalData,
|
|
619
719
|
onComplete,
|
|
620
720
|
particleSystem,
|
|
721
|
+
wrapper,
|
|
621
722
|
creationTime,
|
|
622
723
|
lastEmissionTime,
|
|
623
724
|
duration,
|
|
@@ -640,8 +741,11 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
640
741
|
worldQuaternion,
|
|
641
742
|
worldEuler,
|
|
642
743
|
gravityVelocity,
|
|
744
|
+
hasOrbitalVelocity,
|
|
643
745
|
} = generalData;
|
|
644
746
|
|
|
747
|
+
if (wrapper) generalData.wrapperQuaternion.copy(wrapper.parent.quaternion);
|
|
748
|
+
|
|
645
749
|
const lastWorldPositionSnapshot = { ...lastWorldPosition };
|
|
646
750
|
|
|
647
751
|
const lifetime = now - creationTime;
|
|
@@ -654,7 +758,6 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
654
758
|
currentWorldPosition.y - lastWorldPosition.y,
|
|
655
759
|
currentWorldPosition.z - lastWorldPosition.z
|
|
656
760
|
);
|
|
657
|
-
worldPositionChange.applyQuaternion(worldQuaternion.invert());
|
|
658
761
|
}
|
|
659
762
|
generalData.distanceFromLastEmitByDistance += worldPositionChange.length();
|
|
660
763
|
particleSystem.getWorldPosition(lastWorldPosition);
|
|
@@ -685,9 +788,9 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
685
788
|
deactivateParticle(index);
|
|
686
789
|
else {
|
|
687
790
|
const velocity = velocities[index];
|
|
688
|
-
velocity.x -= gravityVelocity.x;
|
|
689
|
-
velocity.y -= gravityVelocity.y;
|
|
690
|
-
velocity.z -= gravityVelocity.z;
|
|
791
|
+
velocity.x -= gravityVelocity.x * delta;
|
|
792
|
+
velocity.y -= gravityVelocity.y * delta;
|
|
793
|
+
velocity.z -= gravityVelocity.z * delta;
|
|
691
794
|
|
|
692
795
|
if (
|
|
693
796
|
gravity !== 0 ||
|
|
@@ -707,6 +810,7 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
707
810
|
positionArr[positionIndex + 1] -= worldPositionChange.y;
|
|
708
811
|
positionArr[positionIndex + 2] -= worldPositionChange.z;
|
|
709
812
|
}
|
|
813
|
+
|
|
710
814
|
positionArr[positionIndex] += velocity.x * delta;
|
|
711
815
|
positionArr[positionIndex + 1] += velocity.y * delta;
|
|
712
816
|
positionArr[positionIndex + 2] += velocity.z * delta;
|
|
@@ -726,8 +830,11 @@ export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
|
726
830
|
noise: generalData.noise,
|
|
727
831
|
startValues: generalData.startValues,
|
|
728
832
|
lifetimeValues: generalData.lifetimeValues,
|
|
833
|
+
hasOrbitalVelocity: generalData.hasOrbitalVelocity,
|
|
834
|
+
orbitalVelocityData: generalData.orbitalVelocityData,
|
|
729
835
|
normalizedConfig,
|
|
730
836
|
attributes: particleSystem.geometry.attributes,
|
|
837
|
+
particleLifetime,
|
|
731
838
|
particleLifetimePercentage,
|
|
732
839
|
particleIndex: index,
|
|
733
840
|
});
|