@needle-tools/engine 2.27.0-pre → 2.29.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 (79) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/needle-engine.d.ts +193 -132
  3. package/dist/needle-engine.js +345 -345
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +19 -19
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine_input.d.ts +13 -1
  8. package/lib/engine/engine_input.js +47 -16
  9. package/lib/engine/engine_input.js.map +1 -1
  10. package/lib/engine/engine_networking_utils.js +1 -2
  11. package/lib/engine/engine_networking_utils.js.map +1 -1
  12. package/lib/engine/engine_physics.d.ts +1 -0
  13. package/lib/engine/engine_physics.js +2 -1
  14. package/lib/engine/engine_physics.js.map +1 -1
  15. package/lib/engine/engine_playerview.d.ts +26 -0
  16. package/lib/engine/engine_playerview.js +65 -0
  17. package/lib/engine/engine_playerview.js.map +1 -0
  18. package/lib/engine/engine_serialization_core.js +5 -0
  19. package/lib/engine/engine_serialization_core.js.map +1 -1
  20. package/lib/engine/engine_setup.d.ts +8 -1
  21. package/lib/engine/engine_setup.js +38 -3
  22. package/lib/engine/engine_setup.js.map +1 -1
  23. package/lib/engine/extensions/NEEDLE_lighting_settings.js +6 -2
  24. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  25. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +1 -1
  26. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  27. package/lib/engine-components/Component.d.ts +1 -1
  28. package/lib/engine-components/Component.js.map +1 -1
  29. package/lib/engine-components/Light.js +1 -0
  30. package/lib/engine-components/Light.js.map +1 -1
  31. package/lib/engine-components/OrbitControls.js +1 -2
  32. package/lib/engine-components/OrbitControls.js.map +1 -1
  33. package/lib/engine-components/ParticleSystem.d.ts +0 -1
  34. package/lib/engine-components/ParticleSystem.js +24 -27
  35. package/lib/engine-components/ParticleSystem.js.map +1 -1
  36. package/lib/engine-components/PlayerColor.js +1 -2
  37. package/lib/engine-components/PlayerColor.js.map +1 -1
  38. package/lib/engine-components/SpectatorCamera.d.ts +24 -17
  39. package/lib/engine-components/SpectatorCamera.js +410 -181
  40. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  41. package/lib/engine-components/SyncedCamera.d.ts +8 -4
  42. package/lib/engine-components/SyncedCamera.js +15 -18
  43. package/lib/engine-components/SyncedCamera.js.map +1 -1
  44. package/lib/engine-components/WebXR.js +1 -0
  45. package/lib/engine-components/WebXR.js.map +1 -1
  46. package/lib/engine-components/WebXRAvatar.d.ts +3 -0
  47. package/lib/engine-components/WebXRAvatar.js +16 -0
  48. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  49. package/lib/engine-components/WebXRController.js +1 -1
  50. package/lib/engine-components/WebXRController.js.map +1 -1
  51. package/lib/engine-components/WebXRSync.js +3 -3
  52. package/lib/engine-components/WebXRSync.js.map +1 -1
  53. package/lib/engine-components/XRFlag.d.ts +2 -1
  54. package/lib/engine-components/XRFlag.js +1 -0
  55. package/lib/engine-components/XRFlag.js.map +1 -1
  56. package/lib/engine-components/ui/InputField.js +2 -2
  57. package/package.json +1 -1
  58. package/src/engine/engine_components.js +16 -0
  59. package/src/engine/engine_input.ts +62 -20
  60. package/src/engine/engine_networking_utils.ts +1 -2
  61. package/src/engine/engine_physics.ts +2 -1
  62. package/src/engine/engine_playerview.ts +80 -0
  63. package/src/engine/engine_serialization_core.ts +8 -0
  64. package/src/engine/engine_setup.ts +37 -3
  65. package/src/engine/extensions/NEEDLE_lighting_settings.ts +4 -2
  66. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +1 -1
  67. package/src/engine-components/Component.ts +1 -1
  68. package/src/engine-components/Light.ts +3 -0
  69. package/src/engine-components/OrbitControls.ts +1 -2
  70. package/src/engine-components/ParticleSystem.ts +25 -26
  71. package/src/engine-components/PlayerColor.ts +1 -1
  72. package/src/engine-components/SpectatorCamera.ts +466 -194
  73. package/src/engine-components/SyncedCamera.ts +23 -22
  74. package/src/engine-components/WebXR.ts +1 -0
  75. package/src/engine-components/WebXRAvatar.ts +22 -2
  76. package/src/engine-components/WebXRController.ts +1 -1
  77. package/src/engine-components/WebXRSync.ts +3 -3
  78. package/src/engine-components/XRFlag.ts +1 -0
  79. package/src/engine-components/ui/InputField.ts +2 -2
