@needle-tools/engine 3.2.1-alpha → 3.2.3-alpha

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 (33) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/needle-engine.js +3943 -3886
  3. package/dist/needle-engine.min.js +74 -74
  4. package/dist/needle-engine.umd.cjs +86 -86
  5. package/lib/engine/engine_input.js +9 -3
  6. package/lib/engine/engine_input.js.map +1 -1
  7. package/lib/engine/engine_rendererdata.d.ts +1 -1
  8. package/lib/engine/engine_rendererdata.js +3 -1
  9. package/lib/engine/engine_rendererdata.js.map +1 -1
  10. package/lib/engine/extensions/NEEDLE_lighting_settings.js +1 -1
  11. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  12. package/lib/engine-components/ParticleSystem.js +2 -1
  13. package/lib/engine-components/ParticleSystem.js.map +1 -1
  14. package/lib/engine-components/ParticleSystemModules.d.ts +17 -2
  15. package/lib/engine-components/ParticleSystemModules.js +105 -14
  16. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  17. package/lib/engine-components/SceneSwitcher.d.ts +1 -1
  18. package/lib/engine-components/SceneSwitcher.js +9 -7
  19. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  20. package/lib/engine-components/SpriteRenderer.js +3 -0
  21. package/lib/engine-components/SpriteRenderer.js.map +1 -1
  22. package/lib/engine-components/VideoPlayer.js +1 -1
  23. package/lib/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +1 -1
  25. package/src/engine/codegen/register_types.js +2 -2
  26. package/src/engine/engine_input.ts +6 -3
  27. package/src/engine/engine_rendererdata.ts +2 -1
  28. package/src/engine/extensions/NEEDLE_lighting_settings.ts +1 -1
  29. package/src/engine-components/ParticleSystem.ts +2 -1
  30. package/src/engine-components/ParticleSystemModules.ts +98 -15
  31. package/src/engine-components/SceneSwitcher.ts +9 -7
  32. package/src/engine-components/SpriteRenderer.ts +4 -0
  33. package/src/engine-components/VideoPlayer.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "3.2.1-alpha",
3
+ "version": "3.2.3-alpha",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in",
5
5
  "main": "dist/needle-engine.umd.cjs",
6
6
  "type": "module",
@@ -1,5 +1,5 @@
1
1
  import { TypeStore } from "./../engine_typestore"
2
-
2
+
3
3
  // Import types
4
4
  import { __Ignore } from "../../engine-components/codegen/components";
5
5
  import { AlignmentConstraint } from "../../engine-components/AlignmentConstraint";
@@ -184,7 +184,7 @@ import { XRGrabModel } from "../../engine-components/WebXRGrabRendering";
184
184
  import { XRGrabRendering } from "../../engine-components/WebXRGrabRendering";
185
185
  import { XRRig } from "../../engine-components/WebXRRig";
186
186
  import { XRState } from "../../engine-components/XRFlag";
187
-
187
+
188
188
  // Register types
189
189
  TypeStore.add("__Ignore", __Ignore);
190
190
  TypeStore.add("AlignmentConstraint", AlignmentConstraint);
@@ -243,28 +243,31 @@ export class Input extends EventTarget {
243
243
  return null;
244
244
  }
245
245
  isKeyDown(keyCode: KeyCode | string) {
246
+ if (!this.context.application.isVisible || !this.context.application.hasFocus) return false;
246
247
  const codes = this.getCodeForCommonKeyName(keyCode);
247
248
  if (codes !== null) {
248
249
  for (const code of codes) if (this.isKeyDown(code)) return true;
249
250
  return false;
250
251
  }
251
- return this.context.application.isVisible && this.context.application.hasFocus && this.keysPressed[keyCode]?.startFrame === this.context.time.frameCount && this.keysPressed[keyCode].pressed;
252
+ return this.keysPressed[keyCode]?.startFrame === this.context.time.frameCount && this.keysPressed[keyCode].pressed;
252
253
  }
