Library to build WebXR experiences with three.js
Switch branches/tags
Clone or download
Latest commit 4a1fc42 Apr 20, 2018

README.md

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);
  }
}