@newkrok/three-particles 0.1.0 → 0.3.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 +6 -8
- package/package.json +5 -1
- package/src/js/effects/shaders/particle-system-fragment-shader.glsl.js +13 -3
- package/src/js/effects/shaders/particle-system-vertex-shader.glsl.js +13 -7
- package/src/js/effects/three-particles/three-particles-curves.js +74 -0
- package/src/js/effects/three-particles/three-particles-modifiers.js +44 -0
- package/src/js/effects/{three-particles-utils.js → three-particles/three-particles-utils.js} +43 -3
- package/src/js/effects/three-particles.js +278 -203
package/README.md
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
# THREE Particles
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
Particle system for ThreeJS
|
|
3
4
|
|
|
4
5
|
# THREE Particles Editor
|
|
6
|
+
|
|
5
7
|
You can create your own particle effects with it's editor https://github.com/NewKrok/three-particles-editor
|
|
6
8
|
|
|
7
9
|
# Live demo
|
|
10
|
+
|
|
8
11
|
https://newkrok.com/three-particles-editor/index.html
|
|
9
12
|
|
|
10
13
|
# Install
|
|
14
|
+
|
|
11
15
|
npm package https://www.npmjs.com/package/@newkrok/three-particles
|
|
12
16
|
|
|
13
17
|
Install with npm
|
|
14
18
|
`npm i @newkrok/three-particles`
|
|
15
19
|
|
|
16
20
|
Add as a package.json dependency
|
|
17
|
-
`
|
|
18
|
-
"dependencies": {
|
|
19
|
-
...
|
|
20
|
-
"@newkrok/three-particles": "0.0.1"
|
|
21
|
-
...
|
|
22
|
-
},
|
|
23
|
-
`
|
|
21
|
+
`"dependencies": { ... "@newkrok/three-particles": "0.2.2" ... }, `
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newkrok/three-particles",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Particle system for ThreeJS",
|
|
5
5
|
"main": "src/js/three-particles.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"url": "https://github.com/NewKrok/three-particles/issues"
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/NewKrok/three-particles#readme",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"three": "0.135.0",
|
|
27
|
+
"easing-functions": "1.0.1"
|
|
28
|
+
},
|
|
25
29
|
"scripts": {
|
|
26
30
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
27
31
|
}
|
|
@@ -2,20 +2,30 @@ const ParticleSystemFragmentShader = `
|
|
|
2
2
|
uniform sampler2D map;
|
|
3
3
|
uniform float elapsed;
|
|
4
4
|
uniform float fps;
|
|
5
|
+
uniform bool useFPSForFrameIndex;
|
|
5
6
|
uniform vec2 tiles;
|
|
6
7
|
|
|
7
8
|
varying vec4 vColor;
|
|
8
|
-
varying float
|
|
9
|
+
varying float vLifetime;
|
|
10
|
+
varying float vStartLifetime;
|
|
9
11
|
varying float vRotation;
|
|
12
|
+
varying float vStartFrame;
|
|
10
13
|
|
|
11
14
|
void main()
|
|
12
15
|
{
|
|
13
16
|
gl_FragColor = vColor;
|
|
14
17
|
float mid = 0.5;
|
|
15
18
|
|
|
16
|
-
float frameIndex =
|
|
19
|
+
float frameIndex = round(vStartFrame) + (
|
|
20
|
+
useFPSForFrameIndex == true
|
|
21
|
+
? fps == 0.0
|
|
22
|
+
? 0.0
|
|
23
|
+
: max((vLifetime / 1000.0) * fps, 0.0)
|
|
24
|
+
: max(min(floor(min(vLifetime / vStartLifetime, 1.0) * (tiles.x * tiles.y)), tiles.x * tiles.y - 1.0), 0.0)
|
|
25
|
+
);
|
|
26
|
+
|
|
17
27
|
float spriteXIndex = floor(mod(frameIndex, tiles.x));
|
|
18
|
-
float spriteYIndex = floor(mod(frameIndex / tiles.
|
|
28
|
+
float spriteYIndex = floor(mod(frameIndex / tiles.x, tiles.y));
|
|
19
29
|
|
|
20
30
|
vec2 frameUV = vec2(
|
|
21
31
|
gl_PointCoord.x / tiles.x + spriteXIndex / tiles.x,
|
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
const ParticleSystemVertexShader = `
|
|
2
|
-
attribute float
|
|
2
|
+
attribute float size;
|
|
3
3
|
attribute float colorR;
|
|
4
4
|
attribute float colorG;
|
|
5
5
|
attribute float colorB;
|
|
6
6
|
attribute float colorA;
|
|
7
|
-
attribute float
|
|
7
|
+
attribute float lifetime;
|
|
8
|
+
attribute float startLifetime;
|
|
8
9
|
attribute float rotation;
|
|
10
|
+
attribute float startFrame;
|
|
9
11
|
|
|
10
12
|
varying mat4 vPosition;
|
|
11
13
|
varying vec4 vColor;
|
|
12
|
-
varying float
|
|
14
|
+
varying float vLifetime;
|
|
15
|
+
varying float vStartLifetime;
|
|
13
16
|
varying float vRotation;
|
|
17
|
+
varying float vStartFrame;
|
|
14
18
|
|
|
15
19
|
void main()
|
|
16
20
|
{
|
|
17
21
|
vColor = vec4(colorR, colorG, colorB, colorA);
|
|
18
|
-
|
|
22
|
+
vLifetime = lifetime;
|
|
23
|
+
vStartLifetime = startLifetime;
|
|
19
24
|
vRotation = rotation;
|
|
25
|
+
vStartFrame = startFrame;
|
|
20
26
|
|
|
21
27
|
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
22
|
-
gl_PointSize =
|
|
28
|
+
gl_PointSize = size * (100.0 / length(mvPosition.xyz));
|
|
23
29
|
gl_Position = projectionMatrix * mvPosition;
|
|
24
30
|
}
|
|
25
|
-
|
|
31
|
+
`;
|
|
26
32
|
|
|
27
|
-
export default ParticleSystemVertexShader
|
|
33
|
+
export default ParticleSystemVertexShader;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import Easing from "easing-functions";
|
|
2
|
+
|
|
3
|
+
export const CurveFunction = {
|
|
4
|
+
LINEAR: "LINEAR",
|
|
5
|
+
QUADRATIC_IN: "QUADRATIC_IN",
|
|
6
|
+
QUADRATIC_OUT: "QUADRATIC_OUT",
|
|
7
|
+
QUADRATIC_IN_OUT: "QUADRATIC_IN_OUT",
|
|
8
|
+
CUBIC_IN: "CUBIC_IN",
|
|
9
|
+
CUBIC_OUT: "CUBIC_OUT",
|
|
10
|
+
CUBIC_IN_OUT: "CUBIC_IN_OUT",
|
|
11
|
+
QUARTIC_IN: "QUARTIC_IN",
|
|
12
|
+
QUARTIC_OUT: "QUARTIC_OUT",
|
|
13
|
+
QUARTIC_IN_OUT: "QUARTIC_IN_OUT",
|
|
14
|
+
QUINTIC_IN: "QUINTIC_IN",
|
|
15
|
+
QUINTIC_OUT: "QUINTIC_OUT",
|
|
16
|
+
QUINTIC_IN_OUT: "QUINTIC_IN_OUT",
|
|
17
|
+
SINUSOIDAL_IN: "SINUSOIDAL_IN",
|
|
18
|
+
SINUSOIDAL_OUT: "SINUSOIDAL_OUT",
|
|
19
|
+
SINUSOIDAL_IN_OUT: "SINUSOIDAL_IN_OUT",
|
|
20
|
+
EXPONENTIAL_IN: "EXPONENTIAL_IN",
|
|
21
|
+
EXPONENTIAL_OUT: "EXPONENTIAL_OUT",
|
|
22
|
+
EXPONENTIAL_IN_OUT: "EXPONENTIAL_IN_OUT",
|
|
23
|
+
CIRCULAR_IN: "CIRCULAR_IN",
|
|
24
|
+
CIRCULAR_OUT: "CIRCULAR_OUT",
|
|
25
|
+
CIRCULAR_IN_OUT: "CIRCULAR_IN_OUT",
|
|
26
|
+
ELASTIC_IN: "ELASTIC_IN",
|
|
27
|
+
ELASTIC_OUT: "ELASTIC_OUT",
|
|
28
|
+
ELASTIC_IN_OUT: "ELASTIC_IN_OUT",
|
|
29
|
+
BACK_IN: "BACK_IN",
|
|
30
|
+
BACK_OUT: "BACK_OUT",
|
|
31
|
+
BACK_IN_OUT: "BACK_IN_OUT",
|
|
32
|
+
BOUNCE_IN: "BOUNCE_IN",
|
|
33
|
+
BOUNCE_OUT: "BOUNCE_OUT",
|
|
34
|
+
BOUNCE_IN_OUT: "BOUNCE_IN_OUT",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const CurveFunctionMap = {
|
|
38
|
+
[CurveFunction.LINEAR]: Easing.Linear.None,
|
|
39
|
+
[CurveFunction.QUADRATIC_IN]: Easing.Quadratic.In,
|
|
40
|
+
[CurveFunction.QUADRATIC_OUT]: Easing.Quadratic.Out,
|
|
41
|
+
[CurveFunction.QUADRATIC_IN_OUT]: Easing.Quadratic.InOut,
|
|
42
|
+
[CurveFunction.CUBIC_IN]: Easing.Cubic.In,
|
|
43
|
+
[CurveFunction.CUBIC_OUT]: Easing.Cubic.Out,
|
|
44
|
+
[CurveFunction.CUBIC_IN_OUT]: Easing.Cubic.InOut,
|
|
45
|
+
[CurveFunction.QUARTIC_IN]: Easing.Quartic.In,
|
|
46
|
+
[CurveFunction.QUARTIC_OUT]: Easing.Quartic.Out,
|
|
47
|
+
[CurveFunction.QUARTIC_IN_OUT]: Easing.Quartic.InOut,
|
|
48
|
+
[CurveFunction.QUINTIC_IN]: Easing.Quintic.In,
|
|
49
|
+
[CurveFunction.QUINTIC_OUT]: Easing.Quintic.Out,
|
|
50
|
+
[CurveFunction.QUINTIC_IN_OUT]: Easing.Quintic.InOut,
|
|
51
|
+
[CurveFunction.SINUSOIDAL_IN]: Easing.Sinusoidal.In,
|
|
52
|
+
[CurveFunction.SINUSOIDAL_OUT]: Easing.Sinusoidal.Out,
|
|
53
|
+
[CurveFunction.SINUSOIDAL_IN_OUT]: Easing.Sinusoidal.InOut,
|
|
54
|
+
[CurveFunction.EXPONENTIAL_IN]: Easing.Exponential.In,
|
|
55
|
+
[CurveFunction.EXPONENTIAL_OUT]: Easing.Exponential.Out,
|
|
56
|
+
[CurveFunction.EXPONENTIAL_IN_OUT]: Easing.Exponential.InOut,
|
|
57
|
+
[CurveFunction.CIRCULAR_IN]: Easing.Circular.In,
|
|
58
|
+
[CurveFunction.CIRCULAR_OUT]: Easing.Circular.Out,
|
|
59
|
+
[CurveFunction.CIRCULAR_IN_OUT]: Easing.Circular.InOut,
|
|
60
|
+
[CurveFunction.ELASTIC_IN]: Easing.Elastic.In,
|
|
61
|
+
[CurveFunction.ELASTIC_OUT]: Easing.Elastic.Out,
|
|
62
|
+
[CurveFunction.ELASTIC_IN_OUT]: Easing.Elastic.InOut,
|
|
63
|
+
[CurveFunction.BACK_IN]: Easing.Back.In,
|
|
64
|
+
[CurveFunction.BACK_OUT]: Easing.Back.Out,
|
|
65
|
+
[CurveFunction.BACK_IN_OUT]: Easing.Back.InOut,
|
|
66
|
+
[CurveFunction.BOUNCE_IN]: Easing.Bounce.In,
|
|
67
|
+
[CurveFunction.BOUNCE_OUT]: Easing.Bounce.Out,
|
|
68
|
+
[CurveFunction.BOUNCE_IN_OUT]: Easing.Bounce.InOut,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const getCurveFunction = (curveFunction) =>
|
|
72
|
+
typeof curveFunction === "function"
|
|
73
|
+
? curveFunction
|
|
74
|
+
: CurveFunctionMap[curveFunction];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { getCurveFunction } from "./three-particles-curves.js";
|
|
2
|
+
|
|
3
|
+
const modifiers = [
|
|
4
|
+
// {key:"colorOverLifetime", attributeKeys:["colorR", "colorG", "colorB"]},
|
|
5
|
+
{
|
|
6
|
+
key: "opacityOverLifetime",
|
|
7
|
+
attributeKeys: ["colorA"],
|
|
8
|
+
startValueKeys: ["startOpacity"],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
key: "sizeOverLifetime",
|
|
12
|
+
attributeKeys: ["size"],
|
|
13
|
+
startValueKeys: ["startSize"],
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const applyModifiers = ({
|
|
18
|
+
startValues,
|
|
19
|
+
normalizedConfig,
|
|
20
|
+
attributes,
|
|
21
|
+
particleLifetimePercentage,
|
|
22
|
+
particleIndex,
|
|
23
|
+
forceUpdate = false,
|
|
24
|
+
}) => {
|
|
25
|
+
modifiers.forEach(({ key, attributeKeys, startValueKeys }) => {
|
|
26
|
+
const modifier = normalizedConfig[key];
|
|
27
|
+
if (modifier.isActive) {
|
|
28
|
+
const multiplier = getCurveFunction(modifier.curveFunction)(
|
|
29
|
+
particleLifetimePercentage
|
|
30
|
+
);
|
|
31
|
+
attributeKeys.forEach((attributeKey, index) => {
|
|
32
|
+
attributes[attributeKey].array[particleIndex] =
|
|
33
|
+
startValues[startValueKeys[index]][particleIndex] * multiplier;
|
|
34
|
+
attributes[attributeKey].needsUpdate = true;
|
|
35
|
+
});
|
|
36
|
+
} else if (forceUpdate) {
|
|
37
|
+
attributeKeys.forEach((attributeKey, index) => {
|
|
38
|
+
attributes[attributeKey].array[particleIndex] =
|
|
39
|
+
startValues[startValueKeys[index]][particleIndex];
|
|
40
|
+
attributes[attributeKey].needsUpdate = true;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
};
|
package/src/js/effects/{three-particles-utils.js → three-particles/three-particles-utils.js}
RENAMED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import * as THREE from "three/build/three.module.js";
|
|
2
2
|
|
|
3
|
+
export const patchObject = (
|
|
4
|
+
objectA,
|
|
5
|
+
objectB,
|
|
6
|
+
config = { skippedProperties: [], applyToFirstObject: false }
|
|
7
|
+
) => {
|
|
8
|
+
const result = {};
|
|
9
|
+
Object.keys(objectA).forEach((key) => {
|
|
10
|
+
if (!config.skippedProperties || !config.skippedProperties.includes(key)) {
|
|
11
|
+
if (typeof objectA[key] === "object" && objectA[key] && objectB[key]) {
|
|
12
|
+
result[key] = patchObject(objectA[key], objectB[key], config);
|
|
13
|
+
} else {
|
|
14
|
+
result[key] = objectB[key] === 0 ? 0 : objectB[key] || objectA[key];
|
|
15
|
+
if (config.applyToFirstObject) objectA[key] = result[key];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
|
|
3
22
|
export const calculateRandomPositionAndVelocityOnSphere = (
|
|
4
23
|
position,
|
|
5
24
|
velocity,
|
|
@@ -81,7 +100,7 @@ export const calculateRandomPositionAndVelocityOnCone = (
|
|
|
81
100
|
sinNormalizedAngle *
|
|
82
101
|
speedMultiplierByPosition *
|
|
83
102
|
randomizedSpeed,
|
|
84
|
-
|
|
103
|
+
Math.cos(normalizedAngle) * randomizedSpeed
|
|
85
104
|
);
|
|
86
105
|
};
|
|
87
106
|
|
|
@@ -106,12 +125,12 @@ export const calculateRandomPositionAndVelocityOnCircle = (
|
|
|
106
125
|
radius * radiusThickness * randomizedDistanceRatio * yDirection;
|
|
107
126
|
position.z = 0;
|
|
108
127
|
|
|
109
|
-
const positionLength = position.length();
|
|
110
|
-
|
|
111
128
|
const randomizedSpeed = THREE.MathUtils.randFloat(
|
|
112
129
|
startSpeed.min,
|
|
113
130
|
startSpeed.max
|
|
114
131
|
);
|
|
132
|
+
|
|
133
|
+
const positionLength = position.length();
|
|
115
134
|
const speedMultiplierByPosition = 1 / positionLength;
|
|
116
135
|
velocity.set(
|
|
117
136
|
position.x * speedMultiplierByPosition * randomizedSpeed,
|
|
@@ -119,3 +138,24 @@ export const calculateRandomPositionAndVelocityOnCircle = (
|
|
|
119
138
|
0
|
|
120
139
|
);
|
|
121
140
|
};
|
|
141
|
+
|
|
142
|
+
export const calculateRandomPositionAndVelocityOnRectangle = (
|
|
143
|
+
position,
|
|
144
|
+
velocity,
|
|
145
|
+
startSpeed,
|
|
146
|
+
{ rotation, scale }
|
|
147
|
+
) => {
|
|
148
|
+
const xOffset = Math.random() * scale.x - scale.x / 2;
|
|
149
|
+
const yOffset = Math.random() * scale.y - scale.y / 2;
|
|
150
|
+
const rotationX = THREE.Math.degToRad(rotation.x);
|
|
151
|
+
const rotationY = THREE.Math.degToRad(rotation.y);
|
|
152
|
+
position.x = xOffset * Math.cos(rotationY);
|
|
153
|
+
position.y = yOffset * Math.cos(rotationX);
|
|
154
|
+
position.z = xOffset * Math.sin(rotationY) - yOffset * Math.sin(rotationX);
|
|
155
|
+
|
|
156
|
+
const randomizedSpeed = THREE.MathUtils.randFloat(
|
|
157
|
+
startSpeed.min,
|
|
158
|
+
startSpeed.max
|
|
159
|
+
);
|
|
160
|
+
velocity.set(0, 0, randomizedSpeed);
|
|
161
|
+
};
|
|
@@ -3,11 +3,15 @@ import * as THREE from "three/build/three.module.js";
|
|
|
3
3
|
import {
|
|
4
4
|
calculateRandomPositionAndVelocityOnCircle,
|
|
5
5
|
calculateRandomPositionAndVelocityOnCone,
|
|
6
|
+
calculateRandomPositionAndVelocityOnRectangle,
|
|
6
7
|
calculateRandomPositionAndVelocityOnSphere,
|
|
7
|
-
|
|
8
|
+
patchObject,
|
|
9
|
+
} from "./three-particles/three-particles-utils.js";
|
|
8
10
|
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
+
import { CurveFunction } from "./three-particles/three-particles-curves.js";
|
|
12
|
+
import ParticleSystemFragmentShader from "./three-particles/shaders/particle-system-fragment-shader.glsl.js";
|
|
13
|
+
import ParticleSystemVertexShader from "./three-particles/shaders/particle-system-vertex-shader.glsl.js";
|
|
14
|
+
import { applyModifiers } from "./three-particles/three-particles-modifiers.js";
|
|
11
15
|
|
|
12
16
|
// Float32Array is not enough accurate when we are storing timestamp in it so we just remove unnecessary time
|
|
13
17
|
const float32Helper = 1638200000000;
|
|
@@ -27,9 +31,81 @@ export const Shape = {
|
|
|
27
31
|
RECTANGLE: "RECTANGLE",
|
|
28
32
|
};
|
|
29
33
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
export const TimeMode = {
|
|
35
|
+
LIFETIME: "LIFETIME",
|
|
36
|
+
FPS: "FPS",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const getDefaultParticleSystemConfig = () =>
|
|
40
|
+
JSON.parse(JSON.stringify(DEFAULT_PARTICLE_SYSTEM_CONFIG));
|
|
41
|
+
|
|
42
|
+
const DEFAULT_PARTICLE_SYSTEM_CONFIG = {
|
|
43
|
+
transform: {
|
|
44
|
+
position: { x: 0, y: 0, z: 0 },
|
|
45
|
+
rotation: { x: 0, y: 0, z: 0 },
|
|
46
|
+
scale: { x: 1, y: 1, z: 1 },
|
|
47
|
+
},
|
|
48
|
+
duration: 5.0,
|
|
49
|
+
looping: true,
|
|
50
|
+
startDelay: { min: 0.0, max: 0.0 },
|
|
51
|
+
startLifetime: { min: 2.0, max: 2.0 },
|
|
52
|
+
startSpeed: { min: 1.0, max: 1.0 },
|
|
53
|
+
startSize: { min: 1.0, max: 1.0 },
|
|
54
|
+
startRotation: { min: 0.0, max: 0.0 },
|
|
55
|
+
startColor: {
|
|
56
|
+
min: { r: 1.0, g: 1.0, b: 1.0 },
|
|
57
|
+
max: { r: 1.0, g: 1.0, b: 1.0 },
|
|
58
|
+
},
|
|
59
|
+
startOpacity: { min: 1.0, max: 1.0 },
|
|
60
|
+
gravity: 0.0,
|
|
61
|
+
simulationSpace: SimulationSpace.LOCAL,
|
|
62
|
+
maxParticles: 100.0,
|
|
63
|
+
emission: {
|
|
64
|
+
rateOverTime: 10.0,
|
|
65
|
+
rateOverDistance: 0.0,
|
|
66
|
+
},
|
|
67
|
+
shape: {
|
|
68
|
+
shape: Shape.SPHERE,
|
|
69
|
+
sphere: {
|
|
70
|
+
radius: 1.0,
|
|
71
|
+
radiusThickness: 1.0,
|
|
72
|
+
arc: 360.0,
|
|
73
|
+
},
|
|
74
|
+
cone: {
|
|
75
|
+
angle: 25.0,
|
|
76
|
+
radius: 1.0,
|
|
77
|
+
radiusThickness: 1.0,
|
|
78
|
+
arc: 360.0,
|
|
79
|
+
},
|
|
80
|
+
circle: {
|
|
81
|
+
radius: 1.0,
|
|
82
|
+
radiusThickness: 1.0,
|
|
83
|
+
arc: 360.0,
|
|
84
|
+
},
|
|
85
|
+
rectangle: {
|
|
86
|
+
rotation: { x: 0.0, y: 0.0 }, // TODO: add z rotation
|
|
87
|
+
scale: { x: 1.0, y: 1.0 },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
map: null,
|
|
91
|
+
sizeOverLifetime: {
|
|
92
|
+
isActive: false,
|
|
93
|
+
curveFunction: CurveFunction.LINEAR,
|
|
94
|
+
},
|
|
95
|
+
/* colorOverLifetime: {
|
|
96
|
+
isActive: false,
|
|
97
|
+
curveFunction: CurveFunction.LINEAR,
|
|
98
|
+
}, */
|
|
99
|
+
opacityOverLifetime: {
|
|
100
|
+
isActive: false,
|
|
101
|
+
curveFunction: CurveFunction.LINEAR,
|
|
102
|
+
},
|
|
103
|
+
textureSheetAnimation: {
|
|
104
|
+
tiles: new THREE.Vector2(1.0, 1.0),
|
|
105
|
+
timeMode: TimeMode.LIFETIME,
|
|
106
|
+
fps: 10.0,
|
|
107
|
+
startFrame: { min: 0.0, max: 0.0 },
|
|
108
|
+
},
|
|
33
109
|
};
|
|
34
110
|
|
|
35
111
|
const createFloat32Attributes = ({
|
|
@@ -53,7 +129,7 @@ const createFloat32Attributes = ({
|
|
|
53
129
|
};
|
|
54
130
|
|
|
55
131
|
const calculatePositionAndVelocity = (
|
|
56
|
-
{ shape, sphere, cone, circle },
|
|
132
|
+
{ shape, sphere, cone, circle, rectangle },
|
|
57
133
|
startSpeed,
|
|
58
134
|
position,
|
|
59
135
|
velocity
|
|
@@ -85,79 +161,57 @@ const calculatePositionAndVelocity = (
|
|
|
85
161
|
circle
|
|
86
162
|
);
|
|
87
163
|
break;
|
|
164
|
+
|
|
165
|
+
case Shape.RECTANGLE:
|
|
166
|
+
calculateRandomPositionAndVelocityOnRectangle(
|
|
167
|
+
position,
|
|
168
|
+
velocity,
|
|
169
|
+
startSpeed,
|
|
170
|
+
rectangle
|
|
171
|
+
);
|
|
172
|
+
break;
|
|
88
173
|
}
|
|
89
174
|
};
|
|
90
175
|
|
|
91
|
-
export const createParticleSystem = (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
startDelay = { min: 0.0, max: 0.0 },
|
|
95
|
-
startLifeTime = { min: 5.0, max: 5.0 },
|
|
96
|
-
startSpeed = { min: 5.0, max: 5.0 },
|
|
97
|
-
startSize = { min: 1.0, max: 1.0 },
|
|
98
|
-
startRotation = { min: 0.0, max: 0.0 },
|
|
99
|
-
startColor = {
|
|
100
|
-
min: { r: 1.0, g: 1.0, b: 1.0 },
|
|
101
|
-
max: { r: 1.0, g: 1.0, b: 1.0 },
|
|
102
|
-
},
|
|
103
|
-
startOpacity = { min: 1.0, max: 1.0 },
|
|
104
|
-
gravity = 0.0,
|
|
105
|
-
simulationSpace = SimulationSpace.LOCAL,
|
|
106
|
-
maxParticles = 100,
|
|
107
|
-
emission = {
|
|
108
|
-
rateOverTime: 10.0,
|
|
109
|
-
rateOverDistance: 0.0,
|
|
110
|
-
},
|
|
111
|
-
shape,
|
|
112
|
-
map,
|
|
113
|
-
onUpdate = null,
|
|
114
|
-
onComplete = null,
|
|
115
|
-
textureSheetAnimation = defaultTextureSheetAnimation,
|
|
116
|
-
}) => {
|
|
176
|
+
export const createParticleSystem = (
|
|
177
|
+
config = DEFAULT_PARTICLE_SYSTEM_CONFIG
|
|
178
|
+
) => {
|
|
117
179
|
const now = Date.now();
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
min: { r: 1.0, g: 1.0, b: 1.0, ...startColor.min },
|
|
129
|
-
max: { r: 1.0, g: 1.0, b: 1.0, ...startColor.max },
|
|
130
|
-
};
|
|
131
|
-
const normalizedStartOpacity = { min: 0.0, max: 0.0, ...startOpacity };
|
|
132
|
-
const normalizedEmission = {
|
|
133
|
-
rateOverTime: 10.0,
|
|
134
|
-
rateOverDistance: 0.0,
|
|
135
|
-
...emission,
|
|
136
|
-
};
|
|
137
|
-
const normalizedShape = {
|
|
138
|
-
shape: Shape.SPHERE,
|
|
139
|
-
sphere: {
|
|
140
|
-
radius: 1.0,
|
|
141
|
-
radiusThickness: 1.0,
|
|
142
|
-
arc: 360.0,
|
|
143
|
-
...shape.sphere,
|
|
144
|
-
},
|
|
145
|
-
cone: {
|
|
146
|
-
angle: 25,
|
|
147
|
-
radius: 1.0,
|
|
148
|
-
radiusThickness: 1.0,
|
|
149
|
-
arc: 360.0,
|
|
150
|
-
...shape.cone,
|
|
151
|
-
},
|
|
152
|
-
circle: {
|
|
153
|
-
radius: 1.0,
|
|
154
|
-
radiusThickness: 1.0,
|
|
155
|
-
arc: 360.0,
|
|
156
|
-
...shape.circle,
|
|
157
|
-
},
|
|
158
|
-
...shape,
|
|
180
|
+
const generalData = {
|
|
181
|
+
distanceFromLastEmitByDistance: 0,
|
|
182
|
+
lastWorldPosition: new THREE.Vector3(-99999),
|
|
183
|
+
currentWorldPosition: new THREE.Vector3(-99999),
|
|
184
|
+
worldPositionChange: new THREE.Vector3(),
|
|
185
|
+
worldQuaternion: new THREE.Quaternion(),
|
|
186
|
+
lastWorldQuaternion: new THREE.Quaternion(-99999),
|
|
187
|
+
worldEuler: new THREE.Euler(),
|
|
188
|
+
gravityVelocity: new THREE.Vector3(0, 0, 0),
|
|
189
|
+
startValues: {},
|
|
159
190
|
};
|
|
160
191
|
|
|
192
|
+
const normalizedConfig = patchObject(DEFAULT_PARTICLE_SYSTEM_CONFIG, config);
|
|
193
|
+
const {
|
|
194
|
+
transform,
|
|
195
|
+
duration,
|
|
196
|
+
looping,
|
|
197
|
+
startDelay,
|
|
198
|
+
startLifetime,
|
|
199
|
+
startSpeed,
|
|
200
|
+
startSize,
|
|
201
|
+
startRotation,
|
|
202
|
+
startColor,
|
|
203
|
+
startOpacity,
|
|
204
|
+
gravity,
|
|
205
|
+
simulationSpace,
|
|
206
|
+
maxParticles,
|
|
207
|
+
emission,
|
|
208
|
+
shape,
|
|
209
|
+
map,
|
|
210
|
+
onUpdate,
|
|
211
|
+
onComplete,
|
|
212
|
+
textureSheetAnimation,
|
|
213
|
+
} = normalizedConfig;
|
|
214
|
+
|
|
161
215
|
const startPositions = Array.from(
|
|
162
216
|
{ length: maxParticles },
|
|
163
217
|
() => new THREE.Vector3()
|
|
@@ -167,21 +221,15 @@ export const createParticleSystem = ({
|
|
|
167
221
|
() => new THREE.Vector3()
|
|
168
222
|
);
|
|
169
223
|
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
(prev, key) => ({
|
|
180
|
-
...prev,
|
|
181
|
-
[key]: { value: rawUniforms[key] },
|
|
182
|
-
}),
|
|
183
|
-
{}
|
|
184
|
-
);
|
|
224
|
+
const startValueKeys = ["startSize", "startOpacity"];
|
|
225
|
+
startValueKeys.forEach((key) => {
|
|
226
|
+
generalData.startValues[key] = Array.from({ length: maxParticles }, () =>
|
|
227
|
+
THREE.MathUtils.randFloat(
|
|
228
|
+
normalizedConfig[key].min,
|
|
229
|
+
normalizedConfig[key].max
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
});
|
|
185
233
|
|
|
186
234
|
const material = new THREE.ShaderMaterial({
|
|
187
235
|
uniforms: {
|
|
@@ -191,7 +239,15 @@ export const createParticleSystem = ({
|
|
|
191
239
|
map: {
|
|
192
240
|
value: map,
|
|
193
241
|
},
|
|
194
|
-
|
|
242
|
+
tiles: {
|
|
243
|
+
value: textureSheetAnimation.tiles,
|
|
244
|
+
},
|
|
245
|
+
fps: {
|
|
246
|
+
value: textureSheetAnimation.fps,
|
|
247
|
+
},
|
|
248
|
+
useFPSForFrameIndex: {
|
|
249
|
+
value: textureSheetAnimation.timeMode === TimeMode.FPS,
|
|
250
|
+
},
|
|
195
251
|
},
|
|
196
252
|
vertexShader: ParticleSystemVertexShader,
|
|
197
253
|
fragmentShader: ParticleSystemFragmentShader,
|
|
@@ -205,8 +261,8 @@ export const createParticleSystem = ({
|
|
|
205
261
|
|
|
206
262
|
for (let i = 0; i < maxParticles; i++)
|
|
207
263
|
calculatePositionAndVelocity(
|
|
208
|
-
|
|
209
|
-
|
|
264
|
+
shape,
|
|
265
|
+
startSpeed,
|
|
210
266
|
startPositions[i],
|
|
211
267
|
velocities[i]
|
|
212
268
|
);
|
|
@@ -228,39 +284,29 @@ export const createParticleSystem = ({
|
|
|
228
284
|
|
|
229
285
|
createFloat32AttributesRequest("isActive", false);
|
|
230
286
|
createFloat32AttributesRequest("creationTime", 0);
|
|
231
|
-
createFloat32AttributesRequest("
|
|
232
|
-
createFloat32AttributesRequest("
|
|
233
|
-
THREE.MathUtils.randFloat(
|
|
234
|
-
|
|
235
|
-
|
|
287
|
+
createFloat32AttributesRequest("lifetime", 0);
|
|
288
|
+
createFloat32AttributesRequest("startLifetime", () =>
|
|
289
|
+
THREE.MathUtils.randFloat(startLifetime.min, startLifetime.max)
|
|
290
|
+
);
|
|
291
|
+
createFloat32AttributesRequest("startFrame", () =>
|
|
292
|
+
THREE.MathUtils.randInt(
|
|
293
|
+
textureSheetAnimation.startFrame.min,
|
|
294
|
+
textureSheetAnimation.startFrame.max
|
|
236
295
|
)
|
|
237
296
|
);
|
|
238
297
|
|
|
239
298
|
createFloat32AttributesRequest("opacity", 0);
|
|
240
299
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
THREE.Math.degToRad(
|
|
247
|
-
THREE.MathUtils.randFloat(
|
|
248
|
-
normalizedStartRotation.min,
|
|
249
|
-
normalizedStartRotation.max
|
|
250
|
-
)
|
|
251
|
-
),
|
|
252
|
-
});
|
|
300
|
+
createFloat32AttributesRequest("rotation", () =>
|
|
301
|
+
THREE.Math.degToRad(
|
|
302
|
+
THREE.MathUtils.randFloat(startRotation.min, startRotation.max)
|
|
303
|
+
)
|
|
304
|
+
);
|
|
253
305
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
factory: () =>
|
|
259
|
-
THREE.MathUtils.randFloat(
|
|
260
|
-
normalizedStartSize.min,
|
|
261
|
-
normalizedStartSize.max
|
|
262
|
-
),
|
|
263
|
-
});
|
|
306
|
+
createFloat32AttributesRequest(
|
|
307
|
+
"size",
|
|
308
|
+
(_, index) => generalData.startValues.startSize[index]
|
|
309
|
+
);
|
|
264
310
|
|
|
265
311
|
createFloat32AttributesRequest("rotation", 0);
|
|
266
312
|
|
|
@@ -268,30 +314,25 @@ export const createParticleSystem = ({
|
|
|
268
314
|
createFloat32AttributesRequest(
|
|
269
315
|
"colorR",
|
|
270
316
|
() =>
|
|
271
|
-
|
|
272
|
-
colorRandomRatio *
|
|
273
|
-
(normalizedStartColor.max.r - normalizedStartColor.min.r)
|
|
317
|
+
startColor.min.r +
|
|
318
|
+
colorRandomRatio * (startColor.max.r - startColor.min.r)
|
|
274
319
|
);
|
|
275
320
|
createFloat32AttributesRequest(
|
|
276
321
|
"colorG",
|
|
277
322
|
() =>
|
|
278
|
-
|
|
279
|
-
colorRandomRatio *
|
|
280
|
-
(normalizedStartColor.max.g - normalizedStartColor.min.g)
|
|
323
|
+
startColor.min.g +
|
|
324
|
+
colorRandomRatio * (startColor.max.g - startColor.min.g)
|
|
281
325
|
);
|
|
282
326
|
createFloat32AttributesRequest(
|
|
283
327
|
"colorB",
|
|
284
328
|
() =>
|
|
285
|
-
|
|
286
|
-
colorRandomRatio *
|
|
287
|
-
(normalizedStartColor.max.b - normalizedStartColor.min.b)
|
|
329
|
+
startColor.min.b +
|
|
330
|
+
colorRandomRatio * (startColor.max.b - startColor.min.b)
|
|
288
331
|
);
|
|
289
332
|
createFloat32AttributesRequest("colorA", 0);
|
|
290
333
|
|
|
291
334
|
const deactivateParticle = (particleIndex) => {
|
|
292
335
|
geometry.attributes.isActive.array[particleIndex] = false;
|
|
293
|
-
geometry.attributes.lifeTime.array[particleIndex] = 0;
|
|
294
|
-
geometry.attributes.lifeTime.needsUpdate = true;
|
|
295
336
|
geometry.attributes.colorA.array[particleIndex] = 0;
|
|
296
337
|
geometry.attributes.colorA.needsUpdate = true;
|
|
297
338
|
};
|
|
@@ -304,54 +345,46 @@ export const createParticleSystem = ({
|
|
|
304
345
|
const colorRandomRatio = Math.random();
|
|
305
346
|
|
|
306
347
|
geometry.attributes.colorR.array[particleIndex] =
|
|
307
|
-
|
|
308
|
-
colorRandomRatio *
|
|
309
|
-
(normalizedStartColor.max.r - normalizedStartColor.min.r);
|
|
348
|
+
startColor.min.r +
|
|
349
|
+
colorRandomRatio * (startColor.max.r - startColor.min.r);
|
|
310
350
|
geometry.attributes.colorR.needsUpdate = true;
|
|
311
351
|
|
|
312
352
|
geometry.attributes.colorG.array[particleIndex] =
|
|
313
|
-
|
|
314
|
-
colorRandomRatio *
|
|
315
|
-
(normalizedStartColor.max.g - normalizedStartColor.min.g);
|
|
353
|
+
startColor.min.g +
|
|
354
|
+
colorRandomRatio * (startColor.max.g - startColor.min.g);
|
|
316
355
|
geometry.attributes.colorG.needsUpdate = true;
|
|
317
356
|
|
|
318
357
|
geometry.attributes.colorB.array[particleIndex] =
|
|
319
|
-
|
|
320
|
-
colorRandomRatio *
|
|
321
|
-
(normalizedStartColor.max.b - normalizedStartColor.min.b);
|
|
358
|
+
startColor.min.b +
|
|
359
|
+
colorRandomRatio * (startColor.max.b - startColor.min.b);
|
|
322
360
|
geometry.attributes.colorB.needsUpdate = true;
|
|
323
361
|
|
|
324
|
-
geometry.attributes.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
362
|
+
geometry.attributes.startFrame.array[particleIndex] =
|
|
363
|
+
THREE.MathUtils.randInt(
|
|
364
|
+
textureSheetAnimation.startFrame.min,
|
|
365
|
+
textureSheetAnimation.startFrame.max
|
|
366
|
+
);
|
|
367
|
+
geometry.attributes.startFrame.needsUpdate = true;
|
|
329
368
|
|
|
330
|
-
geometry.attributes.
|
|
331
|
-
THREE.MathUtils.randFloat(
|
|
332
|
-
|
|
333
|
-
normalizedStartLifeTime.max
|
|
334
|
-
) * 1000;
|
|
335
|
-
geometry.attributes.startLifeTime.needsUpdate = true;
|
|
369
|
+
geometry.attributes.startLifetime.array[particleIndex] =
|
|
370
|
+
THREE.MathUtils.randFloat(startLifetime.min, startLifetime.max) * 1000;
|
|
371
|
+
geometry.attributes.startLifetime.needsUpdate = true;
|
|
336
372
|
|
|
337
|
-
|
|
338
|
-
THREE.MathUtils.randFloat(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
);
|
|
342
|
-
geometry.attributes.startSize.needsUpdate = true;
|
|
373
|
+
generalData.startValues.startSize[particleIndex] =
|
|
374
|
+
THREE.MathUtils.randFloat(startSize.min, startSize.max);
|
|
375
|
+
generalData.startValues.startOpacity[particleIndex] =
|
|
376
|
+
THREE.MathUtils.randFloat(startOpacity.min, startOpacity.max);
|
|
343
377
|
|
|
344
378
|
geometry.attributes.rotation.array[particleIndex] = THREE.Math.degToRad(
|
|
345
|
-
THREE.MathUtils.randFloat(
|
|
346
|
-
normalizedStartRotation.min,
|
|
347
|
-
normalizedStartRotation.max
|
|
348
|
-
)
|
|
379
|
+
THREE.MathUtils.randFloat(startRotation.min, startRotation.max)
|
|
349
380
|
);
|
|
381
|
+
|
|
350
382
|
geometry.attributes.rotation.needsUpdate = true;
|
|
383
|
+
geometry.attributes.colorB.needsUpdate = true;
|
|
351
384
|
|
|
352
385
|
calculatePositionAndVelocity(
|
|
353
|
-
|
|
354
|
-
|
|
386
|
+
shape,
|
|
387
|
+
startSpeed,
|
|
355
388
|
startPositions[particleIndex],
|
|
356
389
|
velocities[particleIndex]
|
|
357
390
|
);
|
|
@@ -364,26 +397,34 @@ export const createParticleSystem = ({
|
|
|
364
397
|
startPositions[particleIndex].z;
|
|
365
398
|
particleSystem.geometry.attributes.position.needsUpdate = true;
|
|
366
399
|
|
|
367
|
-
geometry.attributes.
|
|
368
|
-
geometry.attributes.
|
|
400
|
+
geometry.attributes.lifetime.array[particleIndex] = 0;
|
|
401
|
+
geometry.attributes.lifetime.needsUpdate = true;
|
|
402
|
+
|
|
403
|
+
applyModifiers({
|
|
404
|
+
startValues: generalData.startValues,
|
|
405
|
+
normalizedConfig,
|
|
406
|
+
attributes: particleSystem.geometry.attributes,
|
|
407
|
+
particleLifetimePercentage: 0,
|
|
408
|
+
particleIndex,
|
|
409
|
+
forceUpdate: true,
|
|
410
|
+
});
|
|
369
411
|
};
|
|
370
412
|
|
|
371
413
|
const particleSystem = new THREE.Points(geometry, material);
|
|
372
414
|
particleSystem.sortParticles = true;
|
|
373
415
|
|
|
416
|
+
particleSystem.position.copy(transform.position);
|
|
417
|
+
particleSystem.rotation.x = THREE.Math.degToRad(transform.rotation.x);
|
|
418
|
+
particleSystem.rotation.y = THREE.Math.degToRad(transform.rotation.y);
|
|
419
|
+
particleSystem.rotation.z = THREE.Math.degToRad(transform.rotation.z);
|
|
420
|
+
particleSystem.scale.copy(transform.scale);
|
|
421
|
+
|
|
374
422
|
const calculatedCreationTime =
|
|
375
|
-
now +
|
|
376
|
-
THREE.MathUtils.randFloat(
|
|
377
|
-
normalizedStartDelay.min,
|
|
378
|
-
normalizedStartDelay.max
|
|
379
|
-
) *
|
|
380
|
-
1000;
|
|
423
|
+
now + THREE.MathUtils.randFloat(startDelay.min, startDelay.max) * 1000;
|
|
381
424
|
|
|
382
425
|
createdParticleSystems.push({
|
|
383
426
|
particleSystem,
|
|
384
427
|
generalData,
|
|
385
|
-
lastWorldPosition,
|
|
386
|
-
worldPositionChange,
|
|
387
428
|
onUpdate,
|
|
388
429
|
onComplete,
|
|
389
430
|
creationTime: calculatedCreationTime,
|
|
@@ -392,7 +433,8 @@ export const createParticleSystem = ({
|
|
|
392
433
|
looping,
|
|
393
434
|
simulationSpace,
|
|
394
435
|
gravity,
|
|
395
|
-
emission
|
|
436
|
+
emission,
|
|
437
|
+
normalizedConfig,
|
|
396
438
|
iterationCount: 0,
|
|
397
439
|
velocities,
|
|
398
440
|
deactivateParticle,
|
|
@@ -412,14 +454,11 @@ export const destroyParticleSystem = (particleSystem) => {
|
|
|
412
454
|
particleSystem.parent.remove(particleSystem);
|
|
413
455
|
};
|
|
414
456
|
|
|
415
|
-
export const updateParticleSystems = ({ delta, elapsed }) => {
|
|
416
|
-
const now = Date.now();
|
|
457
|
+
export const updateParticleSystems = ({ now, delta, elapsed }) => {
|
|
417
458
|
createdParticleSystems.forEach((props) => {
|
|
418
459
|
const {
|
|
419
460
|
onUpdate,
|
|
420
461
|
generalData,
|
|
421
|
-
lastWorldPosition,
|
|
422
|
-
worldPositionChange,
|
|
423
462
|
onComplete,
|
|
424
463
|
particleSystem,
|
|
425
464
|
creationTime,
|
|
@@ -427,6 +466,7 @@ export const updateParticleSystems = ({ delta, elapsed }) => {
|
|
|
427
466
|
duration,
|
|
428
467
|
looping,
|
|
429
468
|
emission,
|
|
469
|
+
normalizedConfig,
|
|
430
470
|
iterationCount,
|
|
431
471
|
velocities,
|
|
432
472
|
deactivateParticle,
|
|
@@ -434,34 +474,65 @@ export const updateParticleSystems = ({ delta, elapsed }) => {
|
|
|
434
474
|
simulationSpace,
|
|
435
475
|
gravity,
|
|
436
476
|
} = props;
|
|
437
|
-
|
|
477
|
+
|
|
478
|
+
const {
|
|
479
|
+
lastWorldPosition,
|
|
480
|
+
currentWorldPosition,
|
|
481
|
+
worldPositionChange,
|
|
482
|
+
lastWorldQuaternion,
|
|
483
|
+
worldQuaternion,
|
|
484
|
+
worldEuler,
|
|
485
|
+
gravityVelocity,
|
|
486
|
+
} = generalData;
|
|
487
|
+
|
|
488
|
+
const lifetime = now - creationTime;
|
|
438
489
|
particleSystem.material.uniforms.elapsed.value = elapsed;
|
|
439
490
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
lastWorldPosition.y !== -99999 &&
|
|
443
|
-
lastWorldPosition.z !== -99999
|
|
444
|
-
)
|
|
491
|
+
particleSystem.getWorldPosition(currentWorldPosition);
|
|
492
|
+
if (lastWorldPosition.x !== -99999)
|
|
445
493
|
worldPositionChange.set(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
494
|
+
currentWorldPosition.x - lastWorldPosition.x,
|
|
495
|
+
currentWorldPosition.y - lastWorldPosition.y,
|
|
496
|
+
currentWorldPosition.z - lastWorldPosition.z
|
|
449
497
|
);
|
|
450
498
|
generalData.distanceFromLastEmitByDistance += worldPositionChange.length();
|
|
451
|
-
|
|
499
|
+
particleSystem.getWorldPosition(lastWorldPosition);
|
|
500
|
+
|
|
501
|
+
particleSystem.getWorldQuaternion(worldQuaternion);
|
|
502
|
+
if (
|
|
503
|
+
lastWorldQuaternion.x === -99999 ||
|
|
504
|
+
lastWorldQuaternion.x != worldQuaternion.x ||
|
|
505
|
+
lastWorldQuaternion.y != worldQuaternion.y ||
|
|
506
|
+
lastWorldQuaternion.z != worldQuaternion.z
|
|
507
|
+
) {
|
|
508
|
+
worldEuler.setFromQuaternion(worldQuaternion);
|
|
509
|
+
lastWorldQuaternion.copy(worldQuaternion);
|
|
510
|
+
|
|
511
|
+
const tempPosX = particleSystem.position.x;
|
|
512
|
+
const tempPosY = particleSystem.position.y;
|
|
513
|
+
const tempPosZ = particleSystem.position.z;
|
|
514
|
+
gravityVelocity.set(0, gravity, 0);
|
|
515
|
+
particleSystem.position.set(0, 0, 0);
|
|
516
|
+
particleSystem.updateMatrixWorld();
|
|
517
|
+
particleSystem.worldToLocal(gravityVelocity);
|
|
518
|
+
particleSystem.position.set(tempPosX, tempPosY, tempPosZ);
|
|
519
|
+
particleSystem.updateMatrixWorld();
|
|
520
|
+
}
|
|
452
521
|
|
|
453
522
|
particleSystem.geometry.attributes.creationTime.array.forEach(
|
|
454
523
|
(entry, index) => {
|
|
455
524
|
if (particleSystem.geometry.attributes.isActive.array[index]) {
|
|
456
|
-
const
|
|
525
|
+
const particleLifetime = now - float32Helper - entry;
|
|
457
526
|
if (
|
|
458
|
-
|
|
459
|
-
particleSystem.geometry.attributes.
|
|
527
|
+
particleLifetime >
|
|
528
|
+
particleSystem.geometry.attributes.startLifetime.array[index]
|
|
460
529
|
)
|
|
461
530
|
deactivateParticle(index);
|
|
462
531
|
else {
|
|
463
532
|
const velocity = velocities[index];
|
|
464
|
-
velocity.
|
|
533
|
+
velocity.x -= gravityVelocity.x;
|
|
534
|
+
velocity.y -= gravityVelocity.y;
|
|
535
|
+
velocity.z -= gravityVelocity.z;
|
|
465
536
|
|
|
466
537
|
if (
|
|
467
538
|
gravity !== 0 ||
|
|
@@ -483,22 +554,26 @@ export const updateParticleSystems = ({ delta, elapsed }) => {
|
|
|
483
554
|
particleSystem.geometry.attributes.position.needsUpdate = true;
|
|
484
555
|
}
|
|
485
556
|
|
|
486
|
-
particleSystem.geometry.attributes.
|
|
487
|
-
|
|
488
|
-
particleSystem.geometry.attributes.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
557
|
+
particleSystem.geometry.attributes.lifetime.array[index] =
|
|
558
|
+
particleLifetime;
|
|
559
|
+
particleSystem.geometry.attributes.lifetime.needsUpdate = true;
|
|
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
|
+
});
|
|
496
571
|
}
|
|
497
572
|
}
|
|
498
573
|
}
|
|
499
574
|
);
|
|
500
575
|
|
|
501
|
-
if (looping ||
|
|
576
|
+
if (looping || lifetime < duration * 1000) {
|
|
502
577
|
const emissionDelta = now - lastEmissionTime;
|
|
503
578
|
const neededParticlesByTime = Math.floor(
|
|
504
579
|
emission.rateOverTime * (emissionDelta / 1000)
|
|
@@ -546,7 +621,7 @@ export const updateParticleSystems = ({ delta, elapsed }) => {
|
|
|
546
621
|
particleSystem,
|
|
547
622
|
delta,
|
|
548
623
|
elapsed,
|
|
549
|
-
|
|
624
|
+
lifetime,
|
|
550
625
|
iterationCount: iterationCount + 1,
|
|
551
626
|
});
|
|
552
627
|
} else if (onComplete)
|