@needle-tools/engine 2.35.4-pre → 2.36.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 (142) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/needle-engine.d.ts +213 -144
  3. package/dist/needle-engine.js +414 -358
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +99 -43
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/api.d.ts +3 -0
  8. package/lib/engine/api.js +3 -0
  9. package/lib/engine/api.js.map +1 -1
  10. package/lib/engine/debug/debug.d.ts +3 -0
  11. package/lib/engine/debug/debug.js +8 -0
  12. package/lib/engine/debug/debug.js.map +1 -0
  13. package/lib/engine/debug/debug_overlay.d.ts +7 -0
  14. package/lib/engine/debug/debug_overlay.js +213 -0
  15. package/lib/engine/debug/debug_overlay.js.map +1 -0
  16. package/lib/engine/engine.js +1 -1
  17. package/lib/engine/engine.js.map +1 -1
  18. package/lib/engine/engine_element_loading.js +1 -1
  19. package/lib/engine/engine_element_loading.js.map +1 -1
  20. package/lib/engine/engine_gameobject.d.ts +1 -0
  21. package/lib/engine/engine_gameobject.js +13 -1
  22. package/lib/engine/engine_gameobject.js.map +1 -1
  23. package/lib/engine/engine_gltf_builtin_components.js +4 -0
  24. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  25. package/lib/engine/engine_mainloop_utils.d.ts +1 -1
  26. package/lib/engine/engine_mainloop_utils.js +7 -3
  27. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  28. package/lib/engine/engine_physics.d.ts +29 -28
  29. package/lib/engine/engine_physics.js +85 -86
  30. package/lib/engine/engine_physics.js.map +1 -1
  31. package/lib/engine/engine_serialization_core.js +43 -0
  32. package/lib/engine/engine_serialization_core.js.map +1 -1
  33. package/lib/engine/engine_setup.js +1 -1
  34. package/lib/engine/engine_setup.js.map +1 -1
  35. package/lib/engine/engine_time.d.ts +1 -0
  36. package/lib/engine/engine_time.js +1 -0
  37. package/lib/engine/engine_time.js.map +1 -1
  38. package/lib/engine/engine_types.d.ts +6 -1
  39. package/lib/engine/engine_types.js.map +1 -1
  40. package/lib/engine/engine_typestore.d.ts +1 -0
  41. package/lib/engine/engine_typestore.js +1 -0
  42. package/lib/engine/engine_typestore.js.map +1 -1
  43. package/lib/engine/engine_utils.js +1 -1
  44. package/lib/engine/engine_utils.js.map +1 -1
  45. package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
  46. package/lib/engine/extensions/NEEDLE_render_objects.d.ts +2 -2
  47. package/lib/engine/extensions/NEEDLE_render_objects.js +2 -2
  48. package/lib/engine/extensions/NEEDLE_render_objects.js.map +1 -1
  49. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +5 -0
  50. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  51. package/lib/engine-components/Animation.d.ts +5 -1
  52. package/lib/engine-components/Animation.js +21 -0
  53. package/lib/engine-components/Animation.js.map +1 -1
  54. package/lib/engine-components/AnimatorController.d.ts +1 -0
  55. package/lib/engine-components/AnimatorController.js +14 -7
  56. package/lib/engine-components/AnimatorController.js.map +1 -1
  57. package/lib/engine-components/AudioSource.d.ts +1 -1
  58. package/lib/engine-components/AudioSource.js +2 -2
  59. package/lib/engine-components/AudioSource.js.map +1 -1
  60. package/lib/engine-components/BoxHelperComponent.d.ts +2 -2
  61. package/lib/engine-components/BoxHelperComponent.js +27 -9
  62. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  63. package/lib/engine-components/Component.d.ts +2 -1
  64. package/lib/engine-components/Component.js +11 -5
  65. package/lib/engine-components/Component.js.map +1 -1
  66. package/lib/engine-components/GroundProjection.d.ts +2 -0
  67. package/lib/engine-components/GroundProjection.js +18 -6
  68. package/lib/engine-components/GroundProjection.js.map +1 -1
  69. package/lib/engine-components/ReflectionProbe.d.ts +22 -0
  70. package/lib/engine-components/ReflectionProbe.js +134 -0
  71. package/lib/engine-components/ReflectionProbe.js.map +1 -0
  72. package/lib/engine-components/Renderer.d.ts +16 -4
  73. package/lib/engine-components/Renderer.js +96 -45
  74. package/lib/engine-components/Renderer.js.map +1 -1
  75. package/lib/engine-components/WebARSessionRoot.d.ts +7 -7
  76. package/lib/engine-components/WebARSessionRoot.js +7 -7
  77. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  78. package/lib/engine-components/WebXR.d.ts +9 -8
  79. package/lib/engine-components/WebXR.js +40 -24
  80. package/lib/engine-components/WebXR.js.map +1 -1
  81. package/lib/engine-components/WebXRAvatar.d.ts +4 -5
  82. package/lib/engine-components/WebXRAvatar.js +9 -8
  83. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  84. package/lib/engine-components/WebXRController.d.ts +21 -21
  85. package/lib/engine-components/WebXRController.js +83 -63
  86. package/lib/engine-components/WebXRController.js.map +1 -1
  87. package/lib/engine-components/WebXRGrabRendering.d.ts +3 -3
  88. package/lib/engine-components/WebXRGrabRendering.js +2 -2
  89. package/lib/engine-components/WebXRGrabRendering.js.map +1 -1
  90. package/lib/engine-components/WebXRSync.d.ts +8 -8
  91. package/lib/engine-components/WebXRSync.js +15 -15
  92. package/lib/engine-components/WebXRSync.js.map +1 -1
  93. package/lib/engine-components/codegen/components.d.ts +1 -0
  94. package/lib/engine-components/codegen/components.js +1 -0
  95. package/lib/engine-components/codegen/components.js.map +1 -1
  96. package/lib/engine-components/js-extensions/ExtensionUtils.js +1 -1
  97. package/lib/engine-components/js-extensions/ExtensionUtils.js.map +1 -1
  98. package/lib/engine-components/ui/EventSystem.d.ts +1 -0
  99. package/lib/engine-components/ui/EventSystem.js +21 -1
  100. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  101. package/package.json +1 -1
  102. package/src/engine/api.ts +3 -0
  103. package/src/engine/codegen/register_types.js +293 -0
  104. package/src/engine/debug/debug.ts +9 -0
  105. package/src/engine/debug/debug_overlay.ts +224 -0
  106. package/src/engine/engine.ts +1 -1
  107. package/src/engine/engine_element_loading.ts +1 -1
  108. package/src/engine/engine_gameobject.ts +17 -4
  109. package/src/engine/engine_gltf_builtin_components.ts +5 -1
  110. package/src/engine/engine_mainloop_utils.ts +7 -3
  111. package/src/engine/engine_physics.ts +130 -130
  112. package/src/engine/engine_serialization_core.ts +41 -0
  113. package/src/engine/engine_setup.ts +1 -1
  114. package/src/engine/engine_time.ts +2 -0
  115. package/src/engine/engine_types.ts +7 -1
  116. package/src/engine/engine_typestore.ts +2 -0
  117. package/src/engine/engine_utils.ts +3 -2
  118. package/src/engine/extensions/EXT_texture_exr.js +1 -1
  119. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +2 -1
  120. package/src/engine/extensions/NEEDLE_render_objects.ts +4 -4
  121. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +7 -0
  122. package/src/engine-components/Animation.ts +16 -1
  123. package/src/engine-components/AnimatorController.ts +19 -9
  124. package/src/engine-components/AudioSource.ts +3 -3
  125. package/src/engine-components/BoxHelperComponent.ts +29 -9
  126. package/src/engine-components/Component.ts +11 -5
  127. package/src/engine-components/GroundProjection.ts +22 -7
  128. package/src/engine-components/ReflectionProbe.ts +141 -0
  129. package/src/engine-components/Renderer.ts +116 -54
  130. package/src/engine-components/WebARSessionRoot.ts +16 -16
  131. package/src/engine-components/WebXR.ts +53 -48
  132. package/src/engine-components/WebXRAvatar.ts +16 -16
  133. package/src/engine-components/WebXRController.ts +133 -107
  134. package/src/engine-components/WebXRGrabRendering.ts +6 -6
  135. package/src/engine-components/WebXRSync.ts +20 -20
  136. package/src/engine-components/codegen/components.ts +1 -0
  137. package/src/engine-components/js-extensions/ExtensionUtils.ts +1 -1
  138. package/src/engine-components/ui/EventSystem.ts +26 -3
  139. package/lib/engine/debug/error_overlay.d.ts +0 -1
  140. package/lib/engine/debug/error_overlay.js +0 -114
  141. package/lib/engine/debug/error_overlay.js.map +0 -1
  142. package/src/engine/debug/error_overlay.ts +0 -126
