@needle-tools/engine 2.40.0-pre → 2.42.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/needle-engine.d.ts +332 -126
  3. package/dist/needle-engine.js +401 -401
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +53 -53
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine_element.js +1 -1
  8. package/lib/engine/engine_element.js.map +1 -1
  9. package/lib/engine/engine_element_loading.js +6 -1
  10. package/lib/engine/engine_element_loading.js.map +1 -1
  11. package/lib/engine/engine_gizmos.d.ts +8 -21
  12. package/lib/engine/engine_gizmos.js +51 -5
  13. package/lib/engine/engine_gizmos.js.map +1 -1
  14. package/lib/engine/engine_math.d.ts +9 -6
  15. package/lib/engine/engine_math.js +9 -0
  16. package/lib/engine/engine_math.js.map +1 -1
  17. package/lib/engine/engine_physics.js +14 -6
  18. package/lib/engine/engine_physics.js.map +1 -1
  19. package/lib/engine/engine_serialization_core.js +2 -0
  20. package/lib/engine/engine_serialization_core.js.map +1 -1
  21. package/lib/engine/engine_setup.d.ts +3 -0
  22. package/lib/engine/engine_setup.js +15 -0
  23. package/lib/engine/engine_setup.js.map +1 -1
  24. package/lib/engine/engine_three_utils.d.ts +16 -1
  25. package/lib/engine/engine_three_utils.js +94 -54
  26. package/lib/engine/engine_three_utils.js.map +1 -1
  27. package/lib/engine/engine_types.d.ts +6 -0
  28. package/lib/engine/engine_types.js.map +1 -1
  29. package/lib/engine/engine_utils.d.ts +1 -0
  30. package/lib/engine/engine_utils.js +3 -0
  31. package/lib/engine/engine_utils.js.map +1 -1
  32. package/lib/engine-components/AnimationCurve.js +20 -5
  33. package/lib/engine-components/AnimationCurve.js.map +1 -1
  34. package/lib/engine-components/BoxHelperComponent.js +9 -10
  35. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  36. package/lib/engine-components/Light.d.ts +2 -0
  37. package/lib/engine-components/Light.js +33 -9
  38. package/lib/engine-components/Light.js.map +1 -1
  39. package/lib/engine-components/ParticleSystem.d.ts +29 -26
  40. package/lib/engine-components/ParticleSystem.js +349 -187
  41. package/lib/engine-components/ParticleSystem.js.map +1 -1
  42. package/lib/engine-components/ParticleSystemModules.d.ts +243 -64
  43. package/lib/engine-components/ParticleSystemModules.js +722 -153
  44. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  45. package/lib/engine-components/ReflectionProbe.js +29 -11
  46. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  47. package/lib/engine-components/Renderer.d.ts +1 -0
  48. package/lib/engine-components/Renderer.js +4 -2
  49. package/lib/engine-components/Renderer.js.map +1 -1
  50. package/lib/engine-components/WebXR.js +8 -3
  51. package/lib/engine-components/WebXR.js.map +1 -1
  52. package/lib/engine-components/codegen/components.d.ts +7 -0
  53. package/lib/engine-components/codegen/components.js +7 -0
  54. package/lib/engine-components/codegen/components.js.map +1 -1
  55. package/package.json +4 -2
  56. package/src/engine/codegen/register_types.js +28 -0
  57. package/src/engine/dist/engine_three_utils.js +279 -0
  58. package/src/engine/engine_element.ts +1 -1
  59. package/src/engine/engine_element_loading.ts +5 -1
  60. package/src/engine/engine_gizmos.ts +58 -6
  61. package/src/engine/engine_math.ts +19 -6
  62. package/src/engine/engine_physics.ts +17 -7
  63. package/src/engine/engine_serialization_core.ts +1 -0
  64. package/src/engine/engine_setup.ts +25 -2
  65. package/src/engine/engine_three_utils.ts +103 -62
  66. package/src/engine/engine_types.ts +8 -1
  67. package/src/engine/engine_utils.ts +5 -0
  68. package/src/engine-components/AnimationCurve.ts +25 -11
  69. package/src/engine-components/BoxHelperComponent.ts +12 -15
  70. package/src/engine-components/Light.ts +39 -8
  71. package/src/engine-components/ParticleSystem.ts +395 -199
  72. package/src/engine-components/ParticleSystemModules.ts +638 -152
  73. package/src/engine-components/ReflectionProbe.ts +37 -13
  74. package/src/engine-components/Renderer.ts +4 -2
  75. package/src/engine-components/WebXR.ts +11 -8
  76. package/src/engine-components/codegen/components.ts +7 -0
  77. package/src/engine/dist/engine_physics.js +0 -739
  78. package/src/engine/dist/engine_setup.js +0 -777
  79. package/src/engine-components/dist/CharacterController.js +0 -123
  80. package/src/engine-components/dist/RigidBody.js +0 -458
