Browse Source

Added basic WebXR support.

Mr.doob 7 years ago
parent
commit
8f2c2fa0b1

+ 46 - 4
examples/js/vr/WebVR.js

@@ -9,7 +9,7 @@ var WEBVR = {
 
 	createButton: function ( renderer ) {
 
-		function showEnterVR( display ) {
+		function showEnterVR( device ) {
 
 			button.style.display = '';
 
@@ -24,11 +24,29 @@ var WEBVR = {
 
 			button.onclick = function () {
 
-				display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: renderer.domElement } ] );
+				if ( 'xr' in navigator ) {
+
+					device.requestSession( { exclusive: true } ).then( function ( session ) {
+
+						renderer.vr.setSession( session );
+
+						session.addEventListener( 'end', function ( event ) {
+
+							renderer.vr.setSession( null );
+
+						} );
+
+					} );
+
+				} else {
+
+					device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] );
+
+				}
 
 			};
 
-			renderer.vr.setDevice( display );
+			renderer.vr.setDevice( device );
 
 		}
 
@@ -68,7 +86,31 @@ var WEBVR = {
 
 		}
 
-		if ( 'getVRDisplays' in navigator ) {
+		var isWebXR = false;
+
+		if ( 'xr' in navigator ) {
+
+			isWebXR = true;
+
+			var button = document.createElement( 'button' );
+			button.style.display = 'none';
+
+			stylizeElement( button );
+
+			navigator.xr.requestDevice().then( function ( device ) {
+
+				device.supportsSession( { exclusive: true } ).then( function () {
+
+					showEnterVR( device );
+					button.textContent = 'ENTER XR'; // TODO
+
+				} ).catch( showVRNotFound );
+
+			} ).catch( showVRNotFound );
+
+			return button;
+
+		} else if ( 'getVRDisplays' in navigator ) {
 
 			var button = document.createElement( 'button' );
 			button.style.display = 'none';

+ 19 - 14
src/renderers/WebGLRenderer.js

@@ -42,6 +42,7 @@ import { WebGLTextures } from './webgl/WebGLTextures.js';
 import { WebGLUniforms } from './webgl/WebGLUniforms.js';
 import { WebGLUtils } from './webgl/WebGLUtils.js';
 import { WebVRManager } from './webvr/WebVRManager.js';
+import { WebXRManager } from './webvr/WebXRManager.js';
 
 /**
  * @author supereggbert / http://www.paulbrunt.co.uk/
@@ -288,7 +289,7 @@ function WebGLRenderer( parameters ) {
 
 	// vr
 
-	var vr = new WebVRManager( _this );
+	var vr = ( 'xr' in navigator ) ? new WebXRManager( _gl ) : new WebVRManager( _this );
 
 	this.vr = vr;
 
@@ -353,9 +354,7 @@ function WebGLRenderer( parameters ) {
 
 	this.setSize = function ( width, height, updateStyle ) {
 
-		var device = vr.getDevice();
-
-		if ( device && device.isPresenting ) {
+		if ( vr.isPresenting() ) {
 
 			console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
 			return;
@@ -1037,11 +1036,9 @@ function WebGLRenderer( parameters ) {
 
 	function requestAnimationLoopFrame() {
 
-		var device = vr.getDevice();
-
-		if ( device && device.isPresenting ) {
+		if ( vr.isPresenting() ) {
 
-			device.requestAnimationFrame( animationLoop );
+			vr.requestAnimationFrame( animationLoop );
 
 		} else {
 
@@ -1388,14 +1385,22 @@ function WebGLRenderer( parameters ) {
 
 					if ( object.layers.test( camera2.layers ) ) {
 
-						var bounds = camera2.bounds;
+						if ( 'viewport' in camera2 ) { // XR
+
+							state.viewport( _currentViewport.copy( camera2.viewport ) );
+
+						} else {
+
+							var bounds = camera2.bounds;
 
-						var x = bounds.x * _width;
-						var y = bounds.y * _height;
-						var width = bounds.z * _width;
-						var height = bounds.w * _height;
+							var x = bounds.x * _width;
+							var y = bounds.y * _height;
+							var width = bounds.z * _width;
+							var height = bounds.w * _height;
 
-						state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
+							state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
+
+						}
 
 						renderObject( object, scene, camera2, geometry, material, group );
 

+ 9 - 1
src/renderers/webvr/WebVRManager.js

@@ -3,8 +3,8 @@
  */
 
 import { Matrix4 } from '../../math/Matrix4.js';
-import { Vector4 } from '../../math/Vector4.js';
 import { Vector3 } from '../../math/Vector3.js';
+import { Vector4 } from '../../math/Vector4.js';
 import { Quaternion } from '../../math/Quaternion.js';
 import { ArrayCamera } from '../../cameras/ArrayCamera.js';
 import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
@@ -226,6 +226,14 @@ function WebVRManager( renderer ) {
 
 	};
 
+	this.isPresenting = isPresenting;
+
+	this.requestAnimationFrame = function ( callback ) {
+
+		device.requestAnimationFrame( callback );
+
+	};
+
 	this.submitFrame = function () {
 
 		if ( isPresenting() ) device.submitFrame();

+ 145 - 0
src/renderers/webvr/WebXRManager.js

@@ -0,0 +1,145 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+import { Matrix4 } from '../../math/Matrix4.js';
+import { Vector4 } from '../../math/Vector4.js';
+import { Vector3 } from '../../math/Vector3.js';
+import { Quaternion } from '../../math/Quaternion.js';
+import { ArrayCamera } from '../../cameras/ArrayCamera.js';
+import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
+
+function WebXRManager( gl ) {
+
+	var scope = this;
+
+	var device = null;
+	var session = null;
+
+	var frameOfRef = null;
+	var isExclusive = false;
+
+	var pose = null;
+
+	function isPresenting() {
+
+		return session !== null && frameOfRef !== null;
+
+	}
+
+	//
+
+	var cameraL = new PerspectiveCamera();
+	cameraL.layers.enable( 1 );
+	cameraL.viewport = new Vector4();
+
+	var cameraR = new PerspectiveCamera();
+	cameraR.layers.enable( 2 );
+	cameraR.viewport = new Vector4();
+
+	var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
+	cameraVR.layers.enable( 1 );
+	cameraVR.layers.enable( 2 );
+
+	//
+
+	this.enabled = false;
+
+	this.getDevice = function () {
+
+		return device;
+
+	};
+
+	this.setDevice = function ( value ) {
+
+		if ( value !== undefined ) device = value;
+
+		gl.setCompatibleXRDevice( value );
+
+	};
+
+	this.setSession = function ( value ) {
+
+		session = value;
+
+		if ( session !== null ) {
+
+			session.baseLayer = new XRWebGLLayer( session, gl );
+			session.requestFrameOfReference( 'stage' ).then( function ( value ) {
+
+				frameOfRef = value;
+				isExclusive = session.exclusive;
+
+				console.log( 0 );
+
+			} );
+
+		}
+
+	};
+
+	this.getCamera = function ( camera ) {
+
+		return isPresenting() ? cameraVR : camera;
+
+	};
+
+	this.isPresenting = isPresenting;
+
+	this.requestAnimationFrame = function ( callback ) {
+
+		console.log( 1 );
+
+		function onFrame( time, frame ) {
+
+			pose = frame.getDevicePose( frameOfRef );
+
+			var layer = session.baseLayer;
+			var views = frame.views;
+
+			for ( var i = 0; i < views.length; i ++ ) {
+
+				var view = views[ i ];
+				var viewport = layer.getViewport( view );
+				var viewMatrix = pose.getViewMatrix( view );
+
+				var camera = cameraVR.cameras[ i ];
+				camera.projectionMatrix.fromArray( view.projectionMatrix );
+				camera.matrixWorldInverse.fromArray( viewMatrix );
+				camera.matrixWorld.getInverse( camera.matrixWorldInverse );
+				camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
+
+				if ( i === 0 ) {
+
+					cameraVR.matrixWorld.copy( camera.matrixWorld );
+					cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
+
+					// HACK (mrdoob)
+					// https://github.com/w3c/webvr/issues/203
+
+					cameraVR.projectionMatrix.copy( camera.projectionMatrix );
+
+				}
+
+			}
+
+			gl.bindFramebuffer( gl.FRAMEBUFFER, session.baseLayer.framebuffer );
+
+			callback();
+
+		}
+
+		session.requestAnimationFrame( onFrame );
+
+	};
+
+	this.submitFrame = function () {
+
+		// if ( device && device.isPresenting ) device.submitFrame();
+
+	};
+
+}
+
+export { WebXRManager };

+ 1 - 0
utils/build/externs.js

@@ -5,3 +5,4 @@ var exports;
 var performance;
 var createImageBitmap;
 var WebGL2RenderingContext;
+var XRWebGLLayer;