Browse Source

Refactored VREffect.
/ping @dmarcos @borismus @toji @spite

Mr.doob 10 years ago
parent
commit
1195e0f3da
1 changed files with 155 additions and 145 deletions
  1. 155 145
      examples/js/effects/VREffect.js

+ 155 - 145
examples/js/effects/VREffect.js

@@ -1,5 +1,6 @@
 /**
  * @author dmarcos / https://github.com/dmarcos
+ * @author mrdoob / http://mrdoob.com
  *
  * It handles stereo rendering
  * If mozGetVRDevices and getVRDevices APIs are not available it gracefuly falls back to a
@@ -22,184 +23,189 @@
  */
 THREE.VREffect = function ( renderer, done ) {
 
-	var cameraLeft = new THREE.PerspectiveCamera();
-	var cameraRight = new THREE.PerspectiveCamera();
+	if ( !navigator.mozGetVRDevices && !navigator.getVRDevices ) {
 
-	this._renderer = renderer;
+		if ( done ) done( 'Your browser is not VR Ready' );
 
-	this._init = function() {
-		var self = this;
-		if ( !navigator.mozGetVRDevices && !navigator.getVRDevices ) {
-			if ( done ) {
-				done( 'Your browser is not VR Ready' );
-			}
-			return;
-		}
-		if ( navigator.getVRDevices ) {
-			navigator.getVRDevices().then( gotVRDevices );
-		} else {
-			navigator.mozGetVRDevices( gotVRDevices );
-		}
-		function gotVRDevices( devices ) {
-			var vrHMD;
-			for ( var i = 0; i < devices.length; i ++ ) {
-				if ( devices[i] instanceof HMDVRDevice ) {
-					vrHMD = devices[i];
-					self._vrHMD = vrHMD;
-
-					if ( vrHMD.getEyeParameters !== undefined ) {
-						var leftEyeParams = vrHMD.getEyeParameters( 'left' );
-						var rightEyeParams = vrHMD.getEyeParameters( 'right' );
-						self.leftEyeTranslation = leftEyeParams.eyeTranslation;
-						self.rightEyeTranslation = rightEyeParams.eyeTranslation;
-						self.leftEyeFOV = leftEyeParams.recommendedFieldOfView;
-						self.rightEyeFOV = rightEyeParams.recommendedFieldOfView;
-					} else {
-						// TODO: This is an older code path and not spec compliant.
-						// It should be removed at some point in the near future.
-						self.leftEyeTranslation = vrHMD.getEyeTranslation( 'left' );
-						self.rightEyeTranslation = vrHMD.getEyeTranslation( 'right' );
-						self.leftEyeFOV = vrHMD.getRecommendedEyeFieldOfView( 'left' );
-						self.rightEyeFOV = vrHMD.getRecommendedEyeFieldOfView( 'right' );
-					}
-
-					break; // We keep the first we encounter
-				}
-			}
-			if ( done ) {
-				if ( !vrHMD ) {
-					done( 'HMD not available' );
-				}
-			}
-		}
-	};
+	}
 
-	this._init();
+	// init
 
-	this.render = function ( scene, camera ) {
-		var renderer = this._renderer;
-		var vrHMD = this._vrHMD;
-		// VR render mode if HMD is available
-		if ( vrHMD ) {
-			this.renderStereo.apply( this, arguments );
-			return;
-		}
-		// Regular render mode if not HMD
-		if ( scene instanceof Array ) scene = scene[ 0 ];
-		renderer.render.apply( this._renderer, arguments );
-	};
+	var vrHMD;
+	var leftEyeTranslation, leftEyeFOV;
+	var rightEyeTranslation, rightEyeFOV;
 
-	this.renderStereo = function( scene, camera, renderTarget, forceClear ) {
+	function gotVRDevices( devices ) {
 
-		var sceneLeft, sceneRight;
+		for ( var i = 0; i < devices.length; i ++ ) {
 
-		if ( scene instanceof Array ) {
+			if ( devices[ i ] instanceof HMDVRDevice ) {
 
-			sceneLeft = scene[ 0 ];
-			sceneRight = scene[ 1 ];
+				vrHMD = devices[ i ];
 
-		} else {
+				if ( vrHMD.getEyeParameters !== undefined ) {
+
+					var leftEyeParams = vrHMD.getEyeParameters( 'left' );
+					var rightEyeParams = vrHMD.getEyeParameters( 'right' );
+
+					leftEyeTranslation = leftEyeParams.eyeTranslation;
+					rightEyeTranslation = rightEyeParams.eyeTranslation;
+					leftEyeFOV = leftEyeParams.recommendedFieldOfView;
+					rightEyeFOV = rightEyeParams.recommendedFieldOfView;
+
+				} else {
+
+					// TODO: This is an older code path and not spec compliant.
+					// It should be removed at some point in the near future.
+					leftEyeTranslation = vrHMD.getEyeTranslation( 'left' );
+					rightEyeTranslation = vrHMD.getEyeTranslation( 'right' );
+					leftEyeFOV = vrHMD.getRecommendedEyeFieldOfView( 'left' );
+					rightEyeFOV = vrHMD.getRecommendedEyeFieldOfView( 'right' );
+
+				}
 
-			sceneLeft = scene;
-			sceneRight = scene;
+				break; // We keep the first we encounter
+
+			}
 
 		}
 
-		var leftEyeTranslation = this.leftEyeTranslation;
-		var rightEyeTranslation = this.rightEyeTranslation;
-		var renderer = this._renderer;
-		var rendererSize = renderer.getSize();
-		rendererSize.width /= 2;
+		if ( vrHMD === undefined ) {
 
-		renderer.enableScissorTest( true );
-		renderer.clear();
+			if ( done ) done( 'HMD not available' );
 
-		if ( camera.parent === undefined ) {
-			camera.updateMatrixWorld();
 		}
 
-		cameraLeft.projectionMatrix = this.FovToProjection( this.leftEyeFOV, true, camera.near, camera.far );
-		cameraRight.projectionMatrix = this.FovToProjection( this.rightEyeFOV, true, camera.near, camera.far );
+	}
 
-		camera.matrixWorld.decompose( cameraLeft.position, cameraLeft.quaternion, cameraLeft.scale );
-		camera.matrixWorld.decompose( cameraRight.position, cameraRight.quaternion, cameraRight.scale );
+	if ( navigator.getVRDevices ) {
 
-		cameraLeft.translateX( leftEyeTranslation.x );
-		cameraRight.translateX( rightEyeTranslation.x );
+		navigator.getVRDevices().then( gotVRDevices );
 
-		// render left eye
-		renderer.setViewport( 0, 0, rendererSize.width, rendererSize.height );
-		renderer.setScissor( 0, 0, rendererSize.width, rendererSize.height );
-		renderer.render( sceneLeft, cameraLeft );
+	} else if ( navigator.mozGetVRDevices ) {
 
-		// render right eye
-		renderer.setViewport( rendererSize.width, 0, rendererSize.width, rendererSize.height );
-		renderer.setScissor( rendererSize.width, 0, rendererSize.width, rendererSize.height );
-		renderer.render( sceneRight, cameraRight );
+		navigator.mozGetVRDevices( gotVRDevices );
 
-		renderer.enableScissorTest( false );
+	}
 
-	};
+	//
 
 	this.setSize = function( width, height ) {
+
 		renderer.setSize( width, height );
+
 	};
 
-	this.setFullScreen = function( enable ) {
-		var renderer = this._renderer;
-		var vrHMD = this._vrHMD;
-		var canvasOriginalSize = this._canvasOriginalSize;
-		if (!vrHMD) {
-			return;
-		}
-		// If state doesn't change we do nothing
-		if ( enable === this._fullScreen ) {
-			return;
-		}
-		this._fullScreen = !!enable;
+	// fullscreen
 
-		// VR Mode disabled
-		if ( !enable ) {
-			// Restores canvas original size
-			renderer.setSize( canvasOriginalSize.width, canvasOriginalSize.height );
-			return;
-		}
-		// VR Mode enabled
-		this._canvasOriginalSize = renderer.getSize();
-		this.startFullscreen();
-	};
+	var isFullscreen = false;
+
+	var canvas = renderer.domElement;
+	var fullscreenchange = canvas.mozRequestFullScreen ? 'mozfullscreenchange' : 'webkitfullscreenchange';
+
+	document.addEventListener( fullscreenchange, function ( event ) {
+
+		isFullscreen = document.mozFullScreenElement || document.webkitFullscreenElement;
+
+	}, false );
+
+	this.setFullScreen = function ( boolean ) {
+
+		if ( vrHMD === undefined ) return;
+		if ( isFullscreen === boolean ) return;
 
-	this.startFullscreen = function() {
-		var self = this;
-		var renderer = this._renderer;
-		var vrHMD = this._vrHMD;
-		var canvas = renderer.domElement;
-		var fullScreenChange =
-			canvas.mozRequestFullScreen ? 'mozfullscreenchange' : 'webkitfullscreenchange';
-
-		document.addEventListener( fullScreenChange, onFullScreenChanged, false );
-		function onFullScreenChanged() {
-			if ( !document.mozFullScreenElement && !document.webkitFullscreenElement ) {
-				self.setFullScreen( false );
-			}
-		}
 		if ( canvas.mozRequestFullScreen ) {
+
 			canvas.mozRequestFullScreen( { vrDisplay: vrHMD } );
+
 		} else if ( canvas.webkitRequestFullscreen ) {
+
 			canvas.webkitRequestFullscreen( { vrDisplay: vrHMD } );
+
 		}
+
+	};
+
+	// render
+
+	var cameraLeft = new THREE.PerspectiveCamera();
+	var cameraRight = new THREE.PerspectiveCamera();
+
+	this.render = function ( scene, camera ) {
+
+		if ( vrHMD ) {
+
+			var sceneLeft, sceneRight;
+
+			if ( scene instanceof Array ) {
+
+				sceneLeft = scene[ 0 ];
+				sceneRight = scene[ 1 ];
+
+			} else {
+
+				sceneLeft = scene;
+				sceneRight = scene;
+
+			}
+
+			var size = renderer.getSize();
+			size.width /= 2;
+
+			renderer.enableScissorTest( true );
+			renderer.clear();
+
+			if ( camera.parent === undefined ) {
+				camera.updateMatrixWorld();
+			}
+
+			cameraLeft.projectionMatrix = fovToProjection( leftEyeFOV, true, camera.near, camera.far );
+			cameraRight.projectionMatrix = fovToProjection( rightEyeFOV, true, camera.near, camera.far );
+
+			camera.matrixWorld.decompose( cameraLeft.position, cameraLeft.quaternion, cameraLeft.scale );
+			camera.matrixWorld.decompose( cameraRight.position, cameraRight.quaternion, cameraRight.scale );
+
+			cameraLeft.translateX( leftEyeTranslation.x );
+			cameraRight.translateX( rightEyeTranslation.x );
+
+			// render left eye
+			renderer.setViewport( 0, 0, size.width, size.height );
+			renderer.setScissor( 0, 0, size.width, size.height );
+			renderer.render( sceneLeft, cameraLeft );
+
+			// render right eye
+			renderer.setViewport( size.width, 0, size.width, size.height );
+			renderer.setScissor( size.width, 0, size.width, size.height );
+			renderer.render( sceneRight, cameraRight );
+
+			renderer.enableScissorTest( false );
+
+			return;
+
+		}
+
+		// Regular render mode if not HMD
+
+		if ( scene instanceof Array ) scene = scene[ 0 ];
+
+		renderer.render( scene, camera );
+
 	};
 
-	this.FovToNDCScaleOffset = function( fov ) {
+	//
+
+	function fovToNDCScaleOffset( fov ) {
+
 		var pxscale = 2.0 / (fov.leftTan + fov.rightTan);
 		var pxoffset = (fov.leftTan - fov.rightTan) * pxscale * 0.5;
 		var pyscale = 2.0 / (fov.upTan + fov.downTan);
 		var pyoffset = (fov.upTan - fov.downTan) * pyscale * 0.5;
 		return { scale: [ pxscale, pyscale ], offset: [ pxoffset, pyoffset ] };
-	};
 
-	this.FovPortToProjection = function( fov, rightHanded /* = true */, zNear /* = 0.01 */, zFar /* = 10000.0 */ )
-	{
+	}
+
+	function fovPortToProjection( fov, rightHanded, zNear, zFar ) {
+
 		rightHanded = rightHanded === undefined ? true : rightHanded;
 		zNear = zNear === undefined ? 0.01 : zNear;
 		zFar = zFar === undefined ? 10000.0 : zFar;
@@ -211,7 +217,7 @@ THREE.VREffect = function ( renderer, done ) {
 		var m = mobj.elements;
 
 		// and with scale/offset info for normalized device coords
-		var scaleAndOffset = this.FovToNDCScaleOffset(fov);
+		var scaleAndOffset = fovToNDCScaleOffset(fov);
 
 		// X result, map clip edges to [-w,+w]
 		m[0 * 4 + 0] = scaleAndOffset.scale[0];
@@ -242,17 +248,21 @@ THREE.VREffect = function ( renderer, done ) {
 		mobj.transpose();
 
 		return mobj;
-	};
+	}
+
+	function fovToProjection( fov, rightHanded, zNear, zFar ) {
+
+		var DEG2RAD = Math.PI / 180.0;
 
-	this.FovToProjection = function( fov, rightHanded /* = true */, zNear /* = 0.01 */, zFar /* = 10000.0 */ )
-	{
 		var fovPort = {
-			upTan: Math.tan(fov.upDegrees * Math.PI / 180.0),
-			downTan: Math.tan(fov.downDegrees * Math.PI / 180.0),
-			leftTan: Math.tan(fov.leftDegrees * Math.PI / 180.0),
-			rightTan: Math.tan(fov.rightDegrees * Math.PI / 180.0)
+			upTan: Math.tan( fov.upDegrees * DEG2RAD ),
+			downTan: Math.tan( fov.downDegrees * DEG2RAD ),
+			leftTan: Math.tan( fov.leftDegrees * DEG2RAD ),
+			rightTan: Math.tan( fov.rightDegrees * DEG2RAD )
 		};
-		return this.FovPortToProjection(fovPort, rightHanded, zNear, zFar);
-	};
+
+		return fovPortToProjection( fovPort, rightHanded, zNear, zFar );
+
+	}
 
 };