@@ -1,248 +1,444 @@
1
1
  import { Behaviour, GameObject } from "./Component";
2
2
  import * as THREE from "three";
3
- import * as Modules from "./ParticleSystemModules"
4
- import { Mathf } from "../engine/engine_math";
3
+ import { MainModule, EmissionModule, ShapeModule, ParticleSystemShapeType, MinMaxCurve, MinMaxGradient, ColorOverLifetimeModule, SizeOverLifetimeModule, NoiseModule, ParticleSystemSimulationSpace, ParticleBurst, IParticleSystem, ParticleSystemRenderMode } from "./ParticleSystemModules"
5
4
  import { getParam } from "../engine/engine_utils";
6
5
 
6
+ // https://github.dev/creativelifeform/three-nebula
7
+ import System, { Emitter, Position, Life, SpriteRenderer, Particle, Body, MeshRenderer, } from 'three-nebula';
8
+
9
+ import { serializeable } from "../engine/engine_serialization";
10
+ import { Time } from "../engine/engine_time";
11
+ import { Context } from "../engine/engine_setup";
12
+ 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";
15
+ import { assign } from "../engine/engine_serialization_core";
16
+
7
17
  const debug = getParam("debugparticles");
8
18
 
9
- class ParticleState {
10
- age: number = 0;
11
- lifetime: number = 0;
12
- position!: THREE.Vector3;
13
- velocity!: THREE.Vector3;
14
- color!: THREE.Color;
15
- }
16
19
 
