@needle-tools/engine 2.29.0-pre → 2.31.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 (101) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/needle-engine.d.ts +847 -757
  3. package/dist/needle-engine.js +347 -343
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +16 -12
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine.d.ts +1 -0
  8. package/lib/engine/engine_physics.d.ts +19 -8
  9. package/lib/engine/engine_physics.js +57 -48
  10. package/lib/engine/engine_physics.js.map +1 -1
  11. package/lib/engine/engine_serialization.d.ts +1 -0
  12. package/lib/engine/engine_serialization.js +1 -0
  13. package/lib/engine/engine_serialization.js.map +1 -1
  14. package/lib/engine/engine_setup.d.ts +5 -0
  15. package/lib/engine/engine_setup.js +6 -0
  16. package/lib/engine/engine_setup.js.map +1 -1
  17. package/lib/engine/engine_utils.d.ts +1 -1
  18. package/lib/engine/engine_utils.js +25 -8
  19. package/lib/engine/engine_utils.js.map +1 -1
  20. package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +1 -1
  21. package/lib/engine/extensions/NEEDLE_deferred_texture.js +26 -14
  22. package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +1 -1
  23. package/lib/engine/extensions/extension_utils.js +24 -13
  24. package/lib/engine/extensions/extension_utils.js.map +1 -1
  25. package/lib/engine/extensions/extensions.js +3 -1
  26. package/lib/engine/extensions/extensions.js.map +1 -1
  27. package/lib/engine-components/Camera.js +7 -1
  28. package/lib/engine-components/Camera.js.map +1 -1
  29. package/lib/engine-components/Component.d.ts +10 -0
  30. package/lib/engine-components/Component.js +53 -0
  31. package/lib/engine-components/Component.js.map +1 -1
  32. package/lib/engine-components/OrbitControls.js +2 -1
  33. package/lib/engine-components/OrbitControls.js.map +1 -1
  34. package/lib/engine-components/Renderer.d.ts +1 -0
  35. package/lib/engine-components/Renderer.js +10 -3
  36. package/lib/engine-components/Renderer.js.map +1 -1
  37. package/lib/engine-components/Rigidbody.d.ts +1 -1
  38. package/lib/engine-components/Rigidbody.js +3 -3
  39. package/lib/engine-components/Rigidbody.js.map +1 -1
  40. package/lib/engine-components/ScreenCapture.d.ts +35 -5
  41. package/lib/engine-components/ScreenCapture.js +542 -25
  42. package/lib/engine-components/ScreenCapture.js.map +1 -1
  43. package/lib/engine-components/SpectatorCamera.js +29 -5
  44. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  45. package/lib/engine-components/SyncedRoom.js +2 -0
  46. package/lib/engine-components/SyncedRoom.js.map +1 -1
  47. package/lib/engine-components/VideoPlayer.d.ts +14 -1
  48. package/lib/engine-components/VideoPlayer.js +86 -16
  49. package/lib/engine-components/VideoPlayer.js.map +1 -1
  50. package/lib/engine-components/Volume.d.ts +4 -0
  51. package/lib/engine-components/Volume.js +44 -3
  52. package/lib/engine-components/Volume.js.map +1 -1
  53. package/lib/engine-components/WebARSessionRoot.d.ts +9 -2
  54. package/lib/engine-components/WebARSessionRoot.js +69 -24
  55. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  56. package/lib/engine-components/WebXR.d.ts +6 -3
  57. package/lib/engine-components/WebXR.js +42 -7
  58. package/lib/engine-components/WebXR.js.map +1 -1
  59. package/lib/engine-components/WebXRAvatar.js +4 -0
  60. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  61. package/lib/engine-components/WebXRController.js +13 -7
  62. package/lib/engine-components/WebXRController.js.map +1 -1
  63. package/lib/engine-components/ui/CanvasGroup.d.ts +1 -0
  64. package/lib/engine-components/ui/CanvasGroup.js +1 -0
  65. package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
  66. package/lib/engine-components/ui/EventSystem.js +13 -4
  67. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  68. package/lib/engine-components/ui/Graphic.d.ts +1 -0
  69. package/lib/engine-components/ui/Graphic.js +2 -0
  70. package/lib/engine-components/ui/Graphic.js.map +1 -1
  71. package/lib/engine-components/ui/Interfaces.d.ts +2 -0
  72. package/lib/needle-engine.d.ts +1 -0
  73. package/lib/needle-engine.js +1 -0
  74. package/lib/needle-engine.js.map +1 -1
  75. package/package.json +2 -2
  76. package/src/engine/engine_physics.ts +74 -57
  77. package/src/engine/engine_serialization.ts +3 -1
  78. package/src/engine/engine_setup.ts +6 -0
  79. package/src/engine/engine_utils.ts +34 -8
  80. package/src/engine/extensions/NEEDLE_deferred_texture.ts +25 -19
  81. package/src/engine/extensions/extension_utils.ts +24 -12
  82. package/src/engine/extensions/extensions.ts +3 -2
  83. package/src/engine-components/Camera.ts +9 -2
  84. package/src/engine-components/Component.ts +58 -0
  85. package/src/engine-components/OrbitControls.ts +2 -1
  86. package/src/engine-components/Renderer.ts +11 -3
  87. package/src/engine-components/RigidBody.ts +2 -2
  88. package/src/engine-components/ScreenCapture.ts +610 -28
  89. package/src/engine-components/SpectatorCamera.ts +28 -5
  90. package/src/engine-components/SyncedRoom.ts +1 -0
  91. package/src/engine-components/VideoPlayer.ts +123 -23
  92. package/src/engine-components/Volume.ts +47 -4
  93. package/src/engine-components/WebARSessionRoot.ts +78 -28
  94. package/src/engine-components/WebXR.ts +50 -15
  95. package/src/engine-components/WebXRAvatar.ts +5 -0
  96. package/src/engine-components/WebXRController.ts +20 -14
  97. package/src/engine-components/ui/CanvasGroup.ts +2 -0
  98. package/src/engine-components/ui/EventSystem.ts +21 -15
  99. package/src/engine-components/ui/Graphic.ts +3 -0
  100. package/src/engine-components/ui/Interfaces.ts +2 -0
  101. package/src/needle-engine.ts +1 -0
