@rzmps/rzmps 1.0.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 +1048 -0
- package/build/EmissionShape.d.ts +33 -0
- package/build/EmissionShape.js +129 -0
- package/build/Emitter.d.ts +58 -0
- package/build/Emitter.js +166 -0
- package/build/GpuModule.d.ts +28 -0
- package/build/GpuModule.js +28 -0
- package/build/Module.d.ts +19 -0
- package/build/Module.js +31 -0
- package/build/Particle.d.ts +60 -0
- package/build/Particle.js +52 -0
- package/build/ParticleForceField.d.ts +39 -0
- package/build/ParticleForceField.js +101 -0
- package/build/ParticleForceFieldHelper.d.ts +18 -0
- package/build/ParticleForceFieldHelper.js +103 -0
- package/build/ParticleSystem.d.ts +122 -0
- package/build/ParticleSystem.js +609 -0
- package/build/Renderer.d.ts +15 -0
- package/build/Renderer.js +11 -0
- package/build/assets/images/default.png +0 -0
- package/build/collision/ThreeCollisionBackend.d.ts +47 -0
- package/build/collision/ThreeCollisionBackend.js +340 -0
- package/build/enums/Axis.d.ts +6 -0
- package/build/enums/Axis.js +7 -0
- package/build/enums/DynamicValueType.d.ts +6 -0
- package/build/enums/DynamicValueType.js +7 -0
- package/build/enums/EmissionSource copy.d.ts +7 -0
- package/build/enums/EmissionSource copy.js +7 -0
- package/build/enums/EmissionSource.d.ts +7 -0
- package/build/enums/EmissionSource.js +7 -0
- package/build/enums/EndBehavior.d.ts +6 -0
- package/build/enums/EndBehavior.js +7 -0
- package/build/enums/SimulationSpace.d.ts +5 -0
- package/build/enums/SimulationSpace.js +6 -0
- package/build/enums/SpriteMaterialType.d.ts +5 -0
- package/build/enums/SpriteMaterialType.js +6 -0
- package/build/enums/TagSelectionMethod.d.ts +6 -0
- package/build/enums/TagSelectionMethod.js +7 -0
- package/build/enums/TrailMode copy.d.ts +5 -0
- package/build/enums/TrailMode copy.js +7 -0
- package/build/enums/TrailMode.d.ts +5 -0
- package/build/enums/TrailMode.js +7 -0
- package/build/enums/TrailTextureMode.d.ts +7 -0
- package/build/enums/TrailTextureMode.js +9 -0
- package/build/gpu/GpuDynamicValue.d.ts +9 -0
- package/build/gpu/GpuDynamicValue.js +113 -0
- package/build/gpu/GpuMath.d.ts +3 -0
- package/build/gpu/GpuMath.js +12 -0
- package/build/gpu/GpuParticleContext.d.ts +63 -0
- package/build/gpu/GpuParticleContext.js +291 -0
- package/build/helpers/acceptMultiple.d.ts +2 -0
- package/build/helpers/acceptMultiple.js +6 -0
- package/build/helpers/evaluateDynamic.d.ts +2 -0
- package/build/helpers/evaluateDynamic.js +18 -0
- package/build/helpers/evaluateDynamicColor.d.ts +3 -0
- package/build/helpers/evaluateDynamicColor.js +5 -0
- package/build/helpers/evaluateDynamicNumber.d.ts +2 -0
- package/build/helpers/evaluateDynamicNumber.js +4 -0
- package/build/helpers/evaluateDynamicVector3.d.ts +3 -0
- package/build/helpers/evaluateDynamicVector3.js +5 -0
- package/build/helpers/isPointInMesh.d.ts +2 -0
- package/build/helpers/isPointInMesh.js +8 -0
- package/build/helpers/particleRatio.d.ts +2 -0
- package/build/helpers/particleRatio.js +13 -0
- package/build/helpers/tagsIntersect.d.ts +2 -0
- package/build/helpers/tagsIntersect.js +4 -0
- package/build/index.d.ts +37 -0
- package/build/index.js +34 -0
- package/build/interfaces/ICollisionBackend.d.ts +21 -0
- package/build/interfaces/ICollisionBackend.js +1 -0
- package/build/interfaces/IParticleForceField.d.ts +5 -0
- package/build/interfaces/IParticleForceField.js +1 -0
- package/build/interfaces/InitialParticleValues.d.ts +18 -0
- package/build/interfaces/InitialParticleValues.js +1 -0
- package/build/materials/BasicSprite.d.ts +21 -0
- package/build/materials/BasicSprite.js +46 -0
- package/build/materials/UnlitSprite.d.ts +13 -0
- package/build/materials/UnlitSprite.js +31 -0
- package/build/materials/WebGPUBasicSprite.d.ts +8 -0
- package/build/materials/WebGPUBasicSprite.js +65 -0
- package/build/materials/WebGPUUnlitSprite.d.ts +8 -0
- package/build/materials/WebGPUUnlitSprite.js +49 -0
- package/build/modules/Audio.d.ts +60 -0
- package/build/modules/Audio.js +181 -0
- package/build/modules/Collision.d.ts +40 -0
- package/build/modules/Collision.js +162 -0
- package/build/modules/ColorBySpeed.d.ts +18 -0
- package/build/modules/ColorBySpeed.js +26 -0
- package/build/modules/ColorOverLifetime.d.ts +12 -0
- package/build/modules/ColorOverLifetime.js +17 -0
- package/build/modules/ExternalForces.d.ts +21 -0
- package/build/modules/ExternalForces.js +61 -0
- package/build/modules/ForceOverLifetime.d.ts +11 -0
- package/build/modules/ForceOverLifetime.js +12 -0
- package/build/modules/LimitVelocityOverLifetime.d.ts +16 -0
- package/build/modules/LimitVelocityOverLifetime.js +34 -0
- package/build/modules/MassOverLifetime.d.ts +11 -0
- package/build/modules/MassOverLifetime.js +15 -0
- package/build/modules/NoiseModule.d.ts +23 -0
- package/build/modules/NoiseModule.js +45 -0
- package/build/modules/RotationBySpeed.d.ts +14 -0
- package/build/modules/RotationBySpeed.js +19 -0
- package/build/modules/RotationOverLifetime.d.ts +11 -0
- package/build/modules/RotationOverLifetime.js +12 -0
- package/build/modules/ScaleBySpeed.d.ts +14 -0
- package/build/modules/ScaleBySpeed.js +19 -0
- package/build/modules/ScaleOverLifetime.d.ts +11 -0
- package/build/modules/ScaleOverLifetime.js +11 -0
- package/build/modules/TransformByNoise.d.ts +17 -0
- package/build/modules/TransformByNoise.js +32 -0
- package/build/modules/VelocityOverLifetime.d.ts +15 -0
- package/build/modules/VelocityOverLifetime.js +32 -0
- package/build/renderers/LightRenderer.d.ts +54 -0
- package/build/renderers/LightRenderer.js +141 -0
- package/build/renderers/MeshRenderer.d.ts +27 -0
- package/build/renderers/MeshRenderer.js +70 -0
- package/build/renderers/SpriteRenderer.d.ts +95 -0
- package/build/renderers/SpriteRenderer.js +456 -0
- package/build/renderers/TrailRenderer.d.ts +71 -0
- package/build/renderers/TrailRenderer.js +400 -0
- package/build/shaders/BasicSprite.frag.js +1 -0
- package/build/shaders/BasicSprite.vert.js +1 -0
- package/build/shaders/UnlitSprite.frag.js +1 -0
- package/build/shaders/UnlitSprite.vert.js +1 -0
- package/build/types/DynamicValue.d.ts +2 -0
- package/build/types/DynamicValue.js +1 -0
- package/build/types/EnumStringLiteral.d.ts +1 -0
- package/build/types/EnumStringLiteral.js +1 -0
- package/build/types/Multiple.d.ts +2 -0
- package/build/types/Multiple.js +1 -0
- package/build/types/Tag.d.ts +1 -0
- package/build/types/Tag.js +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module from '../Module';
|
|
3
|
+
import evaluateDynamicNumber from '../helpers/evaluateDynamicNumber';
|
|
4
|
+
import ThreeCollisionBackend from '../collision/ThreeCollisionBackend';
|
|
5
|
+
const ACTIVE_COLLISION_BACKEND_KEY = "__rzmps_activeCollisionBackend";
|
|
6
|
+
const PREVIOUS_POSITION_KEY = "__rzmps_collision_prevPosition";
|
|
7
|
+
class Collision extends Module {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
10
|
+
// Priority > 0, occurs after movement
|
|
11
|
+
super((particle) => this.collide(particle), Object.assign(Object.assign({}, options), { priority: 1 }));
|
|
12
|
+
this.dampen = 0;
|
|
13
|
+
this.bounce = 1;
|
|
14
|
+
this.lifetimeLoss = 0;
|
|
15
|
+
this.applyImpulses = false;
|
|
16
|
+
this.radiusScale = 1;
|
|
17
|
+
this.minKillSpeed = 0;
|
|
18
|
+
this.maxKillSpeed = Number.POSITIVE_INFINITY;
|
|
19
|
+
this.collisionListeners = [];
|
|
20
|
+
// Priority < 0, cache position before movement
|
|
21
|
+
this.dependents = [
|
|
22
|
+
new Module((particle) => particle.data[PREVIOUS_POSITION_KEY] = particle.position.clone(), Object.assign(Object.assign({}, options), { priority: -1 }))
|
|
23
|
+
];
|
|
24
|
+
this.dampen = (_a = options.dampen) !== null && _a !== void 0 ? _a : this.dampen;
|
|
25
|
+
this.bounce = (_b = options.bounce) !== null && _b !== void 0 ? _b : this.bounce;
|
|
26
|
+
this.lifetimeLoss = (_c = options.lifetimeLoss) !== null && _c !== void 0 ? _c : this.lifetimeLoss;
|
|
27
|
+
this.applyImpulses = (_d = options.applyImpulses) !== null && _d !== void 0 ? _d : this.applyImpulses;
|
|
28
|
+
this.radiusScale = (_e = options.radiusScale) !== null && _e !== void 0 ? _e : this.radiusScale;
|
|
29
|
+
this.minKillSpeed = (_f = options.minKillSpeed) !== null && _f !== void 0 ? _f : this.minKillSpeed;
|
|
30
|
+
this.maxKillSpeed = (_g = options.maxKillSpeed) !== null && _g !== void 0 ? _g : this.maxKillSpeed;
|
|
31
|
+
if (options.onCollision)
|
|
32
|
+
this.collisionListeners.push(options.onCollision);
|
|
33
|
+
}
|
|
34
|
+
onCollision(listener) {
|
|
35
|
+
this.collisionListeners.push(listener);
|
|
36
|
+
}
|
|
37
|
+
removeCollisionListener(listener) {
|
|
38
|
+
this.collisionListeners = this.collisionListeners.filter(l => l !== listener);
|
|
39
|
+
}
|
|
40
|
+
prepare(system, deltaTime) {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
this._system = system;
|
|
43
|
+
if (system.scene) {
|
|
44
|
+
// Check if backend exists or needs to be updated
|
|
45
|
+
const cachedBackend = system.scene.userData[ACTIVE_COLLISION_BACKEND_KEY];
|
|
46
|
+
if (!this.backend || this.backend != cachedBackend) {
|
|
47
|
+
this.backend = cachedBackend !== null && cachedBackend !== void 0 ? cachedBackend : new ThreeCollisionBackend({ world: system.scene });
|
|
48
|
+
system.scene.userData[ACTIVE_COLLISION_BACKEND_KEY] =
|
|
49
|
+
this.backend;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
(_b = (_a = this.backend) === null || _a === void 0 ? void 0 : _a.update) === null || _b === void 0 ? void 0 : _b.call(_a, deltaTime);
|
|
53
|
+
}
|
|
54
|
+
collide(particle) {
|
|
55
|
+
if (!this.backend || !this._system)
|
|
56
|
+
return;
|
|
57
|
+
const startPosition = particle.data[PREVIOUS_POSITION_KEY];
|
|
58
|
+
const endPosition = particle.position;
|
|
59
|
+
if (startPosition.equals(endPosition))
|
|
60
|
+
return;
|
|
61
|
+
this._system.updateWorldMatrix(true, false);
|
|
62
|
+
const start = this._system.simulationSpace === 'world'
|
|
63
|
+
? startPosition.clone()
|
|
64
|
+
: this._system.localToWorld(startPosition.clone());
|
|
65
|
+
const end = this._system.simulationSpace === 'world'
|
|
66
|
+
? endPosition.clone()
|
|
67
|
+
: this._system.localToWorld(endPosition.clone());
|
|
68
|
+
const radius = this.getParticleRadius(particle);
|
|
69
|
+
const hit = this.backend.collide({
|
|
70
|
+
particle,
|
|
71
|
+
start,
|
|
72
|
+
end,
|
|
73
|
+
radius,
|
|
74
|
+
});
|
|
75
|
+
if (!hit)
|
|
76
|
+
return;
|
|
77
|
+
// Collision callbacks
|
|
78
|
+
this.collisionListeners.forEach((listener) => listener(particle, hit));
|
|
79
|
+
this._system.notifyCollision(particle, hit);
|
|
80
|
+
if (this._system.simulationSpace === 'local') {
|
|
81
|
+
const inverseWorld = this._system.matrixWorld.clone().invert();
|
|
82
|
+
hit.point = this._system.worldToLocal(hit.point.clone());
|
|
83
|
+
if (hit.position) {
|
|
84
|
+
hit.position = this._system.worldToLocal(hit.position.clone());
|
|
85
|
+
}
|
|
86
|
+
hit.normal = hit.normal
|
|
87
|
+
.clone()
|
|
88
|
+
.transformDirection(inverseWorld)
|
|
89
|
+
.normalize();
|
|
90
|
+
}
|
|
91
|
+
this.resolvePosition(particle, hit, radius);
|
|
92
|
+
// Store previous veolocity for impulses
|
|
93
|
+
const incomingVelocity = particle.velocity.clone();
|
|
94
|
+
this.resolveVelocity(particle, hit);
|
|
95
|
+
this.resolveLifetime(particle);
|
|
96
|
+
if (particle.mass > 0
|
|
97
|
+
&& this.applyImpulses
|
|
98
|
+
&& this.backend.applyImpulse) {
|
|
99
|
+
const impulse = particle.velocity
|
|
100
|
+
.clone()
|
|
101
|
+
.sub(incomingVelocity)
|
|
102
|
+
.multiplyScalar(-particle.mass);
|
|
103
|
+
this.backend.applyImpulse(hit, impulse);
|
|
104
|
+
}
|
|
105
|
+
const speed = particle.velocity.length();
|
|
106
|
+
if (speed < this.minKillSpeed
|
|
107
|
+
|| speed > this.maxKillSpeed) {
|
|
108
|
+
this.killParticle(particle);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
resolvePosition(particle, hit, radius) {
|
|
112
|
+
if (hit.position) {
|
|
113
|
+
particle.position.copy(hit.position);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
particle.position
|
|
117
|
+
.copy(hit.point)
|
|
118
|
+
.addScaledVector(hit.normal, radius);
|
|
119
|
+
}
|
|
120
|
+
resolveVelocity(particle, hit) {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
const normal = hit.normal.clone().normalize();
|
|
123
|
+
const bounce = THREE.MathUtils.clamp(evaluateDynamicNumber((_a = this.bounce) !== null && _a !== void 0 ? _a : 1, particle.time, particle.id), 0, 1);
|
|
124
|
+
const dampen = THREE.MathUtils.clamp(evaluateDynamicNumber((_b = this.dampen) !== null && _b !== void 0 ? _b : 0, particle.time, particle.id), 0, 1);
|
|
125
|
+
const normalSpeed = particle.velocity.dot(normal);
|
|
126
|
+
/*
|
|
127
|
+
* Don't bounce if we're already travelling away
|
|
128
|
+
* from the surface.
|
|
129
|
+
*/
|
|
130
|
+
if (normalSpeed >= 0)
|
|
131
|
+
return;
|
|
132
|
+
const normalVelocity = normal
|
|
133
|
+
.clone()
|
|
134
|
+
.multiplyScalar(normalSpeed);
|
|
135
|
+
const tangentVelocity = particle.velocity
|
|
136
|
+
.clone()
|
|
137
|
+
.sub(normalVelocity);
|
|
138
|
+
particle.velocity
|
|
139
|
+
.copy(tangentVelocity)
|
|
140
|
+
.addScaledVector(normalVelocity, -bounce)
|
|
141
|
+
.multiplyScalar(1 - dampen);
|
|
142
|
+
}
|
|
143
|
+
resolveLifetime(particle) {
|
|
144
|
+
var _a;
|
|
145
|
+
const loss = THREE.MathUtils.clamp(evaluateDynamicNumber((_a = this.lifetimeLoss) !== null && _a !== void 0 ? _a : 0, particle.time, particle.id), 0, 1);
|
|
146
|
+
if (loss === 0)
|
|
147
|
+
return;
|
|
148
|
+
particle.lifetime -= particle.start.lifetime * loss;
|
|
149
|
+
if (particle.lifetime <= (particle.realtime / 1000)) {
|
|
150
|
+
this.killParticle(particle);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
getParticleRadius(particle) {
|
|
154
|
+
var _a;
|
|
155
|
+
const size = Math.max(Math.abs(particle.scale.x), Math.abs(particle.scale.y), Math.abs(particle.scale.z));
|
|
156
|
+
return size * 0.5 * ((_a = this.radiusScale) !== null && _a !== void 0 ? _a : 1);
|
|
157
|
+
}
|
|
158
|
+
killParticle(particle) {
|
|
159
|
+
particle.lifetime = 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export default Collision;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
export type SpeedRange = [number, number] | {
|
|
5
|
+
min: number;
|
|
6
|
+
max: number;
|
|
7
|
+
};
|
|
8
|
+
export interface ColorBySpeedOptions extends Partial<ModuleOptions> {
|
|
9
|
+
color?: DynamicValue<THREE.Color>;
|
|
10
|
+
alpha?: DynamicValue<number>;
|
|
11
|
+
speedRange?: SpeedRange;
|
|
12
|
+
}
|
|
13
|
+
declare class ColorBySpeed extends Module {
|
|
14
|
+
options: ColorBySpeedOptions;
|
|
15
|
+
constructor(options: ColorBySpeedOptions);
|
|
16
|
+
private getSpeedTime;
|
|
17
|
+
}
|
|
18
|
+
export default ColorBySpeed;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicColor from '../helpers/evaluateDynamicColor';
|
|
3
|
+
import evaluateDynamicNumber from '../helpers/evaluateDynamicNumber';
|
|
4
|
+
class ColorBySpeed extends Module {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super((particle) => {
|
|
7
|
+
const t = this.getSpeedTime(particle.velocity.length());
|
|
8
|
+
if (this.options.color !== undefined) {
|
|
9
|
+
particle.color = particle.start.color.clone().multiply(evaluateDynamicColor(this.options.color, t, particle.id));
|
|
10
|
+
}
|
|
11
|
+
if (this.options.alpha !== undefined) {
|
|
12
|
+
particle.alpha = particle.start.alpha * evaluateDynamicNumber(this.options.alpha, t, particle.id);
|
|
13
|
+
}
|
|
14
|
+
}, options);
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
getSpeedTime(speed) {
|
|
18
|
+
var _a, _b, _c, _d;
|
|
19
|
+
const min = Array.isArray(this.options.speedRange) ? this.options.speedRange[0] : (_b = (_a = this.options.speedRange) === null || _a === void 0 ? void 0 : _a.min) !== null && _b !== void 0 ? _b : 0;
|
|
20
|
+
const max = Array.isArray(this.options.speedRange) ? this.options.speedRange[1] : (_d = (_c = this.options.speedRange) === null || _c === void 0 ? void 0 : _c.max) !== null && _d !== void 0 ? _d : 1;
|
|
21
|
+
if (max === min)
|
|
22
|
+
return speed >= max ? 1 : 0;
|
|
23
|
+
return Math.min(Math.max((speed - min) / (max - min), 0), 1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export default ColorBySpeed;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
export interface ColorOverLifetimeOptions extends Partial<ModuleOptions> {
|
|
5
|
+
color?: DynamicValue<THREE.Color>;
|
|
6
|
+
alpha?: DynamicValue<number>;
|
|
7
|
+
}
|
|
8
|
+
declare class ColorOverLifetime extends Module {
|
|
9
|
+
options: ColorOverLifetimeOptions;
|
|
10
|
+
constructor(options?: ColorOverLifetimeOptions);
|
|
11
|
+
}
|
|
12
|
+
export default ColorOverLifetime;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicColor from '../helpers/evaluateDynamicColor';
|
|
3
|
+
import evaluateDynamicNumber from '../helpers/evaluateDynamicNumber';
|
|
4
|
+
class ColorOverLifetime extends Module {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
super((particle) => {
|
|
7
|
+
if (this.options.color !== undefined) {
|
|
8
|
+
particle.color = particle.start.color.clone().multiply(evaluateDynamicColor(this.options.color, particle.time, particle.id));
|
|
9
|
+
}
|
|
10
|
+
if (this.options.alpha !== undefined) {
|
|
11
|
+
particle.alpha = particle.start.alpha * evaluateDynamicNumber(this.options.alpha, particle.time, particle.id);
|
|
12
|
+
}
|
|
13
|
+
}, options);
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export default ColorOverLifetime;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Module, { ModuleOptions } from '../Module';
|
|
2
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
3
|
+
import { IParticleForceField } from '../interfaces/IParticleForceField';
|
|
4
|
+
import ParticleForceField from '../ParticleForceField';
|
|
5
|
+
import ParticleSystem from '../ParticleSystem';
|
|
6
|
+
export interface ExternalForcesOptions extends Partial<ModuleOptions> {
|
|
7
|
+
multiplier?: DynamicValue<number>;
|
|
8
|
+
forceFieldFilter?: (forceField: ParticleForceField) => boolean;
|
|
9
|
+
forceFields?: IParticleForceField[];
|
|
10
|
+
}
|
|
11
|
+
declare class ExternalForces extends Module {
|
|
12
|
+
multiplier: DynamicValue<number>;
|
|
13
|
+
explicitForceFields?: IParticleForceField[];
|
|
14
|
+
forceFieldFilter?: (forceField: ParticleForceField) => boolean;
|
|
15
|
+
private forceFields;
|
|
16
|
+
private particleSystem?;
|
|
17
|
+
constructor(options: ExternalForcesOptions);
|
|
18
|
+
prepare(particleSystem: ParticleSystem, deltaTime: number): void;
|
|
19
|
+
}
|
|
20
|
+
export default ExternalForces;
|
|
21
|
+
export { IParticleForceField };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module from '../Module';
|
|
3
|
+
import evaluateDynamicNumber from '../helpers/evaluateDynamicNumber';
|
|
4
|
+
import ParticleForceField from '../ParticleForceField';
|
|
5
|
+
class ExternalForces extends Module {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
var _a;
|
|
8
|
+
super((particle, deltaTime) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const multiplier = evaluateDynamicNumber((_a = this.multiplier) !== null && _a !== void 0 ? _a : 1, particle.time, particle.id);
|
|
11
|
+
const particleSystem = this.particleSystem;
|
|
12
|
+
if (!particleSystem)
|
|
13
|
+
return;
|
|
14
|
+
particleSystem.updateWorldMatrix(true, false);
|
|
15
|
+
const particlePosition = particleSystem.simulationSpace === 'world'
|
|
16
|
+
? particle.position
|
|
17
|
+
: particleSystem.localToWorld(particle.position.clone());
|
|
18
|
+
const worldQuaternion = particleSystem.simulationSpace === 'local'
|
|
19
|
+
? particleSystem.getWorldQuaternion(new THREE.Quaternion())
|
|
20
|
+
: undefined;
|
|
21
|
+
const inverseWorldQuaternion = worldQuaternion === null || worldQuaternion === void 0 ? void 0 : worldQuaternion.clone().invert();
|
|
22
|
+
const forceParticle = particleSystem.simulationSpace === 'world'
|
|
23
|
+
? particle
|
|
24
|
+
: Object.assign(Object.create(Object.getPrototypeOf(particle)), particle, {
|
|
25
|
+
position: particlePosition,
|
|
26
|
+
velocity: particle.velocity
|
|
27
|
+
.clone()
|
|
28
|
+
.applyQuaternion(worldQuaternion),
|
|
29
|
+
});
|
|
30
|
+
this.forceFields.forEach((forceField) => {
|
|
31
|
+
const force = forceField.getForce(forceParticle, deltaTime);
|
|
32
|
+
if (inverseWorldQuaternion) {
|
|
33
|
+
force.applyQuaternion(inverseWorldQuaternion);
|
|
34
|
+
}
|
|
35
|
+
particle.acceleration.addScaledVector(force, multiplier);
|
|
36
|
+
});
|
|
37
|
+
}, options);
|
|
38
|
+
this.multiplier = 1;
|
|
39
|
+
this.forceFields = new Set();
|
|
40
|
+
this.explicitForceFields = options.forceFields;
|
|
41
|
+
this.forceFieldFilter = (_a = options.forceFieldFilter) !== null && _a !== void 0 ? _a : (() => true);
|
|
42
|
+
}
|
|
43
|
+
prepare(particleSystem, deltaTime) {
|
|
44
|
+
var _a;
|
|
45
|
+
this.particleSystem = particleSystem;
|
|
46
|
+
// If explicit force fields are provided, just use those
|
|
47
|
+
if (Array.isArray(this.explicitForceFields)) {
|
|
48
|
+
this.forceFields = new Set(this.explicitForceFields);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.forceFields.clear();
|
|
52
|
+
// Otherwise, scan the scene for force fields
|
|
53
|
+
(_a = particleSystem.scene) === null || _a === void 0 ? void 0 : _a.traverse((object) => {
|
|
54
|
+
var _a;
|
|
55
|
+
if (object instanceof ParticleForceField
|
|
56
|
+
&& ((_a = this.forceFieldFilter) === null || _a === void 0 ? void 0 : _a.call(this, object)))
|
|
57
|
+
this.forceFields.add(object);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export default ExternalForces;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
export interface ForceOverLifetimeOptions extends Partial<ModuleOptions> {
|
|
5
|
+
force: DynamicValue<THREE.Vector3>;
|
|
6
|
+
}
|
|
7
|
+
declare class ForceOverLifetime extends Module {
|
|
8
|
+
options: ForceOverLifetimeOptions;
|
|
9
|
+
constructor(options: ForceOverLifetimeOptions);
|
|
10
|
+
}
|
|
11
|
+
export default ForceOverLifetime;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicVector from '../helpers/evaluateDynamicVector3';
|
|
3
|
+
class ForceOverLifetime extends Module {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super((particle) => {
|
|
6
|
+
particle.acceleration = particle.start.acceleration.clone()
|
|
7
|
+
.add(evaluateDynamicVector(this.options.force, particle.time, particle.id));
|
|
8
|
+
}, options);
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export default ForceOverLifetime;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
export interface LimitVelocityOverLifetimeOptions extends Partial<ModuleOptions> {
|
|
5
|
+
limit: DynamicValue<THREE.Vector3>;
|
|
6
|
+
dampen?: number;
|
|
7
|
+
drag?: DynamicValue<number>;
|
|
8
|
+
multiplyDragBySize?: boolean;
|
|
9
|
+
multiplyDragByVelocity?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare class LimitVelocityOverLifetime extends Module {
|
|
12
|
+
options: LimitVelocityOverLifetimeOptions;
|
|
13
|
+
constructor(options: LimitVelocityOverLifetimeOptions);
|
|
14
|
+
private dampenAxis;
|
|
15
|
+
}
|
|
16
|
+
export default LimitVelocityOverLifetime;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicNumber from '../helpers/evaluateDynamicNumber';
|
|
3
|
+
import evaluateDynamicVector from '../helpers/evaluateDynamicVector3';
|
|
4
|
+
class LimitVelocityOverLifetime extends Module {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super((particle, deltaTime) => {
|
|
7
|
+
var _a;
|
|
8
|
+
const limit = evaluateDynamicVector(this.options.limit, particle.time, particle.id);
|
|
9
|
+
const dampen = (_a = this.options.dampen) !== null && _a !== void 0 ? _a : 1;
|
|
10
|
+
this.dampenAxis(particle.velocity, 'x', Math.abs(limit.x), dampen);
|
|
11
|
+
this.dampenAxis(particle.velocity, 'y', Math.abs(limit.y), dampen);
|
|
12
|
+
this.dampenAxis(particle.velocity, 'z', Math.abs(limit.z), dampen);
|
|
13
|
+
if (this.options.drag !== undefined) {
|
|
14
|
+
let drag = evaluateDynamicNumber(this.options.drag, particle.time, particle.id);
|
|
15
|
+
if (this.options.multiplyDragBySize) {
|
|
16
|
+
drag *= (particle.scale.x + particle.scale.y + particle.scale.z) / 3;
|
|
17
|
+
}
|
|
18
|
+
if (this.options.multiplyDragByVelocity) {
|
|
19
|
+
drag *= particle.velocity.length();
|
|
20
|
+
}
|
|
21
|
+
particle.velocity.multiplyScalar(Math.max(0, 1 - drag * deltaTime));
|
|
22
|
+
}
|
|
23
|
+
}, options);
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
// eslint-disable-next-line class-methods-use-this
|
|
27
|
+
dampenAxis(velocity, axis, limit, dampen) {
|
|
28
|
+
if (Math.abs(velocity[axis]) <= limit)
|
|
29
|
+
return;
|
|
30
|
+
const clamped = Math.sign(velocity[axis]) * limit;
|
|
31
|
+
velocity[axis] += (clamped - velocity[axis]) * Math.min(Math.max(dampen, 0), 1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export default LimitVelocityOverLifetime;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Module, { ModuleOptions } from '../Module';
|
|
2
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
3
|
+
export interface MassOverLifetimeOptions extends Partial<ModuleOptions> {
|
|
4
|
+
mass: DynamicValue<number>;
|
|
5
|
+
multiplyMassBySize: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare class MassOverLifetime extends Module {
|
|
8
|
+
options: MassOverLifetimeOptions;
|
|
9
|
+
constructor(options: MassOverLifetimeOptions);
|
|
10
|
+
}
|
|
11
|
+
export default MassOverLifetime;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicNumber from '../helpers/evaluateDynamicNumber';
|
|
3
|
+
class MassOverLifetime extends Module {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super((particle) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const sizeRatio = particle.scale.length() / particle.start.scale.length();
|
|
8
|
+
particle.mass = particle.start.mass
|
|
9
|
+
* evaluateDynamicNumber(this.options.mass, particle.time, particle.id)
|
|
10
|
+
* (((_a = options.multiplyMassBySize) !== null && _a !== void 0 ? _a : true) ? sizeRatio : 1);
|
|
11
|
+
}, options);
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export default MassOverLifetime;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
export interface NoiseOptions extends Partial<ModuleOptions> {
|
|
4
|
+
octaves: number;
|
|
5
|
+
frequency: number;
|
|
6
|
+
lacunarity: number;
|
|
7
|
+
persistence: number;
|
|
8
|
+
time: number;
|
|
9
|
+
offset: THREE.Vector3;
|
|
10
|
+
}
|
|
11
|
+
declare class NoiseModule extends Module {
|
|
12
|
+
octaves: number;
|
|
13
|
+
frequency: number;
|
|
14
|
+
lacunarity: number;
|
|
15
|
+
persistence: number;
|
|
16
|
+
time: number;
|
|
17
|
+
offset: THREE.Vector3;
|
|
18
|
+
key: string;
|
|
19
|
+
private noiseGenerator;
|
|
20
|
+
constructor(key: string, options?: Partial<NoiseOptions>);
|
|
21
|
+
private generateNoise;
|
|
22
|
+
}
|
|
23
|
+
export default NoiseModule;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { makeNoise4D } from 'fast-simplex-noise';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import Module from '../Module';
|
|
4
|
+
class NoiseModule extends Module {
|
|
5
|
+
constructor(key, options = {}) {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f;
|
|
7
|
+
super((particle) => {
|
|
8
|
+
particle.noise[key] = {
|
|
9
|
+
noise: this.generateNoise(particle),
|
|
10
|
+
noise4d: this.generateNoise(particle, true),
|
|
11
|
+
};
|
|
12
|
+
}, options);
|
|
13
|
+
this.octaves = 1;
|
|
14
|
+
this.frequency = 1;
|
|
15
|
+
this.lacunarity = 2.0;
|
|
16
|
+
this.persistence = 0.5;
|
|
17
|
+
this.time = 0;
|
|
18
|
+
this.offset = new THREE.Vector3();
|
|
19
|
+
this.noiseGenerator = makeNoise4D();
|
|
20
|
+
this.key = key;
|
|
21
|
+
this.octaves = (_a = options.octaves) !== null && _a !== void 0 ? _a : this.octaves;
|
|
22
|
+
this.frequency = (_b = options.frequency) !== null && _b !== void 0 ? _b : this.frequency;
|
|
23
|
+
this.lacunarity = (_c = options.lacunarity) !== null && _c !== void 0 ? _c : this.lacunarity;
|
|
24
|
+
this.persistence = (_d = options.persistence) !== null && _d !== void 0 ? _d : this.persistence;
|
|
25
|
+
this.time = (_e = options.time) !== null && _e !== void 0 ? _e : this.time;
|
|
26
|
+
this.offset = (_f = options.offset) !== null && _f !== void 0 ? _f : this.offset;
|
|
27
|
+
}
|
|
28
|
+
generateNoise(particle, w = false) {
|
|
29
|
+
const layers = [];
|
|
30
|
+
for (let i = 0; i < this.octaves; i += 1) {
|
|
31
|
+
const frequency = this.frequency * (Math.pow(this.lacunarity, i));
|
|
32
|
+
const amplitude = Math.pow(this.persistence, i);
|
|
33
|
+
// Clamp because float math is nuts
|
|
34
|
+
const rawNoise = Math.min(Math.max((this.noiseGenerator((particle.position.x + this.offset.x) * frequency, (particle.position.y + this.offset.y) * frequency, (particle.position.z + this.offset.z) * frequency, w ? this.time : 0) + 1) / 2, 0), 1);
|
|
35
|
+
layers.push({
|
|
36
|
+
value: rawNoise * amplitude,
|
|
37
|
+
weight: amplitude,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Use weighted average to maintain 0 - 1 range
|
|
41
|
+
return layers.map((layer) => layer.value).reduce((a, b) => a + b)
|
|
42
|
+
/ layers.map((layer) => layer.weight).reduce((a, b) => a + b);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export default NoiseModule;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
import { SpeedRange } from './ColorBySpeed';
|
|
5
|
+
export interface RotationBySpeedOptions extends Partial<ModuleOptions> {
|
|
6
|
+
angularVelocity: DynamicValue<THREE.Vector3>;
|
|
7
|
+
speedRange?: SpeedRange;
|
|
8
|
+
}
|
|
9
|
+
declare class RotationBySpeed extends Module {
|
|
10
|
+
options: RotationBySpeedOptions;
|
|
11
|
+
constructor(options: RotationBySpeedOptions);
|
|
12
|
+
private getSpeedTime;
|
|
13
|
+
}
|
|
14
|
+
export default RotationBySpeed;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicVector from '../helpers/evaluateDynamicVector3';
|
|
3
|
+
class RotationBySpeed extends Module {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super((particle) => {
|
|
6
|
+
particle.angularVelocity = particle.start.angularVelocity.clone().add(evaluateDynamicVector(this.options.angularVelocity, this.getSpeedTime(particle.velocity.length()), particle.id));
|
|
7
|
+
}, options);
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
getSpeedTime(speed) {
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
|
+
const min = Array.isArray(this.options.speedRange) ? this.options.speedRange[0] : (_b = (_a = this.options.speedRange) === null || _a === void 0 ? void 0 : _a.min) !== null && _b !== void 0 ? _b : 0;
|
|
13
|
+
const max = Array.isArray(this.options.speedRange) ? this.options.speedRange[1] : (_d = (_c = this.options.speedRange) === null || _c === void 0 ? void 0 : _c.max) !== null && _d !== void 0 ? _d : 1;
|
|
14
|
+
if (max === min)
|
|
15
|
+
return speed >= max ? 1 : 0;
|
|
16
|
+
return Math.min(Math.max((speed - min) / (max - min), 0), 1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export default RotationBySpeed;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
export interface RotationOverLifetimeOptions extends Partial<ModuleOptions> {
|
|
5
|
+
angularVelocity: DynamicValue<THREE.Vector3>;
|
|
6
|
+
}
|
|
7
|
+
declare class RotationOverLifetime extends Module {
|
|
8
|
+
options: RotationOverLifetimeOptions;
|
|
9
|
+
constructor(options: RotationOverLifetimeOptions);
|
|
10
|
+
}
|
|
11
|
+
export default RotationOverLifetime;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicVector from '../helpers/evaluateDynamicVector3';
|
|
3
|
+
class RotationOverLifetime extends Module {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super((particle) => {
|
|
6
|
+
particle.angularVelocity = particle.start.angularVelocity.clone()
|
|
7
|
+
.add(evaluateDynamicVector(this.options.angularVelocity, particle.time, particle.id));
|
|
8
|
+
}, options);
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export default RotationOverLifetime;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
import { SpeedRange } from './ColorBySpeed';
|
|
5
|
+
export interface ScaleBySpeedOptions extends Partial<ModuleOptions> {
|
|
6
|
+
scale: DynamicValue<THREE.Vector3>;
|
|
7
|
+
speedRange?: SpeedRange;
|
|
8
|
+
}
|
|
9
|
+
declare class ScaleBySpeed extends Module {
|
|
10
|
+
options: ScaleBySpeedOptions;
|
|
11
|
+
constructor(options: ScaleBySpeedOptions);
|
|
12
|
+
private getSpeedTime;
|
|
13
|
+
}
|
|
14
|
+
export default ScaleBySpeed;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicVector from '../helpers/evaluateDynamicVector3';
|
|
3
|
+
class ScaleBySpeed extends Module {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super((particle) => {
|
|
6
|
+
particle.scale = particle.start.scale.clone().multiply(evaluateDynamicVector(this.options.scale, this.getSpeedTime(particle.velocity.length()), particle.id));
|
|
7
|
+
}, options);
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
getSpeedTime(speed) {
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
|
+
const min = Array.isArray(this.options.speedRange) ? this.options.speedRange[0] : (_b = (_a = this.options.speedRange) === null || _a === void 0 ? void 0 : _a.min) !== null && _b !== void 0 ? _b : 0;
|
|
13
|
+
const max = Array.isArray(this.options.speedRange) ? this.options.speedRange[1] : (_d = (_c = this.options.speedRange) === null || _c === void 0 ? void 0 : _c.max) !== null && _d !== void 0 ? _d : 1;
|
|
14
|
+
if (max === min)
|
|
15
|
+
return speed >= max ? 1 : 0;
|
|
16
|
+
return Math.min(Math.max((speed - min) / (max - min), 0), 1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export default ScaleBySpeed;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
export interface ScaleOverLifetimeOptions extends Partial<ModuleOptions> {
|
|
5
|
+
scale: DynamicValue<THREE.Vector3>;
|
|
6
|
+
}
|
|
7
|
+
declare class ScaleOverLifetime extends Module {
|
|
8
|
+
options: ScaleOverLifetimeOptions;
|
|
9
|
+
constructor(options: ScaleOverLifetimeOptions);
|
|
10
|
+
}
|
|
11
|
+
export default ScaleOverLifetime;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Module from '../Module';
|
|
2
|
+
import evaluateDynamicVector from '../helpers/evaluateDynamicVector3';
|
|
3
|
+
class ScaleOverLifetime extends Module {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super((particle) => {
|
|
6
|
+
particle.scale = particle.start.scale.clone().multiply(evaluateDynamicVector(this.options.scale, particle.time, particle.id));
|
|
7
|
+
}, options);
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export default ScaleOverLifetime;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Module, { ModuleOptions } from '../Module';
|
|
3
|
+
import { DynamicValue } from '../types/DynamicValue';
|
|
4
|
+
import { NoiseOptions } from './NoiseModule';
|
|
5
|
+
export interface TransformByNoiseOptions extends Partial<ModuleOptions>, NoiseOptions {
|
|
6
|
+
strength: DynamicValue<THREE.Vector3>;
|
|
7
|
+
scrollSpeed: DynamicValue<number>;
|
|
8
|
+
damping: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare class TransformByNoise extends Module {
|
|
11
|
+
options: Partial<TransformByNoiseOptions>;
|
|
12
|
+
private noiseX;
|
|
13
|
+
private noiseY;
|
|
14
|
+
private noiseZ;
|
|
15
|
+
constructor(options: Partial<TransformByNoiseOptions>);
|
|
16
|
+
}
|
|
17
|
+
export default TransformByNoise;
|