17
20
  export class ParticleSystemRenderer extends Behaviour {
18
21
 
19
- get mainTexture(): THREE.Texture | null {
20
- if (this.sharedMaterial) {
21
- const tex = this.context.assets.findTexture(this.sharedMaterial);
22
- if (tex) return tex;
23
- }
24
- return null;
25
- }
22
+ @serializeable()
23
+ renderMode?: ParticleSystemRenderMode;
26
24
 
27
- getMesh(_index: number): THREE.Mesh | null {
28
- if (!this.mesh) return null;
29
- return this.context.assets.findMesh(this.mesh);
30
- }
25
+ @serializeable(Material)
26
+ particleMaterial?: SpriteMaterial;
31
27
 
32
- private sharedMaterial?: string;
33
- private mesh?: string;
28
+ // @serializeable(Mesh)
29
+ particleMesh?: Mesh | string;
34
30
 
35
- awake() {
36
- if (debug)
37
- console.log(this);
31
+
32
+ getMesh() {
33
+ let geo: BufferGeometry | null = null;
34
+ if (this.particleMesh instanceof Mesh) {
35
+ geo = this.particleMesh.geometry;
36
+ }
37
+ if (geo === null) geo = new THREE.BoxGeometry(1, 1, 1);
38
+ const res = new Mesh(geo, this.particleMaterial);
39
+ return res;
38
40
  }
39
41
  }
40
42
 
41
- export class ParticleSystem extends Behaviour {
43
+ export class ParticleSystem extends Behaviour implements IParticleSystem {
44
+
45
+ @serializeable(ColorOverLifetimeModule)
46
+ readonly colorOverLifetime!: ColorOverLifetimeModule;
42
47
 
43
- main!: Modules.MainModule;
44
- emission!: Modules.EmissionModule;
45
- shape!: Modules.ShapeModule;
48
+ @serializeable(MainModule)
49
+ readonly main!: MainModule;
46
50
 
47
- private renderer!: ParticleSystemRenderer;
51
+ @serializeable(EmissionModule)
52
+ readonly emission!: EmissionModule;
48
53
 
49
- private geometry: THREE.BufferGeometry | undefined;
50
- private material!: THREE.PointsMaterial;
51
- private particlesMesh!: THREE.Points;
54
+ @serializeable(SizeOverLifetimeModule)
55
+ readonly sizeOverLifetime!: SizeOverLifetimeModule;
52
56
 
53
- private positions!: THREE.Float32BufferAttribute;
54
- private positionsArray!: Float32Array;
55
- private particleStates: Array<ParticleState> = [];
56
- private activeCount: number = 0;
57
+ @serializeable(ShapeModule)
58
+ readonly shape!: ShapeModule;
57
59
 
58
- private shapeRotation: THREE.Quaternion = new THREE.Quaternion();
59
- private tempVec3: THREE.Vector3 = new THREE.Vector3();
60
- private tempQuat: THREE.Quaternion = new THREE.Quaternion();
60
+ @serializeable(NoiseModule)
61
+ readonly noise!: NoiseModule;
62
+
63
+ get renderer(): ParticleSystemRenderer {
64
+ return this._renderer;
65
+ }
66
+
67
+ get currentParticles() {
68
+ return this._system?.getCount() ?? 0;
69
+ }
70
+ get maxParticles() {
71
+ return this.main.maxParticles;
72
+ }
73
+ get time() {
74
+ return this._time;
75
+ }
76
+ get duration() {
77
+ return this.main.duration;
78
+ }
79
+
80
+ private _renderer!: ParticleSystemRenderer;
81
+ private _system!: System;
82
+ private _emitter: Emitter;
83
+ private _size!: SizeBehaviour;
84
+ private _container?: Object3D;
85
+ private _time: number = 0;
86
+
87
+ /** called from deserialization */
88
+ private set bursts(arr: ParticleBurst[]) {
89
+ for (let i = 0; i < arr.length; i++) {
90
+ const burst = arr[i];
91
+ if ((burst instanceof ParticleBurst) === false) {
92
+ const instance = new ParticleBurst();
93
+ assign(instance, burst);
94
+ arr[i] = instance;
95
+ }
96
+ }
97
+ this._bursts = arr;
98
+ }
99
+ private _bursts?: ParticleBurst[];
61
100
 
62
101
  awake(): void {
63
- this.renderer = GameObject.getComponent(this.gameObject, ParticleSystemRenderer)!;
64
- // if (debug)
102
+ this._renderer = this.gameObject.getComponent(ParticleSystemRenderer) as ParticleSystemRenderer;
103
+ this._system = new System();
104
+
105
+ if (this.main.simulationSpace == ParticleSystemSimulationSpace.Local) {
106
+ this._container = new Object3D();
107
+ this._container.matrixAutoUpdate = false;
108
+ this.gameObject.add(this._container);
109
+ }
110
+
111
+ const container = this.main.simulationSpace == ParticleSystemSimulationSpace.Local ? this._container : this.context.scene;
112
+
113
+ if (debug) {
65
114
  console.log(this);
66
- }
115
+ this.gameObject.add(new AxesHelper(1))
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
+ }
67
130
 
68
- onEnable() {
69
- // console.trace();
70
- if (this.geometry) {
131
+ if (!renderer) {
132
+ console.error("No renderer for particle system");
71
133
  return;
72
134
  }
73
- // console.log(this);
74
-
75
- this.particleStates = [];
76
- this.shapeRotation.setFromEuler(new THREE.Euler(this.shape.rotation.x, this.shape.rotation.y, this.shape.rotation.z));
77
-
78
- // TODO: how to render particle mesh
79
- // const assignedMesh = this.renderer?.getMesh(0);
80
- // console.log(assignedMesh);
81
-
82
- this.geometry = new THREE.BufferGeometry();
83
-
84
- this.positionsArray = new Float32Array(this.main.maxParticles * 3);
85
- this.positions = new THREE.Float32BufferAttribute(this.positionsArray, 3);
86
- this.geometry.setAttribute('position', this.positions);
87
-
88
-
89
- // const color = new THREE.Color();
90
- const colorsArray = new Float32Array(this.main.maxParticles * 3);
91
- for (let i = 0; i < colorsArray.length; i++) {
92
- colorsArray[i * 3] = 1;
93
- colorsArray[i * 3 + 1] = 1;
94
- colorsArray[i * 3 + 2] = 1;
95
- }
96
- const colors = new THREE.Float32BufferAttribute(colorsArray, 3);
97
- this.geometry.setAttribute('color', colors);
98
- this.material = new THREE.PointsMaterial({ size: this.main.startSize, color: 0xffffff, vertexColors: true });
99
- this.material.map = this.renderer.mainTexture;
100
- // this.material.onBeforeCompile = (shader) => {
101
- // shader.
102
- // });
103
-
104
- this.particlesMesh = new THREE.Points(this.geometry, this.material);
105
- this.particlesMesh.layers.enable(2);
106
- this.gameObject.add(this.particlesMesh);
107
-
108
- this.activeCount = this.main.prewarm ? this.main.maxParticles : 0;
109
- }
110
-
111
- // update() {
112
- // if (!this.geometry) return;
113
-
114
- // const t = this.context.time.deltaTime;
115
- // this.emit(t);
116
-
117
- // for (let i = 0; i < this.activeCount; i += 1) {
118
- // const ps = this.particleStates[i];
119
- // if (!ps) continue;
120
- // const vx = ps.velocity.x * t;
121
- // const vy = ps.velocity.y * t;
122
- // const vz = ps.velocity.z * t;
123
- // ps.position.x += vx;
124
- // ps.position.y += vy;
125
- // ps.position.z += vz;
126
- // this.updateOverLifetime(i, ps);
127
- // this.geometry.attributes.position.setXYZ(i, ps.position.x, ps.position.y, ps.position.z);
128
- // this.geometry.attributes.color.setXYZ(i, ps.color.r, ps.color.g, ps.color.b);
129
- // }
130
- // if (this.geometry) {
131
- // this.geometry.attributes.position.needsUpdate = true;
132
- // this.geometry.setDrawRange(0, this.activeCount);
133
- // }
134
- // }
135
-
136
- emit(deltaTime: number) {
137
- const count = this.activeCount;
138
- for (let i = 0; i < count; i += 1) {
139
-
140
- if (i >= this.particleStates.length) {
141
- const ps = new ParticleState();
142
- ps.lifetime = this.main.startLifetime ?? 1;
143
- ps.position = new THREE.Vector3();
144
- ps.velocity = new THREE.Vector3();
145
- ps.color = new THREE.Color(1, 0, 0);
146
- this.particleStates.push(ps);
147
- this.initializeParticle(i, ps);
148
- ps.age = ps.lifetime * Math.random();
149
- }
150
- const ps = this.particleStates[i];
151
135
 
152
- if (ps.age > ps.lifetime) {
153
- this.activeCount -= 1;
154
- this.activeCount = Math.max(0, this.activeCount);
155
- this.initializeParticle(i, ps);
156
- continue;
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
157
  }
158
+ }
159
+
160
+ this._system.addRenderer(renderer);
161
+
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);
158
171
 
159
- ps.age += deltaTime;
160
- this.particleStates[i] = ps;
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()))
161
186
  }
162
- this.activeCount += deltaTime * (this.emission.rate);
163
- this.activeCount = Math.min(this.main.maxParticles, this.activeCount);
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;
164
193
  }