@@ -72,6 +72,11 @@ export enum FrameEvent {
72
72
  PhysicsStep = 10,
73
73
  }
74
74
 
75
+ export enum XRSessionMode {
76
+ ImmersiveVR = "immersive-vr",
77
+ ImmersiveAR = "immersive-ar",
78
+ }
79
+
75
80
  export declare type OnBeforeRenderCallback = (renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, geometry: THREE.BufferGeometry, material: THREE.Material, group: THREE.Group) => void
76
81
 
77
82
  export class Context {
@@ -109,6 +114,7 @@ export class Context {
109
114
  get domX(): number { return this.domElement.offsetLeft; }
110
115
  get domY(): number { return this.domElement.offsetTop; }
111
116
  get isInXR() { return this.renderer.xr?.isPresenting || false; }
117
+ xrSessionMode : XRSessionMode | undefined = undefined;
112
118
  get xrSession() { return this.renderer.xr?.getSession(); }
113
119
  get arOverlayElement(): HTMLElement {
114
120
  const el = this.domElement as any;
@@ -181,17 +181,43 @@ export function delay(milliseconds: number): Promise<void> {
181
181
  // if a timeline is exported via menu item the audio clip path is relative to the glb (same folder)
182
182
  // we need to detect that here and build the new audio source path relative to the new glb location
183
183
  // the same is/might be true for any file that is/will be exported via menu item
184
- export function getPath(glbLocation: SourceIdentifier | undefined, path: string) {
185
- if (path && glbLocation && !path.includes("/")) {
186
- // get directory of glb and prepend it to the audio file path
187
- const pathIndex = glbLocation.lastIndexOf("/");
188
- if (pathIndex >= 0) {
189
- const newPath = glbLocation.substring(0, pathIndex + 1) + path;
190
- return newPath;
184
+ const debugGetPath = getParam("debugsourcepath");
185
+ export function getPath(source: SourceIdentifier | undefined, uri: string): string {
186
+ if (source === undefined) {
187
+ if (debugGetPath) console.warn("getPath: source is undefined, returning uri", uri);
188
+ return uri;
189
+ }
190
+ if (uri.startsWith("http")) {
191
+ if (debugGetPath) console.warn("getPath: uri is absolute, returning uri", uri);
192
+ return uri;
193
+ }
194
+ const pathIndex = source.lastIndexOf("/");
195
+ if (pathIndex >= 0) {
196
+ let newUri = source.substring(0, pathIndex + 1);
197
+
198
+ const uriDirectoryIndex = uri.lastIndexOf("/");
199
+ if (uriDirectoryIndex >= 0) {
200
+ newUri += uri.substring(uriDirectoryIndex + 1);
201
+ } else {
202
+ newUri += uri;
191
203
  }
204
+ if (debugGetPath) console.log("getPath:", source, " - changed uri from\n", uri, "\n→ ", newUri);
205
+ return newUri;
192
206
  }
193
- return path;
207
+ return uri;
194
208
  }
209
+ // export function getPath(glbLocation: SourceIdentifier | undefined, path: string) {
210
+ // if (path && glbLocation && !path.includes("/")) {
211
+ // // get directory of glb and prepend it to the audio file path
212
+ // const pathIndex = glbLocation.lastIndexOf("/");
213
+ // if (pathIndex >= 0) {
214
+ // const newPath = glbLocation.substring(0, pathIndex + 1) + path;
215
+ // return newPath;
216
+ // }
217
+ // }
218
+ // return path;
219
+ // }
220
+
195
221
 
196
222
  export type WriteCallback = (data: any) => void;
197
223
 
@@ -3,7 +3,7 @@ import { GLTF, GLTFLoader, GLTFLoaderPlugin, GLTFParser } from "three/examples/j
3
3
  import { SourceIdentifier } from "../engine_gltf";
4
4
  import { Context } from "../engine_setup";
5
5
  import { addDracoAndKTX2Loaders } from "../engine_loaders";
6
- import { getParam } from "../engine_utils";
6
+ import { getParam, getPath } from "../engine_utils";
7
7
 
8
8
  export const EXTENSION_NAME = "NEEDLE_deferred_texture";
9
9
 
@@ -11,24 +11,27 @@ const debug = getParam("debugdeferredtextures")
11
11
 
12
12
  declare type DeferredTextureModel = {
13
13
  uri: string;
14
- guid?: string;
14
+ guid: string;
15
15
  usage?: string,
16
16
  }
17
17
 
18
18
  export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
19
19
 
20
- static assignTextureLOD(context: Context, material: Material, level: number = 0) {
20
+ static assignTextureLOD(context: Context, source : SourceIdentifier | undefined, material: Material, level: number = 0) {
21
21
  if (!material) return;
22
22
  for (const slot of Object.keys(material)) {
23
23
  const val = material[slot];
24
24
  if (val?.isTexture === true) {
25
25
  if (debug)
26
- console.log("FIND", slot, val?.name, val?.userData, val);
27
- NEEDLE_deferred_texture.getOrLoadTexture(context, material, slot, val, level).then(t => {
26
+ console.log("-----------\n", "FIND", material.name, slot, val?.name, val?.userData, val);
27
+ NEEDLE_deferred_texture.getOrLoadTexture(context, source, material, slot, val, level).then(t => {
28
28
  if (t?.isTexture === true) {
29
29
  t.needsUpdate = true;
30
+ if (debug)
31
+ console.log("Assign LOD", material.name, slot, t.name, t["guid"], material, "Prev:", val, "Now:", t, "\n--------------");
30
32
  material[slot] = t;
31
33
  material.needsUpdate = true;
34
+
32
35
  }
33
36
  });
34
37
  }
@@ -67,9 +70,8 @@ export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
67
70
  // }
68
71
 
69
72
  afterRoot(gltf: GLTF): null {
70
-
71
73
  if (debug)
72
- console.log("AFTER", gltf);
74
+ console.log("AFTER", this.sourceId, gltf);
73
75
  this.parser.json.textures?.forEach((textureInfo, index) => {
74
76
  if (textureInfo?.extensions) {
75
77
  const ext: DeferredTextureModel = textureInfo?.extensions[EXTENSION_NAME];
@@ -91,29 +93,31 @@ export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
91
93
  private static cache = new Map<string, DeferredTextureModel>();
92
94
  private static resolved: { [key: string]: Texture } = {};
93
95
 
94
- private static async getOrLoadTexture(context: Context, material: Material, slot: string, current: Texture, _level: number): Promise<Texture | null> {
96
+ private static async getOrLoadTexture(context: Context, source : SourceIdentifier | undefined, material: Material, slot: string, current: Texture, _level: number): Promise<Texture | null> {
95
97
 
96
98
  const key = current.uuid;
97
- const ext: DeferredTextureModel = NEEDLE_deferred_texture.cache.get(key) || current.userData.deferred;
99
+ const ext: DeferredTextureModel | undefined = NEEDLE_deferred_texture.cache.get(key);// || current.userData.deferred;
98
100
  if (ext) {
99
101
  if (debug)
100
102
  console.log(key, ext.uri, ext.guid);
101
- const uri = ext.uri;
103
+ const uri = getPath(source, ext.uri);
102
104
  if (uri.endsWith(".glb") || uri.endsWith(".gltf")) {
103
105
  if (!ext.guid) {
104
106
  console.warn("missing pointer for glb/gltf texture", ext);
105
107
  return null;
106
108
  }
107
- const resolveKey = ext.uri + "_" + ext.guid;
108
- if (this.resolved[resolveKey])
109
+ const resolveKey = uri + "_" + ext.guid;
110
+ if (this.resolved[resolveKey]) {
111
+ if (debug) console.log("Texture has already been loaded: " + resolveKey, material.name, slot, current.name);
109
112
  return this.resolved[resolveKey];
113
+ }
110
114
 
111
115
  const loader = new GLTFLoader();
112
116
  addDracoAndKTX2Loaders(loader, context);
113
- if (debug) console.log("Load " + uri, material.name, slot);
117
+ if (debug) console.log("Load " + uri, material.name, slot, ext.guid);
114
118
  const gltf = await loader.loadAsync(uri);
115
119
  const parser = gltf.parser;
116
-
120
+ if (debug) console.log("Loading finished " + uri, material.name, slot, ext.guid);
117
121
  let index = -1;
118
122
  let found = false;
119
123
  for (const tex of gltf.parser.json.textures) {
@@ -137,20 +141,22 @@ export class NEEDLE_deferred_texture implements GLTFLoaderPlugin {
137
141
 
138
142
  // const index = Number.parseInt(ext.pointer.substring("textures/".length));
139
143
  const tex = await parser.getDependency("texture", index);
144
+ if (tex) {
145
+ tex.guid = ext.guid;
146
+ }
140
147
  this.resolved[resolveKey] = tex as Texture;
141
-
142
148
  if (debug)
143
- console.log(material.name, slot, "change \"" + current.name + "\" → \"" + tex.name + "\"", uri, index, tex, material);
149
+ console.log(material.name, slot, "change \"" + current.name + "\" → \"" + tex.name + "\"", uri, index, tex, material, resolveKey);
144
150
  return tex;
145
151
  }
146
152
  else {
147
-
153
+ if (debug) console.log("Load texture from uri: " + uri);
148
154
  const loader = new TextureLoader();
149
- const loaded = await loader.loadAsync(ext.uri);
155
+ const loaded = await loader.loadAsync(uri);
150
156
  if (loaded && debug) {
151
157
  console.log(ext, loaded);
152
158
  }
153
- else console.warn("failed loading", ext.uri);
159
+ else console.warn("failed loading", uri);
154
160
  return loaded;
155
161
  }
156
162
  // loader.then((h: Texture) => {
@@ -10,13 +10,20 @@ declare type DependencyInfo = {
10
10
  dependencyName: string,
11
11
  }
12
12
 
13
- const rootExtensionPrefix = "/extensions/";
13
+ const rootExtensionPrefix = ["/extensions/", "extensions/"];
14
14
  const defaultDependencies = [
15
15
  { prefix: "/nodes/", dependencyName: "node" },
16
16
  { prefix: "/meshes/", dependencyName: "mesh" },
17
17
  { prefix: "/materials/", dependencyName: "material" },
18
18
  { prefix: "/textures/", dependencyName: "texture" },
19
- { prefix: "/animations/", dependencyName: "animation" }
19
+ { prefix: "/animations/", dependencyName: "animation" },
20
+
21
+ // legacy support
22
+ { prefix: "nodes/", dependencyName: "node" },
23
+ { prefix: "meshes/", dependencyName: "mesh" },
24
+ { prefix: "materials/", dependencyName: "material" },
25
+ { prefix: "textures/", dependencyName: "texture" },
26
+ { prefix: "animations/", dependencyName: "animation" },
20
27
  ]
21
28
 
22
29
  export async function resolveReferences(parser: GLTFParser, obj) {
@@ -95,16 +102,21 @@ function internalResolve(paths: DependencyInfo[], parser: GLTFParser, obj, promi
95
102
 
96
103
 
97
104
  function resolveExtension(parser: GLTFParser, str): Promise<void> | null {
98
- if (parser && parser.plugins && typeof str === "string" && str.startsWith(rootExtensionPrefix)) {
99
- let name = str.substring(rootExtensionPrefix.length);
100
- const endIndex = name.indexOf("/");
101
- if (endIndex >= 0) name = name.substring(0, endIndex);
102
- const ext = parser.plugins[name] as IExtensionReferenceResolver;
103
- if (debugExtension)
104
- console.log(name, ext);
105
- if (typeof ext?.resolve === "function") {
106
- const path = str.substring(rootExtensionPrefix.length + name.length + 1);
107
- return ext.resolve(parser, path);
105
+ if (parser && parser.plugins && typeof str === "string") {
106
+ for (const prefix of rootExtensionPrefix) {
107
+ if (str.startsWith(prefix)) {
108
+ let name = str.substring(prefix.length);
109
+ const endIndex = name.indexOf("/");
110
+ if (endIndex >= 0) name = name.substring(0, endIndex);
111
+ const ext = parser.plugins[name] as IExtensionReferenceResolver;
112
+ if (debugExtension)
113
+ console.log(name, ext);
114
+ if (typeof ext?.resolve === "function") {
115
+ const path = str.substring(prefix.length + name.length + 1);
116
+ return ext.resolve(parser, path);
117
+ }
118
+ break;
119
+ }
108
120
  }
109
121
  }
110
122
  return null;
@@ -26,8 +26,9 @@ export function registerComponentExtension(loader: GLTFLoader): NEEDLE_component
26
26
  class PointerResolver {
27
27
  resolvePath(path: string) {
28
28
  if (path.includes('/extensions/builtin_components/'))
29
- path = path.replace('/extensions/builtin_components/', '/userData/components/');
30
-
29
+ return path.replace('/extensions/builtin_components/', '/userData/components/');
30
+ if (path.includes('extensions/builtin_components/'))
31
+ return path.replace('extensions/builtin_components/', '/userData/components/');
31
32
  return path;
32
33
  }
33
34
  }
@@ -5,6 +5,7 @@ import { getParam } from "../engine/engine_utils";
5
5
  import { serializeable } from "../engine/engine_serialization_decorator";
6
6
  import { RGBAColor } from "./js-extensions/RGBAColor";
7
7
  import { PerspectiveCamera } from "three";
8
+ import { XRSessionMode } from "../engine/engine_setup";
8
9
 
9
10
  export enum ClearFlags {
10
11
  Skybox = 1,
@@ -159,7 +160,6 @@ export class Camera extends Behaviour {
159
160
  }
160
161
 
161
162
  applyClearFlagsIfIsActiveCamera() {
162
- // TODO: need to differentiate between what kind of XR (set skybox in VR but not in mobile AR for example!?)
163
163
  if (this._cam && this.context.mainCameraComponent === this) {
164
164
  switch (this._clearFlags) {
165
165
  case ClearFlags.Skybox:
@@ -192,13 +192,20 @@ export class Camera extends Behaviour {
192
192
  }
193
193
 
194
194
  private environmentIsTransparent(): boolean {
195
- const session = this.context.renderer.xr?.getSession()
195
+ const session = this.context.renderer.xr?.getSession();
196
196
  if (!session) return false;
197
197
  const environmentBlendMode = session.environmentBlendMode;
198
198
  const transparent = environmentBlendMode === 'additive' || environmentBlendMode === 'alpha-blend';
199
+ // workaround for Quest 2 returning opaque when it should be alpha-blend
200
+ // check user agent if this is the Quest browser and return true if so
201
+
202
+ if (environmentBlendMode === "opaque" && navigator.userAgent?.includes("OculusBrowser")) {
203
+ if (this.context.xrSessionMode === XRSessionMode.ImmersiveAR) return true;
204
+ }
199
205
  return transparent;
200
206
  }
201
207
 
208
+
202
209
  private enableSkybox() {
203
210
  if (!this._skybox)
204
211
  this._skybox = new CameraSkybox(this);
@@ -9,6 +9,7 @@ import * as main from "../engine/engine_mainloop_utils";
9
9
  import { Object3D } from "three";
10
10
  import { InstantiateIdProvider, syncDestroy, syncInstantiate } from "../engine/engine_networking_instantiate";
11
11
  import { SourceIdentifier } from "../engine/engine_gltf";
12
+ import { Collision } from "../engine/engine_physics";
12
13
 
13
14
  export interface UIDProvider {
14
15
  seed: number;
@@ -835,6 +836,10 @@ class Component implements EventTarget {
835
836
  onBeforeRender?(frame: THREE.XRFrame | null): void;
836
837
  onAfterRender?(): void;
837
838
 
839
+ onCollisionEnter?(col: Collision);
840
+ onCollisionExit?(col: Collision);
841
+ onCollisionStay?(col: Collision);
842
+
838
843
  startCoroutine(routine: Generator, evt: FrameEvent = FrameEvent.Update): Generator {
839
844
  return this.context.registerCoroutineUpdate(this, routine, evt);
840
845
  }
@@ -865,6 +870,7 @@ class Component implements EventTarget {
865
870
  this.__didEnable = false;
866
871
  this.__isEnabled = undefined;
867
872
  this.__destroyed = false;
873
+ this.__internalResetsCachedPhysicsData();
868
874
  }
869
875
 
870
876
  __internalAwake() {
@@ -892,6 +898,7 @@ class Component implements EventTarget {
892
898
  __internalDisable() {
893
899
  if (!this.__didEnable) return;
894
900
  this.__didEnable = false;
901
+ this._collisionExitRoutine = undefined;
895
902
  this.onDisable();
896
903
  }
897
904
 
@@ -899,6 +906,57 @@ class Component implements EventTarget {
899
906
  this.__internalNewInstanceCreated();
900
907
  }
901
908
 
909
+ private _collisionExitRoutine: any;
910
+ private _collisions: Map<Object3D, { col: Collision, frame: number }> | null = null;
911
+
912
+ private __internalResetsCachedPhysicsData() {
913
+ this._collisionExitRoutine = null;
914
+ this._collisions = null;
915
+ }
916
+
917
+ __internalHandleCollision(col: Collision) {
918
+ if (this.onCollisionEnter || this.onCollisionExit || this.onCollisionStay) {
919
+ const otherObject = col.gameObject;
920
+ if (!this._collisions) this._collisions = new Map();
921
+ if (this._collisions.has(otherObject)) {
922
+ const cur = this._collisions.get(otherObject)!;
923
+ cur.frame = this.context.time.frameCount;
924
+ cur.col = col;
925
+ this.onCollisionStay?.call(this, col);
926
+ }
927
+ else {
928
+ const entry = { col, frame: this.context.time.frameCount };
929
+ this._collisions.set(otherObject, entry);
930
+ this.onCollisionEnter?.call(this, col);
931
+ }
932
+ }
933
+ }
934
+
935
+ sendExitCollisionEvent(obj : Object3D) {
936
+ if(!this._collisions) return;
937
+ const col = this._collisions.get(obj);
938
+ if(!col) return;
939
+ this.onCollisionExit?.call(this, col.col);
940
+ this._collisions.delete(obj);
941
+ }
942
+
943
+ private __waitForCollisionExit() {
944
+ if (this._collisionExitRoutine) return;
945
+ // const self = this;
946
+ // function* routine() {
947
+ // while (self._collisions && self._collisions.size > 0) {
948
+ // for (let ob of self._collisions.keys()) {
949
+ // const entry = self._collisions!.get(ob)!;
950
+ // if (self.context.time.frameCount - entry.frame > 1) {
951
+ // self._collisions!.delete(ob);
952
+ // self.onCollisionExit?.call(self, entry.col);
953
+ // }
954
+ // }
955
+ // yield;
956
+ // }
957
+ // }
958
+ // this._collisionExitRoutine = this.startCoroutine(routine(), FrameEvent.EarlyUpdate);
959
+ }
902
960
 
903
961
 
904
962
  // TODO move this to threeutils
@@ -102,7 +102,8 @@ export class OrbitControls extends Behaviour {
102
102
  if (this._controls) {
103
103
  const camGo = GameObject.getComponent(this.gameObject, Camera);
104
104
  if (camGo && !this.setFromTargetPosition()) {
105
- console.log("NO TARGET");
105
+ if(this.debugLog)
106
+ console.log("NO TARGET");
106
107
  const forward = new THREE.Vector3(0, 0, -1).applyMatrix4(camGo.cam.matrixWorld);
107
108
  this.setTarget(forward, true);
108
109
  }
@@ -13,6 +13,7 @@ const suppressInstancing = getParam("noInstancing");
13
13
  const debugLightmap = getParam("debuglightmaps") ? true : false;
14
14
  const debugInstancing = getParam("debuginstancing");
15
15
  const debugProgressiveLoading = getParam("debugprogressiveload");
16
+ const suppressProgressiveLoading = getParam("noprogressiveload");
16
17
 
17
18
  export class FieldWithDefault {
18
19
  public path: string | null = null;
@@ -172,6 +173,8 @@ export class Renderer extends Behaviour {
172
173
  }
173
174
 
174
175
  awake() {
176
+ this.clearInstancingState();
177
+
175
178
  const type = this.gameObject.type;
176
179
  if (type === "Group") {
177
180
  for (const child of this.gameObject.children) {
@@ -245,6 +248,11 @@ export class Renderer extends Behaviour {
245
248
  private handles: InstanceHandle[] | null | undefined = undefined;
246
249
  private prevLayers: number[] | null | undefined = undefined;
247
250
 
251
+ private clearInstancingState() {
252
+ this._isInstancingEnabled = false;
253
+ this.handles = undefined;
254
+ this.prevLayers = undefined;
255
+ }
248
256
  setInstancingEnabled(enabled: boolean): boolean {
249
257
  if (this._isInstancingEnabled === enabled) return enabled && (this.handles === undefined || this.handles != null && this.handles.length > 0);
250
258
  this._isInstancingEnabled = enabled;
@@ -338,16 +346,16 @@ export class Renderer extends Behaviour {
338
346
  onBeforeRenderThree(_renderer, _scene, _camera, _geometry, material, _group) {
339
347
 
340
348
  // progressive load before rendering so we only load textures for visible materials
341
- if (material._didRequestTextureLOD === undefined) {
349
+ if (!suppressProgressiveLoading && material._didRequestTextureLOD === undefined) {
342
350
  material._didRequestTextureLOD = 0;
343
351
  if (debugProgressiveLoading) {
344
352
  console.log("Load material LOD (with delay)", material.name);
345
353
  setTimeout(() => {
346
- NEEDLE_deferred_texture.assignTextureLOD(this.context, material);
354
+ NEEDLE_deferred_texture.assignTextureLOD(this.context, this.sourceId, material);
347
355
  }, 2000);
348
356
  }
349
357
  else {
350
- NEEDLE_deferred_texture.assignTextureLOD(this.context, material);
358
+ NEEDLE_deferred_texture.assignTextureLOD(this.context, this.sourceId, material);
351
359
  }
352
360
  }
353
361
 
@@ -29,7 +29,7 @@ export class Rigidbody extends Behaviour {
29
29
  @serializeable()
30
30
  angularDrag: number = 1;
31
31
  @serializeable()
32
- detectCollision: boolean = true;
32
+ detectCollisions: boolean = true;
33
33
  @serializeable()
34
34
  sleepThreshold: number = 0.01;
35
35
 
@@ -106,7 +106,7 @@ export class Rigidbody extends Behaviour {
106
106
  options.angularDrag = this.angularDrag;
107
107
  options.mass = this.mass;
108
108
  options.kinematic = this.isKinematic;
109
- options.physicsEvents = this.detectCollision;
109
+ options.physicsEvents = this.detectCollisions;
110
110
  options.sleepThreshold = this.sleepThreshold;
111
111
  this._body = this.context.physics.createBody(this.gameObject, options);
112
112
  }