@shopware-ag/dive 1.16.16-beta.0 → 1.16.16
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/build/dive.cjs +203 -1652
- package/build/dive.cjs.map +1 -1
- package/build/dive.d.cts +8 -50
- package/build/dive.d.ts +8 -50
- package/build/dive.js +159 -1619
- package/build/dive.js.map +1 -1
- package/package.json +1 -1
- package/src/axiscamera/AxisCamera.ts +4 -4
- package/src/axiscamera/__test__/AxisCamera.test.ts +0 -4
- package/src/com/Communication.ts +0 -17
- package/src/com/__test__/Communication.test.ts +1 -1
- package/src/com/actions/index.ts +0 -2
- package/src/dive.ts +9 -51
- package/src/helper/findSceneRecursive/findSceneRecursive.ts +2 -2
- package/src/info/Info.ts +1 -37
- package/src/info/__test__/Info.test.ts +5 -45
- package/src/mediacreator/MediaCreator.ts +4 -4
- package/src/mediacreator/__test__/MediaCreator.test.ts +2 -7
- package/src/renderer/Renderer.ts +11 -21
- package/src/renderer/__test__/Renderer.test.ts +1 -19
- package/src/scene/Scene.ts +12 -35
- package/src/scene/__test__/Scene.test.ts +5 -39
- package/src/scene/root/Root.ts +0 -1
- package/src/toolbox/BaseTool.ts +3 -9
- package/src/toolbox/Toolbox.ts +1 -1
- package/src/toolbox/__test__/Toolbox.test.ts +1 -1
- package/src/toolbox/select/SelectTool.ts +1 -1
- package/src/toolbox/select/__test__/SelectTool.test.ts +1 -1
- package/src/toolbox/transform/TransformTool.ts +4 -4
- package/src/toolbox/transform/__test__/TransformTool.test.ts +4 -2
- package/src/ar/AR.ts +0 -164
- package/src/ar/arquicklook/ARQuickLook.ts +0 -42
- package/src/ar/webxr/WebXR.ts +0 -176
- package/src/ar/webxr/controller/WebXRController.ts +0 -334
- package/src/ar/webxr/crosshair/WebXRCrosshair.ts +0 -35
- package/src/ar/webxr/origin/WebXROrigin.ts +0 -191
- package/src/ar/webxr/overlay/Overlay.ts +0 -50
- package/src/ar/webxr/raycaster/WebXRRaycaster.ts +0 -131
- package/src/ar/webxr/raycaster/ar/WebXRRaycasterAR.ts +0 -102
- package/src/ar/webxr/raycaster/three/WebXRRaycasterTHREE.ts +0 -49
- package/src/ar/webxr/touchscreencontrols/WebXRTouchscreenControls.ts +0 -356
- package/src/events/EventExecutor.ts +0 -35
- package/src/scene/xrroot/XRRoot.ts +0 -56
- package/src/scene/xrroot/xrlightroot/XRLightRoot.ts +0 -80
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DIVEScene } from '../Scene';
|
|
2
2
|
import { type Color } from 'three';
|
|
3
3
|
import { type COMEntity } from '../../com/types';
|
|
4
|
-
import { DIVERenderer } from '../../renderer/Renderer';
|
|
5
4
|
|
|
6
5
|
const mock_AddSceneObject = jest.fn();
|
|
7
6
|
const mock_UpdateSceneObject = jest.fn();
|
|
@@ -27,30 +26,6 @@ jest.mock('../root/Root', () => {
|
|
|
27
26
|
};
|
|
28
27
|
});
|
|
29
28
|
|
|
30
|
-
jest.mock('../xrroot/XRRoot', () => {
|
|
31
|
-
return {
|
|
32
|
-
DIVEXRRoot: jest.fn(function (scene: DIVEScene) {
|
|
33
|
-
this.visible = true;
|
|
34
|
-
this.isObject3D = true;
|
|
35
|
-
this.parent = null;
|
|
36
|
-
this.dispatchEvent = jest.fn();
|
|
37
|
-
this.removeFromParent = jest.fn();
|
|
38
|
-
this.visible = true;
|
|
39
|
-
this.InitLightEstimation = jest.fn();
|
|
40
|
-
this.DisposeLightEstimation = jest.fn();
|
|
41
|
-
return this;
|
|
42
|
-
}),
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
jest.mock('../../renderer/Renderer.ts', () => {
|
|
47
|
-
return {
|
|
48
|
-
DIVERenderer: jest.fn(function () {}),
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const mockRenderer = new DIVERenderer();
|
|
53
|
-
|
|
54
29
|
describe('dive/scene/DIVEScene', () => {
|
|
55
30
|
afterEach(() => {
|
|
56
31
|
jest.clearAllMocks();
|
|
@@ -59,26 +34,17 @@ describe('dive/scene/DIVEScene', () => {
|
|
|
59
34
|
it('should instantiate', () => {
|
|
60
35
|
const scene = new DIVEScene();
|
|
61
36
|
expect(scene).toBeDefined();
|
|
37
|
+
expect(scene.children).toHaveLength(3);
|
|
62
38
|
});
|
|
63
39
|
|
|
64
|
-
it('should have
|
|
65
|
-
const scene = new DIVEScene();
|
|
66
|
-
expect(scene.Root).toBeDefined();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should have XRRoot', () => {
|
|
70
|
-
const scene = new DIVEScene();
|
|
71
|
-
expect(scene.XRRoot).toBeDefined();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should InitXR', () => {
|
|
40
|
+
it('should have Floor', () => {
|
|
75
41
|
const scene = new DIVEScene();
|
|
76
|
-
expect(
|
|
42
|
+
expect(scene.Floor).toBeDefined();
|
|
77
43
|
});
|
|
78
44
|
|
|
79
|
-
it('should
|
|
45
|
+
it('should have Grid', () => {
|
|
80
46
|
const scene = new DIVEScene();
|
|
81
|
-
expect(
|
|
47
|
+
expect(scene.Grid).toBeDefined();
|
|
82
48
|
});
|
|
83
49
|
|
|
84
50
|
it('should set background color', () => {
|
package/src/scene/root/Root.ts
CHANGED
package/src/toolbox/BaseTool.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Intersection,
|
|
3
|
-
type Object3D,
|
|
4
|
-
Raycaster,
|
|
5
|
-
Vector2,
|
|
6
|
-
Vector3,
|
|
7
|
-
} from 'three';
|
|
1
|
+
import { Intersection, Object3D, Raycaster, Vector2, Vector3 } from 'three';
|
|
8
2
|
import {
|
|
9
3
|
PRODUCT_LAYER_MASK,
|
|
10
4
|
UI_LAYER_MASK,
|
|
11
5
|
} from '../constant/VisibilityLayerMask';
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
6
|
+
import { DIVEScene } from '../scene/Scene';
|
|
7
|
+
import DIVEOrbitControls from '../controls/OrbitControls';
|
|
14
8
|
import { type DIVEDraggable } from '../interface/Draggable';
|
|
15
9
|
import { type DIVEHoverable } from '../interface/Hoverable';
|
|
16
10
|
import { findInterface } from '../helper/findInterface/findInterface';
|
package/src/toolbox/Toolbox.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type DIVEOrbitControls from '../controls/OrbitControls.ts';
|
|
2
|
-
import {
|
|
2
|
+
import type { DIVEScene } from '../scene/Scene.ts';
|
|
3
3
|
import { type DIVEBaseTool } from './BaseTool.ts';
|
|
4
4
|
import { type DIVESelectTool } from './select/SelectTool.ts';
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import DIVEToolbox, { type ToolType } from '../Toolbox';
|
|
2
2
|
import type DIVEOrbitControls from '../../controls/OrbitControls';
|
|
3
|
-
import {
|
|
3
|
+
import type { DIVEScene } from '../../scene/Scene';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @jest-environment jsdom
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Object3D } from 'three';
|
|
2
|
-
import {
|
|
2
|
+
import { DIVEScene } from '../../scene/Scene.ts';
|
|
3
3
|
import DIVETransformTool from '../transform/TransformTool.ts';
|
|
4
4
|
import { findInterface } from '../../helper/findInterface/findInterface.ts';
|
|
5
5
|
import type DIVEOrbitControls from '../../controls/OrbitControls.ts';
|
|
@@ -100,7 +100,7 @@ jest.mock('three', () => {
|
|
|
100
100
|
const mock_attach = jest.fn();
|
|
101
101
|
const mock_detach = jest.fn();
|
|
102
102
|
|
|
103
|
-
jest.mock('three/examples/jsm/
|
|
103
|
+
jest.mock('three/examples/jsm/Addons.js', () => {
|
|
104
104
|
return {
|
|
105
105
|
TransformControls: jest.fn(function () {
|
|
106
106
|
(this.addEventListener = (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DIVEBaseTool } from '../BaseTool.ts';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { TransformControls } from 'three/examples/jsm/
|
|
2
|
+
import { DIVEScene } from '../../scene/Scene.ts';
|
|
3
|
+
import DIVEOrbitControls from '../../controls/OrbitControls.ts';
|
|
4
|
+
import { TransformControls } from 'three/examples/jsm/Addons';
|
|
5
5
|
import { type DIVEMovable } from '../../interface/Movable.ts';
|
|
6
6
|
import { implementsInterface } from '../../helper/isInterface/implementsInterface.ts';
|
|
7
7
|
|
|
@@ -81,7 +81,7 @@ export default class DIVETransformTool extends DIVEBaseTool {
|
|
|
81
81
|
this._gizmo.object.onMoveEnd();
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
scene.add(this._gizmo);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
public Activate(): void {}
|
|
@@ -99,7 +99,7 @@ jest.mock('three', () => {
|
|
|
99
99
|
const mock_attach = jest.fn();
|
|
100
100
|
const mock_detach = jest.fn();
|
|
101
101
|
|
|
102
|
-
jest.mock('three/examples/jsm/
|
|
102
|
+
jest.mock('three/examples/jsm/Addons.js', () => {
|
|
103
103
|
return {
|
|
104
104
|
TransformControls: jest.fn(function () {
|
|
105
105
|
(this.addEventListener = (
|
|
@@ -189,7 +189,9 @@ describe('dive/toolbox/select/DIVETransformTool', () => {
|
|
|
189
189
|
const transformTool = new DIVETransformTool(mockScene, mockController);
|
|
190
190
|
expect(() => transformTool.SetGizmoVisibility(true)).not.toThrow();
|
|
191
191
|
|
|
192
|
-
mockScene.
|
|
192
|
+
expect(mockScene.add).toBeCalled();
|
|
193
|
+
|
|
194
|
+
mockScene.children.includes = jest.fn().mockReturnValue(true);
|
|
193
195
|
expect(() => transformTool.SetGizmoVisibility(false)).not.toThrow();
|
|
194
196
|
});
|
|
195
197
|
});
|
package/src/ar/AR.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { DIVEInfo, WebXRUnsupportedReason } from '../info/Info';
|
|
2
|
-
import { DIVEARQuickLook } from './arquicklook/ARQuickLook';
|
|
3
|
-
import { DIVEWebXR } from './webxr/WebXR';
|
|
4
|
-
import { type DIVEScene } from '../scene/Scene';
|
|
5
|
-
import { type DIVERenderer } from '../renderer/Renderer';
|
|
6
|
-
import DIVEOrbitControls from '../controls/OrbitControls';
|
|
7
|
-
|
|
8
|
-
export class DIVEAR {
|
|
9
|
-
private _renderer: DIVERenderer;
|
|
10
|
-
private _scene: DIVEScene;
|
|
11
|
-
private _controller: DIVEOrbitControls;
|
|
12
|
-
|
|
13
|
-
private arPlacement: string = 'floor';
|
|
14
|
-
private arScale: string = 'auto';
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
renderer: DIVERenderer,
|
|
18
|
-
scene: DIVEScene,
|
|
19
|
-
controller: DIVEOrbitControls,
|
|
20
|
-
) {
|
|
21
|
-
this._renderer = renderer;
|
|
22
|
-
this._scene = scene;
|
|
23
|
-
this._controller = controller;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public async Launch(): Promise<void> {
|
|
27
|
-
const system = DIVEInfo.GetSystem();
|
|
28
|
-
|
|
29
|
-
if (system === 'iOS') {
|
|
30
|
-
const support = DIVEInfo.GetSupportsARQuickLook();
|
|
31
|
-
if (!support) {
|
|
32
|
-
console.log('ARQuickLook not supported');
|
|
33
|
-
return Promise.reject();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
console.log('Launching AR on iOS');
|
|
37
|
-
|
|
38
|
-
// Launch ARQuickLook
|
|
39
|
-
await DIVEARQuickLook.Launch(this._scene);
|
|
40
|
-
return Promise.resolve();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (system === 'Android') {
|
|
44
|
-
this.openSceneViewer();
|
|
45
|
-
return;
|
|
46
|
-
|
|
47
|
-
const support = await DIVEInfo.GetSupportsWebXR();
|
|
48
|
-
if (!support) {
|
|
49
|
-
console.log(
|
|
50
|
-
'WebXR not supported. Reason: ' +
|
|
51
|
-
WebXRUnsupportedReason[
|
|
52
|
-
DIVEInfo.GetWebXRUnsupportedReason()!
|
|
53
|
-
],
|
|
54
|
-
);
|
|
55
|
-
return Promise.reject();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
console.log('Launching AR on Android');
|
|
59
|
-
// Launch WebXR
|
|
60
|
-
await DIVEWebXR.Launch(
|
|
61
|
-
this._renderer,
|
|
62
|
-
this._scene,
|
|
63
|
-
this._controller,
|
|
64
|
-
);
|
|
65
|
-
return Promise.resolve();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
console.log(
|
|
69
|
-
'AR not supported. Not a mobile system. (System is ' + system + ')',
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private openSceneViewer(): void {
|
|
74
|
-
const src = this.createSceneViewerSrc();
|
|
75
|
-
const anchor = document.createElement('a');
|
|
76
|
-
const noArViewerSigil = '#model-viewer-no-ar-fallback';
|
|
77
|
-
// let isSceneViewerBlocked = false;
|
|
78
|
-
|
|
79
|
-
const location = self.location.toString();
|
|
80
|
-
const locationUrl = new URL(location);
|
|
81
|
-
const modelUrl = new URL(src, location);
|
|
82
|
-
if (modelUrl.hash) modelUrl.hash = '';
|
|
83
|
-
const params = new URLSearchParams(modelUrl.search);
|
|
84
|
-
|
|
85
|
-
locationUrl.hash = noArViewerSigil;
|
|
86
|
-
|
|
87
|
-
// modelUrl can contain title/link/sound etc.
|
|
88
|
-
params.set('mode', 'ar_preferred');
|
|
89
|
-
if (!params.has('disable_occlusion')) {
|
|
90
|
-
params.set('disable_occlusion', 'true');
|
|
91
|
-
}
|
|
92
|
-
if (this.arScale === 'fixed') {
|
|
93
|
-
params.set('resizable', 'false');
|
|
94
|
-
}
|
|
95
|
-
if (this.arPlacement === 'wall') {
|
|
96
|
-
params.set('enable_vertical_placement', 'true');
|
|
97
|
-
}
|
|
98
|
-
if (params.has('sound')) {
|
|
99
|
-
const soundUrl = new URL(params.get('sound')!, location);
|
|
100
|
-
params.set('sound', soundUrl.toString());
|
|
101
|
-
}
|
|
102
|
-
if (params.has('link')) {
|
|
103
|
-
const linkUrl = new URL(params.get('link')!, location);
|
|
104
|
-
params.set('link', linkUrl.toString());
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
console.log('modelUrl.toString()', modelUrl.toString());
|
|
108
|
-
console.log(
|
|
109
|
-
'encodeURIComponent(modelUrl.toString())',
|
|
110
|
-
encodeURIComponent(modelUrl.toString()),
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const intent = `intent://arvr.google.com/scene-viewer/1.2?${
|
|
114
|
-
params.toString() + '&file=' + modelUrl.toString()
|
|
115
|
-
}#Intent;scheme=https;package=com.google.android.googlequicksearchbox;action=android.intent.action.VIEW;S.browser_fallback_url=${encodeURIComponent(
|
|
116
|
-
locationUrl.toString(),
|
|
117
|
-
)};end;`;
|
|
118
|
-
// intent =
|
|
119
|
-
// 'intent://arvr.google.com/scene-viewer/1.0?file=https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Avocado/glTF/Avocado.gltf#Intent;scheme=https;package=com.google.android.googlequicksearchbox;action=android.intent.action.VIEW;S.browser_fallback_url=https://developers.google.com/ar;end;';
|
|
120
|
-
console.log({ intent });
|
|
121
|
-
|
|
122
|
-
const undoHashChange = (): void => {
|
|
123
|
-
if (self.location.hash === noArViewerSigil) {
|
|
124
|
-
// isSceneViewerBlocked = true;
|
|
125
|
-
// The new history will be the current URL with a new hash.
|
|
126
|
-
// Go back one step so that we reset to the expected URL.
|
|
127
|
-
// NOTE(cdata): this should not invoke any browser-level navigation
|
|
128
|
-
// because hash-only changes modify the URL in-place without
|
|
129
|
-
// navigating:
|
|
130
|
-
self.history.back();
|
|
131
|
-
console.warn(
|
|
132
|
-
'Error while trying to present in AR with Scene Viewer',
|
|
133
|
-
);
|
|
134
|
-
console.warn('Falling back to next ar-mode');
|
|
135
|
-
// this[$selectARMode]();
|
|
136
|
-
// Would be nice to activateAR() here, but webXR fails due to not
|
|
137
|
-
// seeing a user activation.
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
self.addEventListener('hashchange', undoHashChange, { once: true });
|
|
142
|
-
|
|
143
|
-
anchor.setAttribute('href', intent);
|
|
144
|
-
console.log('Attempting to present in AR with Scene Viewer...');
|
|
145
|
-
anchor.click();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
private createSceneViewerSrc(): string {
|
|
149
|
-
let uri: string | null = null;
|
|
150
|
-
|
|
151
|
-
this._scene.traverse((object) => {
|
|
152
|
-
if (uri) return;
|
|
153
|
-
if (object.userData.uri) {
|
|
154
|
-
uri = object.userData.uri;
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
if (!uri) {
|
|
159
|
-
throw new Error('No model found in scene');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return uri;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Object3D } from 'three';
|
|
2
|
-
import { type DIVEScene } from '../../scene/Scene';
|
|
3
|
-
import { USDZExporter } from 'three/examples/jsm/exporters/USDZExporter';
|
|
4
|
-
|
|
5
|
-
export class DIVEARQuickLook {
|
|
6
|
-
private static _usdzExporter: USDZExporter = new USDZExporter();
|
|
7
|
-
|
|
8
|
-
public static Launch(scene: DIVEScene): Promise<void> {
|
|
9
|
-
// create node to build usdz from
|
|
10
|
-
const quickLookScene = new Object3D();
|
|
11
|
-
|
|
12
|
-
// extract models from scene
|
|
13
|
-
quickLookScene.add(...this.extractModels(scene));
|
|
14
|
-
|
|
15
|
-
// launch ARQuickLook
|
|
16
|
-
return this.launchARFromNode(quickLookScene);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
private static extractModels(scene: DIVEScene): Object3D[] {
|
|
20
|
-
// extract models
|
|
21
|
-
return scene.Root.children;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
private static launchARFromNode(node: Object3D): Promise<void> {
|
|
25
|
-
// bundle USDZ
|
|
26
|
-
return this._usdzExporter
|
|
27
|
-
.parse(node, { quickLookCompatible: true })
|
|
28
|
-
.then((usdz: Uint8Array) => {
|
|
29
|
-
// create blob
|
|
30
|
-
const blob = new Blob([usdz], { type: 'model/vnd.usdz+zip' });
|
|
31
|
-
const url = URL.createObjectURL(blob);
|
|
32
|
-
|
|
33
|
-
// launch ARQuickLook
|
|
34
|
-
const a = document.createElement('a');
|
|
35
|
-
a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
|
|
36
|
-
a.rel = 'ar';
|
|
37
|
-
a.href = url;
|
|
38
|
-
a.download = 'scene.usdz';
|
|
39
|
-
a.click();
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
package/src/ar/webxr/WebXR.ts
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { Vector3 } from 'three';
|
|
2
|
-
import DIVEOrbitControls from '../../controls/OrbitControls';
|
|
3
|
-
import { type DIVERenderer } from '../../renderer/Renderer';
|
|
4
|
-
import { type DIVEScene } from '../../scene/Scene';
|
|
5
|
-
import { Overlay } from './overlay/Overlay';
|
|
6
|
-
import { DIVEWebXRController } from './controller/WebXRController';
|
|
7
|
-
|
|
8
|
-
export class DIVEWebXR {
|
|
9
|
-
// general members
|
|
10
|
-
private static _renderer: DIVERenderer;
|
|
11
|
-
private static _scene: DIVEScene;
|
|
12
|
-
private static _controller: DIVEOrbitControls;
|
|
13
|
-
|
|
14
|
-
// camera reset members
|
|
15
|
-
private static _cameraPosition: Vector3;
|
|
16
|
-
private static _cameraTarget: Vector3;
|
|
17
|
-
|
|
18
|
-
// render loop members
|
|
19
|
-
private static _renderCallbackId: string | null = null;
|
|
20
|
-
|
|
21
|
-
// setup members
|
|
22
|
-
private static _session: XRSession | null = null;
|
|
23
|
-
private static _referenceSpaceType: XRReferenceSpaceType = 'local';
|
|
24
|
-
private static _overlay: Overlay | null = null;
|
|
25
|
-
private static _options = {
|
|
26
|
-
requiredFeatures: [
|
|
27
|
-
'local',
|
|
28
|
-
'hit-test',
|
|
29
|
-
],
|
|
30
|
-
optionalFeatures: [
|
|
31
|
-
'light-estimation',
|
|
32
|
-
'local-floor',
|
|
33
|
-
'dom-overlay',
|
|
34
|
-
'depth-sensing',
|
|
35
|
-
],
|
|
36
|
-
depthSensing: {
|
|
37
|
-
usagePreference: ['gpu-optimized'],
|
|
38
|
-
dataFormatPreference: [],
|
|
39
|
-
},
|
|
40
|
-
domOverlay: { root: {} as HTMLElement },
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
private static _xrController: DIVEWebXRController | null = null;
|
|
44
|
-
|
|
45
|
-
public static async Launch(
|
|
46
|
-
renderer: DIVERenderer,
|
|
47
|
-
scene: DIVEScene,
|
|
48
|
-
controller: DIVEOrbitControls,
|
|
49
|
-
): Promise<void> {
|
|
50
|
-
this._renderer = renderer;
|
|
51
|
-
this._scene = scene;
|
|
52
|
-
this._controller = controller;
|
|
53
|
-
|
|
54
|
-
// setting camera reset values
|
|
55
|
-
this._cameraPosition = this._controller.object.position.clone();
|
|
56
|
-
this._cameraTarget = this._controller.target.clone();
|
|
57
|
-
|
|
58
|
-
if (!navigator.xr) {
|
|
59
|
-
console.error('WebXR not supported');
|
|
60
|
-
return Promise.reject();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// setup current instance
|
|
64
|
-
this._renderer.xr.enabled = true;
|
|
65
|
-
this._scene.InitXR(renderer);
|
|
66
|
-
|
|
67
|
-
// creating overlay
|
|
68
|
-
if (!DIVEWebXR._overlay) {
|
|
69
|
-
const overlay = new Overlay();
|
|
70
|
-
DIVEWebXR._overlay = overlay;
|
|
71
|
-
}
|
|
72
|
-
DIVEWebXR._options.domOverlay = { root: DIVEWebXR._overlay.Element };
|
|
73
|
-
|
|
74
|
-
// request session
|
|
75
|
-
const session = await navigator.xr.requestSession(
|
|
76
|
-
'immersive-ar',
|
|
77
|
-
this._options,
|
|
78
|
-
);
|
|
79
|
-
session.addEventListener('end', () => {
|
|
80
|
-
this._onSessionEnded();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// build up session
|
|
84
|
-
renderer.xr.setReferenceSpaceType(this._referenceSpaceType);
|
|
85
|
-
await renderer.xr.setSession(session);
|
|
86
|
-
DIVEWebXR._overlay.Element.style.display = '';
|
|
87
|
-
this._session = session;
|
|
88
|
-
|
|
89
|
-
// add end session event listener
|
|
90
|
-
DIVEWebXR._overlay.CloseButton.addEventListener('click', () =>
|
|
91
|
-
this.End(),
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// start session
|
|
95
|
-
await this._onSessionStarted();
|
|
96
|
-
|
|
97
|
-
return Promise.resolve();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public static Update(_time: DOMHighResTimeStamp, frame: XRFrame): void {
|
|
101
|
-
if (!this._session) return;
|
|
102
|
-
|
|
103
|
-
if (this._xrController) {
|
|
104
|
-
this._xrController.Update(frame);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
public static End(): void {
|
|
109
|
-
if (!this._session) return;
|
|
110
|
-
this._session.end();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private static async _onSessionStarted(): Promise<void> {
|
|
114
|
-
if (!this._session) return;
|
|
115
|
-
|
|
116
|
-
// add update callback to render loop
|
|
117
|
-
this._renderCallbackId = this._renderer.AddPreRenderCallback(
|
|
118
|
-
(time: DOMHighResTimeStamp, frame: XRFrame) => {
|
|
119
|
-
this.Update(time, frame);
|
|
120
|
-
},
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
this._xrController = new DIVEWebXRController(
|
|
124
|
-
this._session,
|
|
125
|
-
this._renderer,
|
|
126
|
-
this._scene,
|
|
127
|
-
);
|
|
128
|
-
await this._xrController.Init().catch(() => {
|
|
129
|
-
this.End();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
return Promise.resolve();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private static _onSessionEnded(): void {
|
|
136
|
-
if (!this._session) return;
|
|
137
|
-
|
|
138
|
-
if (this._xrController) {
|
|
139
|
-
this._xrController.Dispose();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// remove Update() callback
|
|
143
|
-
if (this._renderCallbackId) {
|
|
144
|
-
this._renderer.RemovePreRenderCallback(this._renderCallbackId);
|
|
145
|
-
this._renderCallbackId = null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// disable XR on renderer to restore canvas rendering
|
|
149
|
-
this._renderer.xr.enabled = false;
|
|
150
|
-
|
|
151
|
-
// resize renderer
|
|
152
|
-
const canvasWrapper = this._renderer.domElement.parentElement;
|
|
153
|
-
if (canvasWrapper) {
|
|
154
|
-
const { clientWidth, clientHeight } = canvasWrapper;
|
|
155
|
-
this._renderer.OnResize(clientWidth, clientHeight);
|
|
156
|
-
|
|
157
|
-
// resize camera
|
|
158
|
-
this._controller.object.OnResize(clientWidth, clientHeight);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// reset camera
|
|
162
|
-
this._controller.object.position.copy(this._cameraPosition);
|
|
163
|
-
this._controller.target.copy(this._cameraTarget);
|
|
164
|
-
|
|
165
|
-
// reset camera values
|
|
166
|
-
this._cameraPosition.set(0, 0, 0);
|
|
167
|
-
this._cameraTarget.set(0, 0, 0);
|
|
168
|
-
|
|
169
|
-
// dispose xr scene
|
|
170
|
-
this._scene.DisposeXR();
|
|
171
|
-
|
|
172
|
-
this._session.removeEventListener('end', this._onSessionEnded);
|
|
173
|
-
DIVEWebXR._overlay!.Element.style.display = 'none';
|
|
174
|
-
this._session = null;
|
|
175
|
-
}
|
|
176
|
-
}
|