@needle-tools/engine 4.1.0-experimental.13 → 4.1.1

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 (238) hide show
  1. package/CHANGELOG.md +75 -10
  2. package/README.md +28 -17
  3. package/components.needle.json +1 -1
  4. package/dist/gltf-progressive.js +220 -221
  5. package/dist/gltf-progressive.light.js +220 -221
  6. package/dist/gltf-progressive.light.min.js +6 -6
  7. package/dist/gltf-progressive.light.umd.cjs +7 -7
  8. package/dist/gltf-progressive.min.js +6 -6
  9. package/dist/gltf-progressive.umd.cjs +7 -7
  10. package/dist/needle-engine.bundle.js +8241 -7948
  11. package/dist/needle-engine.bundle.light.js +8194 -7901
  12. package/dist/needle-engine.bundle.light.min.js +140 -141
  13. package/dist/needle-engine.bundle.light.umd.cjs +138 -139
  14. package/dist/needle-engine.bundle.min.js +140 -141
  15. package/dist/needle-engine.bundle.umd.cjs +134 -135
  16. package/dist/needle-engine.d.ts +140 -0
  17. package/dist/needle-engine.js +597 -590
  18. package/dist/needle-engine.light.d.ts +140 -0
  19. package/dist/needle-engine.light.js +597 -590
  20. package/dist/needle-engine.light.min.js +1 -1
  21. package/dist/needle-engine.light.umd.cjs +1 -1
  22. package/dist/needle-engine.min.js +1 -1
  23. package/dist/needle-engine.umd.cjs +1 -1
  24. package/dist/postprocessing.js +1 -1
  25. package/dist/postprocessing.light.js +1 -1
  26. package/dist/postprocessing.light.min.js +1 -1
  27. package/dist/postprocessing.min.js +1 -1
  28. package/dist/three-examples.js +2809 -2450
  29. package/dist/three-examples.light.js +2809 -2450
  30. package/dist/three-examples.light.min.js +47 -15
  31. package/dist/three-examples.light.umd.cjs +47 -15
  32. package/dist/three-examples.min.js +47 -15
  33. package/dist/three-examples.umd.cjs +47 -15
  34. package/dist/three-mesh-ui.js +1 -1
  35. package/dist/three-mesh-ui.light.js +1 -1
  36. package/dist/three-mesh-ui.light.min.js +1 -1
  37. package/dist/three-mesh-ui.min.js +1 -1
  38. package/dist/three.js +577 -572
  39. package/dist/three.light.js +577 -572
  40. package/dist/three.light.min.js +170 -170
  41. package/dist/three.light.umd.cjs +170 -170
  42. package/dist/three.min.js +170 -170
  43. package/dist/three.umd.cjs +170 -170
  44. package/dist/vendor.js +1327 -1331
  45. package/dist/vendor.light.js +1327 -1331
  46. package/dist/vendor.light.min.js +33 -33
  47. package/dist/vendor.light.umd.cjs +33 -33
  48. package/dist/vendor.min.js +33 -33
  49. package/dist/vendor.umd.cjs +33 -33
  50. package/lib/engine/assets/index.js.map +1 -1
  51. package/lib/engine/engine.d.ts +4 -0
  52. package/lib/engine/engine.js +12 -0
  53. package/lib/engine/engine.js.map +1 -0
  54. package/lib/engine/engine_addressables.d.ts +6 -4
  55. package/lib/engine/engine_addressables.js +8 -1
  56. package/lib/engine/engine_addressables.js.map +1 -1
  57. package/lib/engine/engine_context.d.ts +3 -2
  58. package/lib/engine/engine_context.js +28 -4
  59. package/lib/engine/engine_context.js.map +1 -1
  60. package/lib/engine/engine_gameobject.d.ts +2 -12
  61. package/lib/engine/engine_gameobject.js +5 -15
  62. package/lib/engine/engine_gameobject.js.map +1 -1
  63. package/lib/engine/engine_gltf_builtin_components.js +5 -0
  64. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  65. package/lib/engine/engine_input.d.ts +23 -6
  66. package/lib/engine/engine_input.js +4 -10
  67. package/lib/engine/engine_input.js.map +1 -1
  68. package/lib/engine/engine_license.js +1 -1
  69. package/lib/engine/engine_license.js.map +1 -1
  70. package/lib/engine/engine_modules.d.ts +7 -0
  71. package/lib/engine/engine_modules.js +7 -0
  72. package/lib/engine/engine_modules.js.map +1 -1
  73. package/lib/engine/engine_networking_auto.js +6 -11
  74. package/lib/engine/engine_networking_auto.js.map +1 -1
  75. package/lib/engine/engine_networking_instantiate.d.ts +1 -1
  76. package/lib/engine/engine_physics_rapier.d.ts +6 -4
  77. package/lib/engine/engine_physics_rapier.js +38 -24
  78. package/lib/engine/engine_physics_rapier.js.map +1 -1
  79. package/lib/engine/engine_scenetools.js +6 -2
  80. package/lib/engine/engine_scenetools.js.map +1 -1
  81. package/lib/engine/engine_types.d.ts +9 -2
  82. package/lib/engine/engine_types.js +6 -0
  83. package/lib/engine/engine_types.js.map +1 -1
  84. package/lib/engine/engine_web_api.d.ts +12 -0
  85. package/lib/engine/engine_web_api.js +113 -0
  86. package/lib/engine/engine_web_api.js.map +1 -0
  87. package/lib/engine/export/gltf/Writers.js.map +1 -1
  88. package/lib/engine/export/gltf/index.js +11 -1
  89. package/lib/engine/export/gltf/index.js.map +1 -1
  90. package/lib/engine/export/utils.d.ts +2 -0
  91. package/lib/engine/export/utils.js +8 -0
  92. package/lib/engine/export/utils.js.map +1 -0
  93. package/lib/engine/extensions/NEEDLE_gameobject_data.js +1 -1
  94. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  95. package/lib/engine/js-extensions/Object3D.d.ts +5 -1
  96. package/lib/engine/js-extensions/Object3D.js.map +1 -1
  97. package/lib/engine/webcomponents/needle menu/needle-menu.js +8 -2
  98. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  99. package/lib/engine/xr/NeedleXRSession.js +3 -0
  100. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  101. package/lib/engine-components/AvatarLoader.js.map +1 -1
  102. package/lib/engine-components/Camera.d.ts +7 -4
  103. package/lib/engine-components/Camera.js +13 -10
  104. package/lib/engine-components/Camera.js.map +1 -1
  105. package/lib/engine-components/Collider.js +4 -5
  106. package/lib/engine-components/Collider.js.map +1 -1
  107. package/lib/engine-components/Component.d.ts +4 -3
  108. package/lib/engine-components/Component.js +6 -7
  109. package/lib/engine-components/Component.js.map +1 -1
  110. package/lib/engine-components/ContactShadows.d.ts +1 -1
  111. package/lib/engine-components/ContactShadows.js +7 -0
  112. package/lib/engine-components/ContactShadows.js.map +1 -1
  113. package/lib/engine-components/FlyControls.d.ts +10 -0
  114. package/lib/engine-components/FlyControls.js +29 -0
  115. package/lib/engine-components/FlyControls.js.map +1 -0
  116. package/lib/engine-components/GroundProjection.d.ts +1 -1
  117. package/lib/engine-components/GroundProjection.js +39 -32
  118. package/lib/engine-components/GroundProjection.js.map +1 -1
  119. package/lib/engine-components/OrbitControls.js +9 -1
  120. package/lib/engine-components/OrbitControls.js.map +1 -1
  121. package/lib/engine-components/RigidBody.d.ts +1 -0
  122. package/lib/engine-components/RigidBody.js +11 -4
  123. package/lib/engine-components/RigidBody.js.map +1 -1
  124. package/lib/engine-components/SceneSwitcher.d.ts +1 -1
  125. package/lib/engine-components/SceneSwitcher.js +1 -1
  126. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  127. package/lib/engine-components/SpatialTrigger.d.ts +2 -2
  128. package/lib/engine-components/SpatialTrigger.js +4 -4
  129. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  130. package/lib/engine-components/TransformGizmo.d.ts +7 -1
  131. package/lib/engine-components/TransformGizmo.js +39 -32
  132. package/lib/engine-components/TransformGizmo.js.map +1 -1
  133. package/lib/engine-components/VideoPlayer.js +0 -1
  134. package/lib/engine-components/VideoPlayer.js.map +1 -1
  135. package/lib/engine-components/export/gltf/GltfExport.js +23 -4
  136. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  137. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +1 -1
  138. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +2 -2
  139. package/lib/engine-components/export/usdz/index.d.ts +1 -1
  140. package/lib/engine-components/export/usdz/index.js +1 -1
  141. package/lib/engine-components/export/usdz/index.js.map +1 -1
  142. package/lib/engine-components/particlesystem/ParticleSystem.d.ts +5 -6
  143. package/lib/engine-components/particlesystem/ParticleSystem.js +24 -9
  144. package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
  145. package/lib/engine-components/particlesystem/ParticleSystemModules.js +8 -2
  146. package/lib/engine-components/particlesystem/ParticleSystemModules.js.map +1 -1
  147. package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
  148. package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
  149. package/lib/engine-components/postprocessing/Effects/ChromaticAberration.js.map +1 -1
  150. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js.map +1 -1
  151. package/lib/engine-components/postprocessing/Effects/Pixelation.js.map +1 -1
  152. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js.map +1 -1
  153. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js.map +1 -1
  154. package/lib/engine-components/postprocessing/Effects/Sharpening.d.ts +2 -0
  155. package/lib/engine-components/postprocessing/Effects/Sharpening.js +15 -6
  156. package/lib/engine-components/postprocessing/Effects/Sharpening.js.map +1 -1
  157. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js.map +1 -1
  158. package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
  159. package/lib/engine-components/postprocessing/Effects/Vignette.js.map +1 -1
  160. package/lib/engine-components/postprocessing/PostProcessingHandler.js +1 -1
  161. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  162. package/lib/engine-components/webxr/Avatar.js +3 -3
  163. package/lib/engine-components/webxr/Avatar.js.map +1 -1
  164. package/lib/engine-components/webxr/WebXR.js +22 -13
  165. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  166. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +4 -0
  167. package/lib/engine-components/webxr/WebXRImageTracking.js +14 -4
  168. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  169. package/lib/engine-components/webxr/WebXRRig.d.ts +11 -1
  170. package/lib/engine-components/webxr/WebXRRig.js +13 -1
  171. package/lib/engine-components/webxr/WebXRRig.js.map +1 -1
  172. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +4 -1
  173. package/lib/engine-components-experimental/networking/PlayerSync.js +18 -30
  174. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  175. package/lib/needle-engine.js +5 -5
  176. package/lib/needle-engine.js.map +1 -1
  177. package/package.json +14 -8
  178. package/plugins/common/config.cjs +22 -6
  179. package/plugins/common/config.js +27 -11
  180. package/plugins/next/next.js +47 -4
  181. package/plugins/vite/transform.js +3 -3
  182. package/src/engine/assets/index.ts +1 -0
  183. package/src/engine/codegen/register_types.ts +2 -2
  184. package/src/engine/engine_addressables.ts +19 -12
  185. package/src/engine/engine_context.ts +33 -8
  186. package/src/engine/engine_gameobject.ts +12 -16
  187. package/src/engine/engine_gltf_builtin_components.ts +7 -1
  188. package/src/engine/engine_input.ts +16 -5
  189. package/src/engine/engine_license.ts +2 -1
  190. package/src/engine/engine_modules.ts +7 -0
  191. package/src/engine/engine_networking_auto.ts +7 -22
  192. package/src/engine/engine_networking_instantiate.ts +1 -1
  193. package/src/engine/engine_physics_rapier.ts +48 -26
  194. package/src/engine/engine_scenetools.ts +6 -2
  195. package/src/engine/engine_types.ts +10 -2
  196. package/src/engine/export/gltf/Writers.ts +0 -1
  197. package/src/engine/export/gltf/index.ts +13 -3
  198. package/src/engine/export/index.ts +1 -1
  199. package/src/engine/export/utils.ts +10 -0
  200. package/src/engine/extensions/NEEDLE_gameobject_data.ts +1 -2
  201. package/src/engine/js-extensions/Object3D.ts +6 -1
  202. package/src/engine/webcomponents/needle menu/needle-menu.ts +16 -10
  203. package/src/engine/xr/NeedleXRSession.ts +4 -1
  204. package/src/engine-components/AvatarLoader.ts +1 -1
  205. package/src/engine-components/Camera.ts +14 -11
  206. package/src/engine-components/Collider.ts +4 -4
  207. package/src/engine-components/Component.ts +13 -7
  208. package/src/engine-components/ContactShadows.ts +11 -2
  209. package/src/engine-components/GroundProjection.ts +46 -38
  210. package/src/engine-components/OrbitControls.ts +9 -1
  211. package/src/engine-components/RigidBody.ts +13 -5
  212. package/src/engine-components/SceneSwitcher.ts +1 -1
  213. package/src/engine-components/SpatialTrigger.ts +6 -6
  214. package/src/engine-components/TransformGizmo.ts +41 -33
  215. package/src/engine-components/VideoPlayer.ts +0 -1
  216. package/src/engine-components/export/gltf/GltfExport.ts +26 -6
  217. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2 -2
  218. package/src/engine-components/export/usdz/index.ts +1 -1
  219. package/src/engine-components/particlesystem/ParticleSystem.ts +27 -10
  220. package/src/engine-components/particlesystem/ParticleSystemModules.ts +10 -3
  221. package/src/engine-components/postprocessing/Effects/Antialiasing.ts +0 -1
  222. package/src/engine-components/postprocessing/Effects/BloomEffect.ts +1 -1
  223. package/src/engine-components/postprocessing/Effects/ChromaticAberration.ts +1 -1
  224. package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +1 -1
  225. package/src/engine-components/postprocessing/Effects/Pixelation.ts +1 -1
  226. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +1 -1
  227. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +1 -1
  228. package/src/engine-components/postprocessing/Effects/Sharpening.ts +17 -7
  229. package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +0 -1
  230. package/src/engine-components/postprocessing/Effects/Tonemapping.ts +1 -1
  231. package/src/engine-components/postprocessing/Effects/Vignette.ts +1 -1
  232. package/src/engine-components/postprocessing/PostProcessingHandler.ts +2 -3
  233. package/src/engine-components/webxr/Avatar.ts +3 -3
  234. package/src/engine-components/webxr/WebXR.ts +23 -14
  235. package/src/engine-components/webxr/WebXRImageTracking.ts +23 -8
  236. package/src/engine-components/webxr/WebXRRig.ts +15 -2
  237. package/src/engine-components-experimental/networking/PlayerSync.ts +18 -37
  238. package/src/needle-engine.ts +5 -5
