@needle-tools/engine 3.5.9-beta.1 → 3.5.10-beta
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 +14 -0
- package/dist/needle-engine.js +7401 -7355
- package/dist/needle-engine.light.js +8593 -8370
- package/dist/needle-engine.light.min.js +264 -264
- package/dist/needle-engine.light.umd.cjs +271 -271
- package/dist/needle-engine.min.js +264 -264
- package/dist/needle-engine.umd.cjs +263 -263
- package/lib/engine/debug/debug_overlay.js +4 -1
- package/lib/engine/debug/debug_overlay.js.map +1 -1
- package/lib/engine/engine_context.js +9 -4
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_element.d.ts +1 -0
- package/lib/engine/engine_element.js +9 -2
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_element_loading.js +9 -10
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_license.js +5 -4
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +33 -30
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +5 -2
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Component.d.ts +2 -2
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +1 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/SpriteRenderer.d.ts +3 -0
- package/lib/engine-components/SpriteRenderer.js +18 -0
- package/lib/engine-components/SpriteRenderer.js.map +1 -1
- package/lib/engine-components/webxr/WebXRPlaneTracking.d.ts +2 -0
- package/lib/engine-components/webxr/WebXRPlaneTracking.js +22 -0
- package/lib/engine-components/webxr/WebXRPlaneTracking.js.map +1 -1
- package/package.json +1 -1
- package/plugins/vite/config.js +8 -1
- package/plugins/vite/defines.js +1 -1
- package/plugins/vite/license.js +4 -1
- package/src/engine/debug/debug_overlay.ts +5 -2
- package/src/engine/engine_context.ts +11 -5
- package/src/engine/engine_element.ts +8 -3
- package/src/engine/engine_element_loading.ts +9 -10
- package/src/engine/engine_license.ts +5 -4
- package/src/engine/engine_physics_rapier.ts +33 -31
- package/src/engine-components/CameraUtils.ts +7 -3
- package/src/engine-components/Component.ts +2 -2
- package/src/engine-components/OrbitControls.ts +1 -1
- package/src/engine-components/SpriteRenderer.ts +13 -0
- package/src/engine-components/webxr/WebXRPlaneTracking.ts +21 -4
|
@@ -104,7 +104,9 @@ export function addLog(type: LogType, message: string | any[], _file?: string |
|
|
|
104
104
|
|
|
105
105
|
const currentMessages = new Set<string>();
|
|
106
106
|
|
|
107
|
-
function showMessage(type: LogType, element: HTMLElement, msg: string) {
|
|
107
|
+
function showMessage(type: LogType, element: HTMLElement, msg: string | null | undefined) {
|
|
108
|
+
if (msg === null || msg === undefined) return;
|
|
109
|
+
|
|
108
110
|
const container = getLogsContainer(element);
|
|
109
111
|
if (container.childElementCount >= 20) {
|
|
110
112
|
const last = container.lastElementChild;
|
|
@@ -117,8 +119,9 @@ function showMessage(type: LogType, element: HTMLElement, msg: string) {
|
|
|
117
119
|
const msgcontainer = getMessageContainer(type, msg);
|
|
118
120
|
container.prepend(msgcontainer);
|
|
119
121
|
|
|
122
|
+
const _msg = msg;
|
|
120
123
|
setTimeout(() => {
|
|
121
|
-
currentMessages.delete(
|
|
124
|
+
currentMessages.delete(_msg);
|
|
122
125
|
returnMessageContainer(msgcontainer);
|
|
123
126
|
}, 10000);
|
|
124
127
|
}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
BufferGeometry, Camera, Clock, Color, DepthTexture, Group,
|
|
3
3
|
Material, NearestFilter, NoToneMapping, Object3D, PCFSoftShadowMap,
|
|
4
4
|
PerspectiveCamera, RGBAFormat, Scene, sRGBEncoding,
|
|
5
|
-
Texture, WebGLRenderer, WebGLRenderTarget
|
|
5
|
+
Texture, WebGLRenderer, WebGLRendererParameters, WebGLRenderTarget
|
|
6
6
|
} from 'three'
|
|
7
7
|
import { Input } from './engine_input';
|
|
8
8
|
import { Physics } from './engine_physics';
|
|
@@ -259,9 +259,15 @@ export class Context implements IContext {
|
|
|
259
259
|
this.isManagedExternally = true;
|
|
260
260
|
}
|
|
261
261
|
else {
|
|
262
|
-
|
|
263
|
-
antialias: true
|
|
264
|
-
}
|
|
262
|
+
const params: WebGLRendererParameters = {
|
|
263
|
+
antialias: true,
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// get canvas already configured in the Needle Engine Web Component
|
|
267
|
+
const canvas = args?.domElement?.shadowRoot?.querySelector("canvas");
|
|
268
|
+
if (canvas) params.canvas = canvas;
|
|
269
|
+
|
|
270
|
+
this.renderer = new WebGLRenderer(params);
|
|
265
271
|
|
|
266
272
|
// some tonemapping other than "NONE" is required for adjusting exposure with EXR environments
|
|
267
273
|
this.renderer.toneMappingExposure = 1; // range [0...inf] instead of the usual -15..15
|
|
@@ -551,7 +557,7 @@ export class Context implements IContext {
|
|
|
551
557
|
|
|
552
558
|
// console.log(prepare_succeeded);
|
|
553
559
|
|
|
554
|
-
if (!this.isManagedExternally)
|
|
560
|
+
if (!this.isManagedExternally && !this.domElement.shadowRoot)
|
|
555
561
|
this.domElement.prepend(this.renderer.domElement);
|
|
556
562
|
|
|
557
563
|
Context.Current = this;
|
|
@@ -276,18 +276,22 @@ export class NeedleEngineHTMLElement extends HTMLElement implements INeedleEngin
|
|
|
276
276
|
if (currentHash !== null && currentHash !== undefined)
|
|
277
277
|
this._context.hash = currentHash;
|
|
278
278
|
this._context.alias = alias;
|
|
279
|
-
|
|
279
|
+
const contextWasCreated = this._context.isCreated;
|
|
280
|
+
if (!contextWasCreated) {
|
|
280
281
|
await this._context.onCreate(loadFunction);
|
|
282
|
+
}
|
|
281
283
|
else {
|
|
282
284
|
await loadFunction(this._context);
|
|
283
285
|
}
|
|
284
286
|
|
|
285
287
|
|
|
286
288
|
|
|
287
|
-
|
|
289
|
+
console.log("Needle Engine: finished loading", alias ?? "")
|
|
288
290
|
this._loadingProgress01 = 1;
|
|
289
|
-
if (useDefaultLoading)
|
|
291
|
+
if (useDefaultLoading) {
|
|
290
292
|
this._loadingView?.onLoadingUpdate(1, "creating scene");
|
|
293
|
+
if (contextWasCreated) this.onReady();
|
|
294
|
+
}
|
|
291
295
|
this.classList.remove("loading");
|
|
292
296
|
this.classList.add("loading-finished");
|
|
293
297
|
if (debug)
|
|
@@ -301,6 +305,7 @@ export class NeedleEngineHTMLElement extends HTMLElement implements INeedleEngin
|
|
|
301
305
|
|
|
302
306
|
}
|
|
303
307
|
|
|
308
|
+
/** called by the context when the first frame has been rendered */
|
|
304
309
|
private onReady = () => this._loadingView?.onLoadingFinished();
|
|
305
310
|
|
|
306
311
|
|
|
@@ -73,14 +73,15 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
onLoadingBegin(message?: string) {
|
|
76
|
+
const _element = this._element.shadowRoot || this._element;
|
|
76
77
|
if (debug) console.warn("Begin Loading")
|
|
77
78
|
if (!this._loadingElement) {
|
|
78
|
-
for (let i = 0; i <
|
|
79
|
-
const el =
|
|
79
|
+
for (let i = 0; i < _element.children.length; i++) {
|
|
80
|
+
const el = _element.children[i] as HTMLElement;
|
|
80
81
|
if (el.classList.contains(EngineLoadingView.LoadingContainerClassName)) {
|
|
81
82
|
if (!this._allowCustomLoadingElement) {
|
|
82
83
|
if (debug) console.warn("Remove custom loading container")
|
|
83
|
-
|
|
84
|
+
_element.removeChild(el);
|
|
84
85
|
continue;
|
|
85
86
|
}
|
|
86
87
|
this._loadingElement = this.createLoadingElement(el);
|
|
@@ -92,7 +93,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
92
93
|
this._progress = 0;
|
|
93
94
|
this.loadingProgress = 0;
|
|
94
95
|
this._loadingElement.style.display = "flex";
|
|
95
|
-
|
|
96
|
+
_element.appendChild(this._loadingElement);
|
|
96
97
|
this.smoothProgressLoop();
|
|
97
98
|
this.setMessage(message ?? "");
|
|
98
99
|
}
|
|
@@ -141,7 +142,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
141
142
|
if (typeof debugRendering === "number") dt *= debugRendering;
|
|
142
143
|
}
|
|
143
144
|
this._progressLoop = setInterval(() => {
|
|
144
|
-
//
|
|
145
|
+
// increase loading speed when almost done
|
|
145
146
|
if (this.loadingProgress >= .95 && !debugRendering) dt = .9;
|
|
146
147
|
this._progress = Mathf.lerp(this._progress, this.loadingProgress, dt * this.loadingProgress);
|
|
147
148
|
this.updateDisplay();
|
|
@@ -229,15 +230,12 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
229
230
|
else
|
|
230
231
|
loadingBarContainer.style.backgroundColor = "rgba(255,255,255,.2)"
|
|
231
232
|
// loadingBarContainer.style.alignItems = "center";
|
|
232
|
-
this._loadingElement.appendChild(loadingBarContainer);
|
|
233
233
|
|
|
234
234
|
const logo = document.createElement("img");
|
|
235
235
|
const logoSize = 64;
|
|
236
236
|
logo.style.width = `${logoSize}px`;
|
|
237
237
|
logo.style.height = `${logoSize}px`;
|
|
238
|
-
logo.style.
|
|
239
|
-
logo.style.left = "50%";
|
|
240
|
-
logo.style.transform = `translate(-${logoSize * .5}px, -${logoSize + 32}px)`;
|
|
238
|
+
logo.style.marginBottom = "20px";
|
|
241
239
|
logo.addEventListener("click", () => window.open("https://needle.tools", "_blank"));
|
|
242
240
|
logo.style.cursor = "pointer";
|
|
243
241
|
logo.style.userSelect = "none";
|
|
@@ -250,7 +248,8 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
250
248
|
logo.src = customLogo;
|
|
251
249
|
}
|
|
252
250
|
}
|
|
253
|
-
|
|
251
|
+
this._loadingElement.appendChild(logo);
|
|
252
|
+
this._loadingElement.appendChild(loadingBarContainer);
|
|
254
253
|
|
|
255
254
|
|
|
256
255
|
this._loadingBar = document.createElement("div");
|
|
@@ -64,9 +64,10 @@ function insertNonCommercialUseHint(ctx: IContext) {
|
|
|
64
64
|
|
|
65
65
|
const interval = setInterval(() => {
|
|
66
66
|
if (!licenseElement) return;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
const parent = ctx.domElement.shadowRoot || ctx.domElement;
|
|
68
|
+
if (licenseElement.parentNode !== parent) {
|
|
69
|
+
parent.appendChild(licenseElement);
|
|
70
|
+
if (style) parent.appendChild(style);
|
|
70
71
|
}
|
|
71
72
|
}, 100);
|
|
72
73
|
|
|
@@ -121,7 +122,7 @@ async function logNonCommercialUse(_logo?: string) {
|
|
|
121
122
|
function createLicenseElement() {
|
|
122
123
|
const licenseElement = document.createElement("div");
|
|
123
124
|
licenseElement.setAttribute(licenseElementIdentifier, "");
|
|
124
|
-
licenseElement.style.position = "
|
|
125
|
+
licenseElement.style.position = "absolute";
|
|
125
126
|
licenseElement.style.bottom = "12px";
|
|
126
127
|
licenseElement.style.right = "15px";
|
|
127
128
|
|
|
@@ -21,6 +21,7 @@ import { Gizmos } from './engine_gizmos';
|
|
|
21
21
|
import { Mathf } from './engine_math';
|
|
22
22
|
import { SphereOverlapResult } from './engine_types';
|
|
23
23
|
import { ContextEvent, ContextRegistry } from './engine_context_registry';
|
|
24
|
+
import { isDevEnvironment } from './debug/debug';
|
|
24
25
|
|
|
25
26
|
const debugPhysics = getParam("debugphysics");
|
|
26
27
|
const debugColliderPlacement = getParam("debugphysicscolliders");
|
|
@@ -61,48 +62,49 @@ declare type PhysicsBody = {
|
|
|
61
62
|
export class RapierPhysics implements IPhysicsEngine {
|
|
62
63
|
|
|
63
64
|
removeBody(obj: IComponent) {
|
|
65
|
+
if (!obj) return;
|
|
64
66
|
this.validate();
|
|
65
67
|
const body = obj[$bodyKey];
|
|
66
68
|
obj[$bodyKey] = null;
|
|
67
69
|
if (body && this.world) {
|
|
68
70
|
const index = this.objects.findIndex(o => o === obj);
|
|
69
71
|
if (index >= 0) {
|
|
70
|
-
const
|
|
72
|
+
const rapierBody = this.bodies[index];
|
|
73
|
+
// Remove references
|
|
71
74
|
this.bodies.splice(index, 1);
|
|
72
75
|
this.objects.splice(index, 1);
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
// Remove the collider from the physics world
|
|
78
|
+
if (rapierBody instanceof Collider) {
|
|
79
|
+
const rapierCollider = rapierBody as Collider;
|
|
80
|
+
this.world?.removeCollider(rapierCollider, true);
|
|
77
81
|
|
|
78
|
-
// remove the rigidbody if it doesnt have colliders anymore
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
+
// also remove the rigidbody if it doesnt have colliders anymore
|
|
83
|
+
const rapierRigidbody: RigidBody | null = rapierCollider.parent();
|
|
84
|
+
if (rapierRigidbody && rapierRigidbody.numColliders() <= 0) {
|
|
85
|
+
const rigidbody = rapierRigidbody[$componentKey] as IRigidbody;
|
|
86
|
+
this.removeBody(rigidbody);
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
// Remove the rigidbody from the physics world
|
|
90
|
+
else if (rapierBody instanceof RigidBody) {
|
|
91
|
+
if (rapierBody.numColliders() <= 0) {
|
|
92
|
+
this.world?.removeRigidBody(rapierBody);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
if (isDevEnvironment()) {
|
|
96
|
+
if (!rapierBody["did_log_removing"]) {
|
|
97
|
+
setTimeout(() => {
|
|
98
|
+
if (rapierBody.numColliders() > 0) {
|
|
99
|
+
rapierBody["did_log_removing"] = true;
|
|
100
|
+
console.warn("RapierPhysics: removing rigidbody with colliders from the physics world is not possible right now, please remove the colliders first");
|
|
101
|
+
}
|
|
102
|
+
}, 1);
|
|
97
103
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
// if (rb && rb.numColliders() <= 0) {
|
|
103
|
-
// // this.world?.removeRigidBody(rb);
|
|
104
|
-
// }
|
|
105
|
-
// }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
106
108
|
}
|
|
107
109
|
}
|
|
108
110
|
}
|
|
@@ -128,7 +130,7 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
128
130
|
|
|
129
131
|
updateProperties(rigidbody: IRigidbody) {
|
|
130
132
|
this.validate();
|
|
131
|
-
const physicsBody = rigidbody
|
|
133
|
+
const physicsBody = this.internal_getRigidbody(rigidbody);
|
|
132
134
|
if (physicsBody) {
|
|
133
135
|
this.internalUpdateProperties(rigidbody, physicsBody);
|
|
134
136
|
}
|
|
@@ -206,7 +208,7 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
206
208
|
|
|
207
209
|
private async internalInitialization() {
|
|
208
210
|
// NEEDLE_PHYSICS_INIT_START
|
|
209
|
-
// use .env file with VITE_NEEDLE_USE_RAPIER=false to
|
|
211
|
+
// use .env file with VITE_NEEDLE_USE_RAPIER=false to treeshake rapier
|
|
210
212
|
// @ts-ignore
|
|
211
213
|
if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_RAPIER === "false") {
|
|
212
214
|
return false;
|
|
@@ -16,14 +16,15 @@ ContextRegistry.registerCallback(ContextEvent.MissingCamera, (evt) => {
|
|
|
16
16
|
scene.add(cameraObject);
|
|
17
17
|
|
|
18
18
|
const camInstance = new Camera();
|
|
19
|
-
const cam = addNewComponent(cameraObject, camInstance, true) as ICamera
|
|
19
|
+
const cam = addNewComponent(cameraObject, camInstance, true) as ICamera;
|
|
20
20
|
cam.sourceId = srcId;
|
|
21
21
|
cam.clearFlags = 2;
|
|
22
22
|
cam.backgroundColor = new RGBAColor(0.5, 0.5, 0.5, 1);
|
|
23
23
|
|
|
24
|
-
cameraObject.position.x =
|
|
25
|
-
cameraObject.position.y =
|
|
24
|
+
cameraObject.position.x = 0;
|
|
25
|
+
cameraObject.position.y = 1;
|
|
26
26
|
cameraObject.position.z = 2;
|
|
27
|
+
|
|
27
28
|
return cam;
|
|
28
29
|
});
|
|
29
30
|
|
|
@@ -46,6 +47,9 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreated, (evt) => {
|
|
|
46
47
|
if (cameraObject) {
|
|
47
48
|
const orbit = addNewComponent(cameraObject, new OrbitControls(), false) as OrbitControls;
|
|
48
49
|
orbit.sourceId = "unknown";
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
orbit.fitCameraToObjects(evt.context.scene.children, 1);
|
|
52
|
+
}, 100);
|
|
49
53
|
}
|
|
50
54
|
else {
|
|
51
55
|
console.warn("Missing camera object, can not add orbit controls")
|
|
@@ -185,7 +185,7 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
|
|
|
185
185
|
* @param go component to move the component to
|
|
186
186
|
* @param instance component to move to the GO
|
|
187
187
|
*/
|
|
188
|
-
public static addComponent(go: IGameObject, instance: Component): void {
|
|
188
|
+
public static addComponent(go: IGameObject | Object3D, instance: Component): void {
|
|
189
189
|
return this.moveComponent(go, instance);
|
|
190
190
|
}
|
|
191
191
|
|
|
@@ -194,7 +194,7 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
|
|
|
194
194
|
* @param go component to move the component to
|
|
195
195
|
* @param instance component to move to the GO
|
|
196
196
|
*/
|
|
197
|
-
public static moveComponent(go: IGameObject, instance: Component): void {
|
|
197
|
+
public static moveComponent(go: IGameObject | Object3D, instance: Component): void {
|
|
198
198
|
moveComponentInstance(go, instance as any);
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -87,7 +87,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
87
87
|
if (camGo && !this.setFromTargetPosition()) {
|
|
88
88
|
if (this.debugLog)
|
|
89
89
|
console.log("NO TARGET");
|
|
90
|
-
const forward = new Vector3(0, 0, -
|
|
90
|
+
const forward = new Vector3(0, 0, -10).applyMatrix4(camGo.cam.matrixWorld);
|
|
91
91
|
this.setTarget(forward, true);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -161,6 +161,14 @@ export class SpriteRenderer extends Behaviour {
|
|
|
161
161
|
private _spriteSheet?: SpriteData;
|
|
162
162
|
private _currentSprite?: THREE.Mesh;
|
|
163
163
|
|
|
164
|
+
// additional data
|
|
165
|
+
@serializable()
|
|
166
|
+
transparent: boolean = true;
|
|
167
|
+
@serializable()
|
|
168
|
+
cutoutThreshold: number = 0;
|
|
169
|
+
@serializable()
|
|
170
|
+
castShadows: boolean = false;
|
|
171
|
+
|
|
164
172
|
awake(): void {
|
|
165
173
|
this._currentSprite = undefined;
|
|
166
174
|
if(debug) {
|
|
@@ -221,6 +229,11 @@ export class SpriteRenderer extends Behaviour {
|
|
|
221
229
|
this._currentSprite.layers.set(this.layer)
|
|
222
230
|
}
|
|
223
231
|
|
|
232
|
+
if (this.sharedMaterial) {
|
|
233
|
+
this.sharedMaterial.alphaTest = this.cutoutThreshold;
|
|
234
|
+
this.sharedMaterial.transparent = this.transparent;
|
|
235
|
+
}
|
|
236
|
+
this._currentSprite.castShadow = this.castShadows;
|
|
224
237
|
this._spriteSheet?.update();
|
|
225
238
|
}
|
|
226
239
|
}
|
|
@@ -31,12 +31,11 @@ export class WebXRPlaneTracking extends Behaviour {
|
|
|
31
31
|
/** Optional: if assigned it will be instantiated per tracked plane */
|
|
32
32
|
@serializable(Object3D)
|
|
33
33
|
planeTemplate?: Object3D;
|
|
34
|
+
@serializable()
|
|
35
|
+
initiateRoomCaptureIfNoPlanes = true;
|
|
34
36
|
|
|
35
37
|
get trackedPlanes() { return this._allPlanes.values(); }
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
39
|
onEnable(): void {
|
|
41
40
|
WebXR.addEventListener(WebXREvent.XRUpdate, this.onXRUpdate);
|
|
42
41
|
WebXR.addEventListener("modify-ar-options", this.onModifyAROptions);
|
|
@@ -61,6 +60,7 @@ export class WebXRPlaneTracking extends Behaviour {
|
|
|
61
60
|
|
|
62
61
|
private _planeId = 1;
|
|
63
62
|
private readonly _allPlanes = new Map<XRPlane, XRPlaneContext>();
|
|
63
|
+
private firstTimeNoPlanesDetected = -100;
|
|
64
64
|
|
|
65
65
|
private processPlanes(rig: Object3D, frame: XRFramePlanes) {
|
|
66
66
|
const renderer = this.context.renderer;
|
|
@@ -95,6 +95,24 @@ export class WebXRPlaneTracking extends Behaviour {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// When no planes are found and we haven't already run the coroutine,
|
|
99
|
+
// we start it and then wait for 2s before opening the settings.
|
|
100
|
+
// This only works on Quest through a magic method on the frame,
|
|
101
|
+
// see https://developer.oculus.com/documentation/web/webxr-mixed-reality/#:~:text=Because%20few%20people,once%20per%20session.
|
|
102
|
+
if (this.initiateRoomCaptureIfNoPlanes) {
|
|
103
|
+
if (frame.detectedPlanes.size == 0 && this.firstTimeNoPlanesDetected < -10)
|
|
104
|
+
this.firstTimeNoPlanesDetected = Date.now();
|
|
105
|
+
if (frame.detectedPlanes.size > 0)
|
|
106
|
+
this.firstTimeNoPlanesDetected = -1; // we're done
|
|
107
|
+
if (this.firstTimeNoPlanesDetected > 0 && Date.now() - this.firstTimeNoPlanesDetected > 2500) {
|
|
108
|
+
if ("initiateRoomCapture" in frame.session) {
|
|
109
|
+
//@ts-ignore
|
|
110
|
+
frame.session.initiateRoomCapture();
|
|
111
|
+
this.firstTimeNoPlanesDetected = -1; // we're done
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
98
116
|
for (const plane of frame.detectedPlanes) {
|
|
99
117
|
const planePose = frame.getPose(plane.planeSpace, referenceSpace);
|
|
100
118
|
|
|
@@ -212,7 +230,6 @@ export class WebXRPlaneTracking extends Behaviour {
|
|
|
212
230
|
};
|
|
213
231
|
}
|
|
214
232
|
|
|
215
|
-
|
|
216
233
|
createGeometry(polygon: Vec3[]) {
|
|
217
234
|
const geometry = new BufferGeometry();
|
|
218
235
|
|