@@ -335,7 +335,7 @@
|
|
335
335
|
|
336
336
|
if (debug) {
|
337
337
|
const msg = `Camera \"${this.name}\" clear flags: ${ClearFlags[this._clearFlags]}`;
|
338
|
-
console.
|
338
|
+
console.debug(msg);
|
339
339
|
}
|
340
340
|
switch (this._clearFlags) {
|
341
341
|
case ClearFlags.Skybox:
|
@@ -155,46 +155,18 @@
|
|
155
155
|
private _camera: Camera | null = null;
|
156
156
|
private _syncedTransform?: SyncedTransform;
|
157
157
|
private _didStart = false;
|
158
|
+
private _didSetTarget = false;
|
158
159
|
|
159
160
|
targetElement: HTMLElement | null = null;
|
160
161
|
|
161
162
|
awake(): void {
|
162
163
|
this._didStart = false;
|
164
|
+
this._didSetTarget = false;
|
163
165
|
this._startedListeningToKeyEvents = false;
|
164
166
|
}
|
165
167
|
|
166
168
|
start() {
|
167
169
|
this._didStart = true;
|
168
|
-
if (this.autoTarget) {
|
169
|
-
if (this._controls) {
|
170
|
-
const camGo = GameObject.getComponent(this.gameObject, Camera);
|
171
|
-
if (camGo && !this.setLookTargetFromConstraint()) {
|
172
|
-
if (this.debugLog)
|
173
|
-
console.log("NO TARGET");
|
174
|
-
const worldPosition = getWorldPosition(camGo.cam);
|
175
|
-
const distanceToCenter = worldPosition.length();
|
176
|
-
const forward = new Vector3(0, 0, -distanceToCenter).applyMatrix4(camGo.cam.matrixWorld);
|
177
|
-
this.setLookTargetPosition(forward, true);
|
178
|
-
}
|
179
|
-
// we need to wait one frame for the scene be fully populated. E.g. when we added progressive meshes and a heavy scene this was necessary
|
180
|
-
delayForFrames(0).then(() => {
|
181
|
-
if (this.autoTarget && !this.autoFit && !this.setLookTargetFromConstraint()) {
|
182
|
-
const opts = new RaycastOptions();
|
183
|
-
// center of the screen:
|
184
|
-
opts.screenPoint = new Vector2(0, 0);
|
185
|
-
opts.lineThreshold = 0.1;
|
186
|
-
const hits = this.context.physics.raycast(opts);
|
187
|
-
if (hits.length > 0) {
|
188
|
-
this.setLookTargetPosition(hits[0].point, true);
|
189
|
-
}
|
190
|
-
if (debugCameraFit)
|
191
|
-
console.log("OrbitControls hits", ...hits);
|
192
|
-
}
|
193
|
-
if (this.autoFit) this.fitCamera()
|
194
|
-
});
|
195
|
-
}
|
196
|
-
}
|
197
|
-
|
198
170
|
this._eventSystem = EventSystem.get(this.context) ?? undefined;
|
199
171
|
if (this._eventSystem) {
|
200
172
|
this._afterHandleInputFn = this.afterHandleInput.bind(this);
|
@@ -211,15 +183,13 @@
|
|
211
183
|
this._enableTime = this.context.time.time;
|
212
184
|
const cameraComponent = GameObject.getComponent(this.gameObject, Camera);
|
213
185
|
this._camera = cameraComponent;
|
214
|
-
|
186
|
+
let cam = cameraComponent?.cam;
|
187
|
+
if (!cam && this.gameObject instanceof PerspectiveCamera) {
|
188
|
+
cam = this.gameObject;
|
189
|
+
}
|
215
190
|
if (cam) setCameraController(cam, this, true);
|
216
|
-
if (!this._controls) {
|
217
|
-
|
218
|
-
console.warn("OrbitControls: Requires a Camera component on the same object as this component.");
|
219
|
-
return;
|
220
|
-
}
|
221
|
-
if (cam)
|
222
|
-
this._cameraObject = cam;
|
191
|
+
if (!this._controls && cam instanceof PerspectiveCamera) {
|
192
|
+
this._cameraObject = cam;
|
223
193
|
// Using the parent if possible to make it possible to disable input on the canvas
|
224
194
|
// for having HTML content behind it and still receive input
|
225
195
|
const element = this.targetElement ?? this.context.renderer.domElement;
|
@@ -306,6 +276,8 @@
|
|
306
276
|
onBeforeRender() {
|
307
277
|
if (!this._controls) return;
|
308
278
|
if (this._cameraObject !== this.context.mainCamera) return;
|
279
|
+
|
280
|
+
this.__handleSetTargetWhenBecomingActiveTheFirstTime();
|
309
281
|
|
310
282
|
if (this.context.input.getPointerDown(1) || this.context.input.getPointerDown(2) || this.context.input.mouseWheelChanged || (this.context.input.getPointerPressed(0) && this.context.input.getPointerPositionDelta(0)?.length() || 0 > .1)) {
|
311
283
|
this._inputs += 1;
|
@@ -406,7 +378,37 @@
|
|
406
378
|
|
407
379
|
}
|
408
380
|
|
381
|
+
private __handleSetTargetWhenBecomingActiveTheFirstTime() {
|
382
|
+
if (this._didSetTarget) return;
|
383
|
+
this._didSetTarget = true;
|
384
|
+
if (this.autoTarget) {
|
409
385
|
|
386
|
+
const camGo = GameObject.getComponent(this.gameObject, Camera);
|
387
|
+
if (camGo && !this.setLookTargetFromConstraint()) {
|
388
|
+
if (this.debugLog)
|
389
|
+
console.log("NO TARGET");
|
390
|
+
const worldPosition = getWorldPosition(camGo.cam);
|
391
|
+
const distanceToCenter = worldPosition.length();
|
392
|
+
const forward = new Vector3(0, 0, -distanceToCenter).applyMatrix4(camGo.cam.matrixWorld);
|
393
|
+
this.setLookTargetPosition(forward, true);
|
394
|
+
}
|
395
|
+
if (!this.autoFit && !this.setLookTargetFromConstraint()) {
|
396
|
+
const opts = new RaycastOptions();
|
397
|
+
// center of the screen:
|
398
|
+
opts.screenPoint = new Vector2(0, 0);
|
399
|
+
opts.lineThreshold = 0.1;
|
400
|
+
const hits = this.context.physics.raycast(opts);
|
401
|
+
if (hits.length > 0) {
|
402
|
+
this.setLookTargetPosition(hits[0].point, true);
|
403
|
+
}
|
404
|
+
if (debugCameraFit)
|
405
|
+
console.log("OrbitControls hits", ...hits);
|
406
|
+
}
|
407
|
+
if (this.autoFit) this.fitCamera()
|
408
|
+
}
|
409
|
+
}
|
410
|
+
|
411
|
+
|
410
412
|
/**
|
411
413
|
* Sets camera target position and look direction. Does perform a raycast in the forward direction of the passed in object to find an orbit point
|
412
414
|
*/
|
@@ -279,19 +279,16 @@
|
|
279
279
|
if ((isiOS() && isSafari()) || debugQuicklook) {
|
280
280
|
if (this.useQuicklookExport) {
|
281
281
|
const button = this.getButtonsFactory().createQuicklookButton();
|
282
|
-
button.prepend(getIconElement("view_in_ar"));
|
283
282
|
this.addButton(button, xrButtonsPriority);
|
284
283
|
}
|
285
284
|
}
|
286
285
|
// WebXR
|
287
286
|
if (this.createARButton) {
|
288
287
|
const arbutton = this.getButtonsFactory().createARButton();
|
289
|
-
arbutton.prepend(getIconElement("view_in_ar"))
|
290
288
|
this.addButton(arbutton, xrButtonsPriority);
|
291
289
|
}
|
292
290
|
if (this.createVRButton) {
|
293
291
|
const vrbutton = this.getButtonsFactory().createVRButton();
|
294
|
-
vrbutton.prepend(getIconElement("panorama_photosphere"));
|
295
292
|
this.addButton(vrbutton, xrButtonsPriority);
|
296
293
|
}
|
297
294
|
}
|
@@ -300,7 +297,6 @@
|
|
300
297
|
NeedleXRSession.isVRSupported().then(supported => {
|
301
298
|
if (!supported) {
|
302
299
|
const button = this.getButtonsFactory().createSendToQuestButton();
|
303
|
-
button.prepend(getIconElement("share_windows"));
|
304
300
|
this.addButton(button, xrButtonsPriority);
|
305
301
|
}
|
306
302
|
});
|
@@ -310,7 +306,6 @@
|
|
310
306
|
NeedleXRSession.isXRSupported().then(supported => {
|
311
307
|
if (isDesktop() || !supported) {
|
312
308
|
const qrCode = this.getButtonsFactory().createQRCode();
|
313
|
-
qrCode.prepend(getIconElement("qr_code"));
|
314
309
|
this.addButton(qrCode, xrButtonsPriority);
|
315
310
|
}
|
316
311
|
});
|
@@ -2,6 +2,7 @@
|
|
2
2
|
import { generateQRCode } from "../../engine/engine_utils.js";
|
3
3
|
import { isMozillaXR } from "../../engine/engine_utils.js";
|
4
4
|
import { NeedleXRSession } from "../../engine/engine_xr.js";
|
5
|
+
import { getIconElement } from "../../engine/webcomponents/icons.js";
|
5
6
|
import { GameObject } from "../Component.js";
|
6
7
|
import { USDZExporter } from "../export/usdz/USDZExporter.js";
|
7
8
|
|
@@ -49,9 +50,9 @@
|
|
49
50
|
|
50
51
|
const button = document.createElement("button");
|
51
52
|
this._quicklookButton = button;
|
52
|
-
|
53
53
|
button.dataset["needle"] = "quicklook-button";
|
54
54
|
button.innerText = "Open in Quicklook";
|
55
|
+
button.prepend(getIconElement("view_in_ar"));
|
55
56
|
button.addEventListener("click", () => {
|
56
57
|
const usdzExporter = GameObject.findObjectOfType(USDZExporter);
|
57
58
|
if (usdzExporter) {
|
@@ -87,6 +88,7 @@
|
|
87
88
|
button.classList.add("webxr-button");
|
88
89
|
button.dataset["needle"] = "webxr-ar-button";
|
89
90
|
button.innerText = "Enter AR";
|
91
|
+
button.prepend(getIconElement("view_in_ar"))
|
90
92
|
button.title = "Click to start an AR session";
|
91
93
|
button.addEventListener("click", () => NeedleXRSession.start(mode, init));
|
92
94
|
this.updateSessionSupported(button, mode);
|
@@ -120,6 +122,7 @@
|
|
120
122
|
button.classList.add("webxr-button");
|
121
123
|
button.dataset["needle"] = "webxr-vr-button";
|
122
124
|
button.innerText = "Enter VR";
|
125
|
+
button.prepend(getIconElement("panorama_photosphere"));
|
123
126
|
button.title = "Click to start a VR session";
|
124
127
|
button.addEventListener("click", () => NeedleXRSession.start(mode, init));
|
125
128
|
this.updateSessionSupported(button, mode);
|
@@ -148,6 +151,7 @@
|
|
148
151
|
this._sendToQuestButton = button;
|
149
152
|
button.dataset["needle"] = "webxr-sendtoquest-button";
|
150
153
|
button.innerText = "Open on Quest";
|
154
|
+
button.prepend(getIconElement("share_windows"));
|
151
155
|
button.title = "Click to send this page to the Oculus Browser on your Quest";
|
152
156
|
button.addEventListener("click", () => {
|
153
157
|
const urlParameter = encodeURIComponent(window.location.href);
|
@@ -175,6 +179,7 @@
|
|
175
179
|
const qrCodeButton = document.createElement("button");
|
176
180
|
this._qrButton = qrCodeButton;
|
177
181
|
qrCodeButton.innerText = "QR Code";
|
182
|
+
qrCodeButton.prepend(getIconElement("qr_code"));
|
178
183
|
qrCodeButton.title = "Scan this QR code with your phone to open this page";
|
179
184
|
this.hideElementDuringXRSession(qrCodeButton);
|