253
254
  isKeyUp(keyCode: KeyCode | string) {
255
+ if (!this.context.application.isVisible || !this.context.application.hasFocus) return false;
254
256
  const codes = this.getCodeForCommonKeyName(keyCode);
255
257
  if (codes !== null) {
256
258
  for (const code of codes) if (this.isKeyUp(code)) return true;
257
259
  return false;
258
260
  }
259
- return this.context.application.isVisible && this.context.application.hasFocus && this.keysPressed[keyCode]?.frame === this.context.time.frameCount && !this.keysPressed[keyCode].pressed;
261
+ return this.keysPressed[keyCode]?.frame === this.context.time.frameCount && !this.keysPressed[keyCode].pressed;
260
262
  }
261
263
  isKeyPressed(keyCode: KeyCode | string) {
264
+ if (!this.context.application.isVisible || !this.context.application.hasFocus) return false;
262
265
  const codes = this.getCodeForCommonKeyName(keyCode);
263
266
  if (codes !== null) {
264
267
  for (const code of codes) if (this.isKeyPressed(code)) return true;
265
268
  return false;
266
269
  }
267
- return this.context.application.isVisible && this.context.application.hasFocus && this.keysPressed[keyCode]?.pressed;// && time.frameCount - this.keysPressed[keyCode].frame < 100;
270
+ return this.keysPressed[keyCode]?.pressed;// && time.frameCount - this.keysPressed[keyCode].frame < 100;
268
271
  }
269
272
 
270
273
  // utility helper for mapping common names to actual codes; e.g. "Shift" -> "ShiftLeft" and "ShiftRight" or "a" -> "KeyA"
@@ -136,7 +136,8 @@ export class RendererData {
136
136
  }
137
137
  }
138
138
 
139
- disableReflection() {
139
+ disableReflection(sourceId? : SourceIdentifier) {
140
+ if(sourceId && sourceId !== this._currentReflectionId) return;
140
141
  const scene = this.context.scene;
141
142
  scene.environment = null;
142
143
  }
@@ -160,6 +160,6 @@ export class SceneLightSettings extends Behaviour {
160
160
  if (this._lightProbeObj) this._lightProbeObj.removeFromParent();
161
161
  if(this._ambientLightObj) this._ambientLightObj.removeFromParent();
162
162
  if (this.sourceId)
163
- this.context.rendererData.disableReflection();
163
+ this.context.rendererData.disableReflection(this.sourceId);
164
164
  }
165
165
  }
