@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,33 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { EmissionSource } from './enums/EmissionSource';
|
|
3
|
+
interface EmissionShapeOptions {
|
|
4
|
+
geometry: THREE.BufferGeometry;
|
|
5
|
+
source: EmissionSource | `${EmissionSource}`;
|
|
6
|
+
}
|
|
7
|
+
declare class EmissionShape extends THREE.Object3D {
|
|
8
|
+
static maxVolumeIterations: number;
|
|
9
|
+
private static readonly _doubleSidedMaterial;
|
|
10
|
+
static Box(...args: any[]): EmissionShape;
|
|
11
|
+
static Sphere(...args: any[]): EmissionShape;
|
|
12
|
+
static Cone(...args: any[]): EmissionShape;
|
|
13
|
+
static Torus(...args: any[]): EmissionShape;
|
|
14
|
+
source: EmissionSource;
|
|
15
|
+
private _geometry;
|
|
16
|
+
private _surfaceSampler;
|
|
17
|
+
private _vertexNormals;
|
|
18
|
+
private _raycaster;
|
|
19
|
+
private _mesh;
|
|
20
|
+
constructor(options?: Partial<EmissionShapeOptions>);
|
|
21
|
+
set geometry(value: THREE.BufferGeometry);
|
|
22
|
+
get geometry(): THREE.BufferGeometry;
|
|
23
|
+
get vertices(): THREE.Vector3[];
|
|
24
|
+
private _calculatePointNormal;
|
|
25
|
+
computeVertexNormals(): void;
|
|
26
|
+
private _toParentPosition;
|
|
27
|
+
private _toParentNormal;
|
|
28
|
+
getPoint(overrideSource?: EmissionSource): {
|
|
29
|
+
position: THREE.Vector3;
|
|
30
|
+
normal: THREE.Vector3;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export default EmissionShape;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { MeshSurfaceSampler } from 'three/examples/jsm/math/MeshSurfaceSampler.js';
|
|
3
|
+
import { EmissionSource } from './enums/EmissionSource';
|
|
4
|
+
import isPointInMesh from './helpers/isPointInMesh';
|
|
5
|
+
class EmissionShape extends THREE.Object3D {
|
|
6
|
+
static Box(...args) {
|
|
7
|
+
return new EmissionShape({ geometry: new THREE.BoxGeometry(...args) });
|
|
8
|
+
}
|
|
9
|
+
static Sphere(...args) {
|
|
10
|
+
return new EmissionShape({ geometry: new THREE.SphereGeometry(...args) });
|
|
11
|
+
}
|
|
12
|
+
static Cone(...args) {
|
|
13
|
+
return new EmissionShape({ geometry: new THREE.ConeGeometry(...args) });
|
|
14
|
+
}
|
|
15
|
+
static Torus(...args) {
|
|
16
|
+
return new EmissionShape({ geometry: new THREE.TorusGeometry(...args) });
|
|
17
|
+
}
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
var _a, _b;
|
|
20
|
+
super();
|
|
21
|
+
this._vertexNormals = [];
|
|
22
|
+
this._raycaster = new THREE.Raycaster();
|
|
23
|
+
this._geometry = (_a = options.geometry) !== null && _a !== void 0 ? _a : new THREE.SphereGeometry();
|
|
24
|
+
this.source = (_b = options.source) !== null && _b !== void 0 ? _b : EmissionSource.Volume;
|
|
25
|
+
this._mesh = new THREE.Mesh(this._geometry, EmissionShape._doubleSidedMaterial);
|
|
26
|
+
this._surfaceSampler = new MeshSurfaceSampler(this._mesh)
|
|
27
|
+
.build();
|
|
28
|
+
this.computeVertexNormals();
|
|
29
|
+
this._geometry.computeBoundingBox();
|
|
30
|
+
}
|
|
31
|
+
set geometry(value) {
|
|
32
|
+
this._geometry = value;
|
|
33
|
+
this._mesh = new THREE.Mesh(this._geometry, EmissionShape._doubleSidedMaterial);
|
|
34
|
+
this._surfaceSampler = new MeshSurfaceSampler(this._mesh);
|
|
35
|
+
this.computeVertexNormals();
|
|
36
|
+
this._geometry.computeBoundingBox();
|
|
37
|
+
this._mesh.updateMatrix();
|
|
38
|
+
}
|
|
39
|
+
get geometry() { return this._geometry; }
|
|
40
|
+
get vertices() {
|
|
41
|
+
const vertices = this._geometry.getAttribute('position');
|
|
42
|
+
const res = [];
|
|
43
|
+
for (let i = 0; i < vertices.array.length; i += 3) {
|
|
44
|
+
res.push(new THREE.Vector3(vertices.array[i], vertices.array[i + 1], vertices.array[i + 2]));
|
|
45
|
+
}
|
|
46
|
+
return res;
|
|
47
|
+
}
|
|
48
|
+
// Calculate the normal of a point in the geometry volume
|
|
49
|
+
_calculatePointNormal(point, maxVertices = 5) {
|
|
50
|
+
// Get the closest vertices
|
|
51
|
+
const { vertices } = this;
|
|
52
|
+
const closest = vertices
|
|
53
|
+
.sort((a, b) => Math.abs(point.distanceTo(a)) - Math.abs(point.distanceTo(b)))
|
|
54
|
+
.splice(0, maxVertices);
|
|
55
|
+
// Get weighted average
|
|
56
|
+
const sumVectors = (vectors) => vectors.reduce((a, b) => a.addScaledVector(b, 1));
|
|
57
|
+
const sumArray = (values) => values.reduce((a, b) => a + b);
|
|
58
|
+
const weightedMean = (factorsArray, weightsArray) => sumVectors(factorsArray.map((factor, index) => factor.multiplyScalar(weightsArray[index]))).divideScalar(sumArray(weightsArray));
|
|
59
|
+
return weightedMean(closest, closest.map((vector) => Math.abs(point.distanceTo(vector))));
|
|
60
|
+
}
|
|
61
|
+
computeVertexNormals() {
|
|
62
|
+
this._geometry.computeVertexNormals();
|
|
63
|
+
const vertexNormals = this._geometry.getAttribute('normal');
|
|
64
|
+
const res = [];
|
|
65
|
+
for (let i = 0; i < vertexNormals.array.length; i += 3) {
|
|
66
|
+
res.push(new THREE.Vector3(vertexNormals.array[i], vertexNormals.array[i + 1], vertexNormals.array[i + 2]));
|
|
67
|
+
}
|
|
68
|
+
this._vertexNormals = res;
|
|
69
|
+
}
|
|
70
|
+
_toParentPosition(localPosition) {
|
|
71
|
+
this.updateWorldMatrix(true, false);
|
|
72
|
+
const worldPosition = localPosition.clone().applyMatrix4(this.matrixWorld);
|
|
73
|
+
return this.parent
|
|
74
|
+
? this.parent.worldToLocal(worldPosition)
|
|
75
|
+
: worldPosition;
|
|
76
|
+
}
|
|
77
|
+
_toParentNormal(localNormal) {
|
|
78
|
+
const normalMatrix = new THREE.Matrix3().getNormalMatrix(this.matrix);
|
|
79
|
+
return localNormal
|
|
80
|
+
.clone()
|
|
81
|
+
.applyNormalMatrix(normalMatrix)
|
|
82
|
+
.normalize();
|
|
83
|
+
}
|
|
84
|
+
getPoint(overrideSource) {
|
|
85
|
+
switch (overrideSource !== null && overrideSource !== void 0 ? overrideSource : this.source) {
|
|
86
|
+
case EmissionSource.Vertices:
|
|
87
|
+
// Select random vertex
|
|
88
|
+
const { vertices } = this;
|
|
89
|
+
const vertexIndex = Math.floor(Math.random() * vertices.length);
|
|
90
|
+
return {
|
|
91
|
+
position: this._toParentPosition(vertices[vertexIndex]),
|
|
92
|
+
normal: this._toParentNormal(this._vertexNormals[vertexIndex]),
|
|
93
|
+
};
|
|
94
|
+
case EmissionSource.Surface:
|
|
95
|
+
// Use surface sampler to find random point on surface
|
|
96
|
+
const position = new THREE.Vector3(0, 0, 0);
|
|
97
|
+
const normal = new THREE.Vector3(0, 0, 0);
|
|
98
|
+
this._surfaceSampler.sample(position, normal);
|
|
99
|
+
return {
|
|
100
|
+
position: this._toParentPosition(position),
|
|
101
|
+
normal: this._toParentNormal(normal),
|
|
102
|
+
};
|
|
103
|
+
case EmissionSource.Volume:
|
|
104
|
+
default:
|
|
105
|
+
// If no bounding box, fallback to surface
|
|
106
|
+
if (!this._geometry.boundingBox)
|
|
107
|
+
return this.getPoint(EmissionSource.Surface);
|
|
108
|
+
// Choose random points in bounding box until one is contained by geometry (volume)
|
|
109
|
+
const { min, max } = this._geometry.boundingBox;
|
|
110
|
+
const randomPoint = new THREE.Vector3(THREE.MathUtils.lerp(min.x, max.x, Math.random()), THREE.MathUtils.lerp(min.y, max.y, Math.random()), THREE.MathUtils.lerp(min.z, max.z, Math.random()));
|
|
111
|
+
// Search for the allotted iterations
|
|
112
|
+
let iterations = 0;
|
|
113
|
+
while (iterations < EmissionShape.maxVolumeIterations) {
|
|
114
|
+
if (isPointInMesh(randomPoint, this._mesh)) {
|
|
115
|
+
return {
|
|
116
|
+
position: this._toParentPosition(randomPoint),
|
|
117
|
+
normal: this._toParentNormal(this._calculatePointNormal(randomPoint)),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
iterations += 1;
|
|
121
|
+
}
|
|
122
|
+
// If not found, get from surface sampler
|
|
123
|
+
return this.getPoint(EmissionSource.Surface);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
EmissionShape.maxVolumeIterations = 5;
|
|
128
|
+
EmissionShape._doubleSidedMaterial = new THREE.MeshBasicMaterial({ side: THREE.DoubleSide });
|
|
129
|
+
export default EmissionShape;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import EmissionShape from './EmissionShape';
|
|
3
|
+
import Particle from './Particle';
|
|
4
|
+
import { InitialParticleValues } from './interfaces/InitialParticleValues';
|
|
5
|
+
import ParticleSystem from './ParticleSystem';
|
|
6
|
+
import { DynamicUntimedValue, DynamicValue } from './types/DynamicValue';
|
|
7
|
+
import { Multiple, StrictMultiple } from './types/Multiple';
|
|
8
|
+
import { Tag } from './types/Tag';
|
|
9
|
+
import { TagSelectionMethod } from './enums/TagSelectionMethod';
|
|
10
|
+
type SpawnBurst = {
|
|
11
|
+
time: number;
|
|
12
|
+
count: DynamicUntimedValue<number>;
|
|
13
|
+
fired?: boolean;
|
|
14
|
+
};
|
|
15
|
+
interface EmitterOptions {
|
|
16
|
+
initialValues: Partial<InitialParticleValues>;
|
|
17
|
+
source: EmissionShape;
|
|
18
|
+
bursts: Multiple<SpawnBurst>;
|
|
19
|
+
rate: DynamicValue<number>;
|
|
20
|
+
radialSpeed: DynamicValue<number>;
|
|
21
|
+
alignment: DynamicValue<number>;
|
|
22
|
+
tags: StrictMultiple<Tag>;
|
|
23
|
+
tagSelection: TagSelectionMethod | `${TagSelectionMethod}`;
|
|
24
|
+
}
|
|
25
|
+
export interface EmissionContext {
|
|
26
|
+
key?: string;
|
|
27
|
+
transform?: THREE.Matrix4;
|
|
28
|
+
time?: number;
|
|
29
|
+
duration?: number;
|
|
30
|
+
elapsedTime?: number;
|
|
31
|
+
looping?: boolean;
|
|
32
|
+
color?: THREE.Color;
|
|
33
|
+
alpha?: number;
|
|
34
|
+
mass?: number;
|
|
35
|
+
tags?: Tag[];
|
|
36
|
+
}
|
|
37
|
+
declare class Emitter {
|
|
38
|
+
source: EmissionShape;
|
|
39
|
+
rate: DynamicValue<number>;
|
|
40
|
+
bursts: SpawnBurst[];
|
|
41
|
+
initialValues: Partial<InitialParticleValues>;
|
|
42
|
+
radialSpeed: DynamicValue<number>;
|
|
43
|
+
alignment: DynamicValue<number>;
|
|
44
|
+
tags?: Tag[];
|
|
45
|
+
tagSelection: TagSelectionMethod;
|
|
46
|
+
private _lastTagIndex;
|
|
47
|
+
private _contextStates;
|
|
48
|
+
constructor(options?: Partial<EmitterOptions>);
|
|
49
|
+
reset(): void;
|
|
50
|
+
setup(particleSystem: ParticleSystem): void;
|
|
51
|
+
update(particles: Particle[], context?: EmissionContext): Particle[];
|
|
52
|
+
updateAt(particles: Particle[], context: EmissionContext): Particle[];
|
|
53
|
+
clearContext(key: string): void;
|
|
54
|
+
private getContextState;
|
|
55
|
+
private spawnParticle;
|
|
56
|
+
private _selectTags;
|
|
57
|
+
}
|
|
58
|
+
export default Emitter;
|
package/build/Emitter.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import EmissionShape from './EmissionShape';
|
|
3
|
+
import Particle from './Particle';
|
|
4
|
+
import evaluateDynamicVector from './helpers/evaluateDynamicVector3';
|
|
5
|
+
import evaluateDynamicNumber from './helpers/evaluateDynamicNumber';
|
|
6
|
+
import evaluateDynamicColor from './helpers/evaluateDynamicColor';
|
|
7
|
+
import acceptMultiple from './helpers/acceptMultiple';
|
|
8
|
+
import { TagSelectionMethod } from './enums/TagSelectionMethod';
|
|
9
|
+
class Emitter {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
12
|
+
this.tagSelection = TagSelectionMethod.All;
|
|
13
|
+
this._lastTagIndex = 0;
|
|
14
|
+
// Used for subsystems
|
|
15
|
+
this._contextStates = new Map();
|
|
16
|
+
this.source = (_a = options.source) !== null && _a !== void 0 ? _a : EmissionShape.Sphere();
|
|
17
|
+
this.initialValues = (_b = options.initialValues) !== null && _b !== void 0 ? _b : {};
|
|
18
|
+
this.rate = (_c = options.rate) !== null && _c !== void 0 ? _c : 50;
|
|
19
|
+
this.bursts = (_d = acceptMultiple(options.bursts)) !== null && _d !== void 0 ? _d : [];
|
|
20
|
+
this.radialSpeed = (_e = options.radialSpeed) !== null && _e !== void 0 ? _e : 1;
|
|
21
|
+
this.alignment = (_f = options.alignment) !== null && _f !== void 0 ? _f : 0;
|
|
22
|
+
this.tags = acceptMultiple(options.tags);
|
|
23
|
+
this.tagSelection = (_g = options.tagSelection) !== null && _g !== void 0 ? _g : this.tagSelection;
|
|
24
|
+
}
|
|
25
|
+
/*
|
|
26
|
+
* CONTROLS
|
|
27
|
+
*/
|
|
28
|
+
reset() {
|
|
29
|
+
this.bursts.forEach((burst) => {
|
|
30
|
+
burst.fired = false;
|
|
31
|
+
});
|
|
32
|
+
this._contextStates.clear();
|
|
33
|
+
}
|
|
34
|
+
/*
|
|
35
|
+
* SIMULATION
|
|
36
|
+
*/
|
|
37
|
+
setup(particleSystem) {
|
|
38
|
+
particleSystem.add(this.source);
|
|
39
|
+
}
|
|
40
|
+
update(particles, context) {
|
|
41
|
+
var _a;
|
|
42
|
+
return this.updateAt(particles, Object.assign(Object.assign({}, context), { key: (_a = context === null || context === void 0 ? void 0 : context.key) !== null && _a !== void 0 ? _a : '__default' }));
|
|
43
|
+
}
|
|
44
|
+
updateAt(particles, context) {
|
|
45
|
+
var _a, _b, _c, _d, _e;
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const elapsedMilliseconds = context.elapsedTime === undefined
|
|
48
|
+
? undefined
|
|
49
|
+
: context.elapsedTime * 1000;
|
|
50
|
+
const state = this.getContextState((_a = context.key) !== null && _a !== void 0 ? _a : '__default', elapsedMilliseconds !== null && elapsedMilliseconds !== void 0 ? elapsedMilliseconds : now);
|
|
51
|
+
const duration = (_b = context.duration) !== null && _b !== void 0 ? _b : 10;
|
|
52
|
+
const elapsedTime = (_c = context.elapsedTime) !== null && _c !== void 0 ? _c : ((now - state.startTime) / 1000);
|
|
53
|
+
const time = (_d = context.time) !== null && _d !== void 0 ? _d : (elapsedTime / duration);
|
|
54
|
+
const looping = (_e = context.looping) !== null && _e !== void 0 ? _e : true;
|
|
55
|
+
const spawned = [];
|
|
56
|
+
if (context.time === undefined && elapsedTime >= duration) {
|
|
57
|
+
if (!looping)
|
|
58
|
+
return spawned;
|
|
59
|
+
state.startTime = now;
|
|
60
|
+
state.lastSpawn = now;
|
|
61
|
+
state.firedBursts.clear();
|
|
62
|
+
return spawned;
|
|
63
|
+
}
|
|
64
|
+
const rate = evaluateDynamicNumber(this.rate, time);
|
|
65
|
+
if (rate > 0) {
|
|
66
|
+
const secondsPerParticle = 1000 / rate;
|
|
67
|
+
const spawnClock = elapsedMilliseconds !== null && elapsedMilliseconds !== void 0 ? elapsedMilliseconds : now;
|
|
68
|
+
const particlesDue = Math.floor((spawnClock - state.lastSpawn) / secondsPerParticle);
|
|
69
|
+
for (let i = 0; i < particlesDue; i += 1) {
|
|
70
|
+
const particle = this.spawnParticle(particles, time, context);
|
|
71
|
+
spawned.push(particle);
|
|
72
|
+
}
|
|
73
|
+
if (particlesDue > 0) {
|
|
74
|
+
state.lastSpawn = spawnClock;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
this.bursts.forEach((burst, index) => {
|
|
78
|
+
if (!state.firedBursts.has(index) && burst.time <= time) {
|
|
79
|
+
const count = evaluateDynamicNumber(burst.count);
|
|
80
|
+
for (let i = 0; i < Math.floor(count); i += 1) {
|
|
81
|
+
const particle = this.spawnParticle(particles, time, context);
|
|
82
|
+
spawned.push(particle);
|
|
83
|
+
}
|
|
84
|
+
state.firedBursts.add(index);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return spawned;
|
|
88
|
+
}
|
|
89
|
+
clearContext(key) {
|
|
90
|
+
this._contextStates.delete(key);
|
|
91
|
+
}
|
|
92
|
+
getContextState(key, startTime) {
|
|
93
|
+
let state = this._contextStates.get(key);
|
|
94
|
+
if (!state) {
|
|
95
|
+
state = {
|
|
96
|
+
startTime,
|
|
97
|
+
lastSpawn: startTime,
|
|
98
|
+
firedBursts: new Set(),
|
|
99
|
+
};
|
|
100
|
+
this._contextStates.set(key, state);
|
|
101
|
+
}
|
|
102
|
+
return state;
|
|
103
|
+
}
|
|
104
|
+
spawnParticle(particles, time, context) {
|
|
105
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
106
|
+
const point = this.source.getPoint();
|
|
107
|
+
const position = point.position.clone();
|
|
108
|
+
const normal = point.normal.clone();
|
|
109
|
+
if (context === null || context === void 0 ? void 0 : context.transform) {
|
|
110
|
+
position.applyMatrix4(context.transform);
|
|
111
|
+
normal.applyNormalMatrix(new THREE.Matrix3().getNormalMatrix(context.transform)).normalize();
|
|
112
|
+
}
|
|
113
|
+
const defaultRotationQuat = (new THREE.Quaternion).setFromUnitVectors(new THREE.Vector3(0, 0, 1), normal);
|
|
114
|
+
const defaultRotationEuler = new THREE.Euler().setFromQuaternion(defaultRotationQuat, 'YXZ');
|
|
115
|
+
const defaultRotation = new THREE.Vector3(defaultRotationEuler.x, defaultRotationEuler.y, defaultRotationEuler.z);
|
|
116
|
+
const rotation = new THREE.Vector3(0, 0, 0).lerp(defaultRotation, Math.max(Math.min(evaluateDynamicNumber(this.alignment, time), 1), 0));
|
|
117
|
+
const color = evaluateDynamicColor((_a = this.initialValues.color) !== null && _a !== void 0 ? _a : new THREE.Color(1, 1, 1), time);
|
|
118
|
+
if (context === null || context === void 0 ? void 0 : context.color) {
|
|
119
|
+
color.multiply(context.color);
|
|
120
|
+
}
|
|
121
|
+
let alpha = evaluateDynamicNumber((_b = this.initialValues.alpha) !== null && _b !== void 0 ? _b : 1, time);
|
|
122
|
+
if (context === null || context === void 0 ? void 0 : context.alpha) {
|
|
123
|
+
alpha *= context.alpha;
|
|
124
|
+
}
|
|
125
|
+
let mass = evaluateDynamicNumber((_c = this.initialValues.mass) !== null && _c !== void 0 ? _c : 0, time);
|
|
126
|
+
if (context === null || context === void 0 ? void 0 : context.mass) {
|
|
127
|
+
mass *= context.mass;
|
|
128
|
+
}
|
|
129
|
+
const particle = new Particle(Object.assign({ position, rotation: evaluateDynamicVector((_d = this.initialValues.rotation) !== null && _d !== void 0 ? _d : rotation, time), scale: evaluateDynamicVector((_e = this.initialValues.scale) !== null && _e !== void 0 ? _e : new THREE.Vector3(1, 1, 1), time), lifetime: evaluateDynamicNumber((_f = this.initialValues.lifetime) !== null && _f !== void 0 ? _f : 1, time), color,
|
|
130
|
+
alpha,
|
|
131
|
+
mass }, ((this.tags || (context === null || context === void 0 ? void 0 : context.tags)) && {
|
|
132
|
+
tags: [...((_g = context === null || context === void 0 ? void 0 : context.tags) !== null && _g !== void 0 ? _g : []), ...((_h = this._selectTags()) !== null && _h !== void 0 ? _h : [])],
|
|
133
|
+
})));
|
|
134
|
+
particle.speed = evaluateDynamicNumber((_j = this.initialValues.speed) !== null && _j !== void 0 ? _j : 1, time);
|
|
135
|
+
particle.velocity = evaluateDynamicVector((_k = this.initialValues.velocity) !== null && _k !== void 0 ? _k : new THREE.Vector3(0, 0, 0), time).clone()
|
|
136
|
+
.add(normal.multiplyScalar(evaluateDynamicNumber(this.radialSpeed, time)));
|
|
137
|
+
if (this.initialValues.angularVelocity)
|
|
138
|
+
particle.angularVelocity = evaluateDynamicVector(this.initialValues.angularVelocity, time).clone();
|
|
139
|
+
if (this.initialValues.scalarVelocity)
|
|
140
|
+
particle.scalarVelocity = evaluateDynamicVector(this.initialValues.scalarVelocity, time).clone();
|
|
141
|
+
if (this.initialValues.acceleration)
|
|
142
|
+
particle.acceleration = evaluateDynamicVector(this.initialValues.acceleration, time).clone();
|
|
143
|
+
if (this.initialValues.angularAcceleration)
|
|
144
|
+
particle.angularAcceleration = evaluateDynamicVector(this.initialValues.angularAcceleration, time).clone();
|
|
145
|
+
if (this.initialValues.scalarAcceleration)
|
|
146
|
+
particle.scalarAcceleration = evaluateDynamicVector(this.initialValues.scalarAcceleration, time).clone();
|
|
147
|
+
particle.cacheStartValues();
|
|
148
|
+
particles.push(particle);
|
|
149
|
+
return particle;
|
|
150
|
+
}
|
|
151
|
+
_selectTags() {
|
|
152
|
+
if (!this.tags)
|
|
153
|
+
return;
|
|
154
|
+
switch (this.tagSelection) {
|
|
155
|
+
case 'random':
|
|
156
|
+
return [this.tags[Math.floor(Math.random() * this.tags.length)]];
|
|
157
|
+
case 'distribute':
|
|
158
|
+
this._lastTagIndex = (this._lastTagIndex + 1) % this.tags.length;
|
|
159
|
+
return [this.tags[this._lastTagIndex]];
|
|
160
|
+
case 'all':
|
|
161
|
+
default:
|
|
162
|
+
return this.tags;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export default Emitter;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Module, { ModuleOptions } from './Module';
|
|
2
|
+
import Particle from './Particle';
|
|
3
|
+
import type ParticleSystem from './ParticleSystem';
|
|
4
|
+
import { GpuCapableRenderer, GpuParticleContext } from './gpu/GpuParticleContext';
|
|
5
|
+
import { DynamicValue } from './types/DynamicValue';
|
|
6
|
+
export interface GpuModuleBuildContext {
|
|
7
|
+
particles: GpuParticleContext;
|
|
8
|
+
deltaTime: number;
|
|
9
|
+
renderer: GpuCapableRenderer;
|
|
10
|
+
system: ParticleSystem;
|
|
11
|
+
}
|
|
12
|
+
export type GpuModuleBuilder = (context: GpuModuleBuildContext) => any | any[];
|
|
13
|
+
export type GpuModulePredicate = (context: GpuModuleBuildContext) => boolean;
|
|
14
|
+
export interface GpuModuleOptions extends Partial<ModuleOptions> {
|
|
15
|
+
gpu?: GpuModuleBuilder;
|
|
16
|
+
canRunGpu?: GpuModulePredicate;
|
|
17
|
+
}
|
|
18
|
+
declare class GpuModule extends Module {
|
|
19
|
+
readonly supportsGpu = true;
|
|
20
|
+
constructor(modify: ((particle: Particle, deltaTime: number) => void), options?: GpuModuleOptions);
|
|
21
|
+
private _buildGpu?;
|
|
22
|
+
private _canRunGpu?;
|
|
23
|
+
canRunGpu(context: GpuModuleBuildContext): boolean;
|
|
24
|
+
buildGpu(context: GpuModuleBuildContext): any | any[];
|
|
25
|
+
}
|
|
26
|
+
export declare function isGpuModule(module: Module): module is GpuModule;
|
|
27
|
+
export declare function isGpuStaticValue<T>(value: DynamicValue<T> | undefined): value is T;
|
|
28
|
+
export default GpuModule;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Module from './Module';
|
|
2
|
+
class GpuModule extends Module {
|
|
3
|
+
constructor(modify, options = {}) {
|
|
4
|
+
super(modify, options);
|
|
5
|
+
this.supportsGpu = true;
|
|
6
|
+
this._buildGpu = options.gpu;
|
|
7
|
+
this._canRunGpu = options.canRunGpu;
|
|
8
|
+
}
|
|
9
|
+
canRunGpu(context) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
return !!this._buildGpu && ((_b = (_a = this._canRunGpu) === null || _a === void 0 ? void 0 : _a.call(this, context)) !== null && _b !== void 0 ? _b : true);
|
|
12
|
+
}
|
|
13
|
+
buildGpu(context) {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
return (_b = (_a = this._buildGpu) === null || _a === void 0 ? void 0 : _a.call(this, context)) !== null && _b !== void 0 ? _b : [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function isGpuModule(module) {
|
|
19
|
+
return module instanceof GpuModule || (module.supportsGpu === true
|
|
20
|
+
&& typeof module.buildGpu === 'function');
|
|
21
|
+
}
|
|
22
|
+
export function isGpuStaticValue(value) {
|
|
23
|
+
return value !== undefined
|
|
24
|
+
&& typeof value !== 'function'
|
|
25
|
+
&& !Array.isArray(value)
|
|
26
|
+
&& !(value instanceof Set);
|
|
27
|
+
}
|
|
28
|
+
export default GpuModule;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Particle from './Particle';
|
|
2
|
+
import ParticleSystem from './ParticleSystem';
|
|
3
|
+
import { Tag } from './types/Tag';
|
|
4
|
+
import { StrictMultiple } from './types/Multiple';
|
|
5
|
+
export interface ModuleOptions {
|
|
6
|
+
priority: number;
|
|
7
|
+
tags: StrictMultiple<Tag>;
|
|
8
|
+
}
|
|
9
|
+
export default class Module {
|
|
10
|
+
_modify: ((particle: Particle, deltaTime: number) => void);
|
|
11
|
+
dependents: Module[];
|
|
12
|
+
tags?: Tag[];
|
|
13
|
+
priority: number;
|
|
14
|
+
constructor(_modify: ((particle: Particle, deltaTime: number) => void), options?: Partial<ModuleOptions>);
|
|
15
|
+
modify(particles: Particle[], deltaTime: number): void;
|
|
16
|
+
withDependents(): Module[];
|
|
17
|
+
prepare(particleSystem: ParticleSystem, deltaTime: number): void;
|
|
18
|
+
cleanup(): void;
|
|
19
|
+
}
|
package/build/Module.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import acceptMultiple from './helpers/acceptMultiple';
|
|
2
|
+
import tagsIntersect from './helpers/tagsIntersect';
|
|
3
|
+
export default class Module {
|
|
4
|
+
constructor(_modify, options = {}) {
|
|
5
|
+
var _a;
|
|
6
|
+
this._modify = _modify;
|
|
7
|
+
// Sub-modules on which this module depends.
|
|
8
|
+
// Useful for pre-processing or combining priority stages.
|
|
9
|
+
this.dependents = [];
|
|
10
|
+
this.priority = -1;
|
|
11
|
+
this.tags = acceptMultiple(options.tags);
|
|
12
|
+
this.priority = (_a = options.priority) !== null && _a !== void 0 ? _a : this.priority;
|
|
13
|
+
}
|
|
14
|
+
modify(particles, deltaTime) {
|
|
15
|
+
particles.filter((p) => { var _a; return !this.tags || tagsIntersect(this.tags, (_a = p.tags) !== null && _a !== void 0 ? _a : []); })
|
|
16
|
+
.forEach((p) => this._modify(p, deltaTime));
|
|
17
|
+
}
|
|
18
|
+
// Process into array including self and dependents
|
|
19
|
+
withDependents() {
|
|
20
|
+
// Run dependents before this
|
|
21
|
+
return [
|
|
22
|
+
...(this.dependents.flatMap(d => d.withDependents())),
|
|
23
|
+
this,
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
// Optional preparation hook called once-per-update rather than per particle
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
prepare(particleSystem, deltaTime) { }
|
|
29
|
+
// Optional clean up hook for modules that require it
|
|
30
|
+
cleanup() { }
|
|
31
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { Tag } from './types/Tag';
|
|
3
|
+
export interface ParticleOptions {
|
|
4
|
+
position: THREE.Vector3;
|
|
5
|
+
rotation: THREE.Vector3;
|
|
6
|
+
scale: THREE.Vector3;
|
|
7
|
+
color: THREE.Color;
|
|
8
|
+
tags: Tag[];
|
|
9
|
+
alpha: number;
|
|
10
|
+
lifetime: number;
|
|
11
|
+
mass: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ParticleStartValues {
|
|
14
|
+
lifetime: number;
|
|
15
|
+
position: THREE.Vector3;
|
|
16
|
+
rotation: THREE.Vector3;
|
|
17
|
+
scale: THREE.Vector3;
|
|
18
|
+
velocity: THREE.Vector3;
|
|
19
|
+
angularVelocity: THREE.Vector3;
|
|
20
|
+
scalarVelocity: THREE.Vector3;
|
|
21
|
+
acceleration: THREE.Vector3;
|
|
22
|
+
angularAcceleration: THREE.Vector3;
|
|
23
|
+
scalarAcceleration: THREE.Vector3;
|
|
24
|
+
speed: number;
|
|
25
|
+
color: THREE.Color;
|
|
26
|
+
alpha: number;
|
|
27
|
+
mass: number;
|
|
28
|
+
}
|
|
29
|
+
export interface ParticleNoiseValues {
|
|
30
|
+
noise: number;
|
|
31
|
+
noise4d: number;
|
|
32
|
+
}
|
|
33
|
+
declare class Particle {
|
|
34
|
+
position: THREE.Vector3;
|
|
35
|
+
rotation: THREE.Vector3;
|
|
36
|
+
scale: THREE.Vector3;
|
|
37
|
+
velocity: THREE.Vector3;
|
|
38
|
+
angularVelocity: THREE.Vector3;
|
|
39
|
+
scalarVelocity: THREE.Vector3;
|
|
40
|
+
acceleration: THREE.Vector3;
|
|
41
|
+
angularAcceleration: THREE.Vector3;
|
|
42
|
+
scalarAcceleration: THREE.Vector3;
|
|
43
|
+
speed: number;
|
|
44
|
+
color: THREE.Color;
|
|
45
|
+
alpha: number;
|
|
46
|
+
mass: number;
|
|
47
|
+
startTime: number;
|
|
48
|
+
lifetime: number;
|
|
49
|
+
time: number;
|
|
50
|
+
realtime: number;
|
|
51
|
+
id: string;
|
|
52
|
+
start: ParticleStartValues;
|
|
53
|
+
noise: Record<string, ParticleNoiseValues>;
|
|
54
|
+
tags?: Tag[];
|
|
55
|
+
data: any;
|
|
56
|
+
constructor(options?: Partial<ParticleOptions>);
|
|
57
|
+
cacheStartValues(): void;
|
|
58
|
+
private createStartValues;
|
|
59
|
+
}
|
|
60
|
+
export default Particle;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
class Particle {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6
|
+
this.velocity = new THREE.Vector3(0, 0, 0);
|
|
7
|
+
this.angularVelocity = new THREE.Vector3(0, 0, 0);
|
|
8
|
+
this.scalarVelocity = new THREE.Vector3(0, 0, 0);
|
|
9
|
+
this.acceleration = new THREE.Vector3(0, 0, 0);
|
|
10
|
+
this.angularAcceleration = new THREE.Vector3(0, 0, 0);
|
|
11
|
+
this.scalarAcceleration = new THREE.Vector3(0, 0, 0);
|
|
12
|
+
this.speed = 1;
|
|
13
|
+
this.mass = 0;
|
|
14
|
+
this.position = (_a = options.position) !== null && _a !== void 0 ? _a : new THREE.Vector3();
|
|
15
|
+
this.rotation = (_b = options.rotation) !== null && _b !== void 0 ? _b : new THREE.Vector3();
|
|
16
|
+
this.scale = (_c = options.scale) !== null && _c !== void 0 ? _c : new THREE.Vector3(1, 1, 1);
|
|
17
|
+
this.color = (_d = options.color) !== null && _d !== void 0 ? _d : new THREE.Color(0xffffff);
|
|
18
|
+
this.alpha = (_e = options.alpha) !== null && _e !== void 0 ? _e : 1;
|
|
19
|
+
this.mass = (_f = options.mass) !== null && _f !== void 0 ? _f : 0;
|
|
20
|
+
this.lifetime = (_g = options.lifetime) !== null && _g !== void 0 ? _g : 5;
|
|
21
|
+
this.startTime = Date.now();
|
|
22
|
+
this.time = 0;
|
|
23
|
+
this.realtime = 0;
|
|
24
|
+
this.id = nanoid();
|
|
25
|
+
this.tags = options.tags;
|
|
26
|
+
this.start = this.createStartValues();
|
|
27
|
+
this.noise = {};
|
|
28
|
+
this.data = {};
|
|
29
|
+
}
|
|
30
|
+
cacheStartValues() {
|
|
31
|
+
this.start = this.createStartValues();
|
|
32
|
+
}
|
|
33
|
+
createStartValues() {
|
|
34
|
+
return {
|
|
35
|
+
lifetime: this.lifetime,
|
|
36
|
+
position: this.position.clone(),
|
|
37
|
+
rotation: this.rotation.clone(),
|
|
38
|
+
scale: this.scale.clone(),
|
|
39
|
+
velocity: this.velocity.clone(),
|
|
40
|
+
angularVelocity: this.angularVelocity.clone(),
|
|
41
|
+
scalarVelocity: this.scalarVelocity.clone(),
|
|
42
|
+
acceleration: this.acceleration.clone(),
|
|
43
|
+
angularAcceleration: this.angularAcceleration.clone(),
|
|
44
|
+
scalarAcceleration: this.scalarAcceleration.clone(),
|
|
45
|
+
speed: this.speed,
|
|
46
|
+
mass: this.mass,
|
|
47
|
+
color: this.color.clone(),
|
|
48
|
+
alpha: this.alpha,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export default Particle;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import Particle from './Particle';
|
|
3
|
+
import { IParticleForceField } from './interfaces/IParticleForceField';
|
|
4
|
+
import { DynamicValue } from './types/DynamicValue';
|
|
5
|
+
import { StrictMultiple } from './types/Multiple';
|
|
6
|
+
import { Tag } from './types/Tag';
|
|
7
|
+
export interface ForceFieldOptions {
|
|
8
|
+
position: THREE.Vector3;
|
|
9
|
+
direction: DynamicValue<THREE.Vector3>;
|
|
10
|
+
gravity: DynamicValue<number>;
|
|
11
|
+
rotationSpeed: DynamicValue<number>;
|
|
12
|
+
rotationAttraction: DynamicValue<number>;
|
|
13
|
+
drag: DynamicValue<number>;
|
|
14
|
+
scale: THREE.Vector3;
|
|
15
|
+
geometry: THREE.BufferGeometry;
|
|
16
|
+
tags: StrictMultiple<Tag>;
|
|
17
|
+
}
|
|
18
|
+
declare class ParticleForceField extends THREE.Object3D implements IParticleForceField {
|
|
19
|
+
private static readonly _doubleSidedMaterial;
|
|
20
|
+
static Box(options?: Partial<ForceFieldOptions>, ...args: any[]): ParticleForceField;
|
|
21
|
+
static Sphere(options?: Partial<ForceFieldOptions>, ...args: any[]): ParticleForceField;
|
|
22
|
+
static Cone(options?: Partial<ForceFieldOptions>, ...args: any[]): ParticleForceField;
|
|
23
|
+
static Torus(options?: Partial<ForceFieldOptions>, ...args: any[]): ParticleForceField;
|
|
24
|
+
direction?: DynamicValue<THREE.Vector3>;
|
|
25
|
+
gravity?: DynamicValue<number>;
|
|
26
|
+
rotationSpeed?: DynamicValue<number>;
|
|
27
|
+
rotationAttraction?: DynamicValue<number>;
|
|
28
|
+
drag?: DynamicValue<number>;
|
|
29
|
+
tags?: Tag[];
|
|
30
|
+
private _geometry;
|
|
31
|
+
set geometry(value: THREE.BufferGeometry);
|
|
32
|
+
get geometry(): THREE.BufferGeometry;
|
|
33
|
+
private _mesh;
|
|
34
|
+
constructor(options: Partial<ForceFieldOptions>);
|
|
35
|
+
getForce(particle: Particle): THREE.Vector3;
|
|
36
|
+
private contains;
|
|
37
|
+
private getFalloff;
|
|
38
|
+
}
|
|
39
|
+
export default ParticleForceField;
|