@needle-tools/engine 2.41.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 (55) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/needle-engine.d.ts +100 -40
  3. package/dist/needle-engine.js +367 -367
  4. package/dist/needle-engine.js.map +3 -3
  5. package/dist/needle-engine.min.js +37 -37
  6. package/dist/needle-engine.min.js.map +3 -3
  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 -22
  12. package/lib/engine/engine_gizmos.js +37 -3
  13. package/lib/engine/engine_gizmos.js.map +1 -1
  14. package/lib/engine/engine_setup.d.ts +3 -0
  15. package/lib/engine/engine_setup.js +15 -0
  16. package/lib/engine/engine_setup.js.map +1 -1
  17. package/lib/engine/engine_three_utils.d.ts +16 -1
  18. package/lib/engine/engine_three_utils.js +94 -54
  19. package/lib/engine/engine_three_utils.js.map +1 -1
  20. package/lib/engine/engine_types.d.ts +6 -0
  21. package/lib/engine/engine_types.js.map +1 -1
  22. package/lib/engine-components/AnimationCurve.js +2 -2
  23. package/lib/engine-components/AnimationCurve.js.map +1 -1
  24. package/lib/engine-components/BoxHelperComponent.js +9 -10
  25. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  26. package/lib/engine-components/ParticleSystem.d.ts +24 -10
  27. package/lib/engine-components/ParticleSystem.js +136 -41
  28. package/lib/engine-components/ParticleSystem.js.map +1 -1
  29. package/lib/engine-components/ParticleSystemModules.d.ts +40 -6
  30. package/lib/engine-components/ParticleSystemModules.js +103 -21
  31. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  32. package/lib/engine-components/ReflectionProbe.js +29 -11
  33. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  34. package/lib/engine-components/Renderer.d.ts +1 -0
  35. package/lib/engine-components/Renderer.js +4 -2
  36. package/lib/engine-components/Renderer.js.map +1 -1
  37. package/lib/engine-components/codegen/components.d.ts +1 -0
  38. package/lib/engine-components/codegen/components.js +1 -0
  39. package/lib/engine-components/codegen/components.js.map +1 -1
  40. package/package.json +2 -2
  41. package/src/engine/codegen/register_types.js +4 -0
  42. package/src/engine/dist/engine_three_utils.js +279 -0
  43. package/src/engine/engine_element.ts +1 -1
  44. package/src/engine/engine_element_loading.ts +5 -1
  45. package/src/engine/engine_gizmos.ts +45 -8
  46. package/src/engine/engine_setup.ts +25 -2
  47. package/src/engine/engine_three_utils.ts +103 -62
  48. package/src/engine/engine_types.ts +8 -1
  49. package/src/engine-components/AnimationCurve.ts +2 -2
  50. package/src/engine-components/BoxHelperComponent.ts +12 -15
  51. package/src/engine-components/ParticleSystem.ts +151 -75
  52. package/src/engine-components/ParticleSystemModules.ts +127 -24
  53. package/src/engine-components/ReflectionProbe.ts +37 -13
  54. package/src/engine-components/Renderer.ts +4 -2
  55. package/src/engine-components/codegen/components.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import * as THREE from "three";
2
2
  import { Mathf } from "./engine_math"
3
- import { Vector3, Quaternion, Uniform } from "three";
3
+ import { WebGLRenderTarget, WebGLRenderer, Vector3, Quaternion, Uniform, Texture, Material, ShaderMaterial, CanvasTexture } from "three";
4
4
  import { CircularBuffer } from "./engine_utils";
5
5
 
6
6
 
@@ -78,7 +78,7 @@ const _worldScale2: THREE.Vector3 = new THREE.Vector3();
78
78
 
79
79
  export function getWorldScale(obj: THREE.Object3D, vec: THREE.Vector3 | null = null): THREE.Vector3 {
80
80
  if (!obj) return _worldScale.set(0, 0, 0);
81
- if (!obj.parent) return _worldScale.copy(obj.position);
81
+ if (!obj.parent) return _worldScale.copy(obj.scale);
82
82
  obj.getWorldScale(vec ?? _worldScale);
83
83
  return vec ?? _worldScale;
84
84
  }