@@ -0,0 +1,80 @@
1
+ import { getParam } from "./engine_utils";
2
+ import { Object3D } from "three";
3
+ import { Context } from "./engine_setup";
4
+
5
+ const debug = getParam("debugplayerview");
6
+
7
+ export enum ViewDevice {
8
+ Browser = "browser",
9
+ Headset = "headset",
10
+ Handheld = "handheld",
11
+ }
12
+
13
+ export class PlayerView {
14
+ readonly userId: string;
15
+ readonly context: Context;
16
+
17
+ viewDevice: ViewDevice = ViewDevice.Browser;
18
+
19
+ get currentObject(): Object3D | undefined | null {
20
+ return this._object;
21
+ }
22
+ set currentObject(obj: Object3D | undefined | null) {
23
+ this._object = obj;
24
+ }
25
+
26
+ get isConnected(): boolean {
27
+ return this.context.connection.userIsInRoom(this.userId);
28
+ }
29
+
30
+ removed: boolean = false;
31
+
32
+ private _object: undefined | Object3D | null;
33
+
34
+ constructor(userId: string, context: Context) {
35
+ this.userId = userId;
36
+ this.context = context;
37
+ }
38
+ }
39
+
40
+ export class PlayerViewManager {
41
+
42
+ private readonly context: Context;
43
+ private readonly playerViews = new Map<string, PlayerView>();
44
+
45
+ constructor(context: Context) {
46
+ this.context = context;
47
+ }
48
+
49
+ setPlayerView(id: string, obj: Object3D | undefined | null, device: ViewDevice) {
50
+ let view = this.playerViews.get(id);
51
+ if (!view) {
52
+ view = new PlayerView(id, this.context);
53
+ this.playerViews.set(id, view);
54
+ }
55
+ view.viewDevice = device;
56
+ view.currentObject = obj;
57
+ view.removed = false;
58
+ }
59
+
60
+ getPlayerView(id: string | null | undefined): PlayerView | undefined {
61
+ if (!id) return undefined;
62
+ if (!this.context.connection.userIsInRoom(id)) {
63
+ this.playerViews.delete(id);
64
+ return undefined;
65
+ }
66
+ const view = this.playerViews.get(id);
67
+ return view;
68
+ }
69
+
70
+ removePlayerView(id: string, device: ViewDevice) {
71
+ const view = this.playerViews.get(id);
72
+ if (view?.viewDevice === device) {
73
+ if (debug)
74
+ console.log("REMOVE", id);
75
+ view.removed = true;
76
+ this.playerViews.delete(id);
77
+ }
78
+ }
79
+
80
+ }
@@ -248,6 +248,14 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
248
248
  for (const key in typeInfo) {
249
249
  const serializedEntryInfo = typeInfo[key];
250
250
  const data = serializedData[key];
251
+
252
+
253
+ if (obj[key] !== undefined && data === undefined) {
254
+ // if a field is marked as serialized and has some default value
255
+ // but no data was serialized do not override the default value with undefined
256
+ continue;
257
+ }
258
+
251
259
  context.path = key;
252
260
 
253
261
  if (serializedEntryInfo === null) {
@@ -26,6 +26,7 @@ import { RendererData } from './engine_rendererdata';
26
26
  import { Addressables } from './engine_addressables';
27
27
  import { Application } from './engine_application';
28
28
  import { LightDataRegistry, ILightDataRegistry } from './engine_lightdata';
29
+ import { PlayerViewManager } from './engine_playerview';
29
30
 
30
31
 
31
32
  const debug = utils.getParam("debugSetup");
@@ -90,13 +91,26 @@ export class Context {
90
91
  isManagedExternally: boolean = false;
91
92
 
92
93
  domElement: HTMLElement;
94
+ get resolutionScaleFactor() { return this._resolutionScaleFactor; }
95
+ /** use to scale the resolution up or down of the renderer. default is 1 */
96
+ set resolutionScaleFactor(val: number) {
97
+ if(val === this._resolutionScaleFactor) return;
98
+ if(typeof val !== "number") return;
99
+ if(val <= 0) {
100
+ console.error("Invalid resolution scale factor", val);
101
+ return;
102
+ }
103
+ this._resolutionScaleFactor = val;
104
+ this.updateSize();
105
+ }
106
+ private _resolutionScaleFactor: number = 1;
93
107
  get domWidth(): number { return this.domElement.clientWidth; }
94
108
  get domHeight(): number { return this.domElement.clientHeight; }
95
109
  get domX(): number { return this.domElement.offsetLeft; }
96
110
  get domY(): number { return this.domElement.offsetTop; }
97
111
  get isInXR() { return this.renderer.xr?.isPresenting || false; }
98
112
  get xrSession() { return this.renderer.xr?.getSession(); }
99
- get AROverlayElement(): HTMLElement {
113
+ get arOverlayElement(): HTMLElement {
100
114
  const el = this.domElement as any;
101
115
  if (typeof el.getAROverlayContainer === "function")
102
116
  return el.getAROverlayContainer();
@@ -152,6 +166,7 @@ export class Context {
152
166
  rendererData: RendererData;
153
167
  addressables: Addressables;
154
168
  lightmaps: ILightDataRegistry;
169
+ players : PlayerViewManager;
155
170
 
156
171
  private _sizeChanged: boolean = false;
157
172
  private _isCreated: boolean = false;
@@ -199,6 +214,7 @@ export class Context {
199
214
  this.rendererData = new RendererData(this);
200
215
  this.addressables = new Addressables(this);
201
216
  this.lightmaps = new LightDataRegistry(this);
217
+ this.players = new PlayerViewManager(this);
202
218
 
203
219
  window.addEventListener('resize', this.updateSize.bind(this));
204
220
  const ro = new ResizeObserver(_ => this._sizeChanged = true);
@@ -208,12 +224,15 @@ export class Context {
208
224
  private updateSize() {
209
225
  if (!this.isManagedExternally && !this.renderer.xr.isPresenting) {
210
226
  this._sizeChanged = false;
211
- const width = this.domWidth;
212
- const height = this.domHeight;
227
+ const scaleFactor = this.resolutionScaleFactor;
228
+ const width = this.domWidth * scaleFactor;
229
+ const height = this.domHeight * scaleFactor;
213
230
  const camera = this.mainCamera as PerspectiveCamera;
214
231
  this.updateAspect(camera);
215
232
  this.renderer.setSize(width, height);
216
233
  this.renderer.setPixelRatio(window.devicePixelRatio);
234
+ this.renderer.domElement.style.width = this.domWidth + "px";
235
+ this.renderer.domElement.style.height = this.domHeight + "px";
217
236
  if (this.composer) {
218
237
  this.composer.setSize(width, height);
219
238
  this.composer.setPixelRatio(window.devicePixelRatio);
@@ -294,6 +313,21 @@ export class Context {
294
313
  (this.mainCameraComponent as Camera)?.applyClearFlagsIfIsActiveCamera();
295
314
  }
296
315
 
316
+ removeCamera(cam?: Camera | null) {
317
+ if(!cam) return;
318
+ const index = this._cameraStack.indexOf(cam);
319
+ if (index >= 0) this._cameraStack.splice(index, 1);
320
+
321
+ if (this.mainCameraComponent === cam) {
322
+ this.mainCameraComponent = undefined;
323
+
324
+ if (this._cameraStack.length > 0) {
325
+ const last = this._cameraStack[this._cameraStack.length - 1];
326
+ this.setCurrentCamera(last);
327
+ }
328
+ }
329
+ }
330
+
297
331
  private _onBeforeRenderListeners: { [key: string]: OnBeforeRenderCallback[] } = {};
298
332
 
299
333
  /** use this to subscribe to onBeforeRender events on threejs objects */
@@ -99,13 +99,14 @@ export class SceneLightSettings extends Behaviour {
99
99
  onEnable() {
100
100
  const isActive = this.context.mainCameraComponent?.sourceId === this.sourceId;
101
101
  if (debug)
102
- console.log("enable", this.sourceId, isActive, this, this.context.mainCameraComponent?.sourceId);
102
+ console.log("Enable scene lighting", this.sourceId, isActive, this, this.context.mainCameraComponent?.sourceId);
103
103
  if (!isActive) {
104
+ if(debug) console.warn("This is no active?!", this.context.mainCameraComponent?.sourceId)
104
105
  // this.enabled = false;
105
106
  // return;
106
107
  }
107
108
  if (this.ambientMode == AmbientMode.Flat) {
108
- if (this.ambientLight) {
109
+ if (this.ambientLight && !this._ambientLightObj) {
109
110
  this._ambientLightObj = new AmbientLight(this.ambientLight, Math.PI * this.ambientIntensity);
110
111
  }
111
112
  if (this._ambientLightObj) {
@@ -155,6 +156,7 @@ export class SceneLightSettings extends Behaviour {
155
156
  if (debug)
156
157
  console.log("disable", this.sourceId, this);
157
158
  if (this._lightProbeObj) this._lightProbeObj.removeFromParent();
159
+ if(this._ambientLightObj) this._ambientLightObj.removeFromParent();
158
160
  if (this.sourceId)
159
161
  this.context.rendererData.disableReflection();
160
162
  }
@@ -393,7 +393,7 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
393
393
  const val = materialExtension.values[key];
394
394
  if (typeof val === "string") {
395
395
  if (val.startsWith("/textures/")) {
396
- const indexString = val.substring(9);
396
+ const indexString = val.substring("/textures/".length);
397
397
  const texIndex = Number.parseInt(indexString);
398
398
  if (texIndex >= 0) {
399
399
  const tex = await this.parser.getDependency("texture", texIndex);
@@ -644,7 +644,7 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D {
644
644
  return object.getComponentsInChildren(typeName, go, arr);
645
645
  }
646
646
 
647
- public static getComponentInParent<T>(go: GameObject | THREE.Object3D, typeName: Constructor<T>): T | null {
647
+ public static getComponentInParent<T>(go: GameObject | THREE.Object3D | Array<Object3D>, typeName: Constructor<T>): T | null {
648
648
  return object.getComponentInParent(typeName, go);
649
649
  }
650
650
 
@@ -334,7 +334,10 @@ export class Light extends Behaviour {
334
334
  }
335
335
  }
336
336
 
337
+
337
338
  if (this.light !== undefined) {
339
+ this._intensity = this.light.intensity;
340
+
338
341
  if (this.shadows !== LightShadows.None) {
339
342
  this.light.castShadow = true;
340
343
  }
@@ -9,7 +9,6 @@ import { serializeable } from "../engine/engine_serialization_decorator";
9
9
  import { Vector3 } from "three";
10
10
 
11
11
  export class OrbitControls extends Behaviour {
12
-
13
12
  public get controls() {
14
13
  return this._controls;
15
14
  }
@@ -31,7 +30,7 @@ export class OrbitControls extends Behaviour {
31
30
  minZoom: number = 0;
32
31
  maxZoom: number = Infinity;
33
32
  enablePan: boolean = true;
34
- @serializeable(LookAtConstraint)
33
+ @serializeable()
35
34
  lookAtConstraint: LookAtConstraint | null = null;
36
35
  lookAtConstraint01: number = 1;
37
36
  middleClickToFocus: boolean = true;
@@ -61,7 +61,7 @@ export class ParticleSystem extends Behaviour {
61
61
 
62
62
  awake(): void {
63
63
  this.renderer = GameObject.getComponent(this.gameObject, ParticleSystemRenderer)!;
64
- if (debug)
64
+ // if (debug)
65
65
  console.log(this);
66
66
  }
67
67
 
@@ -108,31 +108,30 @@ export class ParticleSystem extends Behaviour {
108
108
  this.activeCount = this.main.prewarm ? this.main.maxParticles : 0;
109
109
  }
110
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
- // console.log(this.activeCount);
135
- }
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
+ // }
136
135
 
137
136
  emit(deltaTime: number) {
138
137
  const count = this.activeCount;
@@ -68,7 +68,7 @@ export class PlayerColor extends Behaviour {
68
68
  mesh.material = mat;
69
69
  // console.log("CLONE", mat);
70
70
  }
71
- else console.log("DONT CLONE", mat);
71
+ // else console.log("DONT CLONE", mat);
72
72
  mat["color"] = col;
73
73
  }
74
74