Browse Source

Added WebVRCamera. See #10927.

Mr.doob 8 years ago
parent
commit
1e85cff6c2
3 changed files with 212 additions and 25 deletions
  1. 30 3
      examples/js/vr/WebVR.js
  2. 170 0
      examples/js/vr/WebVRCamera.js
  3. 12 22
      examples/webvr_daydream.html

+ 30 - 3
examples/js/vr/WebVR.js

@@ -18,6 +18,24 @@ var WEBVR = {
 
 	},
 
+	getVRDisplay: function ( onDisplay ) {
+
+		if ( 'getVRDisplays' in navigator ) {
+
+			navigator.getVRDisplays()
+				.then( function ( displays ) {
+
+					onDisplay( displays[ 0 ] );
+
+				} )
+				.catch( function () {
+					// no displays
+				} );
+
+		}
+
+	},
+
 	getMessage: function () {
 
 		var message;
@@ -65,7 +83,16 @@ var WEBVR = {
 
 	},
 
-	getButton: function ( effect ) {
+	getButton: function ( display, canvas ) {
+
+		/*
+		if ( display instanceof VRDisplay === false ) {
+
+			console.error( 'WebVR.getButton() now expects a VRDisplay.' );
+			return;
+
+		}
+		*/
 
 		var button = document.createElement( 'button' );
 		button.style.position = 'absolute';
@@ -85,13 +112,13 @@ var WEBVR = {
 		button.textContent = 'ENTER VR';
 		button.onclick = function () {
 
-			effect.isPresenting ? effect.exitPresent() : effect.requestPresent();
+			display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: canvas } ] );
 
 		};
 
 		window.addEventListener( 'vrdisplaypresentchange', function () {
 
-			button.textContent = effect.isPresenting ? 'EXIT VR' : 'ENTER VR';
+			button.textContent = display.isPresenting ? 'EXIT VR' : 'ENTER VR';
 
 		}, false );
 

+ 170 - 0
examples/js/vr/WebVRCamera.js

@@ -0,0 +1,170 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.WebVRCamera = function ( display, renderer ) {
+
+	var scope = this;
+
+	var frameData = null;
+
+	if ( 'VRFrameData' in window ) {
+
+		frameData = new window.VRFrameData();
+
+	}
+
+	var eyeTranslationL = new THREE.Vector3();
+	var eyeTranslationR = new THREE.Vector3();
+
+	var cameraL = new THREE.PerspectiveCamera();
+	cameraL.bounds = new THREE.Vector4( 0.0, 0.0, 0.5, 1.0 );
+	cameraL.layers.enable( 1 );
+
+	var cameraR = new THREE.PerspectiveCamera();
+	cameraR.bounds = new THREE.Vector4( 0.5, 0.0, 0.5, 1.0 );
+	cameraR.layers.enable( 2 );
+
+	//
+
+	var currentSize, currentPixelRatio;
+
+	function onVRDisplayPresentChange() {
+
+		if ( display.isPresenting ) {
+
+			var eyeParameters = display.getEyeParameters( 'left' );
+			var renderWidth = eyeParameters.renderWidth;
+			var renderHeight = eyeParameters.renderHeight;
+
+			currentPixelRatio = renderer.getPixelRatio();
+			currentSize = renderer.getSize();
+
+			renderer.setPixelRatio( 1 );
+			renderer.setSize( renderWidth * 2, renderHeight, false );
+
+			scope.enabled = true;
+
+		} else if ( scope.enabled ) {
+
+			scope.enabled = false;
+
+			renderer.setPixelRatio( currentPixelRatio );
+			renderer.setSize( currentSize.width, currentSize.height, true );
+
+		}
+
+	}
+
+	window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
+
+	//
+
+	THREE.ArrayCamera.call( this, [ cameraL, cameraR ] );
+
+	//
+
+	this.onBeforeRender = function () {
+
+		display.depthNear = scope.near;
+		display.depthFar = scope.far;
+
+		display.getFrameData( frameData );
+
+		//
+
+		var pose = frameData.pose;
+
+		if ( pose.orientation !== null ) {
+
+			scope.quaternion.fromArray( pose.orientation );
+
+		}
+
+		if ( pose.position !== null ) {
+
+			scope.position.fromArray( pose.position );
+
+		} else {
+
+			scope.position.set( 0, 0, 0 );
+
+		}
+
+		//
+
+		var eyeParamsL = display.getEyeParameters( 'left' );
+		var eyeParamsR = display.getEyeParameters( 'right' );
+
+		eyeTranslationL.fromArray( eyeParamsL.offset );
+		eyeTranslationR.fromArray( eyeParamsR.offset );
+
+		cameraL.position.copy( scope.position );
+		cameraL.quaternion.copy( scope.quaternion );
+		cameraL.scale.copy( scope.scale );
+
+		cameraR.position.copy( scope.position );
+		cameraR.quaternion.copy( scope.quaternion );
+		cameraR.scale.copy( scope.scale );
+
+		cameraL.translateOnAxis( eyeTranslationL, cameraL.scale.x );
+		cameraR.translateOnAxis( eyeTranslationR, cameraR.scale.x );
+
+		cameraL.updateMatrixWorld();
+		cameraL.matrixWorldInverse.getInverse( cameraL.matrixWorld );
+
+		cameraR.updateMatrixWorld();
+		cameraR.matrixWorldInverse.getInverse( cameraR.matrixWorld );
+
+		cameraL.projectionMatrix.elements = frameData.leftProjectionMatrix;
+		cameraR.projectionMatrix.elements = frameData.rightProjectionMatrix;
+
+		// HACK @mrdoob
+		// Ideally we'll merge both projection matrices so we can frustum cull
+
+		scope.projectionMatrix = cameraL.projectionMatrix;
+
+		//
+
+		var layers = display.getLayers();
+
+		if ( layers.length ) {
+
+			var layer = layers[ 0 ];
+
+			if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {
+
+				cameraL.bounds.fromArray( layer.leftBounds );
+
+			}
+
+			if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {
+
+				cameraR.bounds.fromArray( layer.rightBounds );
+
+			}
+
+		} else {
+
+			cameraL.bounds.set( 0.0, 0.0, 0.5, 1.0 );
+			cameraR.bounds.set( 0.0, 0.0, 0.5, 1.0 );
+
+		}
+
+	};
+
+	this.onAfterRender = function () {
+
+		if ( display.isPresenting ) display.submitFrame();
+
+	};
+
+};
+
+THREE.WebVRCamera.prototype = Object.assign( Object.create( THREE.ArrayCamera.prototype ), {
+
+	constructor: THREE.WebVRCamera,
+
+	isWebVRCamera: true
+
+} );

+ 12 - 22
examples/webvr_daydream.html

@@ -23,10 +23,9 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/DaydreamController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
+		<script src="js/vr/WebVRCamera.js"></script>
 
 		<script>
 
@@ -42,7 +41,7 @@
 
 			var container;
 			var camera, scene, ray, raycaster, renderer;
-			var effect, controls, gamepad;
+			var gamepad, vrdisplay;
 
 			var room;
 
@@ -67,7 +66,6 @@
 				scene = new THREE.Scene();
 
 				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 10 );
-				scene.add( camera );
 
 				room = new THREE.Mesh(
 					new THREE.BoxGeometry( 6, 6, 6, 8, 8, 8 ),
@@ -123,23 +121,15 @@
 
 				//
 
-				controls = new THREE.VRControls( camera );
-				effect = new THREE.VREffect( renderer );
+				WEBVR.getVRDisplay( function ( display ) {
 
-				if ( navigator.getVRDisplays ) {
+					vrdisplay = display;
 
-					navigator.getVRDisplays()
-						.then( function ( displays ) {
-							effect.setVRDisplay( displays[ 0 ] );
-							controls.setVRDisplay( displays[ 0 ] );
-						} )
-						.catch( function () {
-							// no displays
-						} );
+					camera = new THREE.WebVRCamera( display, renderer );
 
-					document.body.appendChild( WEBVR.getButton( effect ) );
+					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
-				}
+				} );
 
 				//
 
@@ -164,7 +154,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
@@ -172,9 +162,10 @@
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
 				gamepad.update();
+				render();
+
+				( vrdisplay ? vrdisplay : window ).requestAnimationFrame( animate );
 
 			}
 
@@ -246,8 +237,7 @@
 
 				}
 
-				controls.update();
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}