@needle-tools/engine 2.42.0-pre → 2.43.0-pre
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/CHANGELOG.md +13 -0
- package/dist/needle-engine.d.ts +130 -40
- package/dist/needle-engine.js +3836 -422
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +40 -40
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine_element_loading.js +22 -6
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_three_utils.d.ts +1 -0
- package/lib/engine/engine_three_utils.js +10 -0
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/engine_time.js +2 -0
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js +42 -0
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
- package/lib/engine-components/Animation.js +9 -1
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +4 -1
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +3 -0
- package/lib/engine-components/Camera.js +17 -9
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/ParticleSystem.d.ts +21 -7
- package/lib/engine-components/ParticleSystem.js +519 -246
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/ParticleSystemBehaviours.d.ts +0 -0
- package/lib/engine-components/ParticleSystemBehaviours.js +2 -0
- package/lib/engine-components/ParticleSystemBehaviours.js.map +1 -0
- package/lib/engine-components/ParticleSystemModules.d.ts +83 -16
- package/lib/engine-components/ParticleSystemModules.js +284 -49
- package/lib/engine-components/ParticleSystemModules.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +4 -0
- package/lib/engine-components/codegen/components.js +4 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/js-extensions/RGBAColor.d.ts +1 -0
- package/lib/engine-components/js-extensions/RGBAColor.js +7 -0
- package/lib/engine-components/js-extensions/RGBAColor.js.map +1 -1
- package/package.json +2 -1
- package/src/engine/codegen/register_types.js +16 -0
- package/src/engine/engine_element_loading.ts +22 -5
- package/src/engine/engine_three_utils.ts +11 -2
- package/src/engine/engine_time.ts +1 -0
- package/src/engine/extensions/NEEDLE_techniques_webgl.ts +43 -1
- package/src/engine-components/Animation.ts +7 -1
- package/src/engine-components/AnimatorController.ts +5 -1
- package/src/engine-components/Camera.ts +17 -10
- package/src/engine-components/ParticleSystem.ts +600 -274
- package/src/engine-components/ParticleSystemBehaviours.ts +0 -0
- package/src/engine-components/ParticleSystemModules.ts +263 -51
- package/src/engine-components/codegen/components.ts +4 -0
- package/src/engine-components/js-extensions/RGBAColor.ts +7 -0
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { Behaviour, GameObject } from "./Component";
|
|
2
2
|
import * as THREE from "three";
|
|
3
|
-
import { MainModule, EmissionModule, ShapeModule, ParticleSystemShapeType, MinMaxCurve, MinMaxGradient, ColorOverLifetimeModule, SizeOverLifetimeModule, NoiseModule, ParticleSystemSimulationSpace, ParticleBurst, IParticleSystem, ParticleSystemRenderMode } from "./ParticleSystemModules"
|
|
3
|
+
import { MainModule, EmissionModule, ShapeModule, ParticleSystemShapeType, MinMaxCurve, MinMaxGradient, ColorOverLifetimeModule, SizeOverLifetimeModule, NoiseModule, ParticleSystemSimulationSpace, ParticleBurst, IParticleSystem, ParticleSystemRenderMode, TrailModule, VelocityOverLifetimeModule, TextureSheetAnimationModule, RotationOverLifetimeModule } from "./ParticleSystemModules"
|
|
4
4
|
import { getParam } from "../engine/engine_utils";
|
|
5
5
|
|
|
6
6
|
// https://github.dev/creativelifeform/three-nebula
|
|
7
|
-
import System, { Emitter, Position, Life, SpriteRenderer, Particle, Body, MeshRenderer, } from 'three-nebula';
|
|
7
|
+
// import System, { Emitter, Position, Life, SpriteRenderer, Particle, Body, MeshRenderer, } from 'three-nebula';
|
|
8
8
|
|
|
9
9
|
import { serializeable } from "../engine/engine_serialization";
|
|
10
|
-
import { Time } from "../engine/engine_time";
|
|
11
|
-
import { Context } from "../engine/engine_setup";
|
|
12
10
|
import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
13
|
-
import { AxesHelper, BufferGeometry, Material, Mesh, Object3D, Sprite, SpriteMaterial, Vector3 } from "three";
|
|
14
|
-
import { getWorldQuaternion, getWorldScale } from "../engine/engine_three_utils";
|
|
11
|
+
import { AxesHelper, BufferGeometry, Color, Material, Mesh, MeshStandardMaterial, Object3D, OneMinusDstAlphaFactor, Quaternion, Sprite, SpriteMaterial, Vector3, Vector4 } from "three";
|
|
12
|
+
import { getWorldPosition, getWorldQuaternion, getWorldScale } from "../engine/engine_three_utils";
|
|
15
13
|
import { assign } from "../engine/engine_serialization_core";
|
|
14
|
+
import { BatchedParticleRenderer, Behavior, BillBoardSettings, BurstParameters, ColorGenerator, ConstantColor, ConstantValue, EmitterShape, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, MeshSettings, Particle, ParticleEmitter, ParticleSystem as _ParticleSystem, ParticleSystemParameters, PointEmitter, RenderMode, RotationGenerator, SizeOverLife, TrailBatch, TrailSettings, ValueGenerator } from "three.quarks";
|
|
15
|
+
import { createFlatTexture } from "../engine/engine_shaders";
|
|
16
|
+
import { Mathf } from "../engine/engine_math";
|
|
16
17
|
|
|
17
18
|
const debug = getParam("debugparticles");
|
|
18
19
|
|
|
@@ -28,6 +29,11 @@ export class ParticleSystemRenderer extends Behaviour {
|
|
|
28
29
|
// @serializeable(Mesh)
|
|
29
30
|
particleMesh?: Mesh | string;
|
|
30
31
|
|
|
32
|
+
get transparent(): boolean {
|
|
33
|
+
const res = this.particleMaterial?.transparent ?? false;
|
|
34
|
+
// console.log(res, this.particleMaterial);
|
|
35
|
+
return res;
|
|
36
|
+
}
|
|
31
37
|
|
|
32
38
|
getMesh() {
|
|
33
39
|
let geo: BufferGeometry | null = null;
|
|
@@ -40,6 +46,335 @@ export class ParticleSystemRenderer extends Behaviour {
|
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
48
|
|
|
49
|
+
class MinMaxCurveFunction implements FunctionValueGenerator {
|
|
50
|
+
|
|
51
|
+
private _curve: MinMaxCurve;
|
|
52
|
+
|
|
53
|
+
constructor(curve: MinMaxCurve) { this._curve = curve; }
|
|
54
|
+
|
|
55
|
+
type: "function" = "function";
|
|
56
|
+
|
|
57
|
+
genValue(t: number): number {
|
|
58
|
+
return this._curve.evaluate(t, Math.random());
|
|
59
|
+
}
|
|
60
|
+
toJSON(): FunctionJSON {
|
|
61
|
+
throw new Error("Method not implemented.");
|
|
62
|
+
}
|
|
63
|
+
clone(): FunctionValueGenerator {
|
|
64
|
+
throw new Error("Method not implemented.");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class MinMaxGradientFunction implements FunctionColorGenerator {
|
|
69
|
+
|
|
70
|
+
private _curve: MinMaxGradient;
|
|
71
|
+
|
|
72
|
+
constructor(curve: MinMaxGradient) { this._curve = curve; }
|
|
73
|
+
|
|
74
|
+
type: "function" = "function";
|
|
75
|
+
|
|
76
|
+
genColor(color: THREE.Vector4, t: number): THREE.Vector4 {
|
|
77
|
+
const col = this._curve.evaluate(t, Math.random());
|
|
78
|
+
// TODO: incoming color should probably be blended?
|
|
79
|
+
color.set(col.r, col.g, col.b, col.alpha);
|
|
80
|
+
return color;
|
|
81
|
+
}
|
|
82
|
+
toJSON(): FunctionJSON {
|
|
83
|
+
throw new Error("Method not implemented.");
|
|
84
|
+
}
|
|
85
|
+
clone(): FunctionColorGenerator {
|
|
86
|
+
throw new Error("Method not implemented.");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
abstract class BaseValueGenerator implements ValueGenerator {
|
|
92
|
+
|
|
93
|
+
type: "value" = "value";
|
|
94
|
+
toJSON(): FunctionJSON {
|
|
95
|
+
throw new Error("Method not implemented.");
|
|
96
|
+
}
|
|
97
|
+
clone(): ValueGenerator {
|
|
98
|
+
throw new Error("Method not implemented.");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
abstract genValue(): number;
|
|
102
|
+
|
|
103
|
+
readonly system: ParticleSystem;
|
|
104
|
+
|
|
105
|
+
constructor(system: ParticleSystem) {
|
|
106
|
+
this.system = system;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
class TextureSheetStartFrameGenerator extends BaseValueGenerator {
|
|
111
|
+
genValue(): number {
|
|
112
|
+
return this.system.textureSheetAnimation.getStartIndex();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class ParticleSystemEmissionOverTime extends BaseValueGenerator {
|
|
118
|
+
|
|
119
|
+
private _lastPosition: Vector3 = new Vector3();
|
|
120
|
+
private _lastDistance: number = 0;
|
|
121
|
+
|
|
122
|
+
update() {
|
|
123
|
+
const currentPosition = getWorldPosition(this.system.gameObject);
|
|
124
|
+
this._lastDistance = this._lastPosition.distanceTo(currentPosition)
|
|
125
|
+
this._lastPosition.copy(currentPosition);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
genValue(): number {
|
|
129
|
+
if (this.system.currentParticles >= this.system.maxParticles) return 0;
|
|
130
|
+
// emission over time
|
|
131
|
+
let emission = this.system.emission.rateOverTime.evaluate(this.system.time / this.system.duration, Math.random());
|
|
132
|
+
// if(this.system.currentParticles + emission > this.system.maxParticles)
|
|
133
|
+
// emission = (this.system.maxParticles - this.system.currentParticles);
|
|
134
|
+
// const res = Mathf.clamp(emission, 0, this.system.maxParticles - this.system.currentParticles);
|
|
135
|
+
|
|
136
|
+
if (this.system.deltaTime > 0) {
|
|
137
|
+
const distanceEmission = this.system.emission.rateOverDistance.evaluate(this.system.time / this.system.duration, Math.random());
|
|
138
|
+
const meterPerSecond = this._lastDistance / this.system.deltaTime;
|
|
139
|
+
let distanceEmissionValue = meterPerSecond * distanceEmission;
|
|
140
|
+
if (!Number.isFinite(distanceEmissionValue)) distanceEmissionValue = 0;
|
|
141
|
+
emission += distanceEmissionValue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const burst = this.system.emission.getBurst();
|
|
145
|
+
if (burst > 0)
|
|
146
|
+
emission += burst / this.system.deltaTime;
|
|
147
|
+
|
|
148
|
+
const maxEmission = (this.system.maxParticles - this.system.currentParticles);
|
|
149
|
+
return Mathf.clamp(emission, 0, maxEmission / this.system.deltaTime);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
class ParticleSystemEmissionOverDistance extends BaseValueGenerator {
|
|
154
|
+
|
|
155
|
+
genValue(): number {
|
|
156
|
+
// this seems not be called yet
|
|
157
|
+
return 0;
|
|
158
|
+
// if (this.system.currentParticles >= this.system.maxParticles) return 0;
|
|
159
|
+
// const emission = this.system.emission.rateOverDistance.evaluate(this.system.time / this.system.duration, Math.random());
|
|
160
|
+
// return emission;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
abstract class ParticleSystemBaseBehaviour implements Behavior {
|
|
165
|
+
readonly system: ParticleSystem;
|
|
166
|
+
|
|
167
|
+
constructor(ps: ParticleSystem) {
|
|
168
|
+
this.system = ps;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
abstract type: string;
|
|
172
|
+
|
|
173
|
+
initialize(_particle: Particle): void {
|
|
174
|
+
}
|
|
175
|
+
update(_particle: Particle, _delta: number): void {
|
|
176
|
+
}
|
|
177
|
+
frameUpdate(_delta: number): void {
|
|
178
|
+
}
|
|
179
|
+
toJSON() { throw new Error("Method not implemented."); }
|
|
180
|
+
clone(): Behavior { throw new Error("Method not implemented."); }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
class TextureSheetAnimationBehaviour extends ParticleSystemBaseBehaviour {
|
|
184
|
+
type: string = "NeedleTextureSheet"
|
|
185
|
+
|
|
186
|
+
update(particle: Particle, _delta: number) {
|
|
187
|
+
const sheet = this.system.textureSheetAnimation;
|
|
188
|
+
if (sheet.enabled) {
|
|
189
|
+
const t01 = particle.age / particle.life;
|
|
190
|
+
const index = sheet.evaluate(t01);;
|
|
191
|
+
if (index !== undefined)
|
|
192
|
+
particle.uvTile = index;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
class RotationBehaviour extends ParticleSystemBaseBehaviour {
|
|
199
|
+
type: string = "NeedleRotation"
|
|
200
|
+
|
|
201
|
+
update(particle: Particle, delta: number) {
|
|
202
|
+
if (particle.rotation === undefined) return;
|
|
203
|
+
if (particle.rotation instanceof Quaternion) {
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
if (this.system.rotationOverLifetime.enabled) {
|
|
208
|
+
particle.rotation += this.system.rotationOverLifetime.evaluate(particle.age / particle.life) * delta;
|
|
209
|
+
}
|
|
210
|
+
// HACK flip y
|
|
211
|
+
else particle.rotation = Math.PI;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
class SizeBehaviour extends ParticleSystemBaseBehaviour {
|
|
217
|
+
|
|
218
|
+
type: string = "NeedleSize";
|
|
219
|
+
|
|
220
|
+
update(particle: Particle, _delta: number): void {
|
|
221
|
+
const t = particle.age / particle.life;
|
|
222
|
+
let size = 1;
|
|
223
|
+
if (this.system.sizeOverLifetime.enabled)
|
|
224
|
+
size *= this.system.sizeOverLifetime.evaluate(t).x;
|
|
225
|
+
const scaleFactor = this.system.scale / this.system.cameraScale;
|
|
226
|
+
particle.size = particle.startSize * size * scaleFactor;
|
|
227
|
+
// console.log(particle.startSize, size, this.system.scale, this.system.cameraScale);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const $startVelocity = Symbol("startVelocity");
|
|
232
|
+
const $gravityFactor = Symbol("gravityModifier");
|
|
233
|
+
const temp3 = new Vector3();
|
|
234
|
+
const temp4 = new Quaternion();
|
|
235
|
+
|
|
236
|
+
class VelocityBehaviour extends ParticleSystemBaseBehaviour {
|
|
237
|
+
type: string = "NeedleVelocity";
|
|
238
|
+
|
|
239
|
+
private _gravityDirection = new Vector3();
|
|
240
|
+
|
|
241
|
+
initialize(particle: Particle): void {
|
|
242
|
+
const scale = this.system.scale;
|
|
243
|
+
particle.startSpeed = this.system.main.startSpeed.evaluate(Math.random(), Math.random());
|
|
244
|
+
particle.velocity.copy(this.system.shape.getDirection(particle.position)).multiplyScalar(particle.startSpeed);
|
|
245
|
+
if (!particle[$startVelocity]) particle[$startVelocity] = particle.velocity.clone();
|
|
246
|
+
else particle[$startVelocity].copy(particle.velocity);
|
|
247
|
+
|
|
248
|
+
let gravityFactor = Math.PI / scale;
|
|
249
|
+
gravityFactor = this.system.main.gravityModifier.evaluate(Math.random(), Math.random()) * gravityFactor;
|
|
250
|
+
particle[$gravityFactor] = gravityFactor;
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
this._gravityDirection.set(0, -1, 0).applyQuaternion(this.system.worldQuaternionInverted);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
update(particle: Particle, delta: number): void {
|
|
257
|
+
// const t = particle.age / particle.life;
|
|
258
|
+
// console.log(this.system.deltaTime, delta);
|
|
259
|
+
|
|
260
|
+
const baseVelocity = particle[$startVelocity];
|
|
261
|
+
let gravityFactor = particle[$gravityFactor];
|
|
262
|
+
if (gravityFactor !== 0) {
|
|
263
|
+
// gravityFactor *= -1;
|
|
264
|
+
temp3.copy(this._gravityDirection).multiplyScalar(gravityFactor * delta * Math.PI);
|
|
265
|
+
// Gizmos.DrawDirection(particle.position, temp3, 0xff0000, 0, false, 10);
|
|
266
|
+
baseVelocity.add(temp3);
|
|
267
|
+
}
|
|
268
|
+
particle.velocity.copy(baseVelocity);
|
|
269
|
+
|
|
270
|
+
const noise = this.system.noise;
|
|
271
|
+
if (noise.enabled) {
|
|
272
|
+
noise.apply(0, particle.position, particle.velocity, delta, particle.age, particle.life);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const velocity = this.system.velocityOverLifetime;
|
|
276
|
+
if (velocity.enabled) {
|
|
277
|
+
velocity.apply(0, particle.position, particle.velocity, delta, particle.age, particle.life);
|
|
278
|
+
}
|
|
279
|
+
// particle.velocity.multiplyScalar(1-delta);
|
|
280
|
+
|
|
281
|
+
// const vel = this.system.velocityOverLifetime.evaluate(particle.age / particle.life);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
class ColorBehaviour extends ParticleSystemBaseBehaviour {
|
|
286
|
+
type: string = "NeedleColor";
|
|
287
|
+
|
|
288
|
+
initialize(particle: Particle): void {
|
|
289
|
+
const col = this.system.main.startColor.evaluate(particle.age / particle.life, Math.random());
|
|
290
|
+
particle.startColor.set(col.r, col.g, col.b, col.alpha);
|
|
291
|
+
particle.color.copy(particle.startColor);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
update(particle: Particle, _delta: number): void {
|
|
295
|
+
if (this.system.colorOverLifetime.enabled) {
|
|
296
|
+
const t = particle.age / particle.life;
|
|
297
|
+
const col = this.system.colorOverLifetime.color.evaluate(t);
|
|
298
|
+
particle.color.set(col.r, col.g, col.b, col.alpha).multiply(particle.startColor);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
class ParticleSystemInterface implements ParticleSystemParameters {
|
|
304
|
+
|
|
305
|
+
private readonly system: ParticleSystem;
|
|
306
|
+
private readonly emission: ParticleSystemEmissionOverTime;
|
|
307
|
+
private get anim(): TextureSheetAnimationModule {
|
|
308
|
+
return this.system.textureSheetAnimation;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
constructor(system: ParticleSystem) {
|
|
312
|
+
this.system = system;
|
|
313
|
+
this.emission = new ParticleSystemEmissionOverTime(this.system);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
update() {
|
|
317
|
+
this.emission.update();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
autoDestroy?: boolean | undefined;
|
|
321
|
+
get looping() { return this.system.main.loop; }
|
|
322
|
+
get duration() { return this.system.duration; }
|
|
323
|
+
get shape(): EmitterShape { return this.system.shape; }
|
|
324
|
+
get startLife() { return new MinMaxCurveFunction(this.system.main.startLifetime); }
|
|
325
|
+
get startSpeed() { return new MinMaxCurveFunction(this.system.main.startSpeed); }
|
|
326
|
+
get startRotation() { return new MinMaxCurveFunction(this.system.main.startRotation); }
|
|
327
|
+
get startSize() { return new MinMaxCurveFunction(this.system.main.startSize); }
|
|
328
|
+
startLength?: ValueGenerator | FunctionValueGenerator | undefined; /** start length is for trails */
|
|
329
|
+
get startColor() { return new ConstantColor(new Vector4(1, 1, 1, 1)); }
|
|
330
|
+
get emissionOverTime() { return this.emission; }
|
|
331
|
+
/** this is not supported yet */
|
|
332
|
+
get emissionOverDistance() { return new ParticleSystemEmissionOverDistance(this.system); }
|
|
333
|
+
/** not used - burst is controled via emissionOverTime */
|
|
334
|
+
emissionBursts?: BurstParameters[] | undefined;
|
|
335
|
+
onlyUsedByOther?: boolean | undefined;
|
|
336
|
+
readonly behaviors: Behavior[] = [];
|
|
337
|
+
get instancingGeometry() {
|
|
338
|
+
return this.system.renderer.getMesh().geometry;
|
|
339
|
+
}
|
|
340
|
+
get renderMode() {
|
|
341
|
+
if (this.system.trails["enabled"] === true) {
|
|
342
|
+
return RenderMode.Trail;
|
|
343
|
+
}
|
|
344
|
+
switch (this.system.renderer.renderMode) {
|
|
345
|
+
case ParticleSystemRenderMode.Billboard: return RenderMode.BillBoard;
|
|
346
|
+
// case ParticleSystemRenderMode.Stretch: return RenderMode.Stretch;
|
|
347
|
+
// case ParticleSystemRenderMode.HorizontalBillboard: return RenderMode.HorizontalBillboard;
|
|
348
|
+
// case ParticleSystemRenderMode.VerticalBillboard: return RenderMode.VerticalBillboard;
|
|
349
|
+
case ParticleSystemRenderMode.Mesh: return RenderMode.LocalSpace;
|
|
350
|
+
}
|
|
351
|
+
return RenderMode.BillBoard;
|
|
352
|
+
}
|
|
353
|
+
rendererEmitterSettings: TrailSettings = {
|
|
354
|
+
startLength: new ConstantValue(220),
|
|
355
|
+
followLocalOrigin: false,
|
|
356
|
+
};
|
|
357
|
+
get speedFactor() { return this.system.main.simulationSpeed; }
|
|
358
|
+
get texture(): THREE.Texture {
|
|
359
|
+
const mat = this.system.renderer.particleMaterial;
|
|
360
|
+
if (mat && mat["map"]) {
|
|
361
|
+
const tex = mat["map"]!;
|
|
362
|
+
tex.premultiplyAlpha = false;
|
|
363
|
+
tex.encoding = THREE.LinearEncoding;
|
|
364
|
+
return tex;
|
|
365
|
+
}
|
|
366
|
+
return createFlatTexture(new RGBAColor(1, 1, 1, 1), 1)
|
|
367
|
+
}
|
|
368
|
+
get startTileIndex() { return new TextureSheetStartFrameGenerator(this.system); }
|
|
369
|
+
get uTileCount() { return this.anim.enabled ? this.anim?.numTilesX : undefined }
|
|
370
|
+
get vTileCount() { return this.anim.enabled ? this.anim?.numTilesY : undefined }
|
|
371
|
+
get renderOrder() { return 1; }
|
|
372
|
+
get blending(): THREE.Blending { return this.system.renderer.particleMaterial?.blending ?? THREE.NormalBlending; }
|
|
373
|
+
get transparent() { return this.system.renderer.transparent; }
|
|
374
|
+
get worldSpace() { return this.system.main.simulationSpace === ParticleSystemSimulationSpace.World; }
|
|
375
|
+
|
|
376
|
+
}
|
|
377
|
+
|
|
43
378
|
export class ParticleSystem extends Behaviour implements IParticleSystem {
|
|
44
379
|
|
|
45
380
|
@serializeable(ColorOverLifetimeModule)
|
|
@@ -60,12 +395,24 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
|
|
|
60
395
|
@serializeable(NoiseModule)
|
|
61
396
|
readonly noise!: NoiseModule;
|
|
62
397
|
|
|
398
|
+
// @serializeable(TrailModule)
|
|
399
|
+
readonly trails!: TrailModule;
|
|
400
|
+
|
|
401
|
+
@serializeable(VelocityOverLifetimeModule)
|
|
402
|
+
readonly velocityOverLifetime!: VelocityOverLifetimeModule;
|
|
403
|
+
|
|
404
|
+
@serializeable(TextureSheetAnimationModule)
|
|
405
|
+
readonly textureSheetAnimation!: TextureSheetAnimationModule;
|
|
406
|
+
|
|
407
|
+
@serializeable(RotationOverLifetimeModule)
|
|
408
|
+
readonly rotationOverLifetime!: RotationOverLifetimeModule;
|
|
409
|
+
|
|
63
410
|
get renderer(): ParticleSystemRenderer {
|
|
64
411
|
return this._renderer;
|
|
65
412
|
}
|
|
66
413
|
|
|
67
414
|
get currentParticles() {
|
|
68
|
-
return this.
|
|
415
|
+
return this._particleSystem?.particleNum ?? 0;
|
|
69
416
|
}
|
|
70
417
|
get maxParticles() {
|
|
71
418
|
return this.main.maxParticles;
|
|
@@ -76,12 +423,40 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
|
|
|
76
423
|
get duration() {
|
|
77
424
|
return this.main.duration;
|
|
78
425
|
}
|
|
426
|
+
get deltaTime() {
|
|
427
|
+
return this.context.time.deltaTime * this.main.simulationSpeed;
|
|
428
|
+
}
|
|
429
|
+
get scale() {
|
|
430
|
+
return this.gameObject.scale.x;
|
|
431
|
+
}
|
|
432
|
+
get cameraScale(): number {
|
|
433
|
+
return this._cameraScale;
|
|
434
|
+
}
|
|
435
|
+
private _cameraScale: number = 1;
|
|
436
|
+
|
|
437
|
+
get container(): Object3D {
|
|
438
|
+
return this._container!;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
private __worldQuaternion = new Quaternion();
|
|
442
|
+
get worldQuaternion(): Quaternion {
|
|
443
|
+
return this.__worldQuaternion;
|
|
444
|
+
}
|
|
445
|
+
private _worldQuaternionInverted = new Quaternion();
|
|
446
|
+
get worldQuaternionInverted(): Quaternion {
|
|
447
|
+
return this._worldQuaternionInverted;
|
|
448
|
+
}
|
|
79
449
|
|
|
80
450
|
private _renderer!: ParticleSystemRenderer;
|
|
81
|
-
|
|
82
|
-
private
|
|
83
|
-
private
|
|
84
|
-
private
|
|
451
|
+
|
|
452
|
+
private _batchSystem?: BatchedParticleRenderer;
|
|
453
|
+
private _particleSystem?: _ParticleSystem;
|
|
454
|
+
private _interface!: ParticleSystemInterface;
|
|
455
|
+
|
|
456
|
+
// private _system!: System;
|
|
457
|
+
// private _emitter: Emitter;
|
|
458
|
+
// private _size!: SizeBehaviour;
|
|
459
|
+
private _container!: Object3D;
|
|
85
460
|
private _time: number = 0;
|
|
86
461
|
|
|
87
462
|
/** called from deserialization */
|
|
@@ -100,107 +475,66 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
|
|
|
100
475
|
|
|
101
476
|
awake(): void {
|
|
102
477
|
this._renderer = this.gameObject.getComponent(ParticleSystemRenderer) as ParticleSystemRenderer;
|
|
103
|
-
this._system = new System();
|
|
104
478
|
|
|
479
|
+
|
|
480
|
+
this._container = new Object3D();
|
|
481
|
+
this._container.matrixAutoUpdate = false;
|
|
105
482
|
if (this.main.simulationSpace == ParticleSystemSimulationSpace.Local) {
|
|
106
|
-
this._container = new Object3D();
|
|
107
|
-
this._container.matrixAutoUpdate = false;
|
|
108
483
|
this.gameObject.add(this._container);
|
|
109
484
|
}
|
|
110
|
-
|
|
111
|
-
|
|
485
|
+
else {
|
|
486
|
+
this.context.scene.add(this._container);
|
|
487
|
+
}
|
|
488
|
+
// else this._container = this.context.scene;
|
|
489
|
+
|
|
490
|
+
this._batchSystem = new BatchedParticleRenderer();
|
|
491
|
+
this._container.add(this._batchSystem);
|
|
492
|
+
this._interface = new ParticleSystemInterface(this);
|
|
493
|
+
this._particleSystem = new _ParticleSystem(this._batchSystem, this._interface);
|
|
494
|
+
this._particleSystem.addBehavior(new SizeBehaviour(this));
|
|
495
|
+
this._particleSystem.addBehavior(new VelocityBehaviour(this));
|
|
496
|
+
this._particleSystem.addBehavior(new ColorBehaviour(this));
|
|
497
|
+
this._particleSystem.addBehavior(new TextureSheetAnimationBehaviour(this));
|
|
498
|
+
this._particleSystem.addBehavior(new RotationBehaviour(this));
|
|
499
|
+
const emitter = this._particleSystem.emitter;
|
|
500
|
+
this.context.scene.add(emitter);
|
|
112
501
|
|
|
113
502
|
if (debug) {
|
|
114
503
|
console.log(this);
|
|
115
|
-
this.
|
|
116
|
-
}
|
|
117
|
-
const renderMode = this._renderer.renderMode;
|
|
118
|
-
let renderer: any = undefined;
|
|
119
|
-
|
|
120
|
-
switch (renderMode) {
|
|
121
|
-
case ParticleSystemRenderMode.Mesh:
|
|
122
|
-
// https://three-nebula-docs.netlify.app/class/src/renderer/meshrenderer.js~meshrenderer
|
|
123
|
-
// mesh renderer example: https://github.com/creativelifeform/three-nebula/blob/master/website/components/Examples/MeshRenderer/init.js
|
|
124
|
-
renderer = new MeshRenderer(container, THREE);
|
|
125
|
-
break;
|
|
126
|
-
case ParticleSystemRenderMode.Billboard:
|
|
127
|
-
renderer = new SpriteRenderer(container, THREE);
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (!renderer) {
|
|
132
|
-
console.error("No renderer for particle system");
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
renderer.logRendererType = () => { };
|
|
137
|
-
if (renderMode === ParticleSystemRenderMode.Billboard) {
|
|
138
|
-
if (this.renderer.particleMaterial) {
|
|
139
|
-
const sprite = renderer._body as Sprite;
|
|
140
|
-
sprite.layers.disableAll();
|
|
141
|
-
sprite.layers.set(2); // ignore raycasting particles
|
|
142
|
-
sprite.renderOrder = 1;
|
|
143
|
-
sprite.material.map = this.renderer.particleMaterial.map;
|
|
144
|
-
sprite.material.transparent = true;
|
|
145
|
-
// sprite.material.sizeAttenuation = false;
|
|
146
|
-
sprite.material.blending = this.renderer.particleMaterial.blending;
|
|
147
|
-
sprite.material.blendDst = this.renderer.particleMaterial.blendDst;
|
|
148
|
-
sprite.material.blendDstAlpha = this.renderer.particleMaterial.blendDstAlpha;
|
|
149
|
-
sprite.material.blendEquation = this.renderer.particleMaterial.blendEquation;
|
|
150
|
-
sprite.material.blendEquationAlpha = this.renderer.particleMaterial.blendEquationAlpha;
|
|
151
|
-
sprite.material.blendSrc = this.renderer.particleMaterial.blendSrc;
|
|
152
|
-
sprite.material.blendSrcAlpha = this.renderer.particleMaterial.blendSrcAlpha;
|
|
153
|
-
sprite.material.premultipliedAlpha = this.renderer.particleMaterial.premultipliedAlpha;
|
|
154
|
-
sprite.material.depthWrite = false;
|
|
155
|
-
sprite.material.depthTest = true;
|
|
156
|
-
if (debug) console.log(sprite);
|
|
157
|
-
}
|
|
504
|
+
this.container.add(new AxesHelper(1))
|
|
158
505
|
}
|
|
159
506
|
|
|
160
|
-
|
|
507
|
+
// renderer.logRendererType = () => { };
|
|
508
|
+
// if (renderMode === ParticleSystemRenderMode.Billboard) {
|
|
509
|
+
// if (this.renderer.particleMaterial) {
|
|
510
|
+
// const sprite = renderer._body as Sprite;
|
|
511
|
+
// sprite.layers.disableAll();
|
|
512
|
+
// sprite.layers.set(2); // ignore raycasting particles
|
|
513
|
+
// sprite.renderOrder = 1;
|
|
514
|
+
// sprite.material.map = this.renderer.particleMaterial.map;
|
|
515
|
+
// sprite.material.transparent = true;
|
|
516
|
+
// // sprite.material.sizeAttenuation = false;
|
|
517
|
+
// sprite.material.blending = this.renderer.particleMaterial.blending;
|
|
518
|
+
// sprite.material.blendDst = this.renderer.particleMaterial.blendDst;
|
|
519
|
+
// sprite.material.blendDstAlpha = this.renderer.particleMaterial.blendDstAlpha;
|
|
520
|
+
// sprite.material.blendEquation = this.renderer.particleMaterial.blendEquation;
|
|
521
|
+
// sprite.material.blendEquationAlpha = this.renderer.particleMaterial.blendEquationAlpha;
|
|
522
|
+
// sprite.material.blendSrc = this.renderer.particleMaterial.blendSrc;
|
|
523
|
+
// sprite.material.blendSrcAlpha = this.renderer.particleMaterial.blendSrcAlpha;
|
|
524
|
+
// sprite.material.premultipliedAlpha = this.renderer.particleMaterial.premultipliedAlpha;
|
|
525
|
+
// sprite.material.depthWrite = false;
|
|
526
|
+
// sprite.material.depthTest = true;
|
|
527
|
+
// if (debug) console.log(sprite);
|
|
528
|
+
// }
|
|
529
|
+
// }
|
|
161
530
|
|
|
162
|
-
const initializers: Array<any> = [];
|
|
163
|
-
const behaviours: Array<any> = [];
|
|
164
|
-
|
|
165
|
-
const life = new Life();
|
|
166
|
-
life.lifePan = new MinMaxCurveSpan(this.main.startLifetime, 1);
|
|
167
|
-
initializers.push(life);
|
|
168
|
-
|
|
169
|
-
const shape = new Position(this.shape);
|
|
170
|
-
initializers.push(shape);
|
|
171
|
-
|
|
172
|
-
const size = this._size = new SizeBehaviour(this.main.startSize, this.main.startSizeMultiplier);
|
|
173
|
-
size.sizeOverLifetimeModule = this.sizeOverLifetime;
|
|
174
|
-
behaviours.push(size);
|
|
175
|
-
|
|
176
|
-
const color = new GradientBehaviour(this.main.startColor, this.colorOverLifetime?.enabled ? this.colorOverLifetime.color : undefined);
|
|
177
|
-
behaviours.push(color);
|
|
178
|
-
|
|
179
|
-
const velocity = new VelocityBehaviour(renderer.container, this.shape, this.noise, this.main.startSpeed, 1);
|
|
180
|
-
velocity.gravity = this.main.gravityModifier;
|
|
181
|
-
velocity.gravityModifierMultiplier = this.main.gravityModifierMultiplier;
|
|
182
|
-
behaviours.push(velocity);
|
|
183
|
-
|
|
184
|
-
if (renderMode === ParticleSystemRenderMode.Mesh) {
|
|
185
|
-
initializers.push(new Body(this._renderer.getMesh()))
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const emitter = this._emitter = new Emitter({});
|
|
189
|
-
emitter.setInitializers(initializers);
|
|
190
|
-
emitter.setBehaviours(behaviours);
|
|
191
|
-
emitter.setRate(this.emission);
|
|
192
|
-
emitter.damping = 0;
|
|
193
531
|
}
|
|
194
532
|
|
|
195
533
|
onEnable() {
|
|
196
|
-
this._emitter.emit();
|
|
197
|
-
this._system.addEmitter(this._emitter);
|
|
198
|
-
this._system.emit({ onStart: () => { }, onUpdate: () => { }, onEnd: () => { }, });
|
|
199
534
|
this._time = 0;
|
|
200
535
|
}
|
|
201
536
|
|
|
202
537
|
onDisable() {
|
|
203
|
-
this._system.removeEmitter(this._emitter);
|
|
204
538
|
}
|
|
205
539
|
|
|
206
540
|
onBeforeRender() {
|
|
@@ -212,233 +546,225 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
|
|
|
212
546
|
const cam = this.context.mainCamera;
|
|
213
547
|
if (cam) {
|
|
214
548
|
const scale = getWorldScale(cam);
|
|
215
|
-
this.
|
|
549
|
+
this._cameraScale = scale.x;
|
|
216
550
|
}
|
|
217
551
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
552
|
+
let rotationSource = this._container;
|
|
553
|
+
if (this.main.simulationSpace === ParticleSystemSimulationSpace.World)
|
|
554
|
+
rotationSource = this.gameObject;
|
|
555
|
+
getWorldQuaternion(rotationSource, this.__worldQuaternion)
|
|
556
|
+
this._worldQuaternionInverted.copy(this.__worldQuaternion).invert()
|
|
221
557
|
|
|
558
|
+
if (this._container && this.gameObject?.parent) {
|
|
222
559
|
const scale = getWorldScale(this.gameObject.parent);
|
|
223
560
|
scale.x = 1 / scale.x;
|
|
224
561
|
scale.y = 1 / scale.y;
|
|
225
562
|
scale.z = 1 / scale.z;
|
|
226
|
-
// console.log(scale);
|
|
227
|
-
// this._container.scale.copy(scale);
|
|
228
|
-
// // this._container.updateMatrix();
|
|
229
|
-
// // this._container.updateMatrixWorld();
|
|
230
|
-
// // // set scale to 1
|
|
231
563
|
this._container.matrix.identity();
|
|
232
564
|
this._container.matrix.scale(scale);
|
|
233
|
-
// this._container.matrixWorld.copy(this._container.matrix);
|
|
234
565
|
}
|
|
235
|
-
|
|
236
|
-
// this._system.duration = this.main.duration;
|
|
566
|
+
|
|
237
567
|
this.emission.system = this;
|
|
568
|
+
const dt = this.deltaTime;
|
|
569
|
+
this._interface.update();
|
|
238
570
|
this.shape.update(this.context, this.main.simulationSpace, this.gameObject);
|
|
239
571
|
this.noise.update(this.context);
|
|
240
|
-
this.
|
|
241
|
-
this.
|
|
572
|
+
this.velocityOverLifetime.update(this);
|
|
573
|
+
this._batchSystem?.update(dt);
|
|
574
|
+
this._time += dt;
|
|
242
575
|
if (this._time > this.duration) this._time = 0;
|
|
243
576
|
}
|
|
244
577
|
|
|
245
578
|
}
|
|
246
579
|
|
|
247
580
|
|
|
248
|
-
class MinMaxCurveSpan {
|
|
249
581
|
|
|
250
|
-
readonly time: Time;
|
|
251
|
-
readonly curve: MinMaxCurve;
|
|
252
|
-
multiplier: number = 1;
|
|
253
582
|
|
|
254
|
-
constructor(minMaxCurve: MinMaxCurve, multiplier: number = 1) {
|
|
255
|
-
this.time = Context.Current.time;
|
|
256
|
-
this.curve = minMaxCurve;
|
|
257
|
-
this.multiplier = multiplier;
|
|
258
|
-
}
|
|
259
583
|
|
|
260
|
-
/** called by nebula */
|
|
261
|
-
getValue(lerp?: number) {
|
|
262
|
-
const res = this.curve.evaluate(this.time.time, lerp) * this.multiplier;
|
|
263
|
-
return res;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
584
|
|
|
267
|
-
abstract class CustomBehaviour extends Behaviour {
|
|
268
|
-
abstract applyBehaviour(target: Particle | Emitter, time: number, index: number);
|
|
269
|
-
abstract initialize(particle: Particle);
|
|
270
|
-
}
|
|
271
585
|
|
|
272
|
-
abstract class MinMaxCurveBehaviour extends CustomBehaviour {
|
|
273
586
|
|
|
274
|
-
readonly startCurve: MinMaxCurve;
|
|
275
|
-
startMultiplier: number = 1;
|
|
276
587
|
|
|
277
|
-
constructor(startCurve: MinMaxCurve, startMultiplier: number = 1) {
|
|
278
|
-
super();
|
|
279
|
-
this.startCurve = startCurve;
|
|
280
|
-
this.startMultiplier = startMultiplier;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
588
|
|
|
284
|
-
declare type ParticleWithScale = Particle & { target: Object3D, start_scale: number };
|
|
285
589
|
|
|
286
|
-
class SizeBehaviour extends MinMaxCurveBehaviour {
|
|
287
590
|
|
|
288
|
-
sizeOverLifetimeModule!: SizeOverLifetimeModule;
|
|
289
591
|
|
|
290
|
-
cameraScale: number = 1;
|
|
291
592
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
else particle.radius = 1;
|
|
297
|
-
|
|
298
|
-
// particle.target.scale.set(1,1,1);
|
|
299
|
-
if (this.sizeOverLifetimeModule?.enabled) {
|
|
300
|
-
const time = particle.age / particle.life;
|
|
301
|
-
const scaleVector = particle.target.scale;
|
|
302
|
-
this.sizeOverLifetimeModule.evaluate?.call(this.sizeOverLifetimeModule, time, scaleVector);
|
|
303
|
-
// scaleVector.set(.1, .1, .1)
|
|
304
|
-
particle.scale = particle.start_scale * scaleVector.x;
|
|
305
|
-
// console.log(time, particle.scale);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
initialize(particle: ParticleWithScale) {
|
|
309
|
-
particle.scale = this.startCurve.evaluate(0, Math.random());// * this.startMultiplier;
|
|
310
|
-
particle.start_scale = particle.scale;
|
|
593
|
+
// abstract class CustomBehaviour extends Behaviour {
|
|
594
|
+
// abstract applyBehaviour(target: Particle | Emitter, time: number, index: number);
|
|
595
|
+
// abstract initialize(particle: Particle);
|
|
596
|
+
// }
|
|
311
597
|
|
|
312
|
-
|
|
313
|
-
}
|
|
598
|
+
// abstract class MinMaxCurveBehaviour extends CustomBehaviour {
|
|
314
599
|
|
|
315
|
-
|
|
600
|
+
// readonly startCurve: MinMaxCurve;
|
|
601
|
+
// startMultiplier: number = 1;
|
|
316
602
|
|
|
317
|
-
|
|
603
|
+
// constructor(startCurve: MinMaxCurve, startMultiplier: number = 1) {
|
|
604
|
+
// super();
|
|
605
|
+
// this.startCurve = startCurve;
|
|
606
|
+
// this.startMultiplier = startMultiplier;
|
|
607
|
+
// }
|
|
608
|
+
// }
|
|
318
609
|
|
|
319
|
-
|
|
320
|
-
private gradient?: MinMaxGradient;
|
|
610
|
+
// declare type ParticleWithScale = Particle & { target: Object3D, start_scale: number };
|
|
321
611
|
|
|
322
|
-
|
|
323
|
-
super();
|
|
324
|
-
this.startGradient = startGradient;
|
|
325
|
-
this.gradient = gradient;
|
|
326
|
-
}
|
|
612
|
+
// class SizeBehaviour extends MinMaxCurveBehaviour {
|
|
327
613
|
|
|
328
|
-
|
|
329
|
-
applyBehaviour(target: ParticleWithColor | Emitter, _deltaTime: number, _index: number) {
|
|
330
|
-
// console.log(target, time, index)
|
|
331
|
-
if (target instanceof Particle) {
|
|
332
|
-
if (this.gradient) {
|
|
333
|
-
const t = target.age / target.life;
|
|
334
|
-
const ev = this.gradient.evaluate(t) as RGBAColor;
|
|
335
|
-
const startColor = target.color_start;
|
|
336
|
-
target.color.r = startColor.r * ev.r;
|
|
337
|
-
target.color.g = startColor.g * ev.g;
|
|
338
|
-
target.color.b = startColor.b * ev.b;
|
|
339
|
-
target.alpha = ev.alpha * target.alpha_start;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private id = Symbol('gradientId');
|
|
345
|
-
private _internalId: number = 0;
|
|
346
|
-
|
|
347
|
-
/** called from nebula */
|
|
348
|
-
initialize(particle: ParticleWithColor) {
|
|
349
|
-
|
|
350
|
-
// console.log(particle);
|
|
351
|
-
// const context = Context.Current;
|
|
352
|
-
// const time = context.time.time;
|
|
353
|
-
const ev = this.startGradient.evaluate(Math.random()) as RGBAColor;
|
|
354
|
-
particle.color.r = ev.r;
|
|
355
|
-
particle.color.g = ev.g;
|
|
356
|
-
particle.color.b = ev.b;
|
|
357
|
-
particle.alpha = ev.alpha
|
|
614
|
+
// sizeOverLifetimeModule!: SizeOverLifetimeModule;
|
|
358
615
|
|
|
359
|
-
|
|
616
|
+
// cameraScale: number = 1;
|
|
360
617
|
|
|
361
|
-
|
|
362
|
-
|
|
618
|
+
// applyBehaviour(particle: ParticleWithScale, _deltaTime: number, _index: number) {
|
|
619
|
+
// if (particle.target.type === "Sprite") {
|
|
620
|
+
// particle.radius = 1 / this.cameraScale;
|
|
621
|
+
// }
|
|
622
|
+
// else particle.radius = 1;
|
|
363
623
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
624
|
+
// // particle.target.scale.set(1,1,1);
|
|
625
|
+
// if (this.sizeOverLifetimeModule?.enabled) {
|
|
626
|
+
// const time = particle.age / particle.life;
|
|
627
|
+
// const scaleVector = particle.target.scale;
|
|
628
|
+
// this.sizeOverLifetimeModule.evaluate?.call(this.sizeOverLifetimeModule, time, scaleVector);
|
|
629
|
+
// // scaleVector.set(.1, .1, .1)
|
|
630
|
+
// particle.scale = particle.start_scale * scaleVector.x;
|
|
631
|
+
// // console.log(time, particle.scale);
|
|
632
|
+
// }
|
|
633
|
+
// }
|
|
634
|
+
// initialize(particle: ParticleWithScale) {
|
|
635
|
+
// particle.scale = this.startCurve.evaluate(0, Math.random());// * this.startMultiplier;
|
|
636
|
+
// particle.start_scale = particle.scale;
|
|
371
637
|
|
|
638
|
+
// }
|
|
639
|
+
// }
|
|
372
640
|
|
|
373
|
-
declare type
|
|
641
|
+
// declare type ParticleWithColor = Particle & { color_start: { r: number, g: number, b: number }, alpha_start: number };
|
|
374
642
|
|
|
375
|
-
class
|
|
643
|
+
// class GradientBehaviour extends CustomBehaviour {
|
|
376
644
|
|
|
377
|
-
|
|
645
|
+
// private startGradient: MinMaxGradient;
|
|
646
|
+
// private gradient?: MinMaxGradient;
|
|
378
647
|
|
|
379
|
-
|
|
380
|
-
|
|
648
|
+
// constructor(startGradient: MinMaxGradient, gradient?: MinMaxGradient) {
|
|
649
|
+
// super();
|
|
650
|
+
// this.startGradient = startGradient;
|
|
651
|
+
// this.gradient = gradient;
|
|
652
|
+
// }
|
|
381
653
|
|
|
382
|
-
|
|
383
|
-
|
|
654
|
+
// /** called from nebula */
|
|
655
|
+
// applyBehaviour(target: ParticleWithColor | Emitter, _deltaTime: number, _index: number) {
|
|
656
|
+
// // console.log(target, time, index)
|
|
657
|
+
// if (target instanceof Particle) {
|
|
658
|
+
// if (this.gradient) {
|
|
659
|
+
// const t = target.age / target.life;
|
|
660
|
+
// const ev = this.gradient.evaluate(t) as RGBAColor;
|
|
661
|
+
// const startColor = target.color_start;
|
|
662
|
+
// target.color.r = startColor.r * ev.r;
|
|
663
|
+
// target.color.g = startColor.g * ev.g;
|
|
664
|
+
// target.color.b = startColor.b * ev.b;
|
|
665
|
+
// target.alpha = ev.alpha * target.alpha_start;
|
|
666
|
+
// }
|
|
667
|
+
// }
|
|
668
|
+
// }
|
|
384
669
|
|
|
385
|
-
|
|
386
|
-
|
|
670
|
+
// private id = Symbol('gradientId');
|
|
671
|
+
// private _internalId: number = 0;
|
|
387
672
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
constructor(container: Object3D, shape: ShapeModule, noise: NoiseModule, startCurve: MinMaxCurve, startMultiplier: number) {
|
|
392
|
-
super();
|
|
393
|
-
this.container = container;
|
|
394
|
-
this.shape = shape;
|
|
395
|
-
this.noise = noise;
|
|
396
|
-
this.startSpeed = startCurve;
|
|
397
|
-
this.startMultiplier = startMultiplier;
|
|
398
|
-
|
|
399
|
-
}
|
|
673
|
+
// /** called from nebula */
|
|
674
|
+
// initialize(particle: ParticleWithColor) {
|
|
400
675
|
|
|
401
|
-
|
|
676
|
+
// // console.log(particle);
|
|
677
|
+
// // const context = Context.Current;
|
|
678
|
+
// // const time = context.time.time;
|
|
679
|
+
// const ev = this.startGradient.evaluate(Math.random()) as RGBAColor;
|
|
680
|
+
// particle.color.r = ev.r;
|
|
681
|
+
// particle.color.g = ev.g;
|
|
682
|
+
// particle.color.b = ev.b;
|
|
683
|
+
// particle.alpha = ev.alpha
|
|
402
684
|
|
|
403
|
-
|
|
404
|
-
// target.velocity.x = target.velocity_start.x;
|
|
405
|
-
// target.velocity.y = target.velocity_start.y;
|
|
406
|
-
// target.velocity.z = target.velocity_start.z;
|
|
407
|
-
if (target.gravity !== 0 && this.gravity) {
|
|
408
|
-
// get world down vector
|
|
409
|
-
this._temp.copy(this.downDirection);
|
|
410
|
-
this._temp.multiplyScalar(target.gravity * deltaTime);
|
|
411
|
-
target.velocity.add(this._temp);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (this.noise) {
|
|
415
|
-
this.noise.applyNoise(index, target.position, target.velocity, deltaTime, target.age, target.life);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
initialize(particle: ParticleWithVelocity) {
|
|
421
|
-
const dir = this.shape.getDirection(particle.position);
|
|
422
|
-
// dir.applyQuaternion(quat);
|
|
423
|
-
const speed = this.startSpeed.evaluate(0, Math.random()) * this.startMultiplier;
|
|
424
|
-
particle.velocity.x = dir.x * speed;
|
|
425
|
-
particle.velocity.y = dir.y * speed;
|
|
426
|
-
particle.velocity.z = dir.z * speed;
|
|
427
|
-
if (!particle.velocity_start)
|
|
428
|
-
particle.velocity_start = {};
|
|
429
|
-
particle.velocity_start.x = particle.velocity.x;
|
|
430
|
-
particle.velocity_start.y = particle.velocity.y;
|
|
431
|
-
particle.velocity_start.z = particle.velocity.z;
|
|
432
|
-
|
|
433
|
-
if (this.gravity) {
|
|
434
|
-
particle.gravity = this.gravity.evaluate(Math.random(), Math.random()) * 9.81;
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
particle.gravity = 0;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
const quat = getWorldQuaternion(this.container);
|
|
441
|
-
this.downDirection.set(0, -1, 0).applyQuaternion(quat);
|
|
442
|
-
}
|
|
685
|
+
// particle.age = 0;
|
|
443
686
|
|
|
444
|
-
}
|
|
687
|
+
// particle.color_start = { r: ev.r, g: ev.g, b: ev.b };
|
|
688
|
+
// particle.alpha_start = ev.alpha;
|
|
689
|
+
|
|
690
|
+
// particle.useColor = true;
|
|
691
|
+
// particle.useAlpha = true;
|
|
692
|
+
|
|
693
|
+
// if (particle[this.id] === undefined)
|
|
694
|
+
// particle[this.id] = this._internalId++;
|
|
695
|
+
// }
|
|
696
|
+
// }
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
// declare type ParticleWithVelocity = Particle & { velocity_start: { x: number, y: number, u: number }, gravity: number };
|
|
700
|
+
|
|
701
|
+
// class VelocityBehaviour extends CustomBehaviour {
|
|
702
|
+
|
|
703
|
+
// container: Object3D;
|
|
704
|
+
|
|
705
|
+
// shape: ShapeModule;
|
|
706
|
+
// noise: NoiseModule;
|
|
707
|
+
|
|
708
|
+
// startSpeed: MinMaxCurve;
|
|
709
|
+
// startMultiplier: number = 1;
|
|
710
|
+
|
|
711
|
+
// gravity?: MinMaxCurve;
|
|
712
|
+
// gravityModifierMultiplier: number = 1;
|
|
713
|
+
|
|
714
|
+
// downDirection = new Vector3();
|
|
715
|
+
// private _temp: Vector3 = new Vector3();
|
|
716
|
+
|
|
717
|
+
// constructor(container: Object3D, shape: ShapeModule, noise: NoiseModule, startCurve: MinMaxCurve, startMultiplier: number) {
|
|
718
|
+
// super();
|
|
719
|
+
// this.container = container;
|
|
720
|
+
// this.shape = shape;
|
|
721
|
+
// this.noise = noise;
|
|
722
|
+
// this.startSpeed = startCurve;
|
|
723
|
+
// this.startMultiplier = startMultiplier;
|
|
724
|
+
|
|
725
|
+
// }
|
|
726
|
+
|
|
727
|
+
// applyBehaviour(target: ParticleWithVelocity | Emitter, deltaTime: number, index: number) {
|
|
728
|
+
|
|
729
|
+
// if (target instanceof Particle) {
|
|
730
|
+
// // target.velocity.x = target.velocity_start.x;
|
|
731
|
+
// // target.velocity.y = target.velocity_start.y;
|
|
732
|
+
// // target.velocity.z = target.velocity_start.z;
|
|
733
|
+
// if (target.gravity !== 0 && this.gravity) {
|
|
734
|
+
// // get world down vector
|
|
735
|
+
// this._temp.copy(this.downDirection);
|
|
736
|
+
// this._temp.multiplyScalar(target.gravity * deltaTime);
|
|
737
|
+
// target.velocity.add(this._temp);
|
|
738
|
+
// }
|
|
739
|
+
|
|
740
|
+
// if (this.noise) {
|
|
741
|
+
// this.noise.applyNoise(index, target.position, target.velocity, deltaTime, target.age, target.life);
|
|
742
|
+
// }
|
|
743
|
+
// }
|
|
744
|
+
// }
|
|
745
|
+
|
|
746
|
+
// initialize(particle: ParticleWithVelocity) {
|
|
747
|
+
// const dir = this.shape.getDirection(particle.position);
|
|
748
|
+
// // dir.applyQuaternion(quat);
|
|
749
|
+
// const speed = this.startSpeed.evaluate(0, Math.random()) * this.startMultiplier;
|
|
750
|
+
// particle.velocity.x = dir.x * speed;
|
|
751
|
+
// particle.velocity.y = dir.y * speed;
|
|
752
|
+
// particle.velocity.z = dir.z * speed;
|
|
753
|
+
// if (!particle.velocity_start)
|
|
754
|
+
// particle.velocity_start = {};
|
|
755
|
+
// particle.velocity_start.x = particle.velocity.x;
|
|
756
|
+
// particle.velocity_start.y = particle.velocity.y;
|
|
757
|
+
// particle.velocity_start.z = particle.velocity.z;
|
|
758
|
+
|
|
759
|
+
// if (this.gravity) {
|
|
760
|
+
// particle.gravity = this.gravity.evaluate(Math.random(), Math.random()) * 9.81;
|
|
761
|
+
// }
|
|
762
|
+
// else {
|
|
763
|
+
// particle.gravity = 0;
|
|
764
|
+
// }
|
|
765
|
+
|
|
766
|
+
// const quat = getWorldQuaternion(this.container);
|
|
767
|
+
// this.downDirection.set(0, -1, 0).applyQuaternion(quat);
|
|
768
|
+
// }
|
|
769
|
+
|
|
770
|
+
// }
|