@@ -1,27 +1,26 @@
1
- import * as CANNON from 'cannon-es'
2
- import * as THREE from 'three'
1
+ import { Body, Box, Constraint, Vec3, World, Sphere as PhysicsSphere, Quaternion as PhysicsQuaternion } from 'cannon-es'
2
+ import { Box3, Camera, Intersection, Layers, Matrix4, Mesh, Object3D, Quaternion, Ray, Raycaster, Sphere, Vector2, Vector3 } from 'three'
3
3
  import { Context } from './engine_setup';
4
4
  import cannonDebugger from 'cannon-es-debugger'
5
- import * as utils from "./engine_utils"
6
- import * as threeutils from "./engine_three_utils"
5
+ import { getParam } from "./engine_utils"
6
+ import { getWorldPosition, getWorldQuaternion, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils"
7
7
  import {
8
8
  IComponent as Component,
9
9
  IGameObject as GameObject,
10
10
  ICollider,
11
- IRigidbody as Rigidbody, $physicsKey,
12
- Collision, CannonCollision,
13
- ICollisionContext,
14
- IComponent
15
- }
16
- from './engine_types';
11
+ IRigidbody as Rigidbody,
12
+ $physicsKey,
13
+ Collision,
14
+ CannonCollision,
15
+ ICollisionContext
16
+ } from './engine_types';
17
17
  import { Shape } from 'cannon-es';
18
18
  import { InstancingUtil } from './engine_instancing';
19
19
  import { foreachComponent } from './engine_gameobject';
20
- import { getComponentInChildren } from './engine_components';
21
20
 
22
21
 
23
- const debugPhysics = utils.getParam("debugphysics");
24
- const debugCollisions = utils.getParam("debugcollisions");
22
+ const debugPhysics = getParam("debugphysics");
23
+ const debugCollisions = getParam("debugcollisions");
25
24
 