@@ -1,5 +1,4 @@
1
1
  import type { Ball, Collider, ColliderDesc, Cuboid, EventQueue, QueryFilterFlags, Ray, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat';
2
-
3
2
  import { BufferAttribute, BufferGeometry, InterleavedBufferAttribute, LineBasicMaterial, LineSegments, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from 'three'
4
3
  import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
5
4
 
@@ -10,6 +9,7 @@ import { ContextEvent, ContextRegistry } from './engine_context_registry.js';
10
9
  import { foreachComponent } from './engine_gameobject.js';
11
10
  import { Gizmos } from './engine_gizmos.js';
12
11
  import { Mathf } from './engine_math.js';
12
+ import { MODULES } from './engine_modules.js';
13
13
  import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils.js"
14
14
  import type {
15
15
  IBoxCollider,
@@ -26,7 +26,6 @@ import type {
26
26
  import { Collision, ContactPoint } from './engine_types.js';
27
27
  import { SphereOverlapResult } from './engine_types.js';
28
28
  import { CircularBuffer, getParam } from "./engine_utils.js"
29
- import { MODULES } from './engine_modules.js';
30
29
 
31
30
  const debugPhysics = getParam("debugphysics");
32
31
  const debugColliderPlacement = getParam("debugcolliderplacement");
@@ -51,12 +50,8 @@ if (NEEDLE_USE_RAPIER) {
51
50
  ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, evt => {
52
51
  if (debugPhysics)
53
52
  console.log("Register rapier physics backend")
54
- evt.context.physics.engine = new RapierPhysics();
55
- // We want the physics engine to be initialized on start so when components start to enable and modify values they don't have delays
56
- // TODO: should the promise be returned here to make the engine creation wait?
57
- if (NEEDLE_USE_RAPIER) {
58
- evt.context.physics.engine.initialize(evt.context);
59
- }
53
+ evt.context.physics.engine = new RapierPhysics(evt.context);
54
+ // We do not initialize physics immediately to avoid loading the physics engine if it is not needed
60
55
  });
61
56
  }
62
57
 
@@ -238,12 +233,17 @@ export class RapierPhysics implements IPhysicsEngine {
238
233
  else console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
239
234
  }
240
235
 
241
- private context?: IContext;
236
+ private readonly context?: IContext;
242
237
  private _initializePromise?: Promise<boolean>;
243
238
  private _isInitialized: boolean = false;
244
239
 
245
- async initialize(context: IContext) {
246
- this.context = context;
240
+ constructor(ctx: IContext) {
241
+ this.context = ctx;
242
+ }
243
+
244
+ get isInitialized() { return this._isInitialized; }
245
+
246
+ async initialize() {
247
247
  if (!this._initializePromise)
248
248
  this._initializePromise = this.internalInitialization();
249
249
  return this._initializePromise;
@@ -270,7 +270,7 @@ export class RapierPhysics implements IPhysicsEngine {
270
270
  }
271
271
  this._hasCreatedWorld = true;
272
272
  if (MODULES.RAPIER_PHYSICS.MAYBEMODULE == undefined) {
273
- if(debugPhysics) console.trace("Loading rapier physics engine");
273
+ if (debugPhysics) console.trace("Loading rapier physics engine");
274
274
  const module = await MODULES.RAPIER_PHYSICS.load();
275
275
  await module.init();
276
276
  }
@@ -317,6 +317,11 @@ export class RapierPhysics implements IPhysicsEngine {
317
317
  })
318
318
  : null | { point: Vector3, collider: ICollider } {
319
319
 
320
+ if (!this._isInitialized) {
321
+ console.log("Physics engine is not initialized");
322
+ return null;
323
+ }
324
+
320
325
  let maxDistance = options?.maxDistance;
321
326
  let solid = options?.solid;
322
327
 
@@ -363,6 +368,10 @@ export class RapierPhysics implements IPhysicsEngine {
363
368
  })
364
369
  : null | { point: Vector3, normal: Vector3, collider: ICollider } {
365
370
 
371
+ if (!this._isInitialized) {
372
+ return null;
373
+ }
374
+
366
375
  let maxDistance = options?.maxDistance;
367
376
  let solid = options?.solid;
368
377
 
@@ -449,7 +458,7 @@ export class RapierPhysics implements IPhysicsEngine {
449
458
 
450
459
 
451
460
  private rapierSphere: Ball | null = null;
452
- private rapierColliderArray: Array<SphereOverlapResult> = [];
461
+ private readonly rapierColliderArray: Array<SphereOverlapResult> = [];
453
462
  private readonly rapierIdentityRotation = { x: 0, y: 0, z: 0, w: 1 };
454
463
  private readonly rapierForwardVector = { x: 0, y: 0, z: 1 };
455
464
  /** Precice sphere overlap detection using rapier against colliders
@@ -459,6 +468,9 @@ export class RapierPhysics implements IPhysicsEngine {
459
468
  */
460
469
  public sphereOverlap(point: Vector3, radius: number): Array<SphereOverlapResult> {
461
470
  this.rapierColliderArray.length = 0;
471
+ if (!this._isInitialized) {
472
+ return this.rapierColliderArray;
473
+ }
462
474
  if (!this.world) return this.rapierColliderArray;
463
475
  this.rapierSphere ??= new MODULES.RAPIER_PHYSICS.MODULE.Ball(radius);
464
476
  this.rapierSphere.radius = radius;
@@ -574,7 +586,7 @@ export class RapierPhysics implements IPhysicsEngine {
574
586
 
575
587
  async addBoxCollider(collider: ICollider, size: Vector3) {
576
588
  if (!this._isInitialized)
577
- await this.initialize(collider.context);
589
+ await this.initialize();
578
590
  if (!collider.activeAndEnabled) return;
579
591
 
580
592
  if (!this.enabled) {
@@ -608,7 +620,7 @@ export class RapierPhysics implements IPhysicsEngine {
608
620
 
609
621
  async addSphereCollider(collider: ICollider) {
610
622
  if (!this._isInitialized)
611
- await this.initialize(collider.context);
623
+ await this.initialize();
612
624
  if (!collider.activeAndEnabled) return;
613
625
  if (!this.enabled) {
614
626
  if (debugPhysics) console.warn("Physics are disabled");
@@ -621,7 +633,7 @@ export class RapierPhysics implements IPhysicsEngine {
621
633
 
622
634
  async addCapsuleCollider(collider: ICollider, height: number, radius: number) {
623
635
  if (!this._isInitialized)
624
- await this.initialize(collider.context);
636
+ await this.initialize();
625
637
  if (!collider.activeAndEnabled) return;
626
638
  if (!this.enabled) {
627
639
  if (debugPhysics) console.warn("Physics are disabled");
@@ -640,14 +652,9 @@ export class RapierPhysics implements IPhysicsEngine {
640
652
  this.createCollider(collider, desc);
641
653
  }
642
654
 
643
- async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3) {
644
- if (!this._isInitialized)
645
- await this.initialize(collider.context);
646
- if (!collider.activeAndEnabled) return;
647
- if (!this.enabled) {
648
- if (debugPhysics) console.warn("Physics are disabled");
649
- return;
650
- }
655
+ async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, extraScale?: Vector3) {
656
+
657
+ // capture the geometry before waiting for phyiscs engine
651
658
  let geo = mesh.geometry;
652
659
  if (!geo) {
653
660
  if (debugPhysics) console.warn("Missing mesh geometry", mesh.name);
@@ -679,12 +686,25 @@ export class RapierPhysics implements IPhysicsEngine {
679
686
  positions = positionAttribute.array as Float32Array;
680
687
  }
681
688
 
689
+ await this.initialize();
690
+
691
+ if (!this.enabled) {
692
+ if (debugPhysics) console.warn("Physics are disabled");
693
+ return;
694
+ }
695
+
696
+ if (!collider.activeAndEnabled) return;
697
+
698
+
682
699
  // let positions = geo.getAttribute("position").array as Float32Array;
683
700
  const indices = geo.index?.array as Uint32Array;
701
+
702
+ const scale = collider.gameObject.worldScale.clone();
703
+ if(extraScale) scale.multiply(extraScale);
684
704
 
685
705
  // scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
686
706
  if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
687
- const key = geo.uuid + "_" + scale.x + "_" + scale.y + "_" + scale.z + "_" + convex;
707
+ const key = `${geo.uuid}_${scale.x}_${scale.y}_${scale.z}_${convex}`;
688
708
  if (this._meshCache.has(key)) {
689
709
  if (debugPhysics) console.warn("Use cached mesh collider")
690
710
  positions = this._meshCache.get(key)!;
@@ -701,7 +721,9 @@ export class RapierPhysics implements IPhysicsEngine {
701
721
  this._meshCache.set(key, scaledPositions);
702
722
  }
703
723
  }
704
- const desc = convex ? MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.convexHull(positions) : MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.trimesh(positions, indices);
724
+ const desc = convex
725
+ ? MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.convexHull(positions)
726
+ : MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.trimesh(positions, indices);
705
727
  if (desc) {
706
728
  this.createCollider(collider, desc);
707
729
  // col.setMassProperties(1, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 });
@@ -183,10 +183,14 @@ export async function parseSync(context: Context, data: string | ArrayBuffer, pa
183
183
  // https://threejs.org/docs/#examples/en/loaders/GLTFLoader.parse
184
184
  // so we make sure that "path" is never a file path
185
185
  let gltfLoaderPath = path.split("?")[0].trimEnd();
186
- if (gltfLoaderPath.endsWith(".glb") || gltfLoaderPath.endsWith(".gltf")) {
186
+ // This assumes that the path is a FILE path and not already a directory
187
+ // (it does not end with "/") – see https://linear.app/needle/issue/NE-6075
188
+ {
187
189
  // strip file from path
188
190
  const parts = gltfLoaderPath.split("/");
189
- parts.pop();
191
+ // check if the last part is a /, otherwise remove it
192
+ if (parts.length > 0 && parts[parts.length - 1] !== "")
193
+ parts.pop();
190
194
  gltfLoaderPath = parts.join("/");
191
195
  if (!gltfLoaderPath.endsWith("/")) gltfLoaderPath += "/";
192
196
  }
@@ -90,6 +90,12 @@ export declare interface INeedleEngineComponent extends HTMLElement {
90
90
  onExitAR(session: XRSession);
91
91
  }
92
92
 
93
+ export enum HideFlags {
94
+ None = 0,
95
+ /** When enabled the glTF exporter will omit this object and all children from being exported */
96
+ DontExport = 1 << 0,
97
+ }
98
+
93
99
  export declare interface IGameObject extends Object3D {
94
100
 
95
101
  /** the object's unique identifier */
@@ -290,6 +296,7 @@ export declare interface IBoxCollider extends ICollider {
290
296
  }
291
297
 
292
298
  export declare interface IRigidbody extends IComponent {
299
+ get isRigidbody(): boolean;
293
300
  constraints: RigidbodyConstraints;
294
301
  isKinematic: boolean;
295
302
  /** When true the mass will automatically calculated by attached colliders */
@@ -435,7 +442,8 @@ export class SphereOverlapResult {
435
442
 
436
443
 
437
444
  export interface IPhysicsEngine {
438
- initialize(ctx: IContext): Promise<boolean>;
445
+ initialize(): Promise<boolean>;
446
+ get isInitialized(): boolean;
439
447
  step(dt: number): void;
440
448
  postStep();
441
449
  get isUpdating(): boolean;
@@ -488,7 +496,7 @@ export interface IPhysicsEngine {
488
496
  addSphereCollider(collider: ICollider);
489
497
  addBoxCollider(collider: ICollider, size: Vector3);
490
498
  addCapsuleCollider(collider: ICollider, radius: number, height: number);
491
- addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3);
499
+ addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale?: Vector3 | undefined);
492
500
 
493
501
  updatePhysicsMaterial(collider: ICollider);
494
502
 
@@ -1,4 +1,3 @@
1
-
2
1
  import { Object3D, Texture } from 'three';
3
2
  import { GLTFExporterPlugin, GLTFWriter } from 'three/examples/jsm/exporters/GLTFExporter.js';
4
3
 
@@ -6,6 +6,7 @@ import { AnimationUtils } from "../../engine_animation.js";
6
6
  import type { Context } from "../../engine_setup.js";
7
7
  import { registerExportExtensions } from "../../extensions/index.js";
8
8
  import { __isExporting } from "../state.js";
9
+ import { shouldExport_HideFlags } from "../utils.js";
9
10
  import { GizmoWriter as GLTFGizmoWriter, RenderTextureWriter as GLTFRenderTextureWriter } from "./Writers.js";
10
11
 
11
12
  declare type ExportOptions = {
@@ -49,8 +50,7 @@ export async function exportAsGLTF(_opts: ExportOptions): Promise<ArrayBuffer |
49
50
  animations: collectAnimations(context, opts.scene, []),
50
51
  }
51
52
  const state = new ExporterState();
52
-
53
- console.log("Exporting GLTF", exporterOptions);
53
+ console.debug("Exporting GLTF", exporterOptions);
54
54
  state.onBeforeExport(opts);
55
55
  __isExporting(true);
56
56
  const res = await exporter.parseAsync(opts.scene, exporterOptions).catch((e) => {
@@ -108,7 +108,17 @@ class ExporterState {
108
108
  }
109
109
  }
110
110
  mixer.update(0);
111
- })
111
+ });
112
+
113
+ opts.context.scene.traverse(obj => {
114
+ if(!shouldExport_HideFlags(obj)) {
115
+ const parent = obj.parent;
116
+ if(parent) {
117
+ obj.removeFromParent();
118
+ this._undo.push(() => parent.add(obj));
119
+ }
120
+ }
121
+ });
112
122
  }
113
123
 
114
124
  onAfterExport(_opts: Required<ExportOptions>) {
@@ -1,2 +1,2 @@
1
1
  export * from "./gltf/index.js";
2
- export { isExporting } from "./state.js";
2
+ export { isExporting } from "./state.js";
@@ -0,0 +1,10 @@
1
+ import { Object3D } from "three";
2
+
3
+ import { HideFlags } from "../engine_types.js";
4
+
5
+
6
+ export function shouldExport_HideFlags(obj: Object3D) {
7
+ const dontExport = HideFlags.DontExport;
8
+ if (obj.hideFlags & dontExport) return false;
9
+ return true;
10
+ }
@@ -7,7 +7,6 @@ declare type GameObjectData = {
7
7
  layers: number,
8
8
  visible: boolean,
9
9
  tag: string,
10
- hideFlags: number,
11
10
  static: boolean,
12
11
  activeSelf: boolean,
13
12
  guid: string
@@ -71,7 +70,7 @@ export class NEEDLE_gameobject_data implements GLTFLoaderPlugin {
71
70
 
72
71
  node.userData.tag = ext.tag ?? "none";
73
72
 
74
- node.userData.hideFlags = ext.hideFlags ?? 0;
73
+ node.hideFlags = 0;
75
74
 
76
75
  node.userData.static = ext.static ?? false;
77
76
 
@@ -15,7 +15,7 @@ import {
15
15
  setWorldScale
16
16
  }
17
17
  from "../../engine/engine_three_utils.js";
18
- import type { ComponentInit, Constructor, ConstructorConcrete, IComponent as Component, IComponent } from "../../engine/engine_types.js";
18
+ import type { ComponentInit, Constructor, ConstructorConcrete, HideFlags,IComponent as Component, IComponent } from "../../engine/engine_types.js";
19
19
  import { applyPrototypeExtensions, registerPrototypeExtensions } from "./ExtensionUtils.js";
20
20
 
21
21
 
@@ -26,6 +26,11 @@ declare module 'three' {
26
26
  get guid(): string | undefined;
27
27
  set guid(value: string | undefined);
28
28
 
29
+ /**
30
+ * Allows to control e.g. if an object should be exported
31
+ */
32
+ hideFlags: HideFlags;
33
+
29
34
  /**
30
35
  * Add a Needle Engine component to the {@link Object3D}.
31
36
  * @param comp The component instance or constructor to add.
@@ -1,7 +1,7 @@
1
1
  import type { Context } from "../../engine_context.js";
2
2
  import { hasCommercialLicense, onLicenseCheckResultChanged } from "../../engine_license.js";
3
3
  import { isLocalNetwork } from "../../engine_networking_utils.js";
4
- import { DeviceUtilities,getParam } from "../../engine_utils.js";
4
+ import { DeviceUtilities, getParam } from "../../engine_utils.js";
5
5
  import { onXRSessionStart, XRSessionEventArgs } from "../../xr/events.js";
6
6
  import { ButtonsFactory } from "../buttons.js";
7
7
  import { ensureFonts, iconFontUrl, loadFont } from "../fonts.js";
@@ -256,7 +256,12 @@ export class NeedleMenuElement extends HTMLElement {
256
256
  if (!element && domElement.shadowRoot) {
257
257
  element = domElement.shadowRoot.querySelector(elementName);
258
258
  }
259
+ // if no needle-menu was found in the domelement then we search the document body
259
260
  if (!element) {
261
+ element = window.document.body.querySelector(elementName) as NeedleMenuElement | null;
262
+ }
263
+ if (!element) {
264
+ // OK no menu element exists yet anywhere
260
265
  element = NeedleMenuElement.create() as NeedleMenuElement;
261
266
  if (domElement.shadowRoot)
262
267
  domElement.shadowRoot.appendChild(element);
@@ -682,14 +687,15 @@ export class NeedleMenuElement extends HTMLElement {
682
687
  });
683
688
 
684
689
  try {
685
- // if the user has a license then we CAN hide the needle logo
686
- onLicenseCheckResultChanged(res => {
687
- if (res == true && hasCommercialLicense() && !debugNonCommercial) {
688
- let visible = this._userRequestedLogoVisible;
689
- if(visible === undefined) visible = false;
690
- this.#onSetLogoVisible(visible);
691
- }
692
- });
690
+ // if the user has a license then we CAN hide the needle logo
691
+ // calling this method immediately will cause an issue with vite bundling tho
692
+ window.requestAnimationFrame(() => onLicenseCheckResultChanged(res => {
693
+ if (res == true && hasCommercialLicense() && !debugNonCommercial) {
694
+ let visible = this._userRequestedLogoVisible;
695
+ if (visible === undefined) visible = false;
696
+ this.#onSetLogoVisible(visible);
697
+ }
698
+ }));
693
699
  } catch (e) {
694
700
  console.error("[Needle Menu] License check failed.", e);
695
701
  }
@@ -824,7 +830,7 @@ export class NeedleMenuElement extends HTMLElement {
824
830
  this.logoContainer.style.display = "";
825
831
  this.logoContainer.style.opacity = "1";
826
832
  this.logoContainer.style.visibility = "visible";
827
- if(visible) {
833
+ if (visible) {
828
834
  this.root.classList.remove("logo-hidden");
829
835
  this.root.classList.add("logo-visible");
830
836
  }
@@ -582,7 +582,7 @@ export class NeedleXRSession implements INeedleXRSession {
582
582
  * The XRSession interface's read-only interactionMode property describes the best space (according to the user agent) for the application to draw an interactive UI for the current session.
583
583
  * @link https://developer.mozilla.org/en-US/docs/Web/API/XRSession/interactionMode
584
584
  */
585
- get interactionMode(): "screen-space" | "world-space" { return this.session["interactionMode"]; }
585
+ get interactionMode(): "screen-space" | "world-space" { return this.session["interactionMode"]!; }
586
586
 
587
587
  /**
588
588
  * @link https://developer.mozilla.org/en-US/docs/Web/API/XRSession/visibilityState
@@ -712,8 +712,11 @@ export class NeedleXRSession implements INeedleXRSession {
712
712
  /** Sets a XRRig to be active which will parent the camera to this rig */
713
713
  setRigActive(rig: IXRRig) {
714
714
  const i = this._rigs.indexOf(rig);
715
+ const currentlyActive = this._rigs[0];
715
716
  this._rigs.splice(i, 1);
716
717
  this._rigs.unshift(rig);
718
+ // if there's another rig currently active we need to make sure we have at least the same priority
719
+ rig.priority = currentlyActive?.priority ?? 0;
717
720
  this.updateActiveXRRig();
718
721
  }
719
722
  /**
@@ -52,7 +52,7 @@ export class AvatarLoader {
52
52
  if (!root) {
53
53
  const opts = new InstantiateOptions();
54
54
  // opts.parent = context.scene.uuid;
55
- root = GameObject.instantiate(utils.tryFindObject(avatarId, context.scene), opts);
55
+ root = GameObject.instantiate(utils.tryFindObject(avatarId, context.scene) as Object3D, opts);
56
56
  }
57
57
  }
58
58
  else root = avatarId;
@@ -51,7 +51,7 @@ export class Camera extends Behaviour implements ICamera {
51
51
  }
52
52
  }
53
53
  }
54
- /** The camera's field of view in degrees if it is a perspective camera */
54
+ /** The camera's field of view in degrees if it is a perspective camera. Calls updateProjectionMatrix when set */
55
55
  get fieldOfView(): number | undefined {
56
56
  if (this._cam instanceof PerspectiveCamera) {
57
57
  return this._cam.fov;
@@ -74,7 +74,7 @@ export class Camera extends Behaviour implements ICamera {
74
74
  }
75
75
  }
76
76
 
77
- /** The camera's near clipping plane */
77
+ /** The camera's near clipping plane. Calls updateProjectionMatrix when set */
78
78
  get nearClipPlane(): number { return this._nearClipPlane; }
79
79
  @serializable()
80
80
  set nearClipPlane(val) {
@@ -87,15 +87,7 @@ export class Camera extends Behaviour implements ICamera {
87
87
  }
88
88
  private _nearClipPlane: number = 0.1;
89
89
 
90
- applyClippingPlane() {
91
- if (this._cam) {
92
- this._cam.near = this._nearClipPlane;
93
- this._cam.far = this._farClipPlane;
94
- this._cam.updateProjectionMatrix();
95
- }
96
- }
97
-
98
- /** The camera's far clipping plane */
90
+ /** The camera's far clipping plane. Calls updateProjectionMatrix when set */
99
91
  get farClipPlane(): number { return this._farClipPlane; }
100
92
  @serializable()
101
93
  set farClipPlane(val) {
@@ -108,6 +100,17 @@ export class Camera extends Behaviour implements ICamera {
108
100
  }
109
101
  private _farClipPlane: number = 1000;
110
102
 
103
+ /**
104
+ * Applys both the camera's near and far plane and calls updateProjectionMatrix on the camera.
105
+ */
106
+ applyClippingPlane() {
107
+ if (this._cam) {
108
+ this._cam.near = this._nearClipPlane;
109
+ this._cam.far = this._farClipPlane;
110
+ this._cam.updateProjectionMatrix();
111
+ }
112
+ }
113
+
111
114
  /** The camera's clear flags - determines if the background is a skybox or a solid color or transparent */
112
115
  @serializable()
113
116
  public get clearFlags(): ClearFlags {
@@ -207,12 +207,12 @@ export class MeshCollider extends Collider {
207
207
  const LOD = 0;
208
208
 
209
209
  if (this.sharedMesh?.isMesh) {
210
- this.context.physics.engine.addMeshCollider(this, this.sharedMesh, this.convex, getWorldScale(this.gameObject));
210
+ this.context.physics.engine.addMeshCollider(this, this.sharedMesh, this.convex);
211
211
  NEEDLE_progressive.assignMeshLOD(this.sharedMesh, LOD).then(res => {
212
212
  if (res && this.activeAndEnabled && this.context.physics.engine && this.sharedMesh) {
213
213
  this.context.physics.engine.removeBody(this);
214
214
  this.sharedMesh.geometry = res;
215
- this.context.physics.engine.addMeshCollider(this, this.sharedMesh, this.convex, getWorldScale(this.gameObject));
215
+ this.context.physics.engine.addMeshCollider(this, this.sharedMesh, this.convex);
216
216
  }
217
217
  })
218
218
  }
@@ -224,7 +224,7 @@ export class MeshCollider extends Collider {
224
224
  for (const ch in group.children) {
225
225
  const child = group.children[ch] as Mesh;
226
226
  if (child.isMesh) {
227
- this.context.physics.engine.addMeshCollider(this, child, this.convex, getWorldScale(this.gameObject));
227
+ this.context.physics.engine.addMeshCollider(this, child, this.convex);
228
228
  promises.push(NEEDLE_progressive.assignMeshLOD(child, LOD));
229
229
  }
230
230
  }
@@ -235,7 +235,7 @@ export class MeshCollider extends Collider {
235
235
  for (const r of res) {
236
236
  if (r && this.activeAndEnabled) {
237
237
  mesh.geometry = r;
238
- this.context.physics.engine?.addMeshCollider(this, mesh, this.convex, getWorldScale(this.gameObject));
238
+ this.context.physics.engine?.addMeshCollider(this, mesh, this.convex);
239
239
  }
240
240
  }
241
241
  });
@@ -1,9 +1,10 @@
1
1
  import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three";
2
2
 
3
3
  import { isDevEnvironment } from "../engine/debug/index.js";
4
+ import { type AssetReference } from "../engine/engine_addressables.js";
4
5
  import { addComponent, destroyComponentInstance, findObjectOfType, findObjectsOfType, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../engine/engine_components.js";
5
6
  import { activeInHierarchyFieldName } from "../engine/engine_constants.js";
6
- import { destroy, findByGuid, foreachComponent, HideFlags, type IInstantiateOptions, instantiate, isActiveInHierarchy, isActiveSelf, isDestroyed, isUsingInstancing, markAsInstancedRendered, setActive } from "../engine/engine_gameobject.js";
7
+ import { destroy, findByGuid, foreachComponent, type IInstantiateOptions, instantiate, isActiveInHierarchy, isActiveSelf, isDestroyed, isUsingInstancing, markAsInstancedRendered, setActive } from "../engine/engine_gameobject.js";
7
8
  import * as main from "../engine/engine_mainloop_utils.js";
8
9
  import { syncDestroy, syncInstantiate, SyncInstantiateOptions } from "../engine/engine_networking_instantiate.js";
9
10
  import { Context, FrameEvent } from "../engine/engine_setup.js";
@@ -117,15 +118,20 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
117
118
  */
118
119
  public static instantiateSynced(instance: GameObject | Object3D | null, opts: SyncInstantiateOptions): GameObject | null {
119
120
  if (!instance) return null;
120
- return syncInstantiate(instance as any, opts) as GameObject | null;
121
+ return syncInstantiate(instance, opts) as GameObject | null;
121
122
  }
122
123
 
123
124
  /** Creates a new instance of the provided object (like cloning it including all components and children)
124
125
  * @param instance object to instantiate
125
126
  * @param opts options for the instantiation (e.g. with what parent, position, etc.)
126
127
  */
127
- public static instantiate(instance: GameObject | Object3D, opts: IInstantiateOptions | null = null): GameObject {
128
- return instantiate(instance, opts) as GameObject;
128
+ public static instantiate(instance: AssetReference, opts?: IInstantiateOptions | null | undefined): Promise<Object3D | null>
129
+ public static instantiate(instance: GameObject | Object3D, opts?: IInstantiateOptions | null | undefined): GameObject
130
+ public static instantiate(instance: AssetReference | GameObject | Object3D, opts: IInstantiateOptions | null | undefined = null): GameObject | Promise<Object3D | null> {
131
+ if ('isAssetReference' in instance) {
132
+ return instantiate(instance as AssetReference, opts);
133
+ }
134
+ return instantiate(instance as GameObject | Object3D, opts) as GameObject;
129
135
  }
130
136
 
131
137
  /** Destroys a object on all connected clients (if you are in a networked session)
@@ -398,9 +404,9 @@ export abstract class Component implements IComponent, EventTarget,
398
404
  this.gameObject.userData.static = value;
399
405
  }
400
406
  }
401
- get hideFlags(): HideFlags {
402
- return this.gameObject?.userData.hideFlags;
403
- }
407
+ // get hideFlags(): HideFlags {
408
+ // return this.gameObject?.hideFlags;
409
+ // }
404
410
 
405
411
  /** @returns true if the object is enabled and active in the hierarchy */
406
412
  get activeAndEnabled(): boolean {
@@ -9,7 +9,7 @@ import { Gizmos } from "../engine/engine_gizmos.js";
9
9
  import { onStart } from "../engine/engine_lifecycle_api.js";
10
10
  import { serializable } from "../engine/engine_serialization_decorator.js";
11
11
  import { getBoundingBox, getVisibleInCustomShadowRendering } from "../engine/engine_three_utils.js";
12
- import { IGameObject, Vec3 } from "../engine/engine_types.js";
12
+ import { HideFlags, IGameObject, Vec3 } from "../engine/engine_types.js";
13
13
  import { getParam } from "../engine/engine_utils.js"
14
14
  import { setCustomVisibility } from "../engine/js-extensions/Layers.js";
15
15
  import { Behaviour, GameObject } from "./Component.js";
@@ -37,7 +37,7 @@ onStart(ctx => {
37
37
  */
38
38
  export class ContactShadows extends Behaviour {
39
39
 
40
- private static _instances: Map<Context, ContactShadows> = new Map();
40
+ private static readonly _instances: Map<Context, ContactShadows> = new Map();
41
41
  /**
42
42
  * Create contact shadows for the scene. Automatically fits the shadows to the scene.
43
43
  * The instance of contact shadows will be created only once.
@@ -162,10 +162,14 @@ export class ContactShadows extends Behaviour {
162
162
 
163
163
  /** @internal */
164
164
  awake() {
165
+ ContactShadows._instances.set(this.context, this);
166
+ this.shadowsRoot.hideFlags = HideFlags.DontExport;
167
+
165
168
  // ignore self for autofitting
166
169
  setAutoFitEnabled(this.shadowsRoot, false);
167
170
  }
168
171
 
172
+
169
173
  /** @internal */
170
174
  start(): void {
171
175
  if (debug) console.log("Create ContactShadows on " + this.gameObject.name, this)
@@ -280,6 +284,11 @@ export class ContactShadows extends Behaviour {
280
284
 
281
285
  /** @internal */
282
286
  onDestroy(): void {
287
+ const instance = ContactShadows._instances.get(this.context);
288
+ if (instance === this) {
289
+ ContactShadows._instances.delete(this.context);
290
+ }
291
+
283
292
  // dispose the render targets
284
293
  this.renderTarget?.dispose();
285
294
  this.renderTargetBlur?.dispose();