提交 1195e0f3 编写于 作者: M Mr.doob

Refactored VREffect.

/ping @dmarcos @borismus @toji @spite
上级 155a9794
/**
* @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 );
}
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册