UNPKG

@vrspace/babylonjs

Version:

vrspace.org babylonjs client

109 lines (103 loc) 4.16 kB
import {VRSPACEUI} from '../ui/vrspace-ui.js'; /** Wrapper around BabylonJS XR/VR classes, whatever is available in current browser, if any. Attached to a World, places the world mesh somewhere in real world TODO */ export class ARHelper { /** @param world attaches the control to the World */ async initXR(world, enter) { this.world = world; this.createMarker(); this.world.scene.createDefaultXRExperienceAsync({ // ask for an ar-session uiOptions: { sessionMode: "immersive-ar", referenceSpaceType: "unbounded" }, optionalFeatures: true }).then( xr => { this.xr = xr; if ( this.xr && this.xr.baseExperience ) { console.log("Available WebXR features: "+BABYLON.WebXRFeaturesManager.GetAvailableFeatures()); // we can also test if ar/vr is available with WebXRSessionManager.IsSessionSupportedAsync // https://doc.babylonjs.com/typedoc/classes/BABYLON.WebXRSessionManager#IsSessionSupportedAsync ["immersive-vr","immersive-ar","inline"].forEach(mode=>{ BABYLON.WebXRSessionManager.IsSessionSupportedAsync(mode).then(isSupported => { console.log("XRMode "+mode+" available: "+isSupported) }) }); console.log(this.xr); // xr.enterExitUI.overlay is div html element, class div.xr-button-overlay // style.position contains absolute; left 20px; etc xr.enterExitUI.overlay.children[0].textContent="AR"; xr.enterExitUI.overlay.style.cssText = xr.enterExitUI.overlay.style.cssText.replace("right","left"); this.featuresManager = xr.baseExperience.featuresManager; this.hitTest = this.featuresManager.enableFeature(BABYLON.WebXRHitTest, "latest"); this.anchorSystem = this.featuresManager.enableFeature(BABYLON.WebXRAnchorSystem, "latest"); if ( enter ) { this.enterAR(); } //this.createMarker(); this.tracker = (results) => { if (this.tracking && results.length) { var hitTest = results[0]; hitTest.transformationMatrix.decompose(this.marker.scaling, this.marker.rotationQuaternion, this.marker.position); } else { //marker.isVisible = false; } }; this.hitTest.onHitTestResultObservable.add(this.tracker); this.startTracking(); } else { console.log("XR unavailable"); } }); return this; } // This must be done within a user interaction e.g. button click async enterAR() { if ( this.xr && this.xr.baseExperience ) { return this.baseExperience.enterXRAsync("immersive-ar", "unbounded", this.xr.renderTarget); } } startTracking() { if (this.anchor) { this.anchor.attachedNode = null; //this.anchor.remove(); // HANGS this.anchor = null; } this.tracking = true; if ( this.world.worldManager ) { // CHECKME stop sending user position/rotation? this.world.worldManager.trackMesh(); } console.log("tracking started"); } async placeMarker() { if ( this.anchorSystem ) { this.anchorSystem.addAnchorAtPositionAndRotationAsync(this.marker.position, this.marker.rotationQuaternion); this.anchorSystem.onAnchorAddedObservable.add((anchor) => { anchor.attachedNode = this.marker; this.anchor = anchor; }); this.tracking = false; if ( this.world.worldManager ) { // TODO start sending user position/rotation - needs to be recalculated this.world.worldManager.trackMesh(this.anchor); } console.log("Anchor placed"); } } createMarker() { this.marker = new BABYLON.TransformNode("Marker", this.world.scene); this.logo = VRSPACEUI.copyMesh(VRSPACEUI.logo, this.marker); this.logo.scaling = new BABYLON.Vector3(0.2, 0.2, 0.2); this.logo.rotation = new BABYLON.Vector3(0,0,0); this.marker.rotationQuaternion = new BABYLON.Quaternion(); } realWorldHeight() { return 1.8; } }