26
25
  export class BodyOptions {
27
26
  mass: number = 1;
@@ -35,16 +34,16 @@ export class BodyOptions {
35
34
 
36
35
  // TODO: refactor to return some kind of handle for adding/removing
37
36
  class PhysicsObject {
38
- obj: THREE.Object3D;
39
- parent: THREE.Object3D | null;
40
- body: CANNON.Body | null;
37
+ obj: Object3D;
38
+ parent: Object3D | null;
39
+ body: Body | null;
41
40
  shapes: Array<Shape> = [];
42
41
  collisonCallback: Function | null = null;
43
42
 
44
43
  _hasRigidbody: boolean = false;
45
44
  _didSleepLastStep: boolean = false;
46
45
 
47
- constructor(obj: THREE.Object3D, body: CANNON.Body | null) {
46
+ constructor(obj: Object3D, body: Body | null) {
48
47
  this.obj = obj;
49
48
  this.parent = obj.parent;
50
49
  this.body = body;
@@ -54,28 +53,28 @@ class PhysicsObject {
54
53
  }
55
54
 
56
55
  export class RaycastOptions {
57
- ray: THREE.Ray | undefined = undefined;
58
- cam: THREE.Camera | undefined | null = undefined;
59
- screenPoint: THREE.Vector2 | undefined = undefined;
60
- raycaster: THREE.Raycaster | undefined = undefined;
61
- results: Array<THREE.Intersection> | undefined = undefined;
62
- targets: Array<THREE.Object3D> | undefined = undefined;
56
+ ray: Ray | undefined = undefined;
57
+ cam: Camera | undefined | null = undefined;
58
+ screenPoint: Vector2 | undefined = undefined;
59
+ raycaster: Raycaster | undefined = undefined;
60
+ results: Array<Intersection> | undefined = undefined;
61
+ targets: Array<Object3D> | undefined = undefined;
63
62
  recursive: boolean | undefined = true;
64
63
  minDistance: number | undefined = undefined;
65
64
  maxDistance: number | undefined = undefined;
66
65
  lineThreshold: number | undefined = undefined;
67
- layerMask: THREE.Layers | number | undefined = undefined;
68
- ignore: THREE.Object3D[] | undefined = undefined;
66
+ layerMask: Layers | number | undefined = undefined;
67
+ ignore: Object3D[] | undefined = undefined;
69
68
 
70
69
  screenPointFromOffset(ox: number, oy: number) {
71
- if (this.screenPoint === undefined) this.screenPoint = new THREE.Vector2();
70
+ if (this.screenPoint === undefined) this.screenPoint = new Vector2();
72
71
  this.screenPoint.x = ox / window.innerWidth * 2 - 1;
73
72
  this.screenPoint.y = -(oy / window.innerHeight) * 2 + 1;
74
73
  }
75
74
 
76
75
  setMask(mask: number) {
77
- if (!this.layerMask) this.layerMask = new THREE.Layers();
78
- const lm = this.layerMask as THREE.Layers;
76
+ if (!this.layerMask) this.layerMask = new Layers();
77
+ const lm = this.layerMask as Layers;
79
78
  if (lm)
80
79
  lm.mask = mask;
81
80
  else this.layerMask = mask;
@@ -84,11 +83,11 @@ export class RaycastOptions {
84
83
  public static AllLayers = 0xFFFFFFFF;
85
84
  }
86
85
 
87
- export class SphereIntersection implements THREE.Intersection {
86
+ export class SphereIntersection implements Intersection {
88
87
  distance: number;
89
- point: THREE.Vector3;
90
- object: THREE.Object3D;
91
- constructor(object: THREE.Object3D, distance: number, point: THREE.Vector3) {
88
+ point: Vector3;
89
+ object: Object3D;
90
+ constructor(object: Object3D, distance: number, point: Vector3) {
92
91
  this.object = object;
93
92
  this.distance = distance;
94
93
  this.point = point;
@@ -99,9 +98,9 @@ export class Physics {
99
98
 
100
99
  // raycasting
101
100
 
102
- private readonly raycaster: THREE.Raycaster = new THREE.Raycaster();
101
+ private readonly raycaster: Raycaster = new Raycaster();
103
102
  private readonly defaultRaycastOptions: RaycastOptions = new RaycastOptions();
104
- private readonly targetBuffer: Array<THREE.Object3D> = new Array<THREE.Object3D>(1);
103
+ private readonly targetBuffer: Array<Object3D> = new Array<Object3D>(1);
105
104
  private readonly defaultThresholds = {
106
105
  Mesh: {},
107
106
  Line: { threshold: 0 },
@@ -111,60 +110,56 @@ export class Physics {
111
110
  }
112
111
 
113
112
 
114
- private sphereResults: Array<THREE.Intersection> = new Array<THREE.Intersection>();
115
- private sphereMask: THREE.Layers = new THREE.Layers();
116
- public sphereOverlap(spherePos: THREE.Vector3, radius: number): Array<THREE.Intersection> {
113
+ private sphereResults: Array<Intersection> = new Array<Intersection>();
114
+ private sphereMask: Layers = new Layers();
115
+ public sphereOverlap(spherePos: Vector3, radius: number, traverseChildsAfterHit: boolean = true): Array<Intersection> {
117
116
  this.sphereResults.length = 0;
118
117
  if (!this.context.scene) return this.sphereResults;
119
- const sphere = new THREE.Sphere(spherePos, radius);
118
+ const sphere = new Sphere(spherePos, radius);
120
119
  const mask = this.sphereMask;
121
120
  mask.enableAll();
122
121
  mask.disable(2);
123
- // mask testing
124
- // const dummy = new THREE.Layers();
125
- // dummy.set(2);
126
- // console.log(dummy.mask, mask.test(dummy))
127
122
  for (const ch of this.context.scene.children) {
128
- const i = this.onSphereOverlap(ch, sphere, mask);
129
- if (i) this.sphereResults.push(i);
123
+ this.onSphereOverlap(ch, sphere, mask, this.sphereResults, traverseChildsAfterHit);
130
124
  }
131
125
  return this.sphereResults.sort((a, b) => a.distance - b.distance);
132
126
  }
133
- private tempBoundingBox: THREE.Box3 = new THREE.Box3();
134
- private onSphereOverlap(obj: THREE.Object3D, sp: THREE.Sphere, mask: THREE.Layers): THREE.Intersection | null {
135
- if (obj.type === "Mesh") {
136
- if (!obj.layers.test(mask)) return null;
137
- const mesh = obj as THREE.Mesh;
127
+ private tempBoundingBox: Box3 = new Box3();
128
+ private onSphereOverlap(obj: Object3D, sp: Sphere, mask: Layers, results: Array<Intersection>, traverseChildsAfterHit: boolean): void {
129
+ if (obj.type === "Mesh" && obj.layers.test(mask)) {
130
+ const mesh = obj as Mesh;
138
131
  const geo = mesh.geometry;
139
132
  if (!geo.boundingBox)
140
133
  geo.computeBoundingBox();
141
- if (!geo.boundingBox) return null;
142
- if (mesh.matrixWorldNeedsUpdate) mesh.updateMatrixWorld();
143
- const test = this.tempBoundingBox.copy(geo.boundingBox).applyMatrix4(mesh.matrixWorld);
144
- if (sp.intersectsBox(test)) {
145
- // console.log(obj, obj.layers.test(mask), obj.layers.mask, mask.mask);
146
- const wp = threeutils.getWorldPosition(obj);
147
- const dist = wp.distanceTo(sp.center);
148
- const int = new SphereIntersection(obj, dist, sp.center.clone());
149
- return int;
134
+ if (geo.boundingBox) {
135
+ if (mesh.matrixWorldNeedsUpdate) mesh.updateMatrixWorld();
136
+ const test = this.tempBoundingBox.copy(geo.boundingBox).applyMatrix4(mesh.matrixWorld);
137
+ if (sp.intersectsBox(test)) {
138
+ // console.log(obj, obj.layers.test(mask), obj.layers.mask, mask.mask);
139
+ const wp = getWorldPosition(obj);
140
+ const dist = wp.distanceTo(sp.center);
141
+ const int = new SphereIntersection(obj, dist, sp.center.clone());
142
+ results.push(int);
143
+ if (!traverseChildsAfterHit) return;
144
+ }
150
145
  }
151
146
  }
152
- else if (obj.children) {
147
+ if (obj.children) {
153
148
  for (const ch of obj.children) {
154
- const i = this.onSphereOverlap(ch, sp, mask);
155
- if (i) return i;
149
+ const len = results.length;
150
+ this.onSphereOverlap(ch, sp, mask, results, traverseChildsAfterHit);
151
+ if (len != results.length && !traverseChildsAfterHit) return;
156
152
  }
157
153
  }
158
- return null;
159
154
  }
160
155
 
161
- public raycastFromRay(ray: THREE.Ray, options: RaycastOptions | null = null): Array<THREE.Intersection> {
156
+ public raycastFromRay(ray: Ray, options: RaycastOptions | null = null): Array<Intersection> {
162
157
  const opts = options ?? this.defaultRaycastOptions;
163
158
  opts.ray = ray;
164
159
  return this.raycast(opts);
165
160
  }
166
161
 
167
- public raycast(options: RaycastOptions | null = null): Array<THREE.Intersection> {
162
+ public raycast(options: RaycastOptions | null = null): Array<Intersection> {
168
163
  if (!options) options = this.defaultRaycastOptions;
169
164
  const mp = options.screenPoint ?? this.context.input.mousePositionRC;
170
165
  const rc = options.raycaster ?? this.raycaster;
@@ -194,14 +189,14 @@ export class Physics {
194
189
  let results = options.results;
195
190
  if (!results) {
196
191
  if (!this.defaultRaycastOptions.results)
197
- this.defaultRaycastOptions.results = new Array<THREE.Intersection>();
192
+ this.defaultRaycastOptions.results = new Array<Intersection>();
198
193
  results = this.defaultRaycastOptions.results;
199
194
  }
200
195
 
201
196
  // layermask
202
- // https://github.com/mrdoob/three.js/blob/master/src/core/Layers.js
197
+ // https://github.com/mrdoob/js/blob/master/src/core/Layers.js
203
198
  if (options.layerMask !== undefined) {
204
- if (options.layerMask instanceof THREE.Layers)
199
+ if (options.layerMask instanceof Layers)
205
200
  rc.layers.mask = options.layerMask.mask;
206
201
  else
207
202
  rc.layers.mask = options.layerMask;
@@ -236,11 +231,11 @@ export class Physics {
236
231
 
237
232
  private context: Context;
238
233
 
239
- private world: CANNON.World = new CANNON.World();
234
+ private world: World = new World();
240
235
  private objects: Array<PhysicsObject> = [];
241
236
 
242
- private tempPosition: THREE.Vector3 = new THREE.Vector3();
243
- private tempQuaternion: THREE.Quaternion = new THREE.Quaternion();
237
+ private tempPosition: Vector3 = new Vector3();
238
+ private tempQuaternion: Quaternion = new Quaternion();
244
239
 
245
240
  constructor(context: Context) {
246
241
  this.context = context;
@@ -248,7 +243,7 @@ export class Physics {
248
243
  if (debugPhysics) {
249
244
  // https://www.npmjs.com/package/cannon-es-debugger
250
245
  const opts = {};
251
- opts["onInit"] = (_body: CANNON.Body, mesh: THREE.Mesh, _shape: CANNON.Shape) => {
246
+ opts["onInit"] = (_body: Body, mesh: Mesh, _shape: Shape) => {
252
247
  // ignore in raycast
253
248
  mesh.layers.set(-1);
254
249
  };
@@ -267,21 +262,21 @@ export class Physics {
267
262
  this.world.addEventListener("postStep", listener);
268
263
  }
269
264
 
270
- public addConstraint(constraint: CANNON.Constraint) {
265
+ public addConstraint(constraint: Constraint) {
271
266
  this.world.addConstraint(constraint);
272
267
  }
273
268
 
274
- public setGravity(vec: THREE.Vector3) {
269
+ public setGravity(vec: Vector3) {
275
270
  this.world.gravity.set(vec.x, vec.y, vec.z);
276
271
  }
277
272
 
278
- public multiplyGravity(vec: THREE.Vector3) {
273
+ public multiplyGravity(vec: Vector3) {
279
274
  this.world.gravity.x *= vec.x;
280
275
  this.world.gravity.y *= vec.y;
281
276
  this.world.gravity.z *= vec.z;
282
277
  }
283
278
 
284
- public addBody(go: GameObject, body: CANNON.Body) {
279
+ public addBody(go: GameObject, body: Body) {
285
280
  for (let i = 0; i < this.objects.length; i++) {
286
281
  const reg = this.objects[i];
287
282
  if (reg.obj === go) {
@@ -295,7 +290,7 @@ export class Physics {
295
290
  this.world.addBody(body);
296
291
  }
297
292
 
298
- public removeBody(go: GameObject, body: CANNON.Body, removeCompletely: boolean = true) {
293
+ public removeBody(go: GameObject, body: Body, removeCompletely: boolean = true) {
299
294
  this.world.removeBody(body);
300
295
  for (let i = 0; i < this.objects.length; i++) {
301
296
  const reg = this.objects[i];
@@ -308,7 +303,7 @@ export class Physics {
308
303
  }
309
304
  }
310
305
 
311
- public removeShape(obj: THREE.Object3D, shape: CANNON.Shape) {
306
+ public removeShape(obj: Object3D, shape: Shape) {
312
307
  for (const reg of this.objects) {
313
308
  if (reg.obj === obj) {
314
309
  if (reg.body) {
@@ -321,13 +316,13 @@ export class Physics {
321
316
  }
322
317
 
323
318
  // TODO: make it work with rigibody in parent
324
- public createBody(obj: THREE.Object3D, settings: BodyOptions): CANNON.Body {
319
+ public createBody(obj: Object3D, settings: BodyOptions): Body {
325
320
  const body = this.internalCreateBody(obj, null);
326
321
  if (settings.mass)
327
322
  body.mass = settings.mass;
328
323
  if (settings.kinematic)
329
- body.type = CANNON.Body.KINEMATIC;
330
- else body.type = CANNON.Body.DYNAMIC;
324
+ body.type = Body.KINEMATIC;
325
+ else body.type = Body.DYNAMIC;
331
326
  if (settings.drag)
332
327
  body.linearDamping = settings.drag;
333
328
  if (settings.angularDrag)
@@ -351,17 +346,17 @@ export class Physics {
351
346
  return body;
352
347
  }
353
348
 
354
- public addBoxCollider(obj: THREE.Object3D, trigger: boolean, center: THREE.Vector3, size: THREE.Vector3, rb: Rigidbody | null): CANNON.Shape {
349
+ public addBoxCollider(obj: Object3D, trigger: boolean, center: Vector3, size: Vector3, rb: Rigidbody | null): Shape {
355
350
 
356
351
  const scale = this.tempPosition;
357
352
  obj.getWorldScale(scale);
358
353
 
359
- const pos = new CANNON.Vec3(
354
+ const pos = new Vec3(
360
355
  .5 * scale.x * size.x,
361
356
  .5 * scale.y * size.y,
362
357
  .5 * scale.z * size.z
363
358
  );
364
- const shape = new CANNON.Box(pos);
359
+ const shape = new Box(pos);
365
360
  shape.collisionResponse = !trigger;
366
361
 
367
362
  center = center.clone();
@@ -377,12 +372,12 @@ export class Physics {
377
372
  return shape;
378
373
  }
379
374
 
380
- public addSphereCollider(obj: THREE.Object3D, center: THREE.Vector3, radius: number, rb: Rigidbody | null): CANNON.Shape {
375
+ public addSphereCollider(obj: Object3D, center: Vector3, radius: number, rb: Rigidbody | null): Shape {
381
376
  const scale = this.tempPosition;
382
377
  obj.getWorldScale(scale);
383
378
 
384
379
  const factor = Math.max(scale.x, scale.y, scale.z);
385
- const shape = new CANNON.Sphere(radius * factor);
380
+ const shape = new PhysicsSphere(radius * factor);
386
381
  // shape.collisionResponse = !trigger;
387
382
 
388
383
  center = center.clone();
@@ -398,11 +393,11 @@ export class Physics {
398
393
  return shape;
399
394
  }
400
395
 
401
- public addMeshCollider(_obj: THREE.Object3D) {
402
- // see https://github.com/schteppe/cannon.js/blob/master/demos/bunny.html
396
+ public addMeshCollider(_obj: Object3D) {
397
+ // see https://github.com/schteppe/js/blob/master/demos/bunny.html
403
398
  if (debugPhysics)
404
399
  console.warn("TODO mesh collider not yet supported")
405
- // const geometry: THREE.BufferGeometry = obj["geometry"];
400
+ // const geometry: BufferGeometry = obj["geometry"];
406
401
  // console.log(geometry);
407
402
  // const size = geometry.boundingBox.max.clone();
408
403
  // size.sub(geometry.boundingBox.min);
@@ -418,31 +413,31 @@ export class Physics {
418
413
  // const i0 = geometry.index.array[i];
419
414
  // const i1 = geometry.index.array[i + 1];
420
415
  // const i2 = geometry.index.array[i + 2];
421
- // const v0 = new THREE.Vector3(verts[i0 * 3], verts[i0 * 3 + 1], verts[i0 * 3 + 2]);
422
- // const v1 = new THREE.Vector3(verts[i1 * 3], verts[i1 * 3 + 1], verts[i1 * 3 + 2]);
423
- // const v2 = new THREE.Vector3(verts[i2 * 3], verts[i2 * 3 + 1], verts[i2 * 3 + 2]);
416
+ // const v0 = new Vector3(verts[i0 * 3], verts[i0 * 3 + 1], verts[i0 * 3 + 2]);
417
+ // const v1 = new Vector3(verts[i1 * 3], verts[i1 * 3 + 1], verts[i1 * 3 + 2]);
418
+ // const v2 = new Vector3(verts[i2 * 3], verts[i2 * 3 + 1], verts[i2 * 3 + 2]);
424
419
  // const face = [v0, v1, v2];
425
420
  // faces.push(face);
426
421
  // }
427
- // const convex = new THREE.ConvexBufferGeometry(faces);
422
+ // const convex = new ConvexBufferGeometry(faces);
428
423
 
429
- // var shape = new CANNON.ConvexPolyhedron({ verts, faces });
424
+ // var shape = new ConvexPolyhedron({ verts, faces });
430
425
  // this.addShape(obj, shape);
431
426
  }
432
427
 
433
- private isAlreadyRegistered(body: CANNON.Body): boolean {
428
+ private isAlreadyRegistered(body: Body): boolean {
434
429
  for (const obj of this.objects) {
435
430
  if (obj.body === body) return true;
436
431
  }
437
432
  return false;
438
433
  }
439
434
 
440
- private readonly tempMat1: THREE.Matrix4 = new THREE.Matrix4();
441
- private readonly tempMat2: THREE.Matrix4 = new THREE.Matrix4();
435
+ private readonly tempMat1: Matrix4 = new Matrix4();
436
+ private readonly tempMat2: Matrix4 = new Matrix4();
442
437
 
443
- private addShape(obj: THREE.Object3D, shape: CANNON.Shape, center: THREE.Vector3, rb: Rigidbody | null): CANNON.Body | null {
438
+ private addShape(obj: Object3D, shape: Shape, center: Vector3, rb: Rigidbody | null): Body | null {
444
439
 
445
- let body: CANNON.Body | null = null;
440
+ let body: Body | null = null;
446
441
 
447
442
  if (rb) {
448
443
  // if (debugPhysics)
@@ -454,7 +449,7 @@ export class Physics {
454
449
  else {
455
450
  // console.log("has no rb", obj);
456
451
  body = this.internalCreateBody(obj, null);
457
- body.type = CANNON.Body.KINEMATIC;
452
+ body.type = Body.KINEMATIC;
458
453
  }
459
454
 
460
455
  if (body) {
@@ -476,14 +471,14 @@ export class Physics {
476
471
  this.tempMat1.decompose(wp, wr, this.tempPosition);
477
472
  }
478
473
  else {
479
- wp = threeutils.getWorldPosition(obj);
474
+ wp = getWorldPosition(obj);
480
475
  const bp = body.position;
481
476
  wp.x -= bp.x;
482
477
  wp.y -= bp.y;
483
478
  wp.z -= bp.z;
484
479
 
485
- wr = threeutils.getWorldQuaternion(obj);
486
- const r = new THREE.Quaternion(body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w);
480
+ wr = getWorldQuaternion(obj);
481
+ const r = new Quaternion(body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w);
487
482
  wr.multiply(r.invert());
488
483
  }
489
484
  // get rotation difference
@@ -497,14 +492,14 @@ export class Physics {
497
492
  // this.tempMat.setPosition(wp);
498
493
  // this.tempMat.makeRotationFromQuaternion(wr);
499
494
  // this.tempMat.multiplyMatrices(this.tempMat, rb?.gameObject.matrix);
500
- // this.tempMat.decompose(this.tempPosition, this.tempQuaternion, new THREE.Vector3());
495
+ // this.tempMat.decompose(this.tempPosition, this.tempQuaternion, new Vector3());
501
496
  // wp.copy(this.tempPosition);
502
497
  // }
503
498
 
504
499
  // wp.applyQuaternion(wr);
505
500
 
506
- const pos = new CANNON.Vec3(wp.x, wp.y, wp.z);
507
- const rot = new CANNON.Quaternion(wr.x, wr.y, wr.z, wr.w);
501
+ const pos = new Vec3(wp.x, wp.y, wp.z);
502
+ const rot = new PhysicsQuaternion(wr.x, wr.y, wr.z, wr.w);
508
503
  body.addShape(shape, pos, rot);
509
504
  body.updateMassProperties();
510
505
  this.world.addBody(body);
@@ -524,8 +519,8 @@ export class Physics {
524
519
  }
525
520
  }
526
521
 
527
- private temp: THREE.Vector3 = new THREE.Vector3();
528
- private tempQuat: THREE.Quaternion = new THREE.Quaternion();
522
+ private temp: Vector3 = new Vector3();
523
+ private tempQuat: Quaternion = new Quaternion();
529
524
 
530
525
  public postStep() {
531
526
  this._isUpdatingPhysicsWorld = true;
@@ -533,43 +528,48 @@ export class Physics {
533
528
  const entry = this.objects[i];
534
529
  const body = entry.body;
535
530
  if (!body || !body.world) continue;
531
+ const obj = entry.obj;
536
532
 
537
533
  body.sleepTick(this.context.time.time);
538
534
 
539
535
  if (debugPhysics) {
540
- if (!entry._didSleepLastStep && body.sleepState === CANNON.Body.SLEEPING) {
536
+ if (!entry._didSleepLastStep && body.sleepState === Body.SLEEPING) {
541
537
  console.log("BODY SLEEPING", body);
542
538
  }
543
- else if (entry._didSleepLastStep && body.sleepState !== CANNON.Body.SLEEPING) {
539
+ else if (entry._didSleepLastStep && body.sleepState !== Body.SLEEPING) {
544
540
  console.log("BODY WOKE UP", body);
545
541
  }
546
542
  }
547
- entry._didSleepLastStep = body.sleepState === CANNON.Body.SLEEPING;
548
- // if(body.sleepState === CANNON.Body.SLEEPING) {
543
+ entry._didSleepLastStep = body.sleepState === Body.SLEEPING;
544
+ // if(body.sleepState === Body.SLEEPING) {
549
545
  // console.log("SLEEP", body.name);
550
546
  // }
551
- // if (body.type == CANNON.Body.KINEMATIC) continue;
552
- const obj = entry.obj;
547
+ // if (body.type == Body.KINEMATIC) continue;
553
548
 
554
- if (body.type === CANNON.Body.KINEMATIC) {
555
- const wp = threeutils.getWorldPosition(obj, this.temp);
549
+ if (body.type === Body.KINEMATIC) {
550
+ const wp = getWorldPosition(obj, this.temp);
556
551
  body.position.set(wp.x, wp.y, wp.z);
557
- const rot = threeutils.getWorldQuaternion(obj, this.tempQuat);
552
+ const rot = getWorldQuaternion(obj, this.tempQuat);
558
553
  body.quaternion.set(rot.x, rot.y, rot.z, rot.w);
559
554
  continue;
560
555
  }
561
556
 
557
+ if ((isNaN(body.position.x) || isNaN(body.position.y) || isNaN(body.position.z))) {
558
+ console.error("body position is NaN on", obj.name, "this usually means some colliders are overlapping", body.previousPosition, obj.position);
559
+ this.world.removeBody(body);
560
+ continue;
561
+ }
562
562
 
563
563
 
564
564
  // when reparenting (e.g. attached to controller) I think it doesnt work with previous parent? need to test again, to tired now
565
565
  if (entry.parent && obj.parent === entry.parent) {
566
566
 
567
- threeutils.setWorldQuaternionXYZW(obj,
567
+ setWorldQuaternionXYZW(obj,
568
568
  body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w
569
569
  );
570
570
 
571
571
  const p = body.position;
572
- threeutils.setWorldPositionXYZ(obj, p.x, p.y, p.z);
572
+ setWorldPositionXYZ(obj, p.x, p.y, p.z);
573
573
 
574
574
  if (body.velocity.length() > body.sleepSpeedLimit) {
575
575
  InstancingUtil.markDirty(obj);
@@ -597,20 +597,20 @@ export class Physics {
597
597
  this._isUpdatingPhysicsWorld = false;
598
598
  }
599
599
 
600
- private internalCreateBody(obj: THREE.Object3D, shape: CANNON.Shape | undefined | null): CANNON.Body {
600
+ private internalCreateBody(obj: Object3D, shape: Shape | undefined | null): Body {
601
601
 
602
- const body = new CANNON.Body();
602
+ const body = new Body();
603
603
  body["_owner"] = obj;
604
604
  body["_name"] = obj.name;
605
605
  obj.getWorldPosition(this.tempPosition);
606
606
  const pos = this.tempPosition;
607
- body.position = new CANNON.Vec3(pos.x, pos.y, pos.z);
607
+ body.position = new Vec3(pos.x, pos.y, pos.z);
608
608
 
609
609
  const quat = this.tempQuaternion;
610
610
  obj.getWorldQuaternion(quat);
611
- body.quaternion = new CANNON.Quaternion(quat.x, quat.y, quat.z, quat.w);
611
+ body.quaternion = new PhysicsQuaternion(quat.x, quat.y, quat.z, quat.w);
612
612
 
613
- body.type = CANNON.Body.KINEMATIC;
613
+ body.type = Body.KINEMATIC;
614
614
  if (shape) {
615
615
  body.addShape(shape);
616
616
  body.updateMassProperties();
@@ -618,7 +618,7 @@ export class Physics {
618
618
  return body;
619
619
  }
620
620
 
621
- // private findObject(obj: THREE.Object3D): PhysicsObject | null {
621
+ // private findObject(obj: Object3D): PhysicsObject | null {
622
622
  // for (let i = 0; i < this.objects.length; i++) {
623
623
  // const entry = this.objects[i];
624
624
  // if (entry.obj == obj)
@@ -648,7 +648,7 @@ export class Physics {
648
648
 
649
649
  private readonly collisionContext: ICollisionContext = new CollisionContext();
650
650
 
651
- private raiseCollisionEvents(obj: THREE.Object3D, event: CannonCollision) {
651
+ private raiseCollisionEvents(obj: Object3D, event: CannonCollision) {
652
652
  const collision = new Collision(obj, event, this.collisionContext);
653
653
  if (debugCollisions)
654
654
  console.log("collision between", event.contact.bi, event.contact.bj, obj, event);
@@ -665,9 +665,9 @@ export class Physics {
665
665
  }
666
666
  }
667
667
 
668
- private onEndContact(args: { bodyA: CANNON.Body, bodyB: CANNON.Body }) {
669
- // if(args.bodyB.sleepState !== CANNON.Body.AWAKE) return;
670
- // console.log("END", CANNON.BODY_SLEEP_STATES, args.bodyB.sleepState);
668
+ private onEndContact(args: { bodyA: Body, bodyB: Body }) {
669
+ // if(args.bodyB.sleepState !== Body.AWAKE) return;
670
+ // console.log("END", BODY_SLEEP_STATES, args.bodyB.sleepState);
671
671
  const obj1 = args.bodyA[$physicsKey];
672
672
  const obj2 = args.bodyB[$physicsKey];
673
673
  // console.log(obj2);
@@ -690,7 +690,7 @@ export class Physics {
690
690
  }
691
691
 
692
692
  export interface IColliderProvider {
693
- getCollider(obj: THREE.Object3D): ICollider;
693
+ getCollider(obj: Object3D): ICollider;
694
694
  }
695
695
 
696
696
  let colliderProvider: IColliderProvider | null = null;
@@ -700,7 +700,7 @@ export function registerColliderProvider(prov: IColliderProvider) {
700
700
 
701
701
  class CollisionContext implements ICollisionContext {
702
702
 
703
- getCollider(obj: THREE.Object3D<THREE.Event>): ICollider {
703
+ getCollider(obj: Object3D<Event>): ICollider {
704
704
  return colliderProvider!.getCollider(obj);
705
705
  }
706
706
 
@@ -5,6 +5,9 @@ import { Context } from "./engine_setup";
5
5
  import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
6
6
  import { SourceIdentifier } from "./engine_types";
7
7
  import { debugExtension } from "../engine/engine_default_parameters";
8
+ import { LogType, showBalloonMessage } from "./debug/debug";
9
+ import { isLocalNetwork } from "./engine_networking_utils";
10
+ import { $BuiltInTypeFlag } from "./engine_typestore";
8
11
 
9
12
  const debug = getParam("debugserializer");
10
13
 
@@ -312,6 +315,8 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
312
315
  implictlyAssignPrimitiveTypes(obj, serializedData);
313
316
  }
314
317
 
318
+ checkObjectAssignments(obj, serializedData);
319
+
315
320
  if (obj.onAfterDeserialize !== undefined) {
316
321
  obj.onAfterDeserialize(serializedData, context);
317
322
  }
@@ -320,6 +325,42 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
320
325
  return true;
321
326
  }
322
327
 
328
+ const blockChecks = getParam("noerrors");
329
+ function checkObjectAssignments(obj: any, _serializedData?: any) {
330
+ if(blockChecks) return;
331
+ if (isLocalNetwork() === false) return;
332
+ if (!obj) return;
333
+
334
+ // ignore builtin components that we dont want to check
335
+ if(obj.constructor && obj.constructor[$BuiltInTypeFlag] === true) return;
336
+
337
+ const typeName = obj.constructor?.name as string;
338
+ // test if any object reference is missing serializable
339
+ const ownKeys = Object.getOwnPropertyNames(obj);
340
+ for (const key of ownKeys) {
341
+ if (key === "sourceId") continue;
342
+ const value = obj[key];
343
+ if (value === undefined || value === null) continue;
344
+ if (typeof value === "object") {
345
+ if (!value.isObject3D) {
346
+ if (typeof value["node"] === "number" || typeof value["guid"] === "string") {
347
+ const hasOtherKeys = Object.keys(value).length > 1;
348
+ if (!hasOtherKeys) {
349
+ showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(Object3D)\n${key}? : Object3D;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializeable" target="_blank">documentation</a>`, LogType.Warn);
350
+ console.warn(typeName, key, obj[key], obj);
351
+ }
352
+ }
353
+ }
354
+ }
355
+ else if (typeof value === "string") {
356
+ if (value.endsWith(".gltf") || value.endsWith(".glb")) {
357
+ showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(AssetReference)\n${key}? : AssetReference;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializeable" target="_blank">documentation</a>`, LogType.Warn);
358
+ console.warn(typeName, key, obj[key], obj);
359
+ }
360
+ }
361
+ }
362
+ }
363
+
323
364
  function implictlyAssignPrimitiveTypes(obj: any, serializedData: any) {
324
365
  // implictly assign serialized primitive fields
325
366
  for (const key of Object.keys(serializedData)) {
@@ -600,7 +600,7 @@ export class Context {
600
600
  this._isRendering = true;
601
601
  this.renderRequiredTextures();
602
602
  if (!this.isManagedExternally) {
603
- if (this.composer) {
603
+ if (this.composer && !this.isInXR) {
604
604
  this.composer.render();
605
605
  }
606
606
  else if (this.mainCamera) {