@needle-tools/engine 2.35.5-pre → 2.37.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.
- package/CHANGELOG.md +31 -0
- package/dist/needle-engine.d.ts +312 -232
- package/dist/needle-engine.js +456 -437
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +81 -76
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/api.d.ts +1 -0
- package/lib/engine/api.js +1 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug.d.ts +1 -0
- package/lib/engine/debug/debug.js +3 -0
- package/lib/engine/debug/debug.js.map +1 -1
- package/lib/engine/debug/debug_overlay.js +12 -1
- package/lib/engine/debug/debug_overlay.js.map +1 -1
- package/lib/engine/engine_element_loading.js +1 -1
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_gameobject.d.ts +1 -0
- package/lib/engine/engine_gameobject.js +15 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +4 -0
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.d.ts +1 -1
- package/lib/engine/engine_mainloop_utils.js +7 -3
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +49 -57
- package/lib/engine/engine_physics.js +464 -417
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics.types.d.ts +16 -0
- package/lib/engine/engine_physics.types.js +19 -0
- package/lib/engine/engine_physics.types.js.map +1 -0
- package/lib/engine/engine_serialization_core.d.ts +3 -0
- package/lib/engine/engine_serialization_core.js +19 -6
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.js +4 -2
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_time.d.ts +1 -0
- package/lib/engine/engine_time.js +1 -0
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/engine_types.d.ts +46 -26
- package/lib/engine/engine_types.js +24 -37
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_typestore.d.ts +1 -0
- package/lib/engine/engine_typestore.js +1 -0
- package/lib/engine/engine_typestore.js.map +1 -1
- package/lib/engine/engine_util_decorator.d.ts +6 -0
- package/lib/engine/engine_util_decorator.js +54 -0
- package/lib/engine/engine_util_decorator.js.map +1 -0
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +2 -2
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_gameobject_data.js +2 -0
- package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js +5 -0
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
- package/lib/engine-components/Animation.d.ts +5 -0
- package/lib/engine-components/Animation.js +14 -0
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +1 -0
- package/lib/engine-components/AnimatorController.js +14 -7
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/BoxHelperComponent.d.ts +2 -2
- package/lib/engine-components/BoxHelperComponent.js +28 -9
- package/lib/engine-components/BoxHelperComponent.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +7 -2
- package/lib/engine-components/Collider.js +27 -15
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +8 -16
- package/lib/engine-components/Component.js +18 -117
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/DragControls.js +9 -6
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +2 -0
- package/lib/engine-components/GroundProjection.js +18 -6
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/NavMesh.d.ts +0 -5
- package/lib/engine-components/NavMesh.js +100 -10
- package/lib/engine-components/NavMesh.js.map +1 -1
- package/lib/engine-components/NestedGltf.js +2 -0
- package/lib/engine-components/NestedGltf.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.d.ts +22 -0
- package/lib/engine-components/ReflectionProbe.js +134 -0
- package/lib/engine-components/ReflectionProbe.js.map +1 -0
- package/lib/engine-components/Renderer.d.ts +13 -2
- package/lib/engine-components/Renderer.js +96 -45
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +40 -25
- package/lib/engine-components/RigidBody.js +253 -142
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SpatialTrigger.js +1 -1
- package/lib/engine-components/SpatialTrigger.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.d.ts +1 -0
- package/lib/engine-components/SpectatorCamera.js +9 -2
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SpringJoint.d.ts +0 -13
- package/lib/engine-components/SpringJoint.js +42 -41
- package/lib/engine-components/SpringJoint.js.map +1 -1
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +7 -7
- package/lib/engine-components/WebARSessionRoot.js +7 -7
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +10 -8
- package/lib/engine-components/WebXR.js +50 -26
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRAvatar.d.ts +4 -5
- package/lib/engine-components/WebXRAvatar.js +9 -8
- package/lib/engine-components/WebXRAvatar.js.map +1 -1
- package/lib/engine-components/WebXRController.d.ts +21 -21
- package/lib/engine-components/WebXRController.js +90 -68
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/WebXRGrabRendering.d.ts +3 -3
- package/lib/engine-components/WebXRGrabRendering.js +2 -2
- package/lib/engine-components/WebXRGrabRendering.js.map +1 -1
- package/lib/engine-components/WebXRSync.d.ts +8 -8
- package/lib/engine-components/WebXRSync.js +15 -15
- package/lib/engine-components/WebXRSync.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +2 -3
- package/lib/engine-components/codegen/components.js +2 -3
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.d.ts +1 -0
- package/lib/engine-components/ui/EventSystem.js +21 -1
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/package.json +3 -4
- package/src/engine/api.ts +2 -1
- package/src/engine/codegen/register_types.js +291 -6
- package/src/engine/debug/debug.ts +4 -0
- package/src/engine/debug/debug_overlay.ts +9 -2
- package/src/engine/engine_element_loading.ts +1 -1
- package/src/engine/engine_gameobject.ts +19 -6
- package/src/engine/engine_gltf_builtin_components.ts +5 -1
- package/src/engine/engine_mainloop_utils.ts +7 -3
- package/src/engine/engine_physics.ts +508 -469
- package/src/engine/engine_physics.types.ts +19 -0
- package/src/engine/engine_serialization_core.ts +22 -8
- package/src/engine/engine_setup.ts +6 -2
- package/src/engine/engine_time.ts +2 -0
- package/src/engine/engine_types.ts +82 -55
- package/src/engine/engine_typestore.ts +2 -0
- package/src/engine/engine_util_decorator.ts +69 -0
- package/src/engine/engine_utils.ts +6 -5
- package/src/engine/extensions/EXT_texture_exr.js +1 -1
- package/src/engine/extensions/NEEDLE_animator_controller_model.ts +2 -1
- package/src/engine/extensions/NEEDLE_gameobject_data.ts +2 -0
- package/src/engine/extensions/NEEDLE_techniques_webgl.ts +7 -0
- package/src/engine-components/Animation.ts +14 -1
- package/src/engine-components/AnimatorController.ts +19 -9
- package/src/engine-components/BoxHelperComponent.ts +30 -9
- package/src/engine-components/Collider.ts +29 -29
- package/src/engine-components/Component.ts +26 -135
- package/src/engine-components/DragControls.ts +9 -5
- package/src/engine-components/GroundProjection.ts +22 -7
- package/src/engine-components/NavMesh.ts +114 -115
- package/src/engine-components/NestedGltf.ts +2 -0
- package/src/engine-components/ReflectionProbe.ts +141 -0
- package/src/engine-components/Renderer.ts +796 -737
- package/src/engine-components/RigidBody.ts +258 -149
- package/src/engine-components/SpatialTrigger.ts +1 -1
- package/src/engine-components/SpectatorCamera.ts +10 -2
- package/src/engine-components/SpringJoint.ts +41 -41
- package/src/engine-components/VideoPlayer.ts +1 -2
- package/src/engine-components/WebARSessionRoot.ts +16 -16
- package/src/engine-components/WebXR.ts +65 -50
- package/src/engine-components/WebXRAvatar.ts +16 -16
- package/src/engine-components/WebXRController.ts +143 -112
- package/src/engine-components/WebXRGrabRendering.ts +6 -6
- package/src/engine-components/WebXRSync.ts +20 -20
- package/src/engine-components/codegen/components.ts +2 -3
- package/src/engine-components/ui/EventSystem.ts +26 -3
|
@@ -1,38 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import * as threeutils from "./engine_three_utils";
|
|
6
|
-
import { $physicsKey, Collision } from './engine_types';
|
|
7
|
-
import { InstancingUtil } from './engine_instancing';
|
|
1
|
+
import { Box3, BufferAttribute, BufferGeometry, Layers, LineBasicMaterial, LineSegments, Matrix4, Quaternion, Raycaster, Sphere, Vector2, Vector3 } from 'three';
|
|
2
|
+
import { getParam } from "./engine_utils";
|
|
3
|
+
import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils";
|
|
4
|
+
import { Collision, ContactPoint } from './engine_types';
|
|
8
5
|
import { foreachComponent } from './engine_gameobject';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
angularDrag = 0.05;
|
|
17
|
-
sleepThreshold = .01;
|
|
18
|
-
}
|
|
19
|
-
// TODO: refactor to return some kind of handle for adding/removing
|
|
20
|
-
class PhysicsObject {
|
|
21
|
-
obj;
|
|
22
|
-
parent;
|
|
23
|
-
body;
|
|
24
|
-
shapes = [];
|
|
25
|
-
collisonCallback = null;
|
|
26
|
-
_hasRigidbody = false;
|
|
27
|
-
_didSleepLastStep = false;
|
|
28
|
-
constructor(obj, body) {
|
|
29
|
-
this.obj = obj;
|
|
30
|
-
this.parent = obj.parent;
|
|
31
|
-
this.body = body;
|
|
32
|
-
if (this.body)
|
|
33
|
-
this.body[$physicsKey] = obj;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
6
|
+
import RAPIER, { ActiveEvents, Collider, ColliderDesc, EventQueue, RigidBody, World } from '@dimforge/rapier3d-compat';
|
|
7
|
+
import { CollisionDetectionMode } from '../engine/engine_physics.types';
|
|
8
|
+
const debugPhysics = getParam("debugphysics");
|
|
9
|
+
const debugColliderPlacement = getParam("debugphysicscolliders");
|
|
10
|
+
const debugCollisions = getParam("debugcollisions");
|
|
11
|
+
const $componentKey = Symbol("needle component");
|
|
12
|
+
const $bodyKey = Symbol("physics body");
|
|
36
13
|
export class RaycastOptions {
|
|
37
14
|
ray = undefined;
|
|
38
15
|
cam = undefined;
|
|
@@ -48,13 +25,13 @@ export class RaycastOptions {
|
|
|
48
25
|
ignore = undefined;
|
|
49
26
|
screenPointFromOffset(ox, oy) {
|
|
50
27
|
if (this.screenPoint === undefined)
|
|
51
|
-
this.screenPoint = new
|
|
28
|
+
this.screenPoint = new Vector2();
|
|
52
29
|
this.screenPoint.x = ox / window.innerWidth * 2 - 1;
|
|
53
30
|
this.screenPoint.y = -(oy / window.innerHeight) * 2 + 1;
|
|
54
31
|
}
|
|
55
32
|
setMask(mask) {
|
|
56
33
|
if (!this.layerMask)
|
|
57
|
-
this.layerMask = new
|
|
34
|
+
this.layerMask = new Layers();
|
|
58
35
|
const lm = this.layerMask;
|
|
59
36
|
if (lm)
|
|
60
37
|
lm.mask = mask;
|
|
@@ -75,7 +52,7 @@ export class SphereIntersection {
|
|
|
75
52
|
}
|
|
76
53
|
export class Physics {
|
|
77
54
|
// raycasting
|
|
78
|
-
raycaster = new
|
|
55
|
+
raycaster = new Raycaster();
|
|
79
56
|
defaultRaycastOptions = new RaycastOptions();
|
|
80
57
|
targetBuffer = new Array(1);
|
|
81
58
|
defaultThresholds = {
|
|
@@ -86,56 +63,50 @@ export class Physics {
|
|
|
86
63
|
Sprite: {}
|
|
87
64
|
};
|
|
88
65
|
sphereResults = new Array();
|
|
89
|
-
sphereMask = new
|
|
90
|
-
sphereOverlap(spherePos, radius) {
|
|
66
|
+
sphereMask = new Layers();
|
|
67
|
+
sphereOverlap(spherePos, radius, traverseChildsAfterHit = true) {
|
|
91
68
|
this.sphereResults.length = 0;
|
|
92
69
|
if (!this.context.scene)
|
|
93
70
|
return this.sphereResults;
|
|
94
|
-
const sphere = new
|
|
71
|
+
const sphere = new Sphere(spherePos, radius);
|
|
95
72
|
const mask = this.sphereMask;
|
|
96
73
|
mask.enableAll();
|
|
97
74
|
mask.disable(2);
|
|
98
|
-
// mask testing
|
|
99
|
-
// const dummy = new THREE.Layers();
|
|
100
|
-
// dummy.set(2);
|
|
101
|
-
// console.log(dummy.mask, mask.test(dummy))
|
|
102
75
|
for (const ch of this.context.scene.children) {
|
|
103
|
-
|
|
104
|
-
if (i)
|
|
105
|
-
this.sphereResults.push(i);
|
|
76
|
+
this.onSphereOverlap(ch, sphere, mask, this.sphereResults, traverseChildsAfterHit);
|
|
106
77
|
}
|
|
107
78
|
return this.sphereResults.sort((a, b) => a.distance - b.distance);
|
|
108
79
|
}
|
|
109
|
-
tempBoundingBox = new
|
|
110
|
-
onSphereOverlap(obj, sp, mask) {
|
|
111
|
-
if (obj.type === "Mesh") {
|
|
112
|
-
if (!obj.layers.test(mask))
|
|
113
|
-
return null;
|
|
80
|
+
tempBoundingBox = new Box3();
|
|
81
|
+
onSphereOverlap(obj, sp, mask, results, traverseChildsAfterHit) {
|
|
82
|
+
if (obj.type === "Mesh" && obj.layers.test(mask)) {
|
|
114
83
|
const mesh = obj;
|
|
115
84
|
const geo = mesh.geometry;
|
|
116
85
|
if (!geo.boundingBox)
|
|
117
86
|
geo.computeBoundingBox();
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
87
|
+
if (geo.boundingBox) {
|
|
88
|
+
if (mesh.matrixWorldNeedsUpdate)
|
|
89
|
+
mesh.updateMatrixWorld();
|
|
90
|
+
const test = this.tempBoundingBox.copy(geo.boundingBox).applyMatrix4(mesh.matrixWorld);
|
|
91
|
+
if (sp.intersectsBox(test)) {
|
|
92
|
+
// console.log(obj, obj.layers.test(mask), obj.layers.mask, mask.mask);
|
|
93
|
+
const wp = getWorldPosition(obj);
|
|
94
|
+
const dist = wp.distanceTo(sp.center);
|
|
95
|
+
const int = new SphereIntersection(obj, dist, sp.center.clone());
|
|
96
|
+
results.push(int);
|
|
97
|
+
if (!traverseChildsAfterHit)
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
129
100
|
}
|
|
130
101
|
}
|
|
131
|
-
|
|
102
|
+
if (obj.children) {
|
|
132
103
|
for (const ch of obj.children) {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
104
|
+
const len = results.length;
|
|
105
|
+
this.onSphereOverlap(ch, sp, mask, results, traverseChildsAfterHit);
|
|
106
|
+
if (len != results.length && !traverseChildsAfterHit)
|
|
107
|
+
return;
|
|
136
108
|
}
|
|
137
109
|
}
|
|
138
|
-
return null;
|
|
139
110
|
}
|
|
140
111
|
raycastFromRay(ray, options = null) {
|
|
141
112
|
const opts = options ?? this.defaultRaycastOptions;
|
|
@@ -179,9 +150,9 @@ export class Physics {
|
|
|
179
150
|
results = this.defaultRaycastOptions.results;
|
|
180
151
|
}
|
|
181
152
|
// layermask
|
|
182
|
-
// https://github.com/mrdoob/
|
|
153
|
+
// https://github.com/mrdoob/js/blob/master/src/core/Layers.js
|
|
183
154
|
if (options.layerMask !== undefined) {
|
|
184
|
-
if (options.layerMask instanceof
|
|
155
|
+
if (options.layerMask instanceof Layers)
|
|
185
156
|
rc.layers.mask = options.layerMask.mask;
|
|
186
157
|
else
|
|
187
158
|
rc.layers.mask = options.layerMask;
|
|
@@ -202,385 +173,343 @@ export class Physics {
|
|
|
202
173
|
return results;
|
|
203
174
|
}
|
|
204
175
|
// physics simulation
|
|
205
|
-
|
|
176
|
+
_tempPosition = new Vector3();
|
|
177
|
+
_tempQuaternion = new Quaternion();
|
|
178
|
+
_tempMatrix = new Matrix4();
|
|
179
|
+
static _didLoadPhysicsEngine = false;
|
|
206
180
|
_isUpdatingPhysicsWorld = false;
|
|
181
|
+
get isUpdating() { return this._isUpdatingPhysicsWorld; }
|
|
207
182
|
context;
|
|
208
|
-
world
|
|
183
|
+
world;
|
|
184
|
+
_hasCreatedWorld = false;
|
|
185
|
+
eventQueue;
|
|
186
|
+
collisionHandler;
|
|
187
|
+
// private rigidbodies: Array<IRigidbody | null> = [];
|
|
209
188
|
objects = [];
|
|
210
|
-
|
|
211
|
-
|
|
189
|
+
bodies = [];
|
|
190
|
+
// private rigidbodiesLookup: Map<IRigidbody, RigidBody> = new Map<IRigidbody, RigidBody>();
|
|
191
|
+
// private kinematicColliders: Array<IComponent> = [];
|
|
192
|
+
// private rigidbodyLookup: Map<IRigidbody, IComponent[]> = new Map<IRigidbody, IComponent[]>();
|
|
193
|
+
// private objectLookup: Map<Object3D, IRigidbody> = new Map<Object3D, IRigidbody>();
|
|
212
194
|
constructor(context) {
|
|
213
195
|
this.context = context;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
196
|
+
}
|
|
197
|
+
async createWorld() {
|
|
198
|
+
if (this._hasCreatedWorld) {
|
|
199
|
+
console.error("Invalid call to create physics world: world is already created");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this._hasCreatedWorld = true;
|
|
203
|
+
if (!Physics._didLoadPhysicsEngine) {
|
|
204
|
+
await RAPIER.init().then(() => RAPIER);
|
|
205
|
+
Physics._didLoadPhysicsEngine = true;
|
|
206
|
+
}
|
|
207
|
+
const gravity = { x: 0.0, y: -9.81, z: 0.0 };
|
|
208
|
+
this.world = new World(gravity);
|
|
209
|
+
}
|
|
210
|
+
addBoxCollider(collider, center, size) {
|
|
211
|
+
const obj = collider.gameObject;
|
|
212
|
+
const scale = getWorldScale(obj, this._tempPosition).multiply(size);
|
|
213
|
+
scale.multiplyScalar(0.5);
|
|
214
|
+
const desc = ColliderDesc.cuboid(scale.x, scale.y, scale.z);
|
|
215
|
+
this.createCollider(collider, desc, center);
|
|
216
|
+
}
|
|
217
|
+
addSphereCollider(collider, center, radius) {
|
|
218
|
+
const obj = collider.gameObject;
|
|
219
|
+
const scale = getWorldScale(obj, this._tempPosition).multiplyScalar(radius);
|
|
220
|
+
const desc = ColliderDesc.ball(scale.x);
|
|
221
|
+
this.createCollider(collider, desc, center);
|
|
222
|
+
}
|
|
223
|
+
addMeshCollider(collider, mesh, convex) {
|
|
224
|
+
const geo = mesh.geometry;
|
|
225
|
+
if (!geo) {
|
|
226
|
+
if (debugPhysics)
|
|
227
|
+
console.warn("Missing mesh geometry", mesh.name);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
let positions = geo.getAttribute("position").array;
|
|
231
|
+
const indices = geo.index?.array;
|
|
232
|
+
// console.log(geo.center())
|
|
233
|
+
// scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
|
|
234
|
+
const scale = getWorldScale(mesh, this._tempPosition);
|
|
235
|
+
if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
|
|
236
|
+
console.warn("Your model is using scaled mesh colliders which is not optimal for performance", mesh.name, Object.assign({}, scale), mesh);
|
|
237
|
+
// showBalloonWarning("Your model is using scaled mesh colliders which is not optimal for performance: " + mesh.name + ", consider using unscaled objects");
|
|
238
|
+
const scaledPositions = new Float32Array(positions.length);
|
|
239
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
240
|
+
scaledPositions[i] = positions[i] * scale.x;
|
|
241
|
+
scaledPositions[i + 1] = positions[i + 1] * scale.y;
|
|
242
|
+
scaledPositions[i + 2] = positions[i + 2] * scale.z;
|
|
250
243
|
}
|
|
244
|
+
positions = scaledPositions;
|
|
245
|
+
}
|
|
246
|
+
const desc = convex ? ColliderDesc.convexMesh(positions) : ColliderDesc.trimesh(positions, indices);
|
|
247
|
+
if (desc) {
|
|
248
|
+
this.createCollider(collider, desc);
|
|
249
|
+
// col.setTranslationWrtParent(new Vector3(0,2,0));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
createCollider(collider, desc, center) {
|
|
253
|
+
if (!this.world)
|
|
254
|
+
throw new Error("Physics world not initialized");
|
|
255
|
+
const matrix = this._tempMatrix;
|
|
256
|
+
const { rigidBody, useExplicitMassProperties } = this.getRigidbody(collider, this._tempMatrix);
|
|
257
|
+
matrix.decompose(this._tempPosition, this._tempQuaternion, new Vector3());
|
|
258
|
+
if (center)
|
|
259
|
+
this._tempPosition.add(center);
|
|
260
|
+
desc.setTranslation(this._tempPosition.x, this._tempPosition.y, this._tempPosition.z);
|
|
261
|
+
desc.setRotation(this._tempQuaternion);
|
|
262
|
+
desc.setSensor(collider.isTrigger);
|
|
263
|
+
// if we want to use explicit mass properties, we need to set the collider density to 0
|
|
264
|
+
// otherwise rapier will compute the mass properties based on the collider shape and density
|
|
265
|
+
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
266
|
+
if (useExplicitMassProperties) {
|
|
267
|
+
// desc.setDensity(0);
|
|
251
268
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
269
|
+
const col = this.world.createCollider(desc, rigidBody);
|
|
270
|
+
col[$componentKey] = collider;
|
|
271
|
+
collider[$bodyKey] = col;
|
|
272
|
+
col.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
|
273
|
+
this.objects.push(collider);
|
|
274
|
+
this.bodies.push(col);
|
|
275
|
+
return col;
|
|
276
|
+
}
|
|
277
|
+
getRigidbody(collider, _matrix) {
|
|
278
|
+
if (!this.world)
|
|
279
|
+
throw new Error("Physics world not initialized");
|
|
280
|
+
let rigidBody = null;
|
|
281
|
+
let useExplicitMassProperties = false;
|
|
282
|
+
if (collider.attachedRigidbody) {
|
|
283
|
+
const rb = collider.attachedRigidbody;
|
|
284
|
+
rigidBody = rb[$bodyKey];
|
|
285
|
+
useExplicitMassProperties = true;
|
|
286
|
+
if (!rigidBody) {
|
|
287
|
+
const kinematic = rb.isKinematic && !debugColliderPlacement;
|
|
288
|
+
if (debugPhysics)
|
|
289
|
+
console.log("Create rigidbody", kinematic);
|
|
290
|
+
const rigidBodyDesc = kinematic ? RAPIER.RigidBodyDesc.kinematicPositionBased() : RAPIER.RigidBodyDesc.dynamic();
|
|
291
|
+
const pos = getWorldPosition(collider.attachedRigidbody.gameObject);
|
|
292
|
+
rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
|
|
293
|
+
rigidBodyDesc.setRotation(getWorldQuaternion(collider.attachedRigidbody.gameObject));
|
|
294
|
+
rigidBody = this.world.createRigidBody(rigidBodyDesc);
|
|
295
|
+
this.bodies.push(rigidBody);
|
|
296
|
+
this.objects.push(rb);
|
|
266
297
|
}
|
|
298
|
+
rigidBody[$componentKey] = rb;
|
|
299
|
+
rb[$bodyKey] = rigidBody;
|
|
300
|
+
this.internalUpdateProperties(rb, rigidBody);
|
|
301
|
+
this.getRigidbodyRelativeMatrix(collider.gameObject, rb.gameObject, _matrix);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
const rigidBodyDesc = RAPIER.RigidBodyDesc.kinematicPositionBased();
|
|
305
|
+
const pos = getWorldPosition(collider.gameObject);
|
|
306
|
+
rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
|
|
307
|
+
rigidBodyDesc.setRotation(getWorldQuaternion(collider.gameObject));
|
|
308
|
+
rigidBody = this.world.createRigidBody(rigidBodyDesc);
|
|
309
|
+
_matrix.identity();
|
|
310
|
+
rigidBody[$componentKey] = null;
|
|
267
311
|
}
|
|
312
|
+
return { rigidBody: rigidBody, useExplicitMassProperties: useExplicitMassProperties };
|
|
268
313
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
314
|
+
removeBody(obj) {
|
|
315
|
+
const body = obj[$bodyKey];
|
|
316
|
+
obj[$bodyKey] = null;
|
|
317
|
+
if (body) {
|
|
318
|
+
const index = this.objects.findIndex(o => o === obj);
|
|
319
|
+
if (index >= 0) {
|
|
320
|
+
const body = this.bodies[index];
|
|
321
|
+
this.bodies.splice(index, 1);
|
|
322
|
+
this.objects.splice(index, 1);
|
|
323
|
+
if (body instanceof Collider) {
|
|
324
|
+
this.world?.removeCollider(body, true);
|
|
325
|
+
}
|
|
326
|
+
else if (body instanceof RigidBody) {
|
|
327
|
+
this.world?.removeRigidBody(body);
|
|
328
|
+
}
|
|
329
|
+
// check if we need to remove the rigidbody too
|
|
330
|
+
const col = obj;
|
|
331
|
+
if (col.isCollider && col.attachedRigidbody) {
|
|
332
|
+
const rb = col.attachedRigidbody[$bodyKey];
|
|
333
|
+
if (rb && rb.numColliders() <= 0 && rb.world() === this.world) {
|
|
334
|
+
this.world?.removeRigidBody(rb);
|
|
335
|
+
}
|
|
275
336
|
}
|
|
276
|
-
return;
|
|
277
337
|
}
|
|
278
338
|
}
|
|
279
339
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
body
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
this.objects.push(po);
|
|
322
|
-
}
|
|
323
|
-
return shape;
|
|
324
|
-
}
|
|
325
|
-
addSphereCollider(obj, center, radius, rb) {
|
|
326
|
-
const scale = this.tempPosition;
|
|
327
|
-
obj.getWorldScale(scale);
|
|
328
|
-
const factor = Math.max(scale.x, scale.y, scale.z);
|
|
329
|
-
const shape = new CANNON.Sphere(radius * factor);
|
|
330
|
-
// shape.collisionResponse = !trigger;
|
|
331
|
-
center = center.clone();
|
|
332
|
-
center.multiply(scale);
|
|
333
|
-
const body = this.addShape(obj, shape, center, rb);
|
|
334
|
-
if (body !== null) {
|
|
335
|
-
this.world.addBody(body);
|
|
336
|
-
if (this.isAlreadyRegistered(body))
|
|
337
|
-
return shape;
|
|
338
|
-
const po = new PhysicsObject(obj, body);
|
|
339
|
-
this.objects.push(po);
|
|
340
|
-
}
|
|
341
|
-
return shape;
|
|
342
|
-
}
|
|
343
|
-
addMeshCollider(_obj) {
|
|
344
|
-
// see https://github.com/schteppe/cannon.js/blob/master/demos/bunny.html
|
|
345
|
-
if (debugPhysics)
|
|
346
|
-
console.warn("TODO mesh collider not yet supported");
|
|
347
|
-
// const geometry: THREE.BufferGeometry = obj["geometry"];
|
|
348
|
-
// console.log(geometry);
|
|
349
|
-
// const size = geometry.boundingBox.max.clone();
|
|
350
|
-
// size.sub(geometry.boundingBox.min);
|
|
351
|
-
// console.log(size);
|
|
352
|
-
// this.addBoxCollider(obj, size);
|
|
353
|
-
// const verts = geometry.getAttribute("position").array;
|
|
354
|
-
// const faces = new Array<Array<number>>();
|
|
355
|
-
// console.log(geometry);
|
|
356
|
-
// for (let i = 0; i < geometry.index.array.length; i += 3) {
|
|
357
|
-
// const i0 = geometry.index.array[i];
|
|
358
|
-
// const i1 = geometry.index.array[i + 1];
|
|
359
|
-
// const i2 = geometry.index.array[i + 2];
|
|
360
|
-
// const v0 = new THREE.Vector3(verts[i0 * 3], verts[i0 * 3 + 1], verts[i0 * 3 + 2]);
|
|
361
|
-
// const v1 = new THREE.Vector3(verts[i1 * 3], verts[i1 * 3 + 1], verts[i1 * 3 + 2]);
|
|
362
|
-
// const v2 = new THREE.Vector3(verts[i2 * 3], verts[i2 * 3 + 1], verts[i2 * 3 + 2]);
|
|
363
|
-
// const face = [v0, v1, v2];
|
|
364
|
-
// faces.push(face);
|
|
340
|
+
updateBody(comp, translation, rotation) {
|
|
341
|
+
if (comp.destroyed || !comp.gameObject)
|
|
342
|
+
return;
|
|
343
|
+
if (!translation && !rotation)
|
|
344
|
+
return;
|
|
345
|
+
if (comp.isCollider === true) {
|
|
346
|
+
// const collider = comp as ICollider;
|
|
347
|
+
console.warn("TODO: implement updating collider position");
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const rigidbody = comp;
|
|
351
|
+
const body = rigidbody[$bodyKey];
|
|
352
|
+
if (body) {
|
|
353
|
+
this.syncPhysicsBody(rigidbody.gameObject, body, translation, rotation);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
updateProperties(rigidbody) {
|
|
358
|
+
const physicsBody = rigidbody[$bodyKey];
|
|
359
|
+
if (physicsBody) {
|
|
360
|
+
this.internalUpdateProperties(rigidbody, physicsBody);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
internal_getRigidbody(rb) {
|
|
364
|
+
return rb[$bodyKey];
|
|
365
|
+
}
|
|
366
|
+
internalUpdateProperties(rb, rigidbody) {
|
|
367
|
+
// continuous collision detection
|
|
368
|
+
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#continuous-collision-detection
|
|
369
|
+
rigidbody.enableCcd(rb.collisionDetectionMode !== CollisionDetectionMode.Discrete);
|
|
370
|
+
rigidbody.setLinearDamping(rb.drag);
|
|
371
|
+
rigidbody.setAngularDamping(rb.angularDrag);
|
|
372
|
+
rigidbody.setGravityScale(rb.useGravity ? 1 : 0, true);
|
|
373
|
+
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
374
|
+
// rigidbody.setAdditionalMass(rb.mass, true);
|
|
375
|
+
// for (let i = 0; i < rigidbody.numColliders(); i++) {
|
|
376
|
+
// const collider = rigidbody.collider(i);
|
|
377
|
+
// if (collider) {
|
|
378
|
+
// collider.setMass(rb.mass);
|
|
379
|
+
// // const density = rb.mass / collider.shape.computeMassProperties().mass;
|
|
380
|
+
// }
|
|
365
381
|
// }
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
for (const obj of this.objects) {
|
|
372
|
-
if (obj.body === body)
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
tempMat1 = new THREE.Matrix4();
|
|
378
|
-
tempMat2 = new THREE.Matrix4();
|
|
379
|
-
addShape(obj, shape, center, rb) {
|
|
380
|
-
let body = null;
|
|
381
|
-
if (rb) {
|
|
382
|
-
// if (debugPhysics)
|
|
383
|
-
// console.log("get rb body", rb);
|
|
384
|
-
rb.initialize();
|
|
385
|
-
console.assert(rb.body ? true : false, "rigidbody didn't initialize / produce a physics body", rb);
|
|
386
|
-
body = rb.body;
|
|
382
|
+
// lock rotations
|
|
383
|
+
rigidbody.setEnabledRotations(!rb.lockRotationX, !rb.lockRotationY, !rb.lockRotationZ, true);
|
|
384
|
+
rigidbody.setEnabledTranslations(!rb.lockPositionX, !rb.lockPositionY, !rb.lockPositionZ, true);
|
|
385
|
+
if (rb.isKinematic) {
|
|
386
|
+
rigidbody.setBodyType(RAPIER.RigidBodyType.KinematicPositionBased);
|
|
387
387
|
}
|
|
388
388
|
else {
|
|
389
|
-
|
|
390
|
-
body = this.internalCreateBody(obj, null);
|
|
391
|
-
body.type = CANNON.Body.KINEMATIC;
|
|
389
|
+
rigidbody.setBodyType(RAPIER.RigidBodyType.Dynamic);
|
|
392
390
|
}
|
|
393
|
-
if (body) {
|
|
394
|
-
// console.log(obj.name, obj.position, obj.rotation)
|
|
395
|
-
// the center is serialized from Unity so we need to move it into threejs space
|
|
396
|
-
// this should probably happen on export for colliders
|
|
397
|
-
center.x *= -1;
|
|
398
|
-
let wp = obj.position;
|
|
399
|
-
let wr = obj.quaternion;
|
|
400
|
-
// console.log(obj.name, wp)
|
|
401
|
-
if (rb && rb.gameObject !== obj) {
|
|
402
|
-
this.tempMat1.copy(obj.matrixWorld);
|
|
403
|
-
this.tempMat2.copy(rb.gameObject.matrixWorld).invert();
|
|
404
|
-
this.tempMat1.premultiply(this.tempMat2);
|
|
405
|
-
this.tempMat1.decompose(wp, wr, this.tempPosition);
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
408
|
-
wp = threeutils.getWorldPosition(obj);
|
|
409
|
-
const bp = body.position;
|
|
410
|
-
wp.x -= bp.x;
|
|
411
|
-
wp.y -= bp.y;
|
|
412
|
-
wp.z -= bp.z;
|
|
413
|
-
wr = threeutils.getWorldQuaternion(obj);
|
|
414
|
-
const r = new THREE.Quaternion(body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w);
|
|
415
|
-
wr.multiply(r.invert());
|
|
416
|
-
}
|
|
417
|
-
// get rotation difference
|
|
418
|
-
wp.add(center);
|
|
419
|
-
// if (rb) {
|
|
420
|
-
// this.tempMat.setPosition(wp);
|
|
421
|
-
// this.tempMat.makeRotationFromQuaternion(wr);
|
|
422
|
-
// this.tempMat.multiplyMatrices(this.tempMat, rb?.gameObject.matrix);
|
|
423
|
-
// this.tempMat.decompose(this.tempPosition, this.tempQuaternion, new THREE.Vector3());
|
|
424
|
-
// wp.copy(this.tempPosition);
|
|
425
|
-
// }
|
|
426
|
-
// wp.applyQuaternion(wr);
|
|
427
|
-
const pos = new CANNON.Vec3(wp.x, wp.y, wp.z);
|
|
428
|
-
const rot = new CANNON.Quaternion(wr.x, wr.y, wr.z, wr.w);
|
|
429
|
-
body.addShape(shape, pos, rot);
|
|
430
|
-
body.updateMassProperties();
|
|
431
|
-
this.world.addBody(body);
|
|
432
|
-
}
|
|
433
|
-
return body;
|
|
434
391
|
}
|
|
435
392
|
// private _lastStepTime: number | undefined = 0;
|
|
436
|
-
|
|
393
|
+
lines;
|
|
394
|
+
step(_deltaTime) {
|
|
395
|
+
if (!this.world)
|
|
396
|
+
return;
|
|
437
397
|
this._isUpdatingPhysicsWorld = true;
|
|
438
|
-
|
|
439
|
-
|
|
398
|
+
if (!this.eventQueue) {
|
|
399
|
+
this.eventQueue = new EventQueue(false);
|
|
400
|
+
}
|
|
401
|
+
this.world.step(this.eventQueue);
|
|
440
402
|
this._isUpdatingPhysicsWorld = false;
|
|
441
|
-
|
|
442
|
-
|
|
403
|
+
this.updateDebugRendering(this.world);
|
|
404
|
+
}
|
|
405
|
+
updateDebugRendering(world) {
|
|
406
|
+
if (debugPhysics || debugColliderPlacement) {
|
|
407
|
+
if (!this.lines) {
|
|
408
|
+
let material = new LineBasicMaterial({
|
|
409
|
+
color: 0xffffff,
|
|
410
|
+
// vertexColors: THREE.VertexColors
|
|
411
|
+
});
|
|
412
|
+
let geometry = new BufferGeometry();
|
|
413
|
+
this.lines = new LineSegments(geometry, material);
|
|
414
|
+
this.context.scene.add(this.lines);
|
|
415
|
+
}
|
|
416
|
+
const buffers = world.debugRender();
|
|
417
|
+
this.lines.geometry.setAttribute('position', new BufferAttribute(buffers.vertices, 3));
|
|
418
|
+
this.lines.geometry.setAttribute('color', new BufferAttribute(buffers.colors, 4));
|
|
443
419
|
}
|
|
444
420
|
}
|
|
445
|
-
temp = new THREE.Vector3();
|
|
446
|
-
tempQuat = new THREE.Quaternion();
|
|
447
421
|
postStep() {
|
|
422
|
+
if (!this.world)
|
|
423
|
+
return;
|
|
448
424
|
this._isUpdatingPhysicsWorld = true;
|
|
449
|
-
|
|
450
|
-
const entry = this.objects[i];
|
|
451
|
-
const body = entry.body;
|
|
452
|
-
if (!body || !body.world)
|
|
453
|
-
continue;
|
|
454
|
-
body.sleepTick(this.context.time.time);
|
|
455
|
-
if (debugPhysics) {
|
|
456
|
-
if (!entry._didSleepLastStep && body.sleepState === CANNON.Body.SLEEPING) {
|
|
457
|
-
console.log("BODY SLEEPING", body);
|
|
458
|
-
}
|
|
459
|
-
else if (entry._didSleepLastStep && body.sleepState !== CANNON.Body.SLEEPING) {
|
|
460
|
-
console.log("BODY WOKE UP", body);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
entry._didSleepLastStep = body.sleepState === CANNON.Body.SLEEPING;
|
|
464
|
-
// if(body.sleepState === CANNON.Body.SLEEPING) {
|
|
465
|
-
// console.log("SLEEP", body.name);
|
|
466
|
-
// }
|
|
467
|
-
// if (body.type == CANNON.Body.KINEMATIC) continue;
|
|
468
|
-
const obj = entry.obj;
|
|
469
|
-
if (body.type === CANNON.Body.KINEMATIC) {
|
|
470
|
-
const wp = threeutils.getWorldPosition(obj, this.temp);
|
|
471
|
-
body.position.set(wp.x, wp.y, wp.z);
|
|
472
|
-
const rot = threeutils.getWorldQuaternion(obj, this.tempQuat);
|
|
473
|
-
body.quaternion.set(rot.x, rot.y, rot.z, rot.w);
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
// when reparenting (e.g. attached to controller) I think it doesnt work with previous parent? need to test again, to tired now
|
|
477
|
-
if (entry.parent && obj.parent === entry.parent) {
|
|
478
|
-
threeutils.setWorldQuaternionXYZW(obj, body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w);
|
|
479
|
-
const p = body.position;
|
|
480
|
-
threeutils.setWorldPositionXYZ(obj, p.x, p.y, p.z);
|
|
481
|
-
if (body.velocity.length() > body.sleepSpeedLimit) {
|
|
482
|
-
InstancingUtil.markDirty(obj);
|
|
483
|
-
}
|
|
484
|
-
// this.worldToLocal.x = body.position.x;
|
|
485
|
-
// this.worldToLocal.y = body.position.y;
|
|
486
|
-
// this.worldToLocal.z = body.position.z;
|
|
487
|
-
// const pos = entry.parent.worldToLocal(this.worldToLocal);
|
|
488
|
-
// obj.position.x = pos.x;
|
|
489
|
-
// obj.position.y = pos.y;
|
|
490
|
-
// obj.position.z = pos.z;
|
|
491
|
-
// if (entry.center) {
|
|
492
|
-
// this.rotatedCenter.copy(entry.center);
|
|
493
|
-
// const rot = this.tempQuaternion;
|
|
494
|
-
// rot.copy(obj.quaternion);
|
|
495
|
-
// // obj.getWorldQuaternion(this.tempQuaternion)
|
|
496
|
-
// this.rotatedCenter.applyQuaternion(rot);
|
|
497
|
-
// obj.getWorldScale(this.tempVector);
|
|
498
|
-
// this.rotatedCenter.divide(this.tempVector);
|
|
499
|
-
// obj.position.sub(this.rotatedCenter);
|
|
500
|
-
// }
|
|
501
|
-
}
|
|
502
|
-
}
|
|
425
|
+
this.syncObjects();
|
|
503
426
|
this._isUpdatingPhysicsWorld = false;
|
|
427
|
+
if (this.eventQueue && !this.collisionHandler) {
|
|
428
|
+
this.collisionHandler = new PhysicsCollisionHandler(this.world, this.eventQueue);
|
|
429
|
+
}
|
|
430
|
+
if (this.collisionHandler) {
|
|
431
|
+
this.collisionHandler.handleCollisionEvents();
|
|
432
|
+
this.collisionHandler.update();
|
|
433
|
+
}
|
|
504
434
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
body["_name"] = obj.name;
|
|
509
|
-
obj.getWorldPosition(this.tempPosition);
|
|
510
|
-
const pos = this.tempPosition;
|
|
511
|
-
body.position = new CANNON.Vec3(pos.x, pos.y, pos.z);
|
|
512
|
-
const quat = this.tempQuaternion;
|
|
513
|
-
obj.getWorldQuaternion(quat);
|
|
514
|
-
body.quaternion = new CANNON.Quaternion(quat.x, quat.y, quat.z, quat.w);
|
|
515
|
-
body.type = CANNON.Body.KINEMATIC;
|
|
516
|
-
if (shape) {
|
|
517
|
-
body.addShape(shape);
|
|
518
|
-
body.updateMassProperties();
|
|
519
|
-
}
|
|
520
|
-
return body;
|
|
521
|
-
}
|
|
522
|
-
// private findObject(obj: THREE.Object3D): PhysicsObject | null {
|
|
523
|
-
// for (let i = 0; i < this.objects.length; i++) {
|
|
524
|
-
// const entry = this.objects[i];
|
|
525
|
-
// if (entry.obj == obj)
|
|
526
|
-
// return entry;
|
|
527
|
-
// }
|
|
528
|
-
// return null;
|
|
529
|
-
// }
|
|
530
|
-
registerCollisionEvents(obj) {
|
|
531
|
-
if (obj.collisonCallback)
|
|
532
|
-
this.unregisterCollisionEvents(obj);
|
|
533
|
-
if (!obj.body)
|
|
534
|
-
return;
|
|
535
|
-
const evt = evt => this.raiseCollisionEvents(obj.obj, evt);
|
|
536
|
-
obj.collisonCallback = evt.bind(this);
|
|
537
|
-
obj.body.addEventListener("collide", obj.collisonCallback);
|
|
538
|
-
}
|
|
539
|
-
unregisterCollisionEvents(obj) {
|
|
540
|
-
if (!obj.collisonCallback)
|
|
541
|
-
return;
|
|
542
|
-
if (!obj.body)
|
|
435
|
+
/** sync rendered objects with physics world (except for colliders without rigidbody) */
|
|
436
|
+
syncObjects() {
|
|
437
|
+
if (debugColliderPlacement)
|
|
543
438
|
return;
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
foreachComponent(collision.gameObject, (c) => {
|
|
562
|
-
c.__internalHandleCollision(collision2, true);
|
|
563
|
-
});
|
|
439
|
+
for (let i = 0; i < this.bodies.length; i++) {
|
|
440
|
+
const obj = this.objects[i];
|
|
441
|
+
const body = this.bodies[i];
|
|
442
|
+
// if the collider is not attached to a rigidbody
|
|
443
|
+
// it means that its kinematic so we need to update its position
|
|
444
|
+
const col = obj;
|
|
445
|
+
if (col?.isCollider === true && !col.attachedRigidbody) {
|
|
446
|
+
const rigidbody = body.parent();
|
|
447
|
+
if (rigidbody)
|
|
448
|
+
this.syncPhysicsBody(obj.gameObject, rigidbody, true, true);
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
// sync
|
|
452
|
+
const pos = body.translation();
|
|
453
|
+
setWorldPositionXYZ(obj.gameObject, pos.x, pos.y, pos.z);
|
|
454
|
+
const rot = body.rotation();
|
|
455
|
+
setWorldQuaternionXYZW(obj.gameObject, rot.x, rot.y, rot.z, rot.w);
|
|
564
456
|
}
|
|
565
457
|
}
|
|
566
|
-
|
|
567
|
-
//
|
|
568
|
-
//
|
|
569
|
-
const
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
458
|
+
syncPhysicsBody(obj, body, translation, rotation) {
|
|
459
|
+
// const bodyType = body.bodyType();
|
|
460
|
+
// const previous = physicsBody.translation();
|
|
461
|
+
// const vel = physicsBody.linvel();
|
|
462
|
+
const worldPosition = getWorldPosition(obj, this._tempPosition);
|
|
463
|
+
const worldQuaternion = getWorldQuaternion(obj, this._tempQuaternion);
|
|
464
|
+
// physicsBody.setBodyType(RAPIER.RigidBodyType.Fixed);
|
|
465
|
+
if (translation)
|
|
466
|
+
body.setTranslation(worldPosition, false);
|
|
467
|
+
if (rotation)
|
|
468
|
+
body.setRotation(worldQuaternion, false);
|
|
469
|
+
// physicsBody.setLinvel(vel, false);
|
|
470
|
+
body.wakeUp();
|
|
471
|
+
// update velocity
|
|
472
|
+
// const pos = physicsBody.translation();
|
|
473
|
+
// pos.x -= previous.x;
|
|
474
|
+
// pos.y -= previous.y;
|
|
475
|
+
// pos.z -= previous.z;
|
|
476
|
+
// // threhold
|
|
477
|
+
// const t = 1;
|
|
478
|
+
// const canUpdateVelocity = Math.abs(pos.x) < t && Math.abs(pos.y) < t && Math.abs(pos.z) < t;
|
|
479
|
+
// if (canUpdateVelocity) {
|
|
480
|
+
// const damping = 1 + this.context.time.deltaTime;
|
|
481
|
+
// vel.x *= damping;
|
|
482
|
+
// vel.y *= damping;
|
|
483
|
+
// vel.z *= damping;
|
|
484
|
+
// vel.x += pos.x;
|
|
485
|
+
// vel.y += pos.y;
|
|
486
|
+
// vel.z += pos.z;
|
|
487
|
+
// console.log(vel);
|
|
488
|
+
// physicsBody.setLinvel(vel, true);
|
|
489
|
+
// }
|
|
490
|
+
// else if(debugPhysics) console.warn("Movement exceeded threshold, not updating velocity", pos);
|
|
491
|
+
// body.setBodyType(bodyType);
|
|
492
|
+
}
|
|
493
|
+
static _matricesBuffer = [];
|
|
494
|
+
getRigidbodyRelativeMatrix(comp, rigidbody, mat, matrices) {
|
|
495
|
+
// collect all matrices to the rigidbody and then build the rigidbody relative matrix
|
|
496
|
+
if (matrices === undefined) {
|
|
497
|
+
matrices = Physics._matricesBuffer;
|
|
498
|
+
matrices.length = 0;
|
|
499
|
+
}
|
|
500
|
+
if (comp === rigidbody) {
|
|
501
|
+
const scale = getWorldScale(comp, this._tempPosition);
|
|
502
|
+
mat.makeScale(scale.x, scale.y, scale.z);
|
|
503
|
+
for (let i = matrices.length - 1; i >= 0; i--) {
|
|
504
|
+
mat.multiply(matrices[i]);
|
|
582
505
|
}
|
|
583
|
-
|
|
506
|
+
return mat;
|
|
507
|
+
}
|
|
508
|
+
matrices.push(comp.matrix);
|
|
509
|
+
if (comp.parent) {
|
|
510
|
+
this.getRigidbodyRelativeMatrix(comp.parent, rigidbody, mat, matrices);
|
|
511
|
+
}
|
|
512
|
+
return mat;
|
|
584
513
|
}
|
|
585
514
|
}
|
|
586
515
|
let colliderProvider = null;
|
|
@@ -592,4 +521,122 @@ class CollisionContext {
|
|
|
592
521
|
return colliderProvider.getCollider(obj);
|
|
593
522
|
}
|
|
594
523
|
}
|
|
524
|
+
/** responsible of processing collision events for the component system */
|
|
525
|
+
class PhysicsCollisionHandler {
|
|
526
|
+
world;
|
|
527
|
+
eventQueue;
|
|
528
|
+
constructor(world, eventQueue) {
|
|
529
|
+
this.world = world;
|
|
530
|
+
this.eventQueue = eventQueue;
|
|
531
|
+
}
|
|
532
|
+
activeCollisions = [];
|
|
533
|
+
activeTriggers = [];
|
|
534
|
+
handleCollisionEvents() {
|
|
535
|
+
if (!this.eventQueue)
|
|
536
|
+
return;
|
|
537
|
+
if (!this.world)
|
|
538
|
+
return;
|
|
539
|
+
this.eventQueue.drainCollisionEvents((handle1, handle2, started) => {
|
|
540
|
+
const col1 = this.world.getCollider(handle1);
|
|
541
|
+
const col2 = this.world.getCollider(handle2);
|
|
542
|
+
const colliderComponent1 = col1[$componentKey];
|
|
543
|
+
const colliderComponent2 = col2[$componentKey];
|
|
544
|
+
// console.log("EVT", colliderComponent1.name, colliderComponent2.name, started);
|
|
545
|
+
if (colliderComponent1 && colliderComponent2) {
|
|
546
|
+
if (started) {
|
|
547
|
+
this.onCollisionStarted(colliderComponent1, col1, colliderComponent2, col2);
|
|
548
|
+
this.onCollisionStarted(colliderComponent2, col2, colliderComponent1, col1);
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
this.onCollisionEnded(colliderComponent1, colliderComponent2);
|
|
552
|
+
this.onCollisionEnded(colliderComponent2, colliderComponent1);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
update() {
|
|
558
|
+
this.onHandleCollisionStay();
|
|
559
|
+
}
|
|
560
|
+
onCollisionStarted(self, selfBody, other, otherBody) {
|
|
561
|
+
let collision = null;
|
|
562
|
+
// if one is a trigger we dont get collisions but want to raise the trigger events
|
|
563
|
+
if (self.isTrigger || other.isTrigger) {
|
|
564
|
+
foreachComponent(self.gameObject, (c) => {
|
|
565
|
+
if (c.onTriggerEnter) {
|
|
566
|
+
c.onTriggerEnter(other);
|
|
567
|
+
}
|
|
568
|
+
this.activeTriggers.push({ collider: self, component: c, otherCollider: other });
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
const object = self.gameObject;
|
|
573
|
+
// TODO: we dont respect the flip value here!
|
|
574
|
+
this.world.contactPair(selfBody, otherBody, (manifold, _flipped) => {
|
|
575
|
+
foreachComponent(object, (c) => {
|
|
576
|
+
if (c.onCollisionEnter) {
|
|
577
|
+
if (!collision) {
|
|
578
|
+
const contacts = [];
|
|
579
|
+
const normal = manifold.normal();
|
|
580
|
+
for (let i = 0; i < manifold.numContacts(); i++) {
|
|
581
|
+
const pt1 = manifold.localContactPoint1(i);
|
|
582
|
+
const dist = manifold.contactDist(i);
|
|
583
|
+
if (pt1) {
|
|
584
|
+
const contact = new ContactPoint(pt1, dist, normal);
|
|
585
|
+
contacts.push(contact);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
collision = new Collision(object, other, contacts);
|
|
589
|
+
}
|
|
590
|
+
c.onCollisionEnter.call(c, collision);
|
|
591
|
+
this.activeCollisions.push({ collider: self, component: c, collision });
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
onHandleCollisionStay() {
|
|
598
|
+
for (const active of this.activeCollisions) {
|
|
599
|
+
const c = active.component;
|
|
600
|
+
if (c.activeAndEnabled && c.onCollisionStay) {
|
|
601
|
+
const arg = active.collision;
|
|
602
|
+
c.onCollisionStay(arg);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
for (const active of this.activeTriggers) {
|
|
606
|
+
const c = active.component;
|
|
607
|
+
if (c.activeAndEnabled && c.onTriggerStay) {
|
|
608
|
+
const arg = active.collider;
|
|
609
|
+
c.onTriggerStay(arg);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
onCollisionEnded(self, other) {
|
|
614
|
+
for (let i = 0; i < this.activeCollisions.length; i++) {
|
|
615
|
+
const active = this.activeCollisions[i];
|
|
616
|
+
const collider = active.collider;
|
|
617
|
+
if (collider === self && active.collision.collider === other) {
|
|
618
|
+
const c = active.component;
|
|
619
|
+
this.activeCollisions.splice(i, 1);
|
|
620
|
+
i--;
|
|
621
|
+
if (c.activeAndEnabled && c.onCollisionExit) {
|
|
622
|
+
const collision = active.collision;
|
|
623
|
+
c.onCollisionExit(collision);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
for (let i = 0; i < this.activeTriggers.length; i++) {
|
|
628
|
+
const active = this.activeTriggers[i];
|
|
629
|
+
const collider = active.collider;
|
|
630
|
+
if (collider === self && active.otherCollider === other) {
|
|
631
|
+
const c = active.component;
|
|
632
|
+
this.activeTriggers.splice(i, 1);
|
|
633
|
+
i--;
|
|
634
|
+
if (c.activeAndEnabled && c.onTriggerExit) {
|
|
635
|
+
const collision = active.otherCollider;
|
|
636
|
+
c.onTriggerExit(collision);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
595
642
|
//# sourceMappingURL=engine_physics.js.map
|