@@ -286,6 +286,16 @@
|
|
286
286
|
abstract getComponentsInChildren<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
287
287
|
abstract getComponentInParent<T>(type: Constructor<T>): T | null;
|
288
288
|
abstract getComponentsInParent<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
289
|
+
|
290
|
+
|
291
|
+
abstract get worldPosition(): Vector3
|
292
|
+
abstract set worldPosition(val: Vector3);
|
293
|
+
abstract set worldQuaternion(val: Quaternion);
|
294
|
+
abstract get worldQuaternion(): Quaternion;
|
295
|
+
abstract set worldRotation(val: Vector3);
|
296
|
+
abstract get worldRotation(): Vector3;
|
297
|
+
abstract set worldScale(val: Vector3);
|
298
|
+
abstract get worldScale(): Vector3;
|
289
299
|
}
|
290
300
|
|
291
301
|
|
@@ -757,19 +757,25 @@
|
|
757
757
|
desc.setMass(.000001);
|
758
758
|
}
|
759
759
|
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
760
|
+
try {
|
761
|
+
const col = this.world.createCollider(desc, rigidBody);
|
762
|
+
col[$componentKey] = collider;
|
763
|
+
collider[$bodyKey] = col;
|
764
|
+
col.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
765
|
+
// We want to receive collisitons between two triggers too
|
766
|
+
col.setActiveCollisionTypes(ActiveCollisionTypes.ALL);
|
766
767
|
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
768
|
+
// const objectLayerMask = collider.gameObject.layers.mask;
|
769
|
+
// const mask = objectLayerMask & ~2;
|
770
|
+
// col.setCollisionGroups(objectLayerMask);
|
771
|
+
this.objects.push(collider);
|
772
|
+
this.bodies.push(col);
|
773
|
+
return col;
|
774
|
+
}
|
775
|
+
catch (e) {
|
776
|
+
console.error("Error creating collider \"" + collider.name + "\"\nError:", e);
|
777
|
+
return null;
|
778
|
+
}
|
773
779
|
}
|
774
780
|
|
775
781
|
private getRigidbody(collider: ICollider, _matrix: Matrix4): { rigidBody: RigidBody, useExplicitMassProperties: boolean } {
|
@@ -46,6 +46,7 @@
|
|
46
46
|
}
|
47
47
|
|
48
48
|
const _worldPositions = new CircularBuffer(() => new Vector3(), 100);
|
49
|
+
const _lastMatrixWorldUpdateKey = Symbol("lastMatrixWorldUpdateKey");
|
49
50
|
|
50
51
|
export function getWorldPosition(obj: Object3D, vec: Vector3 | null = null, updateParents: boolean = true): Vector3 {
|
51
52
|
const wp = vec ?? _worldPositions.get();
|
@@ -53,8 +54,10 @@
|
|
53
54
|
if (!obj.parent) return wp.copy(obj.position);
|
54
55
|
if (updateParents)
|
55
56
|
obj.updateWorldMatrix(true, false);
|
56
|
-
if (obj.matrixWorldNeedsUpdate)
|
57
|
+
if (obj.matrixWorldNeedsUpdate && obj[_lastMatrixWorldUpdateKey] !== Date.now()) {
|
58
|
+
obj[_lastMatrixWorldUpdateKey] = Date.now();
|
57
59
|
obj.updateMatrixWorld();
|
60
|
+
}
|
58
61
|
wp.setFromMatrixPosition(obj.matrixWorld);
|
59
62
|
return wp;
|
60
63
|
}
|
@@ -122,6 +122,15 @@
|
|
122
122
|
getComponentsInChildren<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
123
123
|
getComponentInParent<T>(type: Constructor<T>): T | null;
|
124
124
|
getComponentsInParent<T>(type: Constructor<T>, arr?: T[]): Array<T>;
|
125
|
+
|
126
|
+
get worldPosition(): Vector3;
|
127
|
+
set worldPosition(val: Vector3);
|
128
|
+
get worldQuaternion(): Quaternion;
|
129
|
+
set worldQuaternion(val: Quaternion);
|
130
|
+
get worldRotation(): Vector3;
|
131
|
+
set worldRotation(val: Vector3);
|
132
|
+
get worldScale(): Vector3;
|
133
|
+
set worldScale(val: Vector3);
|
125
134
|
}
|
126
135
|
|
127
136
|
export interface IHasGuid {
|
@@ -1,8 +1,19 @@
|
|
1
1
|
import { applyPrototypeExtensions, registerPrototypeExtensions } from "./ExtensionUtils.js";
|
2
|
-
import { Object3D } from "three";
|
2
|
+
import { Object3D, Quaternion, Vector3 } from "three";
|
3
3
|
import type { Constructor, ConstructorConcrete, IComponent, IComponent as Component } from "../../engine/engine_types.js";
|
4
4
|
import { moveComponentInstance, addNewComponent, getComponent, getComponentInChildren, getComponentInParent, getComponents, getComponentsInChildren, getComponentsInParent, getOrAddComponent, removeComponent } from "../../engine/engine_components.js";
|
5
5
|
import { isActiveSelf, setActive, destroy } from "../../engine/engine_gameobject.js";
|
6
|
+
import {
|
7
|
+
setWorldPosition,
|
8
|
+
getWorldPosition,
|
9
|
+
setWorldQuaternion,
|
10
|
+
getWorldQuaternion,
|
11
|
+
getWorldScale,
|
12
|
+
setWorldScale,
|
13
|
+
setWorldRotation,
|
14
|
+
getWorldRotation
|
15
|
+
}
|
16
|
+
from "../../engine/engine_three_utils.js";
|
6
17
|
|
7
18
|
// used to decorate cloned object3D objects with the same added components defined above
|
8
19
|
export function apply(object: Object3D) {
|
@@ -63,6 +74,7 @@
|
|
63
74
|
return getComponentsInParent(this, type, arr);
|
64
75
|
}
|
65
76
|
|
77
|
+
|
66
78
|
// this is a fix to allow gameObject active animation be applied to a three object
|
67
79
|
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "activeSelf")) {
|
68
80
|
Object.defineProperty(Object3D.prototype, "activeSelf", {
|
@@ -86,5 +98,53 @@
|
|
86
98
|
|
87
99
|
|
88
100
|
|
101
|
+
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldPosition")) {
|
102
|
+
Object.defineProperty(Object3D.prototype, "worldPosition", {
|
103
|
+
get: function () {
|
104
|
+
return getWorldPosition(this);
|
105
|
+
},
|
106
|
+
set: function (val: Vector3) {
|
107
|
+
setWorldPosition(this, val)
|
108
|
+
}
|
109
|
+
});
|
110
|
+
}
|
111
|
+
|
112
|
+
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldQuaternion")) {
|
113
|
+
Object.defineProperty(Object3D.prototype, "worldQuaternion", {
|
114
|
+
get: function () {
|
115
|
+
return getWorldQuaternion(this);
|
116
|
+
},
|
117
|
+
set: function (val: Quaternion) {
|
118
|
+
setWorldQuaternion(this, val)
|
119
|
+
}
|
120
|
+
});
|
121
|
+
}
|
122
|
+
|
123
|
+
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldRotation")) {
|
124
|
+
Object.defineProperty(Object3D.prototype, "worldRotation", {
|
125
|
+
get: function () {
|
126
|
+
return getWorldRotation(this);
|
127
|
+
},
|
128
|
+
set: function (val: Vector3) {
|
129
|
+
setWorldRotation(this, val)
|
130
|
+
}
|
131
|
+
});
|
132
|
+
}
|
133
|
+
|
134
|
+
if (!Object.getOwnPropertyDescriptor(Object3D.prototype, "worldScale")) {
|
135
|
+
Object.defineProperty(Object3D.prototype, "worldScale", {
|
136
|
+
get: function () {
|
137
|
+
return getWorldScale(this);
|
138
|
+
},
|
139
|
+
set: function (val: Vector3) {
|
140
|
+
setWorldScale(this, val)
|
141
|
+
}
|
142
|
+
});
|
143
|
+
}
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
|
89
149
|
// do this after adding the component extensions
|
90
150
|
registerPrototypeExtensions(Object3D);
|
@@ -21,6 +21,8 @@
|
|
21
21
|
get model(): WebXRImageTrackingModel { return this._trackedImage; }
|
22
22
|
readonly measuredSize: number;
|
23
23
|
readonly state: "tracked" | "emulated";
|
24
|
+
/** realtime since startup, is used to keep the object visible even if tracking is gone for a few frames */
|
25
|
+
lastTrackingTime: number = 0;
|
24
26
|
|
25
27
|
/** Copy the image position to a vector */
|
26
28
|
getPosition(vec: Vector3) {
|
@@ -149,9 +151,6 @@
|
|
149
151
|
if (debug) console.log(this)
|
150
152
|
if (!this.trackedImages) return;
|
151
153
|
for (const trackedImage of this.trackedImages) {
|
152
|
-
if (trackedImage.object?.asset) {
|
153
|
-
trackedImage.object.asset.visible = false;
|
154
|
-
}
|
155
154
|
if (trackedImage.image) {
|
156
155
|
if (WebXRImageTracking._imageElements.has(trackedImage.image)) {
|
157
156
|
}
|
@@ -168,7 +167,7 @@
|
|
168
167
|
// TODO better would be to do that once we actually need it
|
169
168
|
const canvas = await imageToCanvas(img);
|
170
169
|
if (canvas) {
|
171
|
-
const blob = await canvas.convertToBlob({type: 'image/png'});
|
170
|
+
const blob = await canvas.convertToBlob({ type: 'image/png' });
|
172
171
|
const arrayBuffer = await blob.arrayBuffer();
|
173
172
|
|
174
173
|
const exporter = GameObject.findObjectOfType(USDZExporter);
|
@@ -225,6 +224,14 @@
|
|
225
224
|
}
|
226
225
|
|
227
226
|
private onXRStarted = (_: any) => {
|
227
|
+
if (this.trackedImages) {
|
228
|
+
for (const trackedImage of this.trackedImages) {
|
229
|
+
if (trackedImage.object?.asset) {
|
230
|
+
const obj = trackedImage.object.asset;
|
231
|
+
obj.visible = false;
|
232
|
+
}
|
233
|
+
}
|
234
|
+
}
|
228
235
|
// clear out all frame counters for tracking
|
229
236
|
for (const trackedData of this.imageToObjectMap.values()) {
|
230
237
|
trackedData.frames = 0;
|
@@ -260,6 +267,8 @@
|
|
260
267
|
if (trackedImage) {
|
261
268
|
const pose = frame.getPose(result.imageSpace, space);
|
262
269
|
const imageData = new WebXRTrackedImage(this, trackedImage, result.image, result.measuredSize, state, pose);
|
270
|
+
if (imageData.state === "tracked")
|
271
|
+
imageData.lastTrackingTime = this.context.time.realtimeSinceStartup;
|
263
272
|
this.currentImages.push(imageData);
|
264
273
|
}
|
265
274
|
else {
|
@@ -284,12 +293,16 @@
|
|
284
293
|
}
|
285
294
|
|
286
295
|
// disable any objects that are no longer tracked
|
296
|
+
const hysteresis = 1;
|
287
297
|
for (const [model, object] of this.imageToObjectMap) {
|
288
298
|
if (!object.object || !model) continue;
|
289
299
|
let found = false;
|
290
300
|
for (const trackedImage of this.currentImages) {
|
291
|
-
if (trackedImage.
|
292
|
-
|
301
|
+
if (trackedImage.model === model) {
|
302
|
+
// Make sure to keep the object visible if it's marked as static OR is tracked OR was tracked very recently (e.g. low framerate or bad tracking on device)
|
303
|
+
const timeSinceLastTracking = this.context.time.realtimeSinceStartup - trackedImage.lastTrackingTime;
|
304
|
+
if (model.imageDoesNotMove || trackedImage.state === "tracked" || timeSinceLastTracking < hysteresis)
|
305
|
+
found = true;
|
293
306
|
break;
|
294
307
|
}
|
295
308
|
}
|