Skip to content

mozilla/three.xr.js

Repository files navigation

three.xr.js

Version License

Library to build WebXR experiences with three.js

Running the examples

Install npm and then run the following:

$ npm install
$ npm start

Supported browsers

AR

VR

Usage

Include three.xr.js after THREE.js:

<script src='three.js'></script>
<script src='three.xr.js'></script>

In your application code you can do:

THREE.WebXRUtils.getDisplays().then(init);

function init(displays) {
  container = document.createElement( 'div' );
  document.body.appendChild( container );

  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera();
  scene.add( camera );

  renderer = new THREE.WebGLRenderer( { alpha: true } );
  renderer.autoClear = false;
  container.appendChild( renderer.domElement );

  // Add custom code here

  window.addEventListener( 'resize', onWindowResize, false );
  onWindowResize();

  // Set XR options
  var options = {
    // Flag to start AR if is the unique display available.
    AR_AUTOSTART: false, // Default: true
  }
  // Init WebXR
  renderer.xr = new THREE.WebXRManager(options, displays, renderer, camera, scene, update);

  // Listen when a session is started or stopped
  renderer.xr.addEventListener('sessionStarted', sessionStarted);
  renderer.xr.addEventListener('sessionEnded', sessionEnded);

  // Auto start if only has one AR display supported
  if(!renderer.xr.autoStarted){
    // Add as many buttons as there are displays that can be started
    addEnterButtons(displays);
  }

  renderer.animate(render);
}

function sessionStarted(data) {
  activeRealityType = data.session.realityType;
  // We can show or hide elements depending on the active reality type
  // ar, magicWindow, vr
}

function sessionEnded(data) {
  activeRealityType = 'magicWindow';
  // We can show or hide elements depending on the active reality type
  // ar, magicWindow, vr
}

function addEnterButtons(displays) {
  for (var i = 0; i < displays.length; i++) {
    var display = displays[i];
    if(display.supportedRealities.vr){
      // Add ENTER VR button
      // and to call enterVR on 'click' event
    }
    if(display.supportedRealities.ar){
      // Add ENTER AR button
      // and to call enterVR on 'click' event
    }
  }
}

function enterAR(){
  renderer.xr.startSession(display, 'ar', true);
}

function exitAR(){
  renderer.xr.endSession();
}

function enterVR(){
  renderer.xr.startPresenting();
}

// To detect and exitVR
window.addEventListener('vrdisplaypresentchange', (evt) => {
  // Polyfill places cameraActivateddisplay inside the detail property
  var display = evt.display || evt.detail.display;
  if (!display.isPresenting) {
    // Exiting VR.
    renderer.xr.endSession();
  }
});

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
}

// Called once per frame, before render, to give the app a chance to update this.scene
function update(frame) {
  render();
}

function render() {
  // We can different commands depending on the active reality type
  // ar, magicWindow, vr
  switch (activeRealityType) {
    case 'ar':
    case 'magicWindow':
    case 'vr':
      
      break;
  } 

  // Only renderer.render out of renderer.xr if the session is not active
  if(!renderer.xr.sessionActive){
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.render(this.scene, this.camera);
  }
}