@needle-tools/engine 4.11.0-next.91b9cf1 → 4.11.0-next.cc37c71
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 +7 -1
- package/README.md +3 -1
- package/components.needle.json +1 -1
- package/dist/{gltf-progressive-B63NpN_i.js → gltf-progressive-BvlZQAkt.js} +4 -4
- package/dist/{gltf-progressive-D4Z_Khp3.min.js → gltf-progressive-CftVUJy3.min.js} +1 -1
- package/dist/{gltf-progressive-CHeORqEv.umd.cjs → gltf-progressive-GwdQV1Qx.umd.cjs} +1 -1
- package/dist/{needle-engine.bundle-D4dsuq2U.js → needle-engine.bundle-BPZ6emFK.js} +7858 -7724
- package/dist/{needle-engine.bundle-DtfAXDjU.umd.cjs → needle-engine.bundle-CTY0RgBZ.umd.cjs} +150 -150
- package/dist/needle-engine.bundle-JV2ghuCa.min.js +1652 -0
- package/dist/needle-engine.d.ts +6 -0
- package/dist/needle-engine.js +4 -4
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-DQ2pynXW.js → postprocessing-CJC0Npcd.js} +2 -2
- package/dist/{postprocessing-BsnRNRRS.umd.cjs → postprocessing-DrM4PWU3.umd.cjs} +1 -1
- package/dist/{postprocessing-BHMVuZQ1.min.js → postprocessing-l7zsdO_Q.min.js} +1 -1
- package/dist/{three-qw28ZtTy.min.js → three-BDW9I486.min.js} +13 -13
- package/dist/{three-CJSAehtG.js → three-MHVqtJYj.js} +1 -0
- package/dist/{three-examples-Doq0rvFU.js → three-examples-C5Ht-QFN.js} +1 -1
- package/dist/{three-examples-Deqc1bNw.umd.cjs → three-examples-CgwGHSgz.umd.cjs} +1 -1
- package/dist/{three-examples-BivkhnvN.min.js → three-examples-fvEPSC8L.min.js} +1 -1
- package/dist/{three-B-jwTHao.umd.cjs → three-iFaDq9U3.umd.cjs} +13 -13
- package/dist/{three-mesh-ui-CktOi6oI.js → three-mesh-ui-BjWTTk1R.js} +1 -1
- package/dist/{three-mesh-ui-CsHwj9cJ.umd.cjs → three-mesh-ui-Bm32sS2a.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-DhYXcXZe.min.js → three-mesh-ui-CLdkp21K.min.js} +1 -1
- package/dist/{vendor-BcsPRUmt.umd.cjs → vendor-CAWj5cBK.umd.cjs} +2 -2
- package/dist/{vendor-CyfN5nor.js → vendor-DJBpoQcM.js} +608 -599
- package/dist/{vendor-DyavoogU.min.js → vendor-DWGd3dEf.min.js} +20 -20
- package/lib/engine/engine_physics.js +25 -2
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/js-extensions/Object3D.d.ts +6 -0
- package/lib/engine/js-extensions/Object3D.js +15 -0
- package/lib/engine/js-extensions/Object3D.js.map +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +2 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +26 -0
- package/lib/engine-components/Collider.js +26 -0
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +11 -2
- package/lib/engine-components/ContactShadows.js +11 -2
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +3 -0
- package/lib/engine-components/DropListener.js +44 -21
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/Duplicatable.d.ts +2 -2
- package/lib/engine-components/Duplicatable.js +2 -2
- package/lib/engine-components/EventList.d.ts +18 -1
- package/lib/engine-components/EventList.js +18 -1
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +3 -0
- package/lib/engine-components/GroundProjection.js +3 -0
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/Interactable.d.ts +4 -0
- package/lib/engine-components/Interactable.js +4 -0
- package/lib/engine-components/Interactable.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -2
- package/lib/engine-components/OrbitControls.js +33 -3
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +5 -0
- package/lib/engine-components/RigidBody.js +5 -0
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SeeThrough.js +20 -0
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +4 -2
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +69 -14
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
- package/lib/engine-components/splines/SplineWalker.d.ts +43 -4
- package/lib/engine-components/splines/SplineWalker.js +88 -12
- package/lib/engine-components/splines/SplineWalker.js.map +1 -1
- package/lib/engine-components/ui/Text.js +6 -1
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/utils/LookAt.d.ts +3 -0
- package/lib/engine-components/utils/LookAt.js +3 -0
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/utils/OpenURL.d.ts +2 -1
- package/lib/engine-components/utils/OpenURL.js +2 -1
- package/lib/engine-components/utils/OpenURL.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.d.ts +2 -0
- package/lib/engine-components/web/Clickthrough.js +23 -1
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +1 -9
- package/lib/engine-components/web/ScrollFollow.js +13 -30
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +16 -0
- package/lib/engine-components/web/ViewBox.js +35 -3
- package/lib/engine-components/web/ViewBox.js.map +1 -1
- package/lib/engine-components/webxr/WebARCameraBackground.d.ts +2 -0
- package/lib/engine-components/webxr/WebARCameraBackground.js +2 -0
- package/lib/engine-components/webxr/WebARCameraBackground.js.map +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.d.ts +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.js +1 -1
- package/lib/engine-components/webxr/WebXR.d.ts +2 -0
- package/lib/engine-components/webxr/WebXR.js +2 -0
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +29 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js +29 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +2 -2
- package/plugins/common/needle-engine.js +41 -0
- package/plugins/common/worker.js +129 -0
- package/plugins/vite/asap.js +5 -23
- package/plugins/vite/dependencies.js +21 -11
- package/plugins/vite/index.js +7 -0
- package/plugins/vite/needle-app.js +194 -0
- package/src/engine/engine_physics.ts +27 -2
- package/src/engine/js-extensions/Object3D.ts +24 -0
- package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +3 -1
- package/src/engine-components/Collider.ts +27 -1
- package/src/engine-components/ContactShadows.ts +12 -4
- package/src/engine-components/DropListener.ts +45 -24
- package/src/engine-components/Duplicatable.ts +2 -2
- package/src/engine-components/EventList.ts +18 -1
- package/src/engine-components/GroundProjection.ts +4 -1
- package/src/engine-components/Interactable.ts +4 -1
- package/src/engine-components/OrbitControls.ts +32 -5
- package/src/engine-components/RigidBody.ts +6 -1
- package/src/engine-components/SeeThrough.ts +42 -2
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +117 -17
- package/src/engine-components/splines/SplineWalker.ts +99 -14
- package/src/engine-components/ui/Text.ts +11 -2
- package/src/engine-components/utils/LookAt.ts +3 -0
- package/src/engine-components/utils/OpenURL.ts +3 -2
- package/src/engine-components/web/Clickthrough.ts +28 -1
- package/src/engine-components/web/ScrollFollow.ts +16 -34
- package/src/engine-components/web/ViewBox.ts +35 -5
- package/src/engine-components/webxr/WebARCameraBackground.ts +2 -0
- package/src/engine-components/webxr/WebARSessionRoot.ts +1 -1
- package/src/engine-components/webxr/WebXR.ts +2 -0
- package/src/engine-components/webxr/WebXRImageTracking.ts +30 -3
- package/dist/needle-engine.bundle-B8HfDBoL.min.js +0 -1652
|
@@ -284,7 +284,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
284
284
|
return opts;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
private feedText(text: string, richText: boolean)
|
|
287
|
+
private feedText(text: string, richText: boolean): void {
|
|
288
288
|
// if (!text || text.length <= 0) return;
|
|
289
289
|
// if (!text ) return;
|
|
290
290
|
if (debug) console.log("feedText", this.uiObject, text, richText);
|
|
@@ -511,6 +511,15 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
private getFamilyNameWithCorrectSuffix(familyName: string, style: FontStyle): string {
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
// the URL decorator resolves the URL to absolute URLs - we need to remove the domain part since we're only interested in the path
|
|
517
|
+
if (familyName.startsWith("https:") || familyName.startsWith("http:")) {
|
|
518
|
+
const url = new URL(familyName);
|
|
519
|
+
familyName = url.pathname;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
|
|
514
523
|
// we can only change the style for the family if the name has a suffix (e.g. Arial-Bold)
|
|
515
524
|
const styleSeparator = familyName.lastIndexOf('-');
|
|
516
525
|
if (styleSeparator < 0) return familyName;
|
|
@@ -532,7 +541,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
|
|
|
532
541
|
fontBaseName = fontBaseName.substring(pathSeparatorIndex + 1);
|
|
533
542
|
}
|
|
534
543
|
const isUpperCase = fontBaseName[0] === fontBaseName[0].toUpperCase();
|
|
535
|
-
const fontNameWithoutSuffix = familyName.substring(0, styleSeparator);
|
|
544
|
+
const fontNameWithoutSuffix = familyName.substring(0, styleSeparator > pathSeparatorIndex ? styleSeparator : familyName.length);
|
|
536
545
|
if (debug) console.log("Select font: ", familyName, FontStyle[style], fontBaseName, isUpperCase, fontNameWithoutSuffix);
|
|
537
546
|
|
|
538
547
|
switch (style) {
|
|
@@ -11,6 +11,9 @@ import { Behaviour } from "../Component.js";
|
|
|
11
11
|
/**
|
|
12
12
|
* LookAt behaviour makes the object look at a target object or the camera.
|
|
13
13
|
* It can also invert the forward direction and keep the up direction.
|
|
14
|
+
*
|
|
15
|
+
* @category Interactivity, Everywhere Actions
|
|
16
|
+
* @group Components
|
|
14
17
|
*/
|
|
15
18
|
export class LookAt extends Behaviour implements UsdzBehaviour {
|
|
16
19
|
|
|
@@ -15,8 +15,9 @@ export enum OpenURLMode {
|
|
|
15
15
|
NewWindow = 2
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* OpenURL behaviour opens a URL in a new tab or window.
|
|
18
|
+
/**
|
|
19
|
+
* OpenURL behaviour opens a URL in a new tab or window when the object (or any if it's children) is clicked.
|
|
20
|
+
*
|
|
20
21
|
* @category Interactivity
|
|
21
22
|
* @group Components
|
|
22
23
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Vector2 } from "three";
|
|
1
2
|
import { NEPointerEvent } from "../../engine/engine_input.js";
|
|
2
3
|
import { onStart } from "../../engine/engine_lifecycle_api.js";
|
|
3
4
|
import { addAttributeChangeCallback } from "../../engine/engine_utils.js";
|
|
@@ -45,12 +46,14 @@ export class ClickThrough extends Behaviour {
|
|
|
45
46
|
this.context.input.addEventListener('pointermove', this.onPointerEvent, {
|
|
46
47
|
queue: 100,
|
|
47
48
|
});
|
|
49
|
+
window.addEventListener("touchstart", this.onTouchStart, { passive: true });
|
|
48
50
|
window.addEventListener("touchend", this.onTouchEnd, { passive: true });
|
|
49
51
|
this._previousPointerEvents = this.context.domElement.style.pointerEvents;
|
|
50
52
|
}
|
|
51
53
|
onDisable() {
|
|
52
54
|
this.context.input.removeEventListener('pointerdown', this.onPointerEvent);
|
|
53
55
|
this.context.input.removeEventListener('pointermove', this.onPointerEvent);
|
|
56
|
+
window.removeEventListener("touchstart", this.onTouchStart);
|
|
54
57
|
window.removeEventListener("touchend", this.onTouchEnd);
|
|
55
58
|
this.context.domElement.style.pointerEvents = this._previousPointerEvents;
|
|
56
59
|
}
|
|
@@ -69,9 +72,33 @@ export class ClickThrough extends Behaviour {
|
|
|
69
72
|
}
|
|
70
73
|
};
|
|
71
74
|
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
// #region Touch hack
|
|
78
|
+
|
|
79
|
+
private _touchDidHitAnything = false;
|
|
80
|
+
|
|
81
|
+
private onTouchStart = (_evt: TouchEvent) => {
|
|
82
|
+
|
|
83
|
+
const touch = _evt.touches[0];
|
|
84
|
+
if (!touch) return;
|
|
85
|
+
|
|
86
|
+
const ndx = touch.clientX / window.innerWidth * 2 - 1;
|
|
87
|
+
const ndy = -(touch.clientY / window.innerHeight) * 2 + 1;
|
|
88
|
+
// console.log(ndx, ndy);
|
|
89
|
+
const hits = this.context.physics.raycast({
|
|
90
|
+
screenPoint: new Vector2(ndx, ndy),
|
|
91
|
+
})
|
|
92
|
+
if (hits.length > 0) {
|
|
93
|
+
this._touchDidHitAnything = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
72
97
|
private onTouchEnd = (_evt: TouchEvent) => {
|
|
98
|
+
const _didHit = this._touchDidHitAnything;
|
|
99
|
+
this._touchDidHitAnything = false;
|
|
73
100
|
setTimeout(() => {
|
|
74
|
-
this.context.domElement.style.pointerEvents = 'all';
|
|
101
|
+
if (_didHit) this.context.domElement.style.pointerEvents = 'all';
|
|
75
102
|
}, 100);
|
|
76
103
|
}
|
|
77
104
|
}
|
|
@@ -96,6 +96,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
96
96
|
@serializable()
|
|
97
97
|
invert: boolean = false;
|
|
98
98
|
|
|
99
|
+
|
|
99
100
|
/**
|
|
100
101
|
* **Experimental - might change in future updates**
|
|
101
102
|
* If set, the scroll position will be read from the specified element instead of the window.
|
|
@@ -106,7 +107,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
106
107
|
htmlSelector: string | null = null;
|
|
107
108
|
|
|
108
109
|
@serializable()
|
|
109
|
-
|
|
110
|
+
mode: "window" = "window";
|
|
110
111
|
|
|
111
112
|
/**
|
|
112
113
|
* Event fired when the scroll position changes
|
|
@@ -126,11 +127,6 @@ export class ScrollFollow extends Behaviour {
|
|
|
126
127
|
private _appliedValue: number = -1;
|
|
127
128
|
|
|
128
129
|
|
|
129
|
-
private _scrollStart: number = 0;
|
|
130
|
-
private _scrollEnd: number = 0;
|
|
131
|
-
private _scrollValue: number = 0;
|
|
132
|
-
private _scrollContainerHeight: number = 0;
|
|
133
|
-
|
|
134
130
|
/** @internal */
|
|
135
131
|
onEnable() {
|
|
136
132
|
window.addEventListener("wheel", this.updateCurrentScrollValue, { passive: true });
|
|
@@ -159,8 +155,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
159
155
|
}
|
|
160
156
|
}
|
|
161
157
|
|
|
162
|
-
|
|
163
|
-
{
|
|
158
|
+
if (this._current_value !== this._appliedValue) {
|
|
164
159
|
this._appliedValue = this._current_value;
|
|
165
160
|
|
|
166
161
|
let defaultPrevented = false;
|
|
@@ -182,9 +177,6 @@ export class ScrollFollow extends Behaviour {
|
|
|
182
177
|
|
|
183
178
|
const value = this.invert ? 1 - this._current_value : this._current_value;
|
|
184
179
|
|
|
185
|
-
// const height = this._rangeEndValue - this._rangeStartValue;
|
|
186
|
-
// const pixelValue = this._rangeStartValue + value * height;
|
|
187
|
-
|
|
188
180
|
// apply scroll to target(s)
|
|
189
181
|
if (Array.isArray(this.target)) {
|
|
190
182
|
this.target.forEach(t => t && this.applyScroll(t, value));
|
|
@@ -202,16 +194,11 @@ export class ScrollFollow extends Behaviour {
|
|
|
202
194
|
|
|
203
195
|
private _lastSelectorValue: string | null = null;
|
|
204
196
|
private _lastSelectorElement: Element | null = null;
|
|
205
|
-
/** Top y */
|
|
206
|
-
private _rangeStartValue: number = 0;
|
|
207
|
-
/** Bottom y */
|
|
208
|
-
private _rangeEndValue: number = 0;
|
|
209
197
|
|
|
210
198
|
private updateCurrentScrollValue = () => {
|
|
211
199
|
|
|
212
200
|
switch (this.mode) {
|
|
213
201
|
case "window":
|
|
214
|
-
|
|
215
202
|
if (this.htmlSelector?.length) {
|
|
216
203
|
if (this.htmlSelector !== this._lastSelectorValue) {
|
|
217
204
|
this._lastSelectorElement = document.querySelector(this.htmlSelector);
|
|
@@ -219,26 +206,20 @@ export class ScrollFollow extends Behaviour {
|
|
|
219
206
|
}
|
|
220
207
|
if (this._lastSelectorElement) {
|
|
221
208
|
const rect = this._lastSelectorElement.getBoundingClientRect();
|
|
222
|
-
|
|
223
|
-
this._scrollStart = rect.top + window.scrollY;
|
|
224
|
-
this._scrollEnd = rect.height - window.innerHeight;
|
|
225
|
-
this._scrollValue = -rect.top;
|
|
226
209
|
this._target_value = -rect.top / (rect.height - window.innerHeight);
|
|
227
|
-
this._rangeStartValue = rect.top + window.scrollY;
|
|
228
|
-
this._rangeEndValue = this._rangeStartValue + rect.height - window.innerHeight;
|
|
229
|
-
this._scrollContainerHeight = rect.height;
|
|
230
210
|
break;
|
|
231
211
|
}
|
|
232
212
|
}
|
|
233
213
|
else {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
214
|
+
if (window.document.body.scrollHeight <= window.innerHeight) {
|
|
215
|
+
// If the page is not scrollable we can still increment the scroll value to allow triggering timelines etc.
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const diff = window.document.body.scrollHeight - window.innerHeight;
|
|
219
|
+
this._target_value = window.scrollY / (diff || 1);
|
|
220
|
+
}
|
|
241
221
|
}
|
|
222
|
+
|
|
242
223
|
break;
|
|
243
224
|
}
|
|
244
225
|
|
|
@@ -272,11 +253,12 @@ export class ScrollFollow extends Behaviour {
|
|
|
272
253
|
target.intensity = value;
|
|
273
254
|
}
|
|
274
255
|
else if (target instanceof Object3D) {
|
|
256
|
+
const t = target as any;
|
|
275
257
|
// When objects are assigned they're expected to move vertically based on scroll
|
|
276
|
-
if (
|
|
277
|
-
|
|
258
|
+
if (t["needle:scrollbounds"] === undefined) {
|
|
259
|
+
t["needle:scrollbounds"] = getBoundingBox(target) || null;
|
|
278
260
|
}
|
|
279
|
-
const bounds =
|
|
261
|
+
const bounds = t["needle:scrollbounds"] as Box3;
|
|
280
262
|
if (bounds) {
|
|
281
263
|
// TODO: remap position to use upper screen edge and lower edge instead of center
|
|
282
264
|
target.position.y = -bounds.min.y - value * (bounds.max.y - bounds.min.y);
|
|
@@ -473,7 +455,7 @@ function tryGetElementsForSelector(index: number): Element | null {
|
|
|
473
455
|
|
|
474
456
|
if (!needsScrollMarkerRefresh) {
|
|
475
457
|
const element = needleScrollMarkerCache[index] || null;
|
|
476
|
-
|
|
458
|
+
return element;
|
|
477
459
|
}
|
|
478
460
|
needsScrollMarkerRefresh = false;
|
|
479
461
|
needleScrollMarkerCache.length = 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Camera, Matrix4, PerspectiveCamera,
|
|
1
|
+
import { Camera, Matrix4, PerspectiveCamera, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment } from "../../engine/debug/debug.js";
|
|
4
4
|
import { Gizmos } from "../../engine/engine_gizmos.js";
|
|
@@ -13,6 +13,8 @@ import { Behaviour } from "../Component.js";
|
|
|
13
13
|
const debugParam = getParam("debugviewbox");
|
|
14
14
|
const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
|
|
15
15
|
|
|
16
|
+
export type ViewBoxMode = "continuous" | "once";
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* This component can be used to automatically fit a certain box area into the camera view - no matter your screen size or aspect ratio.
|
|
18
20
|
* This is useful for example to frame a character or object in the center of the screen and ensure it is always fully visible. You can also animate or scale the viewbox to create zoom or framing effects.
|
|
@@ -36,6 +38,9 @@ const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
|
|
|
36
38
|
@registerType
|
|
37
39
|
export class ViewBox extends Behaviour {
|
|
38
40
|
|
|
41
|
+
/**
|
|
42
|
+
* All active ViewBox instances. The last one in the array is the currently active one.
|
|
43
|
+
*/
|
|
39
44
|
static readonly instances: ViewBox[] = [];
|
|
40
45
|
|
|
41
46
|
/**
|
|
@@ -45,21 +50,39 @@ export class ViewBox extends Behaviour {
|
|
|
45
50
|
@serializable()
|
|
46
51
|
referenceFieldOfView: number = -1;
|
|
47
52
|
|
|
53
|
+
/**
|
|
54
|
+
* The mode determines if the viewbox should be applied once or continuously while it is the active viewbox.
|
|
55
|
+
* Options:
|
|
56
|
+
* - "once": The viewbox will be applied once when it becomes the active viewbox. This is useful if you want to fit the view once and then allow the user to zoom or pan freely.
|
|
57
|
+
* - "continuous": The viewbox will be applied continuously while it is the active viewbox. This is useful if you animate or scale the viewbox over time.
|
|
58
|
+
*/
|
|
59
|
+
@serializable()
|
|
60
|
+
get mode() { return this._mode; }
|
|
61
|
+
set mode(v: ViewBoxMode) {
|
|
62
|
+
if (v === this._mode) return;
|
|
63
|
+
this._mode = v;
|
|
64
|
+
if (v === "once") this._applyCount = 0;
|
|
65
|
+
if (debugParam || this.debug) console.debug("[ViewBox] Set mode:", v);
|
|
66
|
+
}
|
|
67
|
+
private _mode: ViewBoxMode = "continuous";
|
|
68
|
+
|
|
48
69
|
/**
|
|
49
70
|
* Enable debug logs and rendering for this component instance
|
|
50
71
|
*/
|
|
51
72
|
@serializable()
|
|
52
73
|
debug: boolean = false;
|
|
53
74
|
|
|
75
|
+
/** @internal */
|
|
54
76
|
onEnable(): void {
|
|
55
77
|
if (debugParam || this.debug || isDevEnvironment()) console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
|
|
56
78
|
// register instance
|
|
57
79
|
ViewBox.instances.push(this);
|
|
58
|
-
|
|
80
|
+
this._applyCount = 0;
|
|
59
81
|
this.removeUpdateCallback();
|
|
60
82
|
this.context.pre_render_callbacks.push(this.internalUpdate);
|
|
61
83
|
}
|
|
62
84
|
|
|
85
|
+
/** @internal */
|
|
63
86
|
onDisable(): void {
|
|
64
87
|
if (debugParam || this.debug) console.debug("[ViewBox] Disabled");
|
|
65
88
|
// unregister instance
|
|
@@ -77,6 +100,7 @@ export class ViewBox extends Behaviour {
|
|
|
77
100
|
|
|
78
101
|
private static readonly _tempProjectionMatrix: Matrix4 = new Matrix4();
|
|
79
102
|
private static readonly _tempProjectionMatrixInverse: Matrix4 = new Matrix4();
|
|
103
|
+
private _applyCount = 0;
|
|
80
104
|
|
|
81
105
|
private internalUpdate = () => {
|
|
82
106
|
if (this.context.isInXR) return;
|
|
@@ -108,6 +132,11 @@ export class ViewBox extends Behaviour {
|
|
|
108
132
|
return;
|
|
109
133
|
}
|
|
110
134
|
|
|
135
|
+
if (this._applyCount >= 1 && this.mode === "once") {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this._applyCount++;
|
|
139
|
+
|
|
111
140
|
const domWidth = this.context.domWidth;
|
|
112
141
|
const domHeight = this.context.domHeight;
|
|
113
142
|
|
|
@@ -129,7 +158,7 @@ export class ViewBox extends Behaviour {
|
|
|
129
158
|
ViewBox._tempProjectionMatrix.copy(camera.projectionMatrix);
|
|
130
159
|
ViewBox._tempProjectionMatrixInverse.copy(camera.projectionMatrixInverse);
|
|
131
160
|
const view = camera.view;
|
|
132
|
-
const
|
|
161
|
+
const cameraZoom = camera.zoom;
|
|
133
162
|
const aspect = camera.aspect;
|
|
134
163
|
const fov = camera.fov;
|
|
135
164
|
// Set values to default so we can calculate the box size correctly
|
|
@@ -194,6 +223,7 @@ export class ViewBox extends Behaviour {
|
|
|
194
223
|
width / diffWidth,
|
|
195
224
|
height / diffHeight
|
|
196
225
|
);
|
|
226
|
+
const zoom = scale / (height * .5);
|
|
197
227
|
// console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
|
|
198
228
|
// this.context.focusRectSettings.zoom = 1.39;
|
|
199
229
|
// if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
|
|
@@ -202,13 +232,13 @@ export class ViewBox extends Behaviour {
|
|
|
202
232
|
vec.project(camera);
|
|
203
233
|
this.context.focusRectSettings.offsetX = vec.x;
|
|
204
234
|
this.context.focusRectSettings.offsetY = vec.y;
|
|
205
|
-
this.context.focusRectSettings.zoom =
|
|
235
|
+
this.context.focusRectSettings.zoom = zoom;
|
|
206
236
|
// if we don't have a focus rect yet, set it to the dom element
|
|
207
237
|
if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
|
|
208
238
|
|
|
209
239
|
// Reset values
|
|
210
240
|
camera.view = view;
|
|
211
|
-
camera.zoom =
|
|
241
|
+
camera.zoom = cameraZoom;
|
|
212
242
|
camera.aspect = aspect;
|
|
213
243
|
camera.fov = fov;
|
|
214
244
|
camera.projectionMatrix.copy(ViewBox._tempProjectionMatrix);
|
|
@@ -24,6 +24,8 @@ const debug = getParam("debugarcamera");
|
|
|
24
24
|
/**
|
|
25
25
|
* WebARCameraBackground is a component that allows to display the camera feed as a background in an AR session to more easily blend the real world with the virtual world or applying effects to the camera feed.
|
|
26
26
|
*
|
|
27
|
+
* - Example: https://samples.needle.tools/ar-camera-background
|
|
28
|
+
*
|
|
27
29
|
* @category XR
|
|
28
30
|
* @group Components
|
|
29
31
|
*/
|
|
@@ -20,7 +20,7 @@ const invertForwardMatrix = new Matrix4().makeRotationY(Math.PI);
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* The WebARSessionRoot is the root object for a WebAR session and used to place the scene in AR.
|
|
23
|
-
* It is also responsible for scaling the user in AR.
|
|
23
|
+
* It is also responsible for scaling the user in AR and to define the center of the AR scene. If not present in the scene it will be created automatically by the WebXR component when entering an AR session.
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
26
|
* ```ts
|
|
@@ -27,6 +27,8 @@ const debugQuicklook = getParam("debugusdz");
|
|
|
27
27
|
*
|
|
28
28
|
* The WebXR component is a simple to use wrapper around the {@link NeedleXRSession} API and adds some additional features like creating buttons for AR, VR, enabling default movement behaviour ({@link XRControllerMovement}) and controller rendering ({@link XRControllerModel}), as well as handling AR placement and Quicklook USDZ export.
|
|
29
29
|
*
|
|
30
|
+
* - Example: https://samples.needle.tools/collaborative-sandbox
|
|
31
|
+
*
|
|
30
32
|
* @example Enable VR and AR support using code
|
|
31
33
|
* ```ts
|
|
32
34
|
* import { onStart, WebXR } from "@needle-tools/engine";
|
|
@@ -290,6 +290,16 @@ class ImageTrackingExtension implements IUSDExporterExtension {
|
|
|
290
290
|
|
|
291
291
|
|
|
292
292
|
/**
|
|
293
|
+
* Add this component to a object to enable image tracking in WebXR sessions.
|
|
294
|
+
*
|
|
295
|
+
* You need to add at least one {@link WebXRImageTrackingModel} to the `trackedImages` array to define which images to track and which objects to place on top of them.
|
|
296
|
+
*
|
|
297
|
+
* **NOTE:** For Android devices, image tracking currently requires the user to enable the `chrome://flags/#webxr-incubations` flag in Chrome.
|
|
298
|
+
*
|
|
299
|
+
* **NOTE:** For iOS only one image can be tracked at a time. If you have multiple images in the `trackedImages` array, only the first one will be tracked. You can use the {@link setPrimaryImage} method to change which image is tracked before entering the XR session.
|
|
300
|
+
*
|
|
301
|
+
* - Example: https://samples.needle.tools/image-tracking
|
|
302
|
+
*
|
|
293
303
|
* @category XR
|
|
294
304
|
* @group Components
|
|
295
305
|
*/
|
|
@@ -313,7 +323,14 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
313
323
|
|
|
314
324
|
/**
|
|
315
325
|
* Add an image to track. If the image is already in the trackedImages array it won't be added again.
|
|
316
|
-
* Note: that adding images at runtime *while* in AR is not supported.
|
|
326
|
+
* Note: that adding images at runtime *while* in AR is not supported.
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```ts
|
|
330
|
+
* const imageTracking = GameObject.getComponent(myGameObject, WebXRImageTracking);
|
|
331
|
+
* const image = new WebXRImageTrackingModel({ url: "https://example.com/my-marker.png", widthInMeters: 0.2, object: myObject });
|
|
332
|
+
* imageTracking.addImage(image, true); // add and set as primary image
|
|
333
|
+
* ```
|
|
317
334
|
*/
|
|
318
335
|
addImage(image: WebXRImageTrackingModel, asPrimary: boolean = false) {
|
|
319
336
|
if (!this.trackedImages.includes(image)) {
|
|
@@ -324,7 +341,11 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
324
341
|
}
|
|
325
342
|
|
|
326
343
|
|
|
327
|
-
|
|
344
|
+
/**
|
|
345
|
+
* List of images to track in the WebXR session. Use {@link WebXRImageTrackingModel} to define each image and the object to place on top of it.
|
|
346
|
+
*
|
|
347
|
+
* Use the `addImage()` and `setPrimaryImage()` methods to modify this array at runtime.
|
|
348
|
+
*/
|
|
328
349
|
@serializable(WebXRImageTrackingModel)
|
|
329
350
|
readonly trackedImages: WebXRImageTrackingModel[] = [];
|
|
330
351
|
|
|
@@ -339,6 +360,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
339
360
|
|
|
340
361
|
private _supported: boolean = true;
|
|
341
362
|
|
|
363
|
+
/** @internal */
|
|
342
364
|
awake(): void {
|
|
343
365
|
if (debug) console.log(this)
|
|
344
366
|
if (!this.trackedImages) return;
|
|
@@ -348,9 +370,11 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
348
370
|
}
|
|
349
371
|
}
|
|
350
372
|
}
|
|
373
|
+
/** @internal */
|
|
351
374
|
onEnable() {
|
|
352
375
|
USDZExporter.beforeExport.addEventListener(this.onBeforeUSDZExport);
|
|
353
376
|
}
|
|
377
|
+
/** @internal */
|
|
354
378
|
onDisable(): void {
|
|
355
379
|
USDZExporter.beforeExport.removeEventListener(this.onBeforeUSDZExport);
|
|
356
380
|
}
|
|
@@ -362,7 +386,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
362
386
|
}
|
|
363
387
|
|
|
364
388
|
|
|
365
|
-
|
|
389
|
+
/** @internal */
|
|
366
390
|
onBeforeXR(_mode: XRSessionMode, args: XRSessionInit & { trackedImages: Array<any> }): void {
|
|
367
391
|
// console.log("onXRRequested", args, this.trackedImages)
|
|
368
392
|
if (this.trackedImages) {
|
|
@@ -386,6 +410,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
386
410
|
}
|
|
387
411
|
}
|
|
388
412
|
|
|
413
|
+
/** @internal */
|
|
389
414
|
onEnterXR(_args: NeedleXREventArgs): void {
|
|
390
415
|
if (this.trackedImages) {
|
|
391
416
|
for (const trackedImage of this.trackedImages) {
|
|
@@ -408,6 +433,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
408
433
|
}
|
|
409
434
|
};
|
|
410
435
|
|
|
436
|
+
/** @internal */
|
|
411
437
|
onLeaveXR(_args: NeedleXREventArgs): void {
|
|
412
438
|
|
|
413
439
|
if (!this.supported && DeviceUtilities.isAndroidDevice()) {
|
|
@@ -440,6 +466,7 @@ export class WebXRImageTracking extends Behaviour {
|
|
|
440
466
|
|
|
441
467
|
private readonly webXRIncubationsWarning = "Image tracking is currently not supported on this device. On Chrome for Android, you can enable the <a target=\"_blank\" href=\"#\" onclick=\"() => console.log('I')\">chrome://flags/#webxr-incubations</a> flag.";
|
|
442
468
|
|
|
469
|
+
/** @internal */
|
|
443
470
|
onUpdateXR(args: NeedleXREventArgs): void {
|
|
444
471
|
this.currentImages.length = 0;
|
|
445
472
|
|