165
194
 
166
- private initializeParticle(index: number, particle: ParticleState) {
195
+ onEnable() {
196
+ this._emitter.emit();
197
+ this._system.addEmitter(this._emitter);
198
+ this._system.emit({ onStart: () => { }, onUpdate: () => { }, onEnd: () => { }, });
199
+ this._time = 0;
200
+ }
167
201
 
168
- if (!this.geometry) return;
169
- particle.age = 0;
170
- particle.color.set(this.main.startColor);
171
- if (this.main.startColor1) {
172
- particle.color.lerp(this.main.startColor1, Math.random());
202
+ onDisable() {
203
+ this._system.removeEmitter(this._emitter);
204
+ }
205
+
206
+ onBeforeRender() {
207
+ if (this._bursts) {
208
+ this.emission.bursts = this._bursts;
173
209
  }
174
- this.geometry.attributes.color.needsUpdate = true;
175
210
 
176
- this.assignPosition(particle.position);
177
- this.assignVelocity(particle.position, particle.velocity);
211
+ // sprite materials must be scaled in AR
212
+ const cam = this.context.mainCamera;
213
+ if (cam) {
214
+ const scale = getWorldScale(cam);
215
+ this._size.cameraScale = scale.x;
216
+ }
178
217
 
179
- const position = particle.position;
180
- position.multiply(this.shape.scale);
181
- position.applyQuaternion(this.shapeRotation);
182
- position.add(this.shape.position);
183
- // push back
184
- this.particleStates.splice(index, 1);
185
- this.particleStates.push(particle);
218
+ if (this._container && this.gameObject?.parent) {
219
+ // this._container.matrix.copy(this.gameObject.matrixWorld);
220
+ // this._container.matrixWorld.copy(this.gameObject.matrixWorld);
221
+
222
+ const scale = getWorldScale(this.gameObject.parent);
223
+ scale.x = 1 / scale.x;
224
+ scale.y = 1 / scale.y;
225
+ 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
+ this._container.matrix.identity();
232
+ this._container.matrix.scale(scale);
233
+ // this._container.matrixWorld.copy(this._container.matrix);
234
+ }
235
+ // this._system.time
236
+ // this._system.duration = this.main.duration;
237
+ this.emission.system = this;
238
+ this.shape.update(this.context, this.main.simulationSpace, this.gameObject);
239
+ this.noise.update(this.context);
240
+ this._system.update(this.context.time.deltaTime * this.main.simulationSpeed);
241
+ this._time += this.context.time.deltaTime;
242
+ if (this._time > this.duration) this._time = 0;
186
243
  }
187
244
 
188
- private updateOverLifetime(_index: number, _particle: ParticleState) {
189
- // particle.position.multiplyScalar()
245
+ }
246
+
247
+
248
+ class MinMaxCurveSpan {
249
+
250
+ readonly time: Time;
251
+ readonly curve: MinMaxCurve;
252
+ multiplier: number = 1;
253
+
254
+ constructor(minMaxCurve: MinMaxCurve, multiplier: number = 1) {
255
+ this.time = Context.Current.time;
256
+ this.curve = minMaxCurve;
257
+ this.multiplier = multiplier;
190
258
  }
191
259
 
192
- private assignPosition(position: THREE.Vector3) {
193
- switch (this.shape.shapeType) {
194
- case Modules.ParticleSystemShapeType.Sphere:
195
- position.set(Math.random() - .5, Math.random() - .5, Math.random() - .5).multiplyScalar(this.shape.radius);
196
- break;
197
- case Modules.ParticleSystemShapeType.Box:
198
- position.set(Math.random() - .5, Math.random() - .5, Math.random() - .5);
199
- break;
200
- default:
201
- position.set(0, 0, 0);
202
- break;
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
+
267
+ abstract class CustomBehaviour extends Behaviour {
268
+ abstract applyBehaviour(target: Particle | Emitter, time: number, index: number);
269
+ abstract initialize(particle: Particle);
270
+ }
271
+
272
+ abstract class MinMaxCurveBehaviour extends CustomBehaviour {
273
+
274
+ readonly startCurve: MinMaxCurve;
275
+ startMultiplier: number = 1;
276
+
277
+ constructor(startCurve: MinMaxCurve, startMultiplier: number = 1) {
278
+ super();
279
+ this.startCurve = startCurve;
280
+ this.startMultiplier = startMultiplier;
281
+ }
282
+ }
283
+
284
+ declare type ParticleWithScale = Particle & { target: Object3D, start_scale: number };
285
+
286
+ class SizeBehaviour extends MinMaxCurveBehaviour {
287
+
288
+ sizeOverLifetimeModule!: SizeOverLifetimeModule;
289
+
290
+ cameraScale: number = 1;
291
+
292
+ applyBehaviour(particle: ParticleWithScale, _deltaTime: number, _index: number) {
293
+ if (particle.target.type === "Sprite") {
294
+ particle.radius = 1 / this.cameraScale;
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);
203
306
  }
204
307
  }
308
+ initialize(particle: ParticleWithScale) {
309
+ particle.scale = this.startCurve.evaluate(0, Math.random());// * this.startMultiplier;
310
+ particle.start_scale = particle.scale;
205
311
 
206
- private assignVelocity(position: THREE.Vector3, velocity: THREE.Vector3) {
207
- switch (this.shape.shapeType) {
208
- case Modules.ParticleSystemShapeType.Sphere:
209
- velocity.set(position.x, position.y, position.z);
210
- break;
211
- case Modules.ParticleSystemShapeType.Box:
212
- velocity.set(0, 0, 1);
213
- if (this.shape.sphericalDirectionAmount > 0) {
214
- this.tempVec3.set(position.x, position.y, position.z).multiply(this.shape.scale).normalize();
215
- velocity.lerp(this.tempVec3, this.shape.sphericalDirectionAmount);
216
- }
217
- break;
218
- case Modules.ParticleSystemShapeType.Cone:
219
- // const maxAngle = 90;
220
- // const fwd = this.shape.angle / maxAngle;
221
- // const side = 1 - fwd;
222
- // const angle = Mathf.toRadians(this.shape.angle);
223
- // const upDir = Math.random();
224
- // const sideDir = 1 - upDir;
225
- // const quat = new THREE.Quaternion().setFromAxisAngle(this.tempVec3.set(side, 0, fwd), angle * Math.random())
226
- const dir = new THREE.Vector3(0, 1, 0);//.applyQuaternion(quat);
227
- velocity.copy(dir);
228
- break;
229
- case Modules.ParticleSystemShapeType.Circle:
230
- this.tempQuat.setFromAxisAngle(this.tempVec3.set(0, 0, 1), Math.random() * Mathf.toRadians(this.shape.arc));
231
- velocity.copy(this.tempVec3.set(1, 0, 0).applyQuaternion(this.tempQuat));
232
- break;
233
- default:
234
- velocity.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1);
235
- break;
312
+ }
313
+ }
314
+
315
+ declare type ParticleWithColor = Particle & { color_start: { r: number, g: number, b: number }, alpha_start: number };
316
+
317
+ class GradientBehaviour extends CustomBehaviour {
318
+
319
+ private startGradient: MinMaxGradient;
320
+ private gradient?: MinMaxGradient;
321
+
322
+ constructor(startGradient: MinMaxGradient, gradient?: MinMaxGradient) {
323
+ super();
324
+ this.startGradient = startGradient;
325
+ this.gradient = gradient;
326
+ }
327
+
328
+ /** called from nebula */
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
+ }
236
341
  }
237
- velocity.normalize();
342
+ }
238
343
 
239
- // set position
240
- switch (this.shape.shapeType) {
241
- case Modules.ParticleSystemShapeType.Circle:
242
- position.add(velocity).multiplyScalar(this.shape.radius);
243
- break;
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
358
+
359
+ particle.age = 0;
360
+
361
+ particle.color_start = { r: ev.r, g: ev.g, b: ev.b };
362
+ particle.alpha_start = ev.alpha;
363
+
364
+ particle.useColor = true;
365
+ particle.useAlpha = true;
366
+
367
+ if (particle[this.id] === undefined)
368
+ particle[this.id] = this._internalId++;
369
+ }
370
+ }
371
+
372
+
373
+ declare type ParticleWithVelocity = Particle & { velocity_start: { x: number, y: number, u: number }, gravity: number };
374
+
375
+ class VelocityBehaviour extends CustomBehaviour {
376
+
377
+ container: Object3D;
378
+
379
+ shape: ShapeModule;
380
+ noise: NoiseModule;
381
+
382
+ startSpeed: MinMaxCurve;
383
+ startMultiplier: number = 1;
384
+
385
+ gravity?: MinMaxCurve;
386
+ gravityModifierMultiplier: number = 1;
387
+
388
+ downDirection = new Vector3();
389
+ private _temp: Vector3 = new Vector3();
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
+ }
400
+
401
+ applyBehaviour(target: ParticleWithVelocity | Emitter, deltaTime: number, index: number) {
402
+
403
+ if (target instanceof Particle) {
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
+ }
244
417
  }
418
+ }
245
419
 
246
- velocity.multiplyScalar(this.main.startSpeedMultiplier);
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);
247
442
  }
443
+
248
444
  }