@@ -50,13 +50,11 @@
|
|
50
50
|
// Workaround: seems WebXR Viewer has a non-standard behaviour when it comes to DOM Overlay and Canvas;
|
51
51
|
// HTMLElements that are inside the Canvas element are not visible in the DOM Overlay.
|
52
52
|
const isWebXRViewer = /WebXRViewer\//i.test( navigator.userAgent );
|
53
|
-
|
54
|
-
if (isWebXRViewer)
|
55
|
-
{
|
53
|
+
if (isWebXRViewer) {
|
56
54
|
if(options.domOverlay?.root) {
|
57
|
-
|
58
|
-
|
59
|
-
{
|
55
|
+
const overlayElement = options.domOverlay.root;
|
56
|
+
originalDomOverlayParent = overlayElement.parentElement;
|
57
|
+
if (originalDomOverlayParent) {
|
60
58
|
console.log("Reparent DOM Overlay to body", overlayElement, overlayElement.style.display);
|
61
59
|
// mozilla webxr does hide elements on session start
|
62
60
|
// this is only necessary if we generated the overlay element
|
@@ -92,13 +90,12 @@
|
|
92
90
|
|
93
91
|
button.textContent = 'START AR';
|
94
92
|
|
95
|
-
const overlayElement = options.domOverlay.root;
|
96
93
|
// if we reparented the DOM overlay, we're reverting it here
|
97
94
|
if (originalDomOverlayParent)
|
98
|
-
originalDomOverlayParent.appendChild(
|
95
|
+
originalDomOverlayParent.appendChild(options.domOverlay.root);
|
99
96
|
|
100
97
|
if (ARButtonControlsDomOverlay)
|
101
|
-
|
98
|
+
options.domOverlay.root.style.display = 'none';
|
102
99
|
|
103
100
|
currentSession = null;
|
104
101
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TypeStore } from "./../engine_typestore"
|
2
|
-
|
2
|
+
|
3
3
|
// Import types
|
4
4
|
import { __Ignore } from "../../engine-components/codegen/components";
|
5
5
|
import { ActionBuilder } from "../../engine-components/export/usdz/extensions/behavior/BehavioursBuilder";
|
@@ -216,7 +216,7 @@
|
|
216
216
|
import { XRGrabRendering } from "../../engine-components/webxr/WebXRGrabRendering";
|
217
217
|
import { XRRig } from "../../engine-components/webxr/WebXRRig";
|
218
218
|
import { XRState } from "../../engine-components/XRFlag";
|
219
|
-
|
219
|
+
|
220
220
|
// Register types
|
221
221
|
TypeStore.add("__Ignore", __Ignore);
|
222
222
|
TypeStore.add("ActionBuilder", ActionBuilder);
|
@@ -171,10 +171,17 @@
|
|
171
171
|
}
|
172
172
|
|
173
173
|
private selfModel!: USDObject;
|
174
|
-
private targetModels
|
174
|
+
private targetModels!: USDObject[];
|
175
175
|
|
176
176
|
private static _materialTriggersPerId: { [key: string]: ChangeMaterialOnClick[] } = {}
|
177
177
|
|
178
|
+
|
179
|
+
beforeCreateDocument(_ext: BehaviorExtension, _context) {
|
180
|
+
this.targetModels = [];
|
181
|
+
ChangeMaterialOnClick._materialTriggersPerId = {}
|
182
|
+
}
|
183
|
+
|
184
|
+
|
178
185
|
createBehaviours(_ext: BehaviorExtension, model: USDObject, _context) {
|
179
186
|
|
180
187
|
const shouldExport = this._objectsWithThisMaterial.find(o => o.gameObject.uuid === model.uuid);
|
@@ -20,31 +20,19 @@
|
|
20
20
|
if (isLocalNetwork())
|
21
21
|
console.log("Add the ?console query parameter to the url to show the debug console (on mobile it will automatically open for local development when your get errors)");
|
22
22
|
const isMobile = isMobileDevice();
|
23
|
-
if (isMobile)
|
24
|
-
{
|
23
|
+
if (isMobile) {
|
25
24
|
beginWatchingLogs();
|
26
25
|
createConsole(true);
|
27
|
-
if (isMobile)
|
28
|
-
{
|
26
|
+
if (isMobile) {
|
29
27
|
const engineElement = document.querySelector("needle-engine");
|
30
|
-
// setTimeout(() => {
|
31
|
-
// const el = getConsoleElement();
|
32
|
-
// console.log(el);
|
33
|
-
// if (el) {
|
34
|
-
// const overlay = engineElement["getAROverlayContainer"]?.call(engineElement);
|
35
|
-
// overlay.appendChild(el);
|
36
|
-
// }
|
37
|
-
// }, 1000)
|
38
28
|
engineElement?.addEventListener("enter-ar", () => {
|
39
29
|
if (showConsole || consoleInstance || getErrorCount() > 0) {
|
40
30
|
if (getParam("noerrors")) return;
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
// overlay.appendChild(consoleElement);
|
47
|
-
// }
|
31
|
+
const overlay = engineElement["getAROverlayContainer"]?.call(engineElement);
|
32
|
+
const consoleElement = getConsoleElement();
|
33
|
+
if (consoleElement && overlay) {
|
34
|
+
overlay.appendChild(consoleElement);
|
35
|
+
}
|
48
36
|
}
|
49
37
|
});
|
50
38
|
engineElement?.addEventListener("exit-ar", () => {
|
@@ -115,6 +103,7 @@
|
|
115
103
|
isLoading = true;
|
116
104
|
|
117
105
|
const script = document.createElement("script");
|
106
|
+
script.src = "https://unpkg.com/vconsole@latest/dist/vconsole.min.js";
|
118
107
|
script.onload = () => {
|
119
108
|
isLoading = false;
|
120
109
|
isVisible = true;
|
@@ -126,21 +115,6 @@
|
|
126
115
|
consoleHtmlElement[$defaultConsoleParent] = consoleHtmlElement.parentElement;
|
127
116
|
consoleHtmlElement.style.position = "absolute";
|
128
117
|
consoleHtmlElement.style.zIndex = Number.MAX_SAFE_INTEGER.toString();
|
129
|
-
// const styleSheetList = document.styleSheets;
|
130
|
-
// for (let i = 0; i < styleSheetList.length; i++) {
|
131
|
-
// const styleSheet = styleSheetList[i];
|
132
|
-
// const firstRule = styleSheet.cssRules[0] as CSSStyleRule;
|
133
|
-
// if(firstRule && firstRule.selectorText === "#__vconsole") {
|
134
|
-
// console.log("found vconsole style sheet");
|
135
|
-
// const styleTag = document.createElement("style");
|
136
|
-
// styleTag.innerHTML = "#__needleconsole {}";
|
137
|
-
// for (let j = 0; j < styleSheet.cssRules.length; j++) {
|
138
|
-
// const rule = styleSheet.cssRules[j] as CSSStyleRule;
|
139
|
-
// styleTag.innerHTML += rule.cssText;
|
140
|
-
// }
|
141
|
-
// consoleHtmlElement.appendChild(styleTag);
|
142
|
-
// }
|
143
|
-
// }
|
144
118
|
}
|
145
119
|
consoleInstance.setSwitchPosition(20, 10);
|
146
120
|
consoleSwitchButton = getConsoleSwitchButton();
|
@@ -189,13 +163,12 @@
|
|
189
163
|
}
|
190
164
|
}
|
191
165
|
`;
|
192
|
-
|
166
|
+
document.head.appendChild(styles);
|
193
167
|
if (startHidden === true)
|
194
168
|
hideDebugConsole();
|
195
169
|
}
|
196
170
|
|
197
171
|
};
|
198
|
-
script.src = "https://unpkg.com/vconsole@latest/dist/vconsole.min.js";
|
199
172
|
document.body.appendChild(script);
|
200
173
|
}
|
201
174
|
|
@@ -97,7 +97,7 @@
|
|
97
97
|
}
|
98
98
|
message = newMessage;
|
99
99
|
}
|
100
|
-
if (
|
100
|
+
if (message.length <= 0) return;
|
101
101
|
showMessage(type, domElement, message);
|
102
102
|
}
|
103
103
|
|
@@ -185,25 +185,26 @@
|
|
185
185
|
const container = document.createElement("div");
|
186
186
|
errorsMap.set(domElement, container);
|
187
187
|
container.setAttribute("data-needle_engine_debug_overlay", "");
|
188
|
+
container.classList.add(arContainerClassName);
|
189
|
+
container.classList.add("desktop");
|
188
190
|
container.classList.add("debug-container");
|
189
|
-
container.style.
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
else domElement.appendChild(container);
|
191
|
+
container.style.position = "absolute";
|
192
|
+
container.style.top = "0";
|
193
|
+
container.style.right = "5px";
|
194
|
+
container.style.paddingTop = "0px";
|
195
|
+
container.style.maxWidth = "70%";
|
196
|
+
container.style.maxHeight = "calc(100% - 5px)";
|
197
|
+
container.style.zIndex = "1000";
|
198
|
+
// container.style.pointerEvents = "none";
|
199
|
+
container.style.pointerEvents = "scroll";
|
200
|
+
// container.style["-webkit-overflow-scrolling"] = "touch";
|
201
|
+
container.style.display = "flex";
|
202
|
+
container.style.alignItems = "end";
|
203
|
+
container.style.flexDirection = "column";
|
204
|
+
container.style.color = "white";
|
205
|
+
container.style.overflow = "auto";
|
206
|
+
// container.style.border = "1px solid red";
|
207
|
+
domElement.appendChild(container);
|
207
208
|
|
208
209
|
const style = document.createElement("style");
|
209
210
|
style.innerHTML = logsContainerStyles;
|
@@ -140,12 +140,6 @@
|
|
140
140
|
/** the <needle-engine> HTML element */
|
141
141
|
domElement: HTMLElement;
|
142
142
|
|
143
|
-
appendHTMLElement(element: HTMLElement) {
|
144
|
-
if (this.domElement.shadowRoot)
|
145
|
-
return this.domElement.shadowRoot.appendChild(element);
|
146
|
-
else return this.domElement.appendChild(element);
|
147
|
-
}
|
148
|
-
|
149
143
|
get resolutionScaleFactor() { return this._resolutionScaleFactor; }
|
150
144
|
/** use to scale the resolution up or down of the renderer. default is 1 */
|
151
145
|
set resolutionScaleFactor(val: number) {
|
@@ -320,7 +314,7 @@
|
|
320
314
|
this._disposeCallbacks.push(() => this._intersectionObserver?.disconnect());
|
321
315
|
}
|
322
316
|
|
323
|
-
private createRenderer() {
|
317
|
+
private createRenderer(domElement?: HTMLElement) {
|
324
318
|
this.renderer?.dispose();
|
325
319
|
|
326
320
|
const params: WebGLRendererParameters = {
|
@@ -328,7 +322,7 @@
|
|
328
322
|
};
|
329
323
|
|
330
324
|
// get canvas already configured in the Needle Engine Web Component
|
331
|
-
const canvas =
|
325
|
+
const canvas = domElement?.shadowRoot?.querySelector("canvas");
|
332
326
|
if (canvas) params.canvas = canvas;
|
333
327
|
|
334
328
|
this.renderer = new WebGLRenderer(params);
|
@@ -722,8 +716,8 @@
|
|
722
716
|
this._sizeChanged = true;
|
723
717
|
|
724
718
|
if (this._stats) {
|
725
|
-
this._stats.showPanel(
|
726
|
-
this.domElement.
|
719
|
+
this._stats.showPanel(1);
|
720
|
+
this.domElement.appendChild(this._stats.dom);
|
727
721
|
}
|
728
722
|
|
729
723
|
if (debug)
|
@@ -4,11 +4,6 @@
|
|
4
4
|
DO NOT IMPORT ENGINE_ELEMENT FROM HERE
|
5
5
|
*/
|
6
6
|
|
7
|
-
/**
|
8
|
-
* Call with the name of an attribute that you want to receive change events for
|
9
|
-
* This is useful for example if you want to add custom attributes to <needle-engine>
|
10
|
-
* Use the addAttributeChangeCallback utility methods to register callback events
|
11
|
-
*/
|
12
7
|
export async function registerObservableAttribute(name: string) {
|
13
8
|
const { NeedleEngineHTMLElement } = await import("./engine_element");
|
14
9
|
if (!NeedleEngineHTMLElement.observedAttributes.includes(name))
|
@@ -30,7 +30,7 @@
|
|
30
30
|
this.currentSession = session;
|
31
31
|
this.arContainer = overlayContainer;
|
32
32
|
|
33
|
-
const arElements = context.domElement.
|
33
|
+
const arElements = context.domElement.querySelectorAll(`.${arContainerClassName}`);
|
34
34
|
arElements.forEach(el => {
|
35
35
|
if (!el) return;
|
36
36
|
if (el === this.arContainer) return;
|
@@ -76,7 +76,7 @@
|
|
76
76
|
// Canvas is not in DOM anymore after AR using Mozilla XR
|
77
77
|
const canvas = _context.renderer.domElement;
|
78
78
|
if (canvas) {
|
79
|
-
_context.domElement.
|
79
|
+
_context.domElement.insertBefore(canvas, _context.domElement.firstChild);
|
80
80
|
}
|
81
81
|
|
82
82
|
// Fix visibility
|
@@ -92,45 +92,35 @@
|
|
92
92
|
}
|
93
93
|
|
94
94
|
findOrCreateARContainer(element: HTMLElement): HTMLElement {
|
95
|
-
if(debug) console.log("findOrCreateARContainer");
|
96
95
|
// search in the needle-engine element
|
97
96
|
if (element.classList.contains(arContainerClassName)) {
|
98
|
-
if(debug) console.log("Found overlay container in needle-engine element");
|
99
97
|
return element;
|
100
98
|
}
|
101
|
-
if (element.
|
102
|
-
|
103
|
-
|
104
|
-
if
|
105
|
-
|
106
|
-
|
99
|
+
if (element.children) {
|
100
|
+
for (let i = 0; i < element.children.length; i++) {
|
101
|
+
const ch = element.children[i] as HTMLElement;
|
102
|
+
if (!ch || !ch.classList) continue;
|
103
|
+
if (ch.classList.contains(arContainerClassName)) {
|
104
|
+
return ch;
|
105
|
+
}
|
106
|
+
}
|
107
107
|
}
|
108
108
|
|
109
109
|
// search in document as well; "ar" element could live outside needle-engine element
|
110
110
|
const arElements = document.getElementsByClassName(arContainerClassName);
|
111
|
-
if (arElements && arElements.length > 0)
|
112
|
-
if(debug) console.log("Found overlay container in document");
|
111
|
+
if (arElements && arElements.length > 0)
|
113
112
|
return arElements[0] as HTMLElement;
|
114
|
-
}
|
115
113
|
|
116
114
|
if (debug)
|
117
115
|
console.log("No overlay container found in document - generating new ony");
|
118
116
|
const el = document.createElement("div");
|
119
117
|
el.classList.add(arContainerClassName);
|
120
|
-
el.style.
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
display: flex;
|
127
|
-
visibility: visible;
|
128
|
-
z-index: 9999;
|
129
|
-
pointer-events: none;
|
130
|
-
// background: rgba(0,0,0,1);
|
131
|
-
`;
|
132
|
-
if(debug) this.createFallbackCloseARButton(element);
|
133
|
-
return this.appendElement(el, element) as HTMLElement;
|
118
|
+
el.style.position = "absolute";
|
119
|
+
el.style.width = "100%";
|
120
|
+
el.style.height = "100%";
|
121
|
+
el.style.display = "flex";
|
122
|
+
el.style.visibility = "visible";
|
123
|
+
return element.appendChild(el);
|
134
124
|
}
|
135
125
|
|
136
126
|
private onRequestedEndAR() {
|
@@ -145,33 +135,24 @@
|
|
145
135
|
}
|
146
136
|
|
147
137
|
private createFallbackCloseARButton(element: HTMLElement) {
|
148
|
-
const quitARSlot = document.createElement("slot");
|
149
|
-
quitARSlot.setAttribute("name", "quit-ar");
|
150
|
-
this.appendElement(quitARSlot, element);
|
151
|
-
if(debug) quitARSlot.addEventListener('click', () => console.log("Clicked fallback close button"));
|
152
|
-
quitARSlot.addEventListener('click', this.closeARCallback);
|
153
|
-
this._createdAROnlyElements.push(quitARSlot);
|
154
|
-
// for mozilla XR reparenting we have to make sure the close button is clickable so we set it on the element directly
|
155
|
-
// it's in general perhaps more safe to set it on the element to ensure it's clickable
|
156
|
-
quitARSlot.style.pointerEvents = "auto";
|
157
|
-
|
158
138
|
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
159
|
-
svg.classList.add("quit-ar-button");
|
160
139
|
svg.setAttribute('width', "38px");
|
161
140
|
svg.setAttribute('height', "38px");
|
162
|
-
|
141
|
+
svg.style.position = 'absolute';
|
142
|
+
svg.style.right = '20px';
|
143
|
+
svg.style.top = '40px';
|
144
|
+
svg.style.zIndex = '9999';
|
145
|
+
svg.style.pointerEvents = 'auto';
|
146
|
+
svg.addEventListener('click', this.closeARCallback);
|
147
|
+
element.appendChild(svg);
|
148
|
+
this._createdAROnlyElements.push(svg);
|
163
149
|
|
164
150
|
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
165
151
|
path.setAttribute('d', 'M 12,12 L 28,28 M 28,12 12,28');
|
166
152
|
path.setAttribute('stroke', '#ddd');
|
167
153
|
path.setAttribute('stroke-width', "3px");
|
168
154
|
svg.appendChild(path);
|
169
|
-
|
155
|
+
this._createdAROnlyElements.push(path);
|
170
156
|
}
|
171
157
|
|
172
|
-
private appendElement(element: Element, parent: HTMLElement) {
|
173
|
-
if(parent.shadowRoot) return parent.shadowRoot.appendChild(element);
|
174
|
-
return parent.appendChild(element);
|
175
|
-
}
|
176
|
-
|
177
158
|
}
|
@@ -91,41 +91,9 @@
|
|
91
91
|
constructor() {
|
92
92
|
super();
|
93
93
|
this._overlay_ar = new AROverlayHandler();
|
94
|
+
this._context = new Context({ domElement: this });
|
94
95
|
// TODO: do we want to rename this event?
|
95
96
|
this.addEventListener("ready", this.onReady);
|
96
|
-
|
97
|
-
this.attachShadow({mode: 'open'});
|
98
|
-
const template = document.createElement('template');
|
99
|
-
template.innerHTML =
|
100
|
-
`<style>
|
101
|
-
:host {
|
102
|
-
position: relative;
|
103
|
-
display: block;
|
104
|
-
width: 600px;
|
105
|
-
height: 300px;
|
106
|
-
}
|
107
|
-
:host canvas {
|
108
|
-
position: absolute;
|
109
|
-
user-select: none;
|
110
|
-
touch-action: none;
|
111
|
-
}
|
112
|
-
:host slot[name="quit-ar"]:hover {
|
113
|
-
cursor: pointer;
|
114
|
-
}
|
115
|
-
:host .quit-ar-button {
|
116
|
-
position: absolute;
|
117
|
-
top: 40px;
|
118
|
-
right: 20px;
|
119
|
-
z-index: 9999;
|
120
|
-
}
|
121
|
-
</style>
|
122
|
-
<canvas></canvas>
|
123
|
-
`;
|
124
|
-
|
125
|
-
if (this.shadowRoot)
|
126
|
-
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
127
|
-
|
128
|
-
this._context = new Context({ domElement: this });
|
129
97
|
this.addEventListener("error", this.onError);
|
130
98
|
}
|
131
99
|
|
@@ -169,7 +137,7 @@
|
|
169
137
|
}
|
170
138
|
|
171
139
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
172
|
-
|
140
|
+
// console.log(name, oldValue, newValue);
|
173
141
|
switch (name) {
|
174
142
|
case "src":
|
175
143
|
if (debug) console.warn("src changed to type:", typeof newValue, ", from \"", _oldValue, "\" to \"", newValue, "\"")
|
@@ -445,7 +413,6 @@
|
|
445
413
|
this.classList.add(arSessionActiveClassName);
|
446
414
|
this.classList.remove(desktopSessionActiveClassName);
|
447
415
|
const arContainer = this.getAROverlayContainer();
|
448
|
-
if(debug) console.warn("onSetupAR:", arContainer)
|
449
416
|
if (arContainer) {
|
450
417
|
arContainer.classList.add(arSessionActiveClassName);
|
451
418
|
arContainer.classList.remove(desktopSessionActiveClassName);
|
@@ -397,12 +397,7 @@
|
|
397
397
|
// if(evt.target === this.context.renderer.domElement) return true;
|
398
398
|
// const css = window.getComputedStyle(evt.target as HTMLElement);
|
399
399
|
// if(css.pointerEvents === "all") return false;
|
400
|
-
|
401
|
-
// We only check the target elements here since the canvas may be overlapped by other elements
|
402
|
-
// in which case we do not want to use the input (e.g. if a HTML element is being triggered)
|
403
|
-
if(evt.target === this.context.renderer.domElement) return true;
|
404
|
-
if(evt.target === this.context.domElement) return true;
|
405
|
-
return false;
|
400
|
+
return evt.target === this.context.renderer.domElement;
|
406
401
|
}
|
407
402
|
|
408
403
|
private keysPressed: { [key: KeyCode | string]: { pressed: boolean, frame: number, startFrame: number, key: string, code: KeyCode | string } } = {};
|
@@ -18,7 +18,6 @@
|
|
18
18
|
import { XRFlag, XRState, XRStateFlag } from "../XRFlag";
|
19
19
|
import { showBalloonWarning } from '../../engine/debug';
|
20
20
|
|
21
|
-
const debugWebXR = getParam("debugwebxr");
|
22
21
|
|
23
22
|
export async function detectARSupport() {
|
24
23
|
if(isMozillaXR()) return true;
|
@@ -239,26 +238,10 @@
|
|
239
238
|
let arButton, vrButton;
|
240
239
|
const buttonsContainer = document.createElement('div');
|
241
240
|
buttonsContainer.classList.add("webxr-buttons");
|
242
|
-
|
243
|
-
position: fixed;
|
244
|
-
bottom: 21px;
|
245
|
-
left: 50%;
|
246
|
-
transform: translate(-50%, 0%);
|
247
|
-
z-index: 1000;
|
248
|
-
|
249
|
-
display: flex;
|
250
|
-
flex-direction: row;
|
251
|
-
justify-content: center;
|
252
|
-
align-items: flex-start;
|
253
|
-
gap: 10px;
|
254
|
-
`;
|
255
|
-
this.context.appendHTMLElement(buttonsContainer);
|
241
|
+
this.context.domElement.append(buttonsContainer);
|
256
242
|
|
257
|
-
const forceButtons = debugWebXR;
|
258
|
-
if(debugWebXR) console.log("ARSupported?", arSupported, "VRSupported?", vrSupported);
|
259
|
-
|
260
243
|
// AR support
|
261
|
-
if (
|
244
|
+
if (this.enableAR && this.createARButton && arSupported)
|
262
245
|
{
|
263
246
|
arButton = WebXR.createARButton(this);
|
264
247
|
this._arButton = arButton;
|
@@ -266,7 +249,7 @@
|
|
266
249
|
}
|
267
250
|
|
268
251
|
// VR support
|
269
|
-
if (
|
252
|
+
if (this.createVRButton && this.enableVR && vrSupported) {
|
270
253
|
vrButton = WebXR.createVRButton(this);
|
271
254
|
this._vrButton = vrButton;
|
272
255
|
buttonsContainer.appendChild(vrButton);
|