@@ -180,39 +180,109 @@ export function logHierarchy(root: THREE.Object3D | null | undefined, collapsibl
180
180
 
181
181
 
182
182
 
183
- const planeGeometry = new THREE.PlaneGeometry(2, 2, 1, 1);
184
- const renderer = new THREE.WebGLRenderer({ antialias: false });
185
- const perspectiveCam = new THREE.PerspectiveCamera();
186
- const scene = new THREE.Scene();
187
- const shaderMaterial = new THREE.ShaderMaterial({
188
- uniforms: { blitTexture: new Uniform(null) },
189
- vertexShader: `
190
- varying vec2 vUv;
191
- void main(){
192
- vUv = uv;
193
- gl_Position = vec4(position.xy * 1.0,0.,.999999);
194
- }`,
195
- fragmentShader: `
196
- uniform sampler2D blitTexture;
197
- varying vec2 vUv;
198
- void main(){
199
- vec2 uv = vUv;
200
- uv.y = 1.0 - uv.y;
201
- gl_FragColor = vec4(uv.xy, 0, 1);
202
- gl_FragColor = texture2D( blitTexture, uv);
203
- }`
204
- });
205
183
 
184
+ export class Graphics {
185
+ private static planeGeometry = new THREE.PlaneGeometry(2, 2, 1, 1);
186
+ private static renderer = new WebGLRenderer({ antialias: false });
187
+ private static perspectiveCam = new THREE.PerspectiveCamera();
188
+ private static scene = new THREE.Scene();
189
+ private static readonly vertex = `
190
+ varying vec2 vUv;
191
+ void main(){
192
+ vUv = uv;
193
+ gl_Position = vec4(position.xy * 1.0,0.,.999999);
194
+ }`;
195
+ private static readonly fragment = `
196
+ uniform sampler2D map;
197
+ varying vec2 vUv;
198
+ void main(){
199
+ vec2 uv = vUv;
200
+ uv.y = 1.0 - uv.y;
201
+ gl_FragColor = texture2D( map, uv);
202
+ // gl_FragColor = vec4(uv.xy, 0, 1);
203
+ }`;
204
+ private static readonly blipMaterial = new ShaderMaterial({
205
+ uniforms: { map: new Uniform(null) },
206
+ vertexShader: this.vertex,
207
+ fragmentShader: this.fragment
208
+ });
209
+
210
+ static createBlitMaterial(fragment: string): ShaderMaterial {
211
+ return new ShaderMaterial({
212
+ uniforms: { map: new Uniform(null) },
213
+ vertexShader: this.vertex,
214
+ fragmentShader: fragment
215
+ });
216
+ }
217
+ private static readonly mesh = new THREE.Mesh(this.planeGeometry, this.blipMaterial);
218
+
219
+ static copyTexture(texture: Texture, blitMaterial?: ShaderMaterial) {
220
+ const material = blitMaterial ?? this.blipMaterial;
221
+ material.uniforms.map.value = texture;
222
+ material.needsUpdate = true;
223
+ material.uniformsNeedUpdate = true;
224
+ const mesh = this.mesh;
225
+ mesh.material = material;
226
+ mesh.frustumCulled = false;
227
+ this.scene.children.length = 0;
228
+ this.scene.add(mesh);
229
+ this.renderer.setSize(texture.image.width, texture.image.height);
230
+ this.renderer.clear();
231
+ this.renderer.render(this.scene, this.perspectiveCam);
232
+ const tex = new Texture(this.renderer.domElement);
233
+ tex.name = "Copy";
234
+ tex.needsUpdate = true; // < important!
235
+ return tex;
236
+ }
237
+
238
+ // static blit(src: Texture, target: Texture, blitMaterial?: ShaderMaterial) {
239
+ // let material = blitMaterial ?? this.blipMaterial;
240
+ // material.uniforms.map.value = src;
241
+ // this.mesh.material = material;
242
+ // this.mesh.frustumCulled = false;
243
+ // this.mesh.matrix.identity();
244
+ // this.scene.children.length = 0;
245
+ // this.scene.add(this.mesh);
246
+ // this.renderer.setSize(src.image.width, src.image.height);
247
+ // this.renderer.clear();
248
+ // this.renderer.render(this.scene, this.perspectiveCam);
249
+ // return new Texture(this.renderer.domElement);
250
+ // }
251
+
252
+ static textureToCanvas(texture: Texture, force: boolean) {
253
+ if (!texture) return null;
254
+
255
+ if (force === true || texture["isCompressedTexture"] === true) {
256
+ texture = copyTexture(texture);
257
+ }
258
+ const image = texture.image;
259
+ if (isImageBitmap(image)) {
260
+
261
+ const canvas = document.createElement('canvas');
262
+ canvas.width = image.width;
263
+ canvas.height = image.height;
264
+
265
+ const context = canvas.getContext('2d');
266
+ if (!context) {
267
+ console.error("Failed getting canvas 2d context");
268
+ return null;
269
+ }
270
+ context.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
271
+ return canvas;
272
+
273
+ }
274
+ return null;
275
+ }
276
+ }
277
+
278
+ /**@obsolete use Graphics.copyTexture */
206
279
  export function copyTexture(texture: THREE.Texture): THREE.Texture {
207
- shaderMaterial.uniforms.blitTexture.value = texture;
208
- const mesh = new THREE.Mesh(planeGeometry, shaderMaterial);
209
- mesh.frustumCulled = false;
210
- scene.children.length = 0;
211
- scene.add(mesh);
212
- renderer.setSize(texture.image.width, texture.image.height);
213
- renderer.clear();
214
- renderer.render(scene, perspectiveCam);
215
- return new THREE.Texture(renderer.domElement);
280
+ return Graphics.copyTexture(texture);
281
+ }
282
+
283
+ /**@obsolete use Graphics.textureToCanvas */
284
+ export function textureToCanvas(texture: THREE.Texture, force: boolean = false): HTMLCanvasElement | null {
285
+ return Graphics.textureToCanvas(texture, force);
216
286
  }
217
287
 
218
288
  declare class OffscreenCanvas { };
@@ -222,33 +292,4 @@ function isImageBitmap(image) {
222
292
  (typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement) ||
223
293
  (typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas) ||
224
294
  (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap);
225
- }
226
-
227
-
228
- export function textureToCanvas(texture: THREE.Texture, force : boolean = false): HTMLCanvasElement | null {
229
-
230
- if(!texture) return null;
231
-
232
- if (force === true || texture["isCompressedTexture"] === true) {
233
- texture = copyTexture(texture);
234
- }
235
-
236
- const image = texture.image;
237
-
238
- if (isImageBitmap(image)) {
239
-
240
- const canvas = document.createElement('canvas');
241
- canvas.width = image.width;
242
- canvas.height = image.height;
243
-
244
- const context = canvas.getContext('2d');
245
- if (!context) {
246
- console.error("Failed getting canvas 2d context");
247
- return null;
248
- }
249
- context.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
250
- return canvas;
251
-
252
- }
253
- return null;
254
295
  }
@@ -157,7 +157,14 @@ export type Vec2 = {
157
157
  export type Vec3 = {
158
158
  x: number,
159
159
  y: number,
160
- z: number
160
+ z: number,
161
+ }
162
+
163
+ export type Vec4 = {
164
+ x: number,
165
+ y: number,
166
+ z: number,
167
+ w: number,
161
168
  }
162
169
 
163
170
  const contactsVectorBuffer = new CircularBuffer(() => new Vector3(), 20);
@@ -32,12 +32,12 @@ export class AnimationCurve {
32
32
  if (!this.keys || this.keys.length == 0) return 0;
33
33
  // if the first keyframe time is already greater than the time we want to evaluate
34
34
  // then we dont need to iterate
35
- if (this.keys[0].time > time) {
35
+ if (this.keys[0].time >= time) {
36
36
  return this.keys[0].value;
37
37
  }
38
38
  for (let i = 0; i < this.keys.length; i++) {
39
39
  const kf = this.keys[i];
40
- if (kf.time < time) {
40
+ if (kf.time <= time) {
41
41
  const hasNextKeyframe = i+1 < this.keys.length;
42
42
  if (hasNextKeyframe) {
43
43
  const nextKf = this.keys[i+1];
@@ -1,10 +1,11 @@
1
1
  import { Behaviour } from "./Component";
2
2
  import * as THREE from "three";
3
3
  import { getParam } from "../engine/engine_utils";
4
- import { CreateWireCube } from "../engine/engine_gizmos";
4
+ import { CreateWireCube, Gizmos } from "../engine/engine_gizmos";
5
5
  import { getWorldPosition, getWorldScale } from "../engine/engine_three_utils";
6
6
 
7
7
  const gizmos = getParam("gizmos");
8
+ const debug = getParam("debugboxhelper");
8
9
 
9
10
  export class BoxHelperComponent extends Behaviour {
10
11
 
@@ -14,7 +15,7 @@ export class BoxHelperComponent extends Behaviour {
14
15
  private static _position: THREE.Vector3 = new THREE.Vector3();
15
16
  private static _size: THREE.Vector3 = new THREE.Vector3(.01, .01, .01);
16
17
 
17
- public isInBox(obj: THREE.Object3D, scaleFactor? : number): boolean | undefined {
18
+ public isInBox(obj: THREE.Object3D, scaleFactor?: number): boolean | undefined {
18
19
  if (!obj) return undefined;
19
20
 
20
21
  // if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
@@ -24,15 +25,13 @@ export class BoxHelperComponent extends Behaviour {
24
25
  this.box = new THREE.Box3();
25
26
  }
26
27
 
28
+
27
29
  if (obj.type === "Mesh") {
28
30
  BoxHelperComponent.testBox.setFromObject(obj);
29
31
  }
30
32
  else if (obj.type === "Group") {
33
+ BoxHelperComponent.testBox.makeEmpty();
31
34
  if (obj.children.length > 0) {
32
- BoxHelperComponent.testBox.setFromCenterAndSize(
33
- BoxHelperComponent._position.set(0, 0, 0),
34
- BoxHelperComponent._size.set(0, 0, 0)
35
- );
36
35
  for (let i = 0; i < obj.children.length; i++) {
37
36
  const ch = obj.children[i];
38
37
  if (ch.type === "Mesh") {
@@ -44,19 +43,17 @@ export class BoxHelperComponent extends Behaviour {
44
43
  else {
45
44
  const wp = getWorldPosition(obj, BoxHelperComponent._position);
46
45
  const size = getWorldScale(obj, BoxHelperComponent._size);
47
- if(scaleFactor !== undefined) size.multiplyScalar(scaleFactor);
46
+ if (scaleFactor !== undefined) size.multiplyScalar(scaleFactor);
48
47
  BoxHelperComponent.testBox.setFromCenterAndSize(wp, size);
49
48
  }
50
49
 
51
- // console.log("Obj box:", obj.name, obj.uuid, BoxHelperComponent.testBox.getCenter(new THREE.Vector3()), BoxHelperComponent.testBox.getSize(new THREE.Vector3()),
52
- // "\nTest box:", this.box.getCenter(new THREE.Vector3()), this.box.getSize(new THREE.Vector3()), this.context.time.frameCount);
53
- // this.tp.copy(obj.geometry.boundingBox);
54
- // // this.tp.setFromCenterAndSize(obj.position, obj.scale);
55
- // this.tp.applyMatrix4(obj.matrixWorld);
56
- // console.log(this.tp);
57
- // console.log(this.box?.min, this.box?.max, this.tp.min, this.tp.max);
58
50
  this.updateBox();
59
- return this.box?.intersectsBox(BoxHelperComponent.testBox);
51
+ const intersects = this.box?.intersectsBox(BoxHelperComponent.testBox);
52
+ if (intersects) {
53
+ if (debug)
54
+ Gizmos.DrawBox3(BoxHelperComponent.testBox, 0xff0000, 5);
55
+ }
56
+ return intersects;
60
57
  }
61
58
 
62
59
  public intersects(box: THREE.Box3): boolean {
@@ -1,107 +1,160 @@
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 } from "./ParticleSystemModules"
3
+ import { MainModule, EmissionModule, ShapeModule, ParticleSystemShapeType, MinMaxCurve, MinMaxGradient, ColorOverLifetimeModule, SizeOverLifetimeModule, NoiseModule, ParticleSystemSimulationSpace, ParticleBurst, IParticleSystem, ParticleSystemRenderMode } from "./ParticleSystemModules"
4
4
  import { getParam } from "../engine/engine_utils";
5
- import System, {
6
- Emitter,
7
- Rate,
8
- Span,
9
- Position,
10
- Mass,
11
- Radius,
12
- Life,
13
- PointZone,
14
- Vector3D,
15
- Alpha,
16
- Scale,
17
- Color,
18
- SpriteRenderer,
19
- RadialVelocity,
20
- BoxZone,
21
- Particle,
22
- Gravity,
23
- SphereZone,
24
- } from 'three-nebula';
5
+
25
6
  // https://github.dev/creativelifeform/three-nebula
7
+ import System, { Emitter, Position, Life, SpriteRenderer, Particle, Body, MeshRenderer, } from 'three-nebula';
26
8
 
27
9
  import { serializeable } from "../engine/engine_serialization";
28
10
  import { Time } from "../engine/engine_time";
29
11
  import { Context } from "../engine/engine_setup";
30
12
  import { RGBAColor } from "./js-extensions/RGBAColor";
31
- import { Mathf } from "../engine/engine_math";
32
- import { Vec3 } from "../engine/engine_types";
33
- import { AxesHelper, Material, Object3D, Sprite, SpriteMaterial, Vector3 } from "three";
34
- import { Renderer } from "./Renderer";
13
+ import { AxesHelper, BufferGeometry, Material, Mesh, Object3D, Sprite, SpriteMaterial, Vector3 } from "three";
35
14
  import { getWorldQuaternion, getWorldScale } from "../engine/engine_three_utils";
15
+ import { assign } from "../engine/engine_serialization_core";
36
16
 
37
17
  const debug = getParam("debugparticles");
38
18
 
39
19
 
40
-
41
20
  export class ParticleSystemRenderer extends Behaviour {
42
21
 
22
+ @serializeable()
23
+ renderMode?: ParticleSystemRenderMode;
24
+
43
25
  @serializeable(Material)
44
26
  particleMaterial?: SpriteMaterial;
27
+
28
+ // @serializeable(Mesh)
29
+ particleMesh?: Mesh | string;
30
+
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;
40
+ }
45
41
  }
46
42
 
47
- export class ParticleSystem extends Behaviour {
43
+ export class ParticleSystem extends Behaviour implements IParticleSystem {
48
44
 
49
45
  @serializeable(ColorOverLifetimeModule)
50
- colorOverLifetime!: ColorOverLifetimeModule;
46
+ readonly colorOverLifetime!: ColorOverLifetimeModule;
51
47
 
52
48
  @serializeable(MainModule)
53
- main!: MainModule;
49
+ readonly main!: MainModule;
54
50
 
55
51
  @serializeable(EmissionModule)
56
- emission!: EmissionModule;
52
+ readonly emission!: EmissionModule;
57
53
 
58
54
  @serializeable(SizeOverLifetimeModule)
59
- sizeOverLifetime!: SizeOverLifetimeModule;
55
+ readonly sizeOverLifetime!: SizeOverLifetimeModule;
60
56
 
61
57
  @serializeable(ShapeModule)
62
- shape!: ShapeModule;
58
+ readonly shape!: ShapeModule;
63
59
 
64
60
  @serializeable(NoiseModule)
65
- noise!: NoiseModule;
61
+ readonly noise!: NoiseModule;
62
+
63
+ get renderer(): ParticleSystemRenderer {
64
+ return this._renderer;
65
+ }
66
66
 
67
- renderer!: ParticleSystemRenderer;
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
+ }
68
79
 
80
+ private _renderer!: ParticleSystemRenderer;
69
81
  private _system!: System;
70
82
  private _emitter: Emitter;
71
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[];
72
100
 
73
101
  awake(): void {
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
+
74
113
  if (debug) {
75
114
  console.log(this);
76
115
  this.gameObject.add(new AxesHelper(1))
77
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
+ }
78
130
 
79
- this.renderer = this.gameObject.getComponent(ParticleSystemRenderer) as ParticleSystemRenderer;
80
- this._system = new System();
81
- const container = this.main.simulationSpace == ParticleSystemSimulationSpace.Local ? this.gameObject : this.context.scene;
82
-
131
+ if (!renderer) {
132
+ console.error("No renderer for particle system");
133
+ return;
134
+ }
83
135
 
84
- const renderer = new SpriteRenderer(container, THREE);
85
136
  renderer.logRendererType = () => { };
86
- if (this.renderer.particleMaterial) {
87
- const sprite = renderer._body as Sprite;
88
- sprite.layers.disableAll();
89
- sprite.layers.set(2); // ignore raycasting particles
90
- sprite.renderOrder = 1;
91
- sprite.material.map = this.renderer.particleMaterial.map;
92
- sprite.material.transparent = true;
93
- // sprite.material.sizeAttenuation = false;
94
- sprite.material.blending = this.renderer.particleMaterial.blending;
95
- sprite.material.blendDst = this.renderer.particleMaterial.blendDst;
96
- sprite.material.blendDstAlpha = this.renderer.particleMaterial.blendDstAlpha;
97
- sprite.material.blendEquation = this.renderer.particleMaterial.blendEquation;
98
- sprite.material.blendEquationAlpha = this.renderer.particleMaterial.blendEquationAlpha;
99
- sprite.material.blendSrc = this.renderer.particleMaterial.blendSrc;
100
- sprite.material.blendSrcAlpha = this.renderer.particleMaterial.blendSrcAlpha;
101
- sprite.material.premultipliedAlpha = this.renderer.particleMaterial.premultipliedAlpha;
102
- sprite.material.depthWrite = false;
103
- sprite.material.depthTest = true;
104
- if (debug) console.log(sprite);
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
+ }
105
158
  }
106
159
 
107
160
  this._system.addRenderer(renderer);
@@ -109,8 +162,6 @@ export class ParticleSystem extends Behaviour {
109
162
  const initializers: Array<any> = [];
110
163
  const behaviours: Array<any> = [];
111
164
 
112
-
113
-
114
165
  const life = new Life();
115
166
  life.lifePan = new MinMaxCurveSpan(this.main.startLifetime, 1);
116
167
  initializers.push(life);
@@ -130,6 +181,9 @@ export class ParticleSystem extends Behaviour {
130
181
  velocity.gravityModifierMultiplier = this.main.gravityModifierMultiplier;
131
182
  behaviours.push(velocity);
132
183
 
184
+ if (renderMode === ParticleSystemRenderMode.Mesh) {
185
+ initializers.push(new Body(this._renderer.getMesh()))
186
+ }
133
187
 
134
188
  const emitter = this._emitter = new Emitter({});
135
189
  emitter.setInitializers(initializers);
@@ -142,6 +196,7 @@ export class ParticleSystem extends Behaviour {
142
196
  this._emitter.emit();
143
197
  this._system.addEmitter(this._emitter);
144
198
  this._system.emit({ onStart: () => { }, onUpdate: () => { }, onEnd: () => { }, });
199
+ this._time = 0;
145
200
  }
146
201
 
147
202
  onDisable() {
@@ -149,11 +204,9 @@ export class ParticleSystem extends Behaviour {
149
204
  }
150
205
 
151
206
  onBeforeRender() {
152
- this.emission.currentParticles = this._system.getCount();
153
- this.emission.maxParticles = this.main.maxParticles;
154
- this.shape.update(this.context, this.main.simulationSpace, this.gameObject);
155
- this.noise.update(this.context);
156
- this._system.update(this.context.time.deltaTime * this.main.simulationSpeed);
207
+ if (this._bursts) {
208
+ this.emission.bursts = this._bursts;
209
+ }
157
210
 
158
211
  // sprite materials must be scaled in AR
159
212
  const cam = this.context.mainCamera;
@@ -161,13 +214,37 @@ export class ParticleSystem extends Behaviour {
161
214
  const scale = getWorldScale(cam);
162
215
  this._size.cameraScale = scale.x;
163
216
  }
217
+
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;
164
243
  }
165
244
 
166
245
  }
167
246
 
168
247
 
169
-
170
-
171
248
  class MinMaxCurveSpan {
172
249
 
173
250
  readonly time: Time;
@@ -308,7 +385,7 @@ class VelocityBehaviour extends CustomBehaviour {
308
385
  gravity?: MinMaxCurve;
309
386
  gravityModifierMultiplier: number = 1;
310
387
 
311
- downDirection = new Vector3(0, -1, 0);
388
+ downDirection = new Vector3();
312
389
  private _temp: Vector3 = new Vector3();
313
390
 
314
391
  constructor(container: Object3D, shape: ShapeModule, noise: NoiseModule, startCurve: MinMaxCurve, startMultiplier: number) {
@@ -319,8 +396,6 @@ class VelocityBehaviour extends CustomBehaviour {
319
396
  this.startSpeed = startCurve;
320
397
  this.startMultiplier = startMultiplier;
321
398
 
322
- const quat = getWorldQuaternion(container);
323
- this.downDirection.applyQuaternion(quat);
324
399
  }
325
400
 
326
401
  applyBehaviour(target: ParticleWithVelocity | Emitter, deltaTime: number, index: number) {
@@ -329,11 +404,11 @@ class VelocityBehaviour extends CustomBehaviour {
329
404
  // target.velocity.x = target.velocity_start.x;
330
405
  // target.velocity.y = target.velocity_start.y;
331
406
  // target.velocity.z = target.velocity_start.z;
332
- if (target.gravity) {
407
+ if (target.gravity !== 0 && this.gravity) {
333
408
  // get world down vector
334
409
  this._temp.copy(this.downDirection);
335
410
  this._temp.multiplyScalar(target.gravity * deltaTime);
336
- target.velocity.sub(this._temp);
411
+ target.velocity.add(this._temp);
337
412
  }
338
413
 
339
414
  if (this.noise) {
@@ -344,6 +419,7 @@ class VelocityBehaviour extends CustomBehaviour {
344
419
 
345
420
  initialize(particle: ParticleWithVelocity) {
346
421
  const dir = this.shape.getDirection(particle.position);
422
+ // dir.applyQuaternion(quat);
347
423
  const speed = this.startSpeed.evaluate(0, Math.random()) * this.startMultiplier;
348
424
  particle.velocity.x = dir.x * speed;
349
425
  particle.velocity.y = dir.y * speed;
@@ -355,14 +431,14 @@ class VelocityBehaviour extends CustomBehaviour {
355
431
  particle.velocity_start.z = particle.velocity.z;
356
432
 
357
433
  if (this.gravity) {
358
- particle.gravity = this.gravity.evaluate(0, Math.random()) * this.gravityModifierMultiplier * 9.81;
434
+ particle.gravity = this.gravity.evaluate(Math.random(), Math.random()) * 9.81;
359
435
  }
360
436
  else {
361
437
  particle.gravity = 0;
362
438
  }
363
439
 
364
- // particle.acceleration.y = 1;
365
- // console.log(particle);
440
+ const quat = getWorldQuaternion(this.container);
441
+ this.downDirection.set(0, -1, 0).applyQuaternion(quat);
366
442
  }
367
443
 
368
444
  }