@@ -414,6 +414,7 @@ class VelocityBehaviour extends ParticleSystemBaseBehaviour {
414
414
  particle[$gravitySpeed] = 1;
415
415
 
416
416
  particle[$velocityLerpFactor] = Math.random();
417
+ this.system.velocityOverLifetime?.init(particle);
417
418
 
418
419
  this._gravityDirection.set(0, -1, 0);
419
420
  if (this.system.main.simulationSpace === ParticleSystemSimulationSpace.Local)
@@ -463,7 +464,7 @@ class VelocityBehaviour extends ParticleSystemBaseBehaviour {
463
464
  // limit or modify speed
464
465
  const velocity = this.system.velocityOverLifetime;
465
466
  if (velocity.enabled) {
466
- velocity.apply(0, particle.position, particle.velocity, delta, particle.age, particle.life);
467
+ velocity.apply(particle, 0, particle.position, particle.velocity, delta, particle.age, particle.life);
467
468
  }
468
469
 
469
470
  const limitVelocityOverLifetime = this.system.limitVelocityOverLifetime;
@@ -567,12 +567,24 @@ export class ShapeModule implements EmitterShape {
567
567
  }
568
568
  }
569
569
 
570
- private updateRotation() {
570
+ private applyRotation(vector: Vector3) {
571
571
  const isRotated = this.rotation.x !== 0 || this.rotation.y !== 0 || this.rotation.z !== 0;
572
572
  if (isRotated) {
573
+ // console.log(this._rotation);
574
+ // TODO: we need to convert this to threejs euler
573
575
  this._rotation.x = Mathf.toRadians(this.rotation.x);
574
- this._rotation.y = -Mathf.toRadians(this.rotation.y);
575
- this._rotation.z = -Mathf.toRadians(this.rotation.z);
576
+ this._rotation.y = Mathf.toRadians(this.rotation.y);
577
+ this._rotation.z = Mathf.toRadians(this.rotation.z);
578
+ this._rotation.order = 'ZYX';
579
+ vector.applyEuler(this._rotation);
580
+ // this._quat.setFromEuler(this._rotation);
581
+ // // this._quat.invert();
582
+ // this._quat.x *= -1;
583
+ // // this._quat.y *= -1;
584
+ // // this._quat.z *= -1;
585
+ // this._quat.w *= -1;
586
+ // vector.applyQuaternion(this._quat);
587
+
576
588
  }
577
589
  return isRotated;
578
590
  }
@@ -624,8 +636,7 @@ export class ShapeModule implements EmitterShape {
624
636
  this.randomizePosition(this._vector, this.randomPositionAmount);
625
637
  }
626
638
 
627
- if (this.updateRotation())
628
- this._vector.applyEuler(this._rotation);
639
+ this.applyRotation(this._vector);
629
640
 
630
641
  if (isWorldSpace) {
631
642
  this._vector.applyQuaternion(this.system.worldQuaternion);
@@ -663,6 +674,8 @@ export class ShapeModule implements EmitterShape {
663
674
  this._dir.set(rx, ry, rz)
664
675
  if (this.system?.worldspace)
665
676
  this._dir.sub(this.system.worldPos)
677
+ else
678
+ this._dir.sub(this.position)
666
679
  break;
667
680
  default:
668
681
  this._dir.set(0, 0, 1);
@@ -671,8 +684,7 @@ export class ShapeModule implements EmitterShape {
671
684
  if (this._space === ParticleSystemSimulationSpace.World) {
672
685
  this._dir.applyQuaternion(this.system.worldQuaternion);
673
686
  }
674
- if (this.updateRotation())
675
- this._dir.applyEuler(this._rotation);
687
+ this.applyRotation(this._dir);
676
688
  this._dir.normalize();
677
689
  this.spherizeDirection(this._dir, this.sphericalDirectionAmount);
678
690
  this.randomizeDirection(this._dir, this.randomDirectionAmount);
@@ -982,11 +994,29 @@ export class VelocityOverLifetimeModule {
982
994
  @serializable()
983
995
  enabled!: boolean;
984
996
 
985
- /* orbital settings */
997
+ @serializable()
998
+ space: ParticleSystemSimulationSpace = ParticleSystemSimulationSpace.Local;
986
999
 
1000
+ @serializable(MinMaxCurve)
1001
+ orbitalX!: MinMaxCurve;
1002
+ @serializable(MinMaxCurve)
1003
+ orbitalY!: MinMaxCurve;
1004
+ @serializable(MinMaxCurve)
1005
+ orbitalZ!: MinMaxCurve;
987
1006
 
988
1007
  @serializable()
989
- space: ParticleSystemSimulationSpace = ParticleSystemSimulationSpace.Local;
1008
+ orbitalXMultiplier!: number;
1009
+ @serializable()
1010
+ orbitalYMultiplier!: number;
1011
+ @serializable()
1012
+ orbitalZMultiplier!: number;
1013
+
1014
+ @serializable()
1015
+ orbitalOffsetX!: number;
1016
+ @serializable()
1017
+ orbitalOffsetY!: number;
1018
+ @serializable()
1019
+ orbitalOffsetZ!: number;
990
1020
 
991
1021
  @serializable(MinMaxCurve)
992
1022
  speedModifier!: MinMaxCurve;
@@ -1013,8 +1043,23 @@ export class VelocityOverLifetimeModule {
1013
1043
  }
1014
1044
 
1015
1045
  private _temp: Vector3 = new Vector3();
1046
+ private _temp2: Vector3 = new Vector3();
1047
+ private _temp3: Vector3 = new Vector3();
1048
+ private _hasOrbital = false;
1049
+ private _index = 0;
1050
+ private _orbitalMatrix: Matrix4 = new Matrix4();
1051
+
1052
+ init(particle: object) {
1053
+ if (this._index == 0) particle["debug"] = true;
1054
+ this._index += 1;
1055
+ particle["orbitx"] = this.orbitalX.evaluate(Math.random());
1056
+ particle["orbity"] = this.orbitalY.evaluate(Math.random());
1057
+ particle["orbitz"] = this.orbitalZ.evaluate(Math.random());
1058
+ // console.log(particle["orbitx"], particle["orbity"], particle["orbitz"])
1059
+ this._hasOrbital = particle["orbitx"] != 0 || particle["orbity"] != 0 || particle["orbitz"] != 0;
1060
+ }
1016
1061
 
1017
- apply(_index: number, _pos: Vec3, vel: Vec3, _dt: number, age: number, life: number) {
1062
+ apply(_particle: object, _index: number, _pos: Vec3, vel: Vec3, _dt: number, age: number, life: number) {
1018
1063
  if (!this.enabled) return;
1019
1064
  const t = age / life;
1020
1065
 
@@ -1024,13 +1069,51 @@ export class VelocityOverLifetimeModule {
1024
1069
  const z = this.z.evaluate(t);
1025
1070
  this._temp.set(-x, y, z);
1026
1071
  if (this._system) {
1027
- if (this.space === ParticleSystemSimulationSpace.World) {
1028
- this._temp.applyQuaternion(this._system.worldQuaternionInverted);
1029
- }
1030
- if (this._system.main.simulationSpace === ParticleSystemSimulationSpace.World) {
1031
- this._temp.applyQuaternion(this._system.worldQuaternion);
1072
+ // if (this.space === ParticleSystemSimulationSpace.World) {
1073
+ // this._temp.applyQuaternion(this._system.worldQuaternionInverted);
1074
+ // }
1075
+ // if (this._system.main.simulationSpace === ParticleSystemSimulationSpace.World) {
1076
+ // this._temp.applyQuaternion(this._system.worldQuaternion);
1077
+ // }
1078
+ }
1079
+
1080
+ if (this._hasOrbital) {
1081
+ const position = this._system?.worldPos;
1082
+ if (position) {
1083
+
1084
+ // TODO: we absolutely need to fix this, this is a hack for a specific usecase and doesnt work yet correctly
1085
+ // https://github.com/needle-tools/needle-tiny/issues/710
1086
+
1087
+ const pos = this._temp2.set(_pos.x, _pos.y, _pos.z);
1088
+
1089
+ const ox = this.orbitalXMultiplier;// particle["orbitx"];
1090
+ const oy = this.orbitalYMultiplier;// particle["orbity"];
1091
+ const oz = this.orbitalZMultiplier;// particle["orbitz"];
1092
+ const angle = speed * Math.PI * 2 * 10; // < Oh god
1093
+
1094
+ const cosX = Math.cos(angle * ox);
1095
+ const sinX = Math.sin(angle * ox);
1096
+ const cosY = Math.cos(angle * oy);
1097
+ const sinY = Math.sin(angle * oy);
1098
+ const cosZ = Math.cos(angle * oz);
1099
+ const sinZ = Math.sin(angle * oz);
1100
+
1101
+ const newX = pos.x * (cosY * cosZ) + pos.y * (cosY * sinZ) + pos.z * (-sinY);
1102
+ const newY = pos.x * (sinX * sinY * cosZ - cosX * sinZ) + pos.y * (sinX * sinY * sinZ + cosX * cosZ) + pos.z * (sinX * cosY);
1103
+ const newZ = pos.x * (cosX * sinY * cosZ + sinX * sinZ) + pos.y * (cosX * sinY * sinZ - sinX * cosZ) + pos.z * (cosX * cosY);
1104
+
1105
+ // pos.x += this.orbitalOffsetX;
1106
+ // pos.y += this.orbitalOffsetY;
1107
+ // pos.z += this.orbitalOffsetZ;
1108
+ const v = this._temp3.set(pos.x - newX, pos.y - newY, pos.z - newZ);
1109
+ v.normalize();
1110
+ v.multiplyScalar(.2 / _dt * (Math.max(this.orbitalXMultiplier, this.orbitalYMultiplier, this.orbitalZMultiplier)));
1111
+ vel.x += v.x;
1112
+ vel.y += v.y;
1113
+ vel.z += v.z;
1032
1114
  }
1033
1115
  }
1116
+
1034
1117
  vel.x += this._temp.x;
1035
1118
  vel.y += this._temp.y;
1036
1119
  vel.z += this._temp.z;
@@ -47,14 +47,16 @@ export class SceneSwitcher extends Behaviour {
47
47
  private _currentScene: AssetReference | undefined = undefined;
48
48
  private _engineElementOverserver: MutationObserver | undefined = undefined;
49
49
 
50
- start() {
51
- if (!this.tryLoadFromQueryParam()) {
50
+ async start() {
51
+ if (this._currentIndex === -1 && !await this.tryLoadFromQueryParam()) {
52
52
  const value = this.context.domElement.getAttribute(ENGINE_ELEMENT_SCENE_ATTRIBUTE_NAME);
53
53
  // let locked = this.lock;
54
54
  try {
55
55
  // this.lock = false;
56
- if (value === null || !this.trySelectSceneFromValue(value))
57
- this.select(0);
56
+ if (value === null || !await this.trySelectSceneFromValue(value)) {
57
+ if (this._currentIndex === -1)
58
+ this.select(0);
59
+ }
58
60
  }
59
61
  finally {
60
62
  // this.lock = locked;
@@ -202,10 +204,10 @@ export class SceneSwitcher extends Behaviour {
202
204
  }
203
205
 
204
206
  private tryLoadFromQueryParam() {
205
- if (!this.queryParameterName?.length) return false;
207
+ if (!this.queryParameterName?.length) return couldNotLoadScenePromise;
206
208
  // try restore the scene from the url
207
209
  const value = getParam(this.queryParameterName);
208
- if (typeof value === "boolean") return false;
210
+ if (typeof value === "boolean") return couldNotLoadScenePromise;
209
211
  return this.trySelectSceneFromValue(value);
210
212
  }
211
213
 
@@ -233,7 +235,7 @@ export class SceneSwitcher extends Behaviour {
233
235
  }
234
236
  }
235
237
 
236
- if (isLocalNetwork()) console.warn("Unknown scene value or index: \"" + value + "\"", this)
238
+ if (isLocalNetwork()) console.warn("Can not find scene: \"" + value + "\"", this)
237
239
 
238
240
  return couldNotLoadScenePromise;
239
241
  }
@@ -217,6 +217,10 @@ export class SpriteRenderer extends Behaviour {
217
217
  this.gameObject.add(this._currentSprite);
218
218
  }
219
219
 
220
+ if(this._currentSprite){
221
+ this._currentSprite.layers.set(this.layer)
222
+ }
223
+
220
224
  this._spriteSheet?.update();
221
225
  }
222
226
  }
@@ -424,7 +424,7 @@ export class VideoPlayer extends Behaviour {
424
424
  this._videoElement.playbackRate = this._playbackSpeed;
425
425
  // dont open in fullscreen on ios
426
426
  this._videoElement.playsInline = true;
427
- let muted = !this._receivedInput && this.audioOutputMode !== VideoAudioOutputMode.None;
427
+ let muted = !this._receivedInput || this.audioOutputMode === VideoAudioOutputMode.None;
428
428
  if (!muted && this._muted) muted = true;
429
429
  this._videoElement.muted = muted;
430
430
  if (this.playOnAwake)