@preference-sl/pref-viewer 2.10.0-beta.1 → 2.10.0-beta.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +70 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.10.0-beta.1",
3
+ "version": "2.10.0-beta.3",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -39,7 +39,7 @@
39
39
  * </pref-viewer>
40
40
  * ```
41
41
  */
42
- import { Engine, Scene, ArcRotateCamera, Vector3, Color4, HemisphericLight, DirectionalLight, PointLight, ShadowGenerator, LoadAssetContainerAsync, Tools } from "@babylonjs/core";
42
+ import { Engine, Scene, ArcRotateCamera, Vector3, Color4, HemisphericLight, DirectionalLight, PointLight, ShadowGenerator, LoadAssetContainerAsync, Tools, WebXRSessionManager, WebXRDefaultExperience, MeshBuilder, WebXRFeatureName } from "@babylonjs/core";
43
43
  import "@babylonjs/loaders";
44
44
  import { USDZExportAsync, GLTF2Export } from "@babylonjs/serializers";
45
45
  import "@babylonjs/loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression";
@@ -63,6 +63,8 @@ class PrefViewer extends HTMLElement {
63
63
  visible: false,
64
64
  };
65
65
 
66
+ // DOM elements
67
+ #wrapper = null;
66
68
  #canvas = null;
67
69
 
68
70
  // Babylon.js core objects
@@ -73,6 +75,7 @@ class PrefViewer extends HTMLElement {
73
75
  #dirLight = null;
74
76
  #cameraLight = null;
75
77
  #shadowGen = null;
78
+ #XRExperience = null;
76
79
 
77
80
  constructor() {
78
81
  super();
@@ -162,19 +165,18 @@ class PrefViewer extends HTMLElement {
162
165
  }
163
166
 
164
167
  #wrapCanvas() {
165
- const wrapper = document.createElement("div");
166
- Object.assign(wrapper.style, {
168
+ this.#wrapper = document.createElement("div");
169
+ Object.assign(this.#wrapper.style, {
167
170
  width: "100%",
168
171
  height: "100%",
169
172
  position: "relative",
170
173
  });
171
- wrapper.appendChild(this.#canvas);
172
- this.shadowRoot.append(wrapper);
174
+ this.#wrapper.appendChild(this.#canvas);
175
+ this.shadowRoot.append(this.#wrapper);
173
176
  }
174
-
175
177
 
176
178
  // Bbylon.js
177
- #initializeBabylon() {
179
+ async #initializeBabylon() {
178
180
  this.#engine = new Engine(this.#canvas, true, { alpha: true });
179
181
  this.#scene = new Scene(this.#engine);
180
182
  this.#scene.clearColor = new Color4(1, 1, 1, 1);
@@ -184,6 +186,66 @@ class PrefViewer extends HTMLElement {
184
186
 
185
187
  this.#engine.runRenderLoop(() => this.#scene && this.#scene.render());
186
188
  this.#canvasResizeObserver.observe(this.#canvas);
189
+
190
+ await this.#createXRExperience();
191
+
192
+ }
193
+
194
+ addStylesToARButton(){
195
+ const css = '.babylonVRicon { color: #868686; border-color: #868686; border-style: solid; margin-left: 10px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%222048%22%20height%3D%221152%22%20viewBox%3D%220%200%202048%201152%22%20version%3D%221.1%22%3E%3Cpath%20transform%3D%22rotate%28180%201024%2C576.0000000000001%29%22%20d%3D%22m1109%2C896q17%2C0%2030%2C-12t13%2C-30t-12.5%2C-30.5t-30.5%2C-12.5l-170%2C0q-18%2C0%20-30.5%2C12.5t-12.5%2C30.5t13%2C30t30%2C12l170%2C0zm-85%2C256q59%2C0%20132.5%2C-1.5t154.5%2C-5.5t164.5%2C-11.5t163%2C-20t150%2C-30t124.5%2C-41.5q23%2C-11%2042%2C-24t38%2C-30q27%2C-25%2041%2C-61.5t14%2C-72.5l0%2C-257q0%2C-123%20-47%2C-232t-128%2C-190t-190%2C-128t-232%2C-47l-81%2C0q-37%2C0%20-68.5%2C14t-60.5%2C34.5t-55.5%2C45t-53%2C45t-53%2C34.5t-55.5%2C14t-55.5%2C-14t-53%2C-34.5t-53%2C-45t-55.5%2C-45t-60.5%2C-34.5t-68.5%2C-14l-81%2C0q-123%2C0%20-232%2C47t-190%2C128t-128%2C190t-47%2C232l0%2C257q0%2C68%2038%2C115t97%2C73q54%2C24%20124.5%2C41.5t150%2C30t163%2C20t164.5%2C11.5t154.5%2C5.5t132.5%2C1.5zm939%2C-298q0%2C39%20-24.5%2C67t-58.5%2C42q-54%2C23%20-122%2C39.5t-143.5%2C28t-155.5%2C19t-157%2C11t-148.5%2C5t-129.5%2C1.5q-59%2C0%20-130%2C-1.5t-148%2C-5t-157%2C-11t-155.5%2C-19t-143.5%2C-28t-122%2C-39.5q-34%2C-14%20-58.5%2C-42t-24.5%2C-67l0%2C-257q0%2C-106%2040.5%2C-199t110%2C-162.5t162.5%2C-109.5t199%2C-40l81%2C0q27%2C0%2052%2C14t50%2C34.5t51%2C44.5t55.5%2C44.5t63.5%2C34.5t74%2C14t74%2C-14t63.5%2C-34.5t55.5%2C-44.5t51%2C-44.5t50%2C-34.5t52%2C-14l14%2C0q37%2C0%2070%2C0.5t64.5%2C4.5t63.5%2C12t68%2C23q71%2C30%20128.5%2C78.5t98.5%2C110t63.5%2C133.5t22.5%2C149l0%2C257z%22%20fill%3D%22white%22%20/%3E%3C/svg%3E%0A); background-size: 80%; background-repeat:no-repeat; background-position: center; border: none; outline: none; transition: transform 0.125s ease-out } .babylonVRicon:hover { transform: scale(1.05) } .babylonVRicon:active {background-color: rgba(51,51,51,1) } .babylonVRicon:focus {background-color: rgba(51,51,51,1) }.babylonVRicon.vrdisplaypresenting { background-image: none;} .vrdisplaypresenting::after { content: "EXIT"} .xr-error::after { content: "ERROR"}';
196
+ const style = document.createElement("style");
197
+ style.appendChild(document.createTextNode(css));
198
+ this.#wrapper.appendChild(style);
199
+ }
200
+
201
+ async #createXRExperience() {
202
+ if (this.#XRExperience) {
203
+ return true;
204
+ }
205
+
206
+ const sessionMode = "immersive-ar";
207
+ const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
208
+ if (!sessionSupported) {
209
+ console.info("PrefViewer: WebXR in mode AR is not supported");
210
+ return false;
211
+ }
212
+
213
+ try {
214
+ const ground = MeshBuilder.CreateGround("ground", { width: 1000, height: 1000 }, this.#scene);
215
+ ground.isVisible = false;
216
+
217
+ const options = {
218
+ floorMeshes: [ground],
219
+ uiOptions: {
220
+ sessionMode: sessionMode,
221
+ renderTarget: "xrLayer",
222
+ referenceSpaceType: "local",
223
+ },
224
+ optionalFeatures: true,
225
+ };
226
+
227
+ this.#XRExperience = await WebXRDefaultExperience.CreateAsync(this.#scene, options);
228
+
229
+ const featuresManager = this.#XRExperience.baseExperience.featuresManager;
230
+ featuresManager.enableFeature(WebXRFeatureName.TELEPORTATION, "stable", {
231
+ xrInput: this.#XRExperience.input,
232
+ floorMeshes: [ground],
233
+ timeToTeleport: 1500,
234
+ useMainComponentOnly: true,
235
+ });
236
+
237
+ this.#XRExperience.baseExperience.sessionManager.onXRReady.add(() => {
238
+ // Set the initial position of xrCamera: use nonVRCamera, which contains a copy of the original this.#scene.activeCamera before entering XR
239
+ this.#XRExperience.baseExperience.camera.setTransformationFromNonVRCamera(this.#XRExperience.baseExperience._nonVRCamera);
240
+ this.#XRExperience.baseExperience.camera.setTarget(Vector3.Zero());
241
+ this.#XRExperience.baseExperience.onInitialXRPoseSetObservable.notifyObservers(this.#XRExperience.baseExperience.camera);
242
+ });
243
+
244
+ this.addStylesToARButton();
245
+ } catch (error) {
246
+ console.warn("PrefViewer: failed to create WebXR experience", error);
247
+ this.#XRExperience = null;
248
+ }
187
249
  }
188
250
 
189
251
  #canvasResizeObserver = new ResizeObserver(() => this.#engine && this.#engine.resize());
@@ -371,7 +433,7 @@ class PrefViewer extends HTMLElement {
371
433
  }
372
434
 
373
435
  this.#setVisibilityOfWallAndFloorInModel();
374
-
436
+
375
437
  this.dispatchEvent(
376
438
  new CustomEvent("model-loaded", {
377
439
  detail: { success: "" },