提交 f7687afe 编写于 作者: T tschw 提交者: Mr.doob

Revised PerspectiveCamera.

* Revised PerspectiveCamera.

- Allows extra skew for stereo rendering.
- Allows to query effective FOV angle (considering .zoom).
- Proper copy / serialization of all properties.
- Tidier, single code path frustum calculation.
- No longer uses ProjectionMatrix.makePerspective.

* Revised PerspectiveCamera physical interface.
上级 aca8c970
......@@ -42,14 +42,11 @@ scene.add( camera );</code>
<h2>Properties</h2>
<h3>[property:number zoom]</h3>
<div>Gets or sets the zoom factor of the camera. </div>
<h3>[property:Float fov]</h3>
<div>Camera frustum vertical field of view, from bottom to top of view, in degrees.</div>
<h3>[property:Float aspect]</h3>
<div>Camera frustum aspect ratio, window width divided by window height.</div>
<h3>[property:number zoom]</h3>
<div>Gets or sets the zoom factor of the camera. </div>
<h3>[property:Float near]</h3>
<div>Camera frustum near plane.</div>
......@@ -57,18 +54,60 @@ scene.add( camera );</code>
<h3>[property:Float far]</h3>
<div>Camera frustum far plane.</div>
<h3>[property:Float focus]</h3>
<div>Object distance used for stereoscopy and depth-of-field effects. This parameter does not influence the projection matrix unless a StereoCamera is being used.</div>
<h3>[property:Float aspect]</h3>
<div>Camera frustum aspect ratio, window width divided by window height.</div>
<h3>[property:Object view]</h3>
<div>Frustum window specification or null.</div>
<h3>[property:Float filmGauge]</h3>
<div>Film size used for the larger axis. Default is 35 (millimeters). This parameter does not influence the projection matrix unless .filmOffset is set to a nonzero value.</div>
<h3>[property:Float filmOffset]</h3>
<div>Horizontal off-center offset in the same unit as .filmGauge.</div>
<h2>Methods</h2>
<h3>[method:null setLens]( [page:Float focalLength], [page:Float frameSize] )</h3>
<h3>[method:Float getEffectiveFOV]()</h3>
<div>
Returns the current vertical field of view angle in degrees considering .zoom.
</div>
<h3>[method:Float getFocalLength]()</h3>
<div>
Returns the focal length of the current .fov in respect to .filmGauge.
</div>
<h3>[method:Float getFilmWidth]()</h3>
<div>
Returns the width of the image on the film. If .aspect is greater than or equal to one (landscape format), the result equals .filmGauge.
</div>
<h3>[method:Float getFilmHeight]()</h3>
<div>
Returns the height of the image on the film. If .aspect is less than or equal to one (portrait format), the result equals .fimlGauge.
</div>
<h3>[method:null setFocalLength]( [page:Float focalLength] )</h3>
<div>
Sets the FOV by focal length in respect to the current .filmGauge.
</div>
<div>
By default, the focal length is specified for a 35mm (full frame) camera.
</div>
<h3>[method:null setLens]( [page:Float focalLength], [page:Float filmGauge] )</h3>
<div>
focalLength — focal length<br />
frameSize — frame size
frameGauge — film gauge
</div>
<div>
Uses focal length (in mm) to estimate and set FOV 35mm (fullframe) camera is used if frame size is not specified.<br />
Formula based on [link:http://www.bobatkins.com/photography/technical/field_of_view.html]
Sets .fov by focal length. Optionally also sets .filmGauge.
This method is deprecated, please use .setFocalLength instead.
</div>
<h3>[method:null setViewOffset]( [page:Float fullWidth], [page:Float fullHeight], [page:Float x], [page:Float y], [page:Float width], [page:Float height] )</h3>
......
......@@ -130,10 +130,10 @@
Sets the zoomfactor.
</div>
<h3>[method:null setLens]([page:number focalLength], [page:Number frameHeight])</h3>
<h3>[method:null setLens]([page:number focalLength], [page:Number filmGauge])</h3>
<div>
focalLength -- The focal length of a lens is defined as the distance from the optical center of a lens (or, the secondary principal point for a complex lens like a camera lens) to the focal point (sensor) when the lens is focused on an object at infinity. <br />
frameHeight -- the size of the frame in mm. (default is *35*)
filmGauge -- the size of the frame in mm. (default is *35*)
</div>
<div>
Sets the fov based on lens data.
......
......@@ -31,26 +31,26 @@ THREE.CinematicCamera.prototype.constructor = THREE.CinematicCamera;
// providing fnumber and coc(Circle of Confusion) as extra arguments
THREE.CinematicCamera.prototype.setLens = function ( focalLength, frameHeight, fNumber, coc ) {
THREE.CinematicCamera.prototype.setLens = function ( focalLength, filmGauge, fNumber, coc ) {
// In case of cinematicCamera, having a default lens set is important
if ( focalLength === undefined ) focalLength = 35;
if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
THREE.PerspectiveCamera.prototype.setLens.call( this, focalLength, frameHeight );
this.setFocalLength( focalLength );
// if fnumber and coc are not provided, cinematicCamera tries to act as a basic PerspectiveCamera
if ( fNumber === undefined ) fNumber = 8;
if ( coc === undefined ) coc = 0.019;
this.focalLength = focalLength;
this.fNumber = fNumber;
this.coc = coc;
// fNumber is focalLength by aperture
this.aperture = this.focalLength / this.fNumber;
this.aperture = focalLength / this.fNumber;
// hyperFocal is required to calculate depthOfField when a lens tries to focus at a distance with given fNumber and focalLength
this.hyperFocal = ( this.focalLength * this.focalLength ) / ( this.aperture * this.coc );
this.hyperFocal = ( focalLength * focalLength ) / ( this.aperture * this.coc );
};
......@@ -80,14 +80,16 @@ THREE.CinematicCamera.prototype.focusAt = function ( focusDistance ) {
if ( focusDistance === undefined ) focusDistance = 20;
// distance from the camera (normal to frustrum) to focus on (unused)
this.focusDistance = focusDistance;
var focalLength = this.getFocalLength();
// distance from the camera (normal to frustrum) to focus on
this.focus = focusDistance;
// the nearest point from the camera which is in focus (unused)
this.nearPoint = ( this.hyperFocal * this.focusDistance ) / ( this.hyperFocal + ( this.focusDistance - this.focalLength ) );
this.nearPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal + ( this.focus - focalLength ) );
// the farthest point from the camera which is in focus (unused)
this.farPoint = ( this.hyperFocal * this.focusDistance ) / ( this.hyperFocal - ( this.focusDistance - this.focalLength ) );
this.farPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal - ( this.focus - focalLength ) );
// the gap or width of the space in which is everything is in focus (unused)
this.depthOfField = this.farPoint - this.nearPoint;
......@@ -95,7 +97,7 @@ THREE.CinematicCamera.prototype.focusAt = function ( focusDistance ) {
// Considering minimum distance of focus for a standard lens (unused)
if ( this.depthOfField < 0 ) this.depthOfField = 0;
this.sdistance = this.smoothstep( this.near, this.far, this.focusDistance );
this.sdistance = this.smoothstep( this.near, this.far, this.focus );
this.ldistance = this.linearize( 1 - this.sdistance );
......
......@@ -146,14 +146,17 @@ THREE.CombinedCamera.prototype.updateProjectionMatrix = function() {
/*
* Uses Focal Length (in mm) to estimate and set FOV
* 35mm (fullframe) camera is used if frame size is not specified;
* 35mm (full frame) camera is used if frame size is not specified;
* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
*/
THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) {
THREE.CombinedCamera.prototype.setLens = function ( focalLength, filmGauge ) {
if ( frameHeight === undefined ) frameHeight = 24;
if ( filmGauge === undefined ) filmGauge = 35;
var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
var vExtentSlope = 0.5 * filmGauge /
( focalLength * Math.max( this.cameraP.aspect, 1 ) );
var fov = THREE.Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
this.setFov( fov );
......
......@@ -2,46 +2,121 @@
* @author mrdoob / http://mrdoob.com/
* @author greggman / http://games.greggman.com/
* @author zz85 / http://www.lab4games.net/zz85/blog
* @author tschw
*/
THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {
THREE.PerspectiveCamera = function( fov, aspect, near, far ) {
THREE.Camera.call( this );
this.type = 'PerspectiveCamera';
this.focalLength = 10;
this.fov = fov !== undefined ? fov : 50;
this.zoom = 1;
this.fov = fov !== undefined ? fov : 50;
this.aspect = aspect !== undefined ? aspect : 1;
this.near = near !== undefined ? near : 0.1;
this.far = far !== undefined ? far : 2000;
this.focus = 10;
this.aspect = aspect !== undefined ? aspect : 1;
this.view = null;
this.filmGauge = 35; // width of the film (default in millimeters)
this.filmOffset = 0; // horizontal film offset (same unit as gauge)
this.updateProjectionMatrix();
};
THREE.PerspectiveCamera._assignProps = function( dest, source ) {
dest.fov = source.fov;
dest.zoom = source.zoom;
dest.near = source.near;
dest.far = source.far;
dest.focs = source.focus;
dest.aspect = source.aspect;
dest.view = ! source.view ? null : Object.assign( {}, source.view );
dest.filmGauge = source.filmGauge;
dest.filmOffset = source.filmOffset;
};
THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );
THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera;
/**
* Uses Focal Length (in mm) to estimate and set FOV
* 35mm (full-frame) camera is used if frame size is not specified;
* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
* Sets the FOV by focal length (DEPRECATED).
*
* Optionally also sets .filmGauge, otherwise uses it. See .setFocalLength.
*/
THREE.PerspectiveCamera.prototype.setLens = function( focalLength, filmGauge ) {
console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " +
"Use .setFocalLength and .filmGauge for a photographic setup." );
THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {
if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
this.setFocalLength( focalLength );
if ( frameHeight === undefined ) frameHeight = 24;
};
this.fov = 2 * THREE.Math.RAD2DEG * Math.atan( frameHeight / ( focalLength * 2 ) );
/**
* Sets the FOV by focal length in respect to the current .filmGauge.
*
* The default film gauge is 35, so that the focal length can be specified for
* a 35mm (full frame) camera.
*
* Values for focal length and film gauge must have the same unit.
*/
THREE.PerspectiveCamera.prototype.setFocalLength = function( focalLength ) {
// see http://www.bobatkins.com/photography/technical/field_of_view.html
var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
this.fov = THREE.Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
this.updateProjectionMatrix();
};
/**
* Calculates the focal length from the current .fov and .filmGauge.
*/
THREE.PerspectiveCamera.prototype.getFocalLength = function() {
var vExtentSlope = Math.tan( THREE.Math.DEG2RAD * 0.5 * this.fov );
return 0.5 * this.getFilmHeight() / vExtentSlope;
};
THREE.PerspectiveCamera.prototype.getEffectiveFOV = function() {
return THREE.Math.RAD2DEG * 2 * Math.atan(
Math.tan( THREE.Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );
};
THREE.PerspectiveCamera.prototype.getFilmWidth = function() {
// film not completely covered in portrait format (aspect < 1)
return this.filmGauge * Math.min( this.aspect, 1 );
};
THREE.PerspectiveCamera.prototype.getFilmHeight = function() {
// film not completely covered in landscape format (aspect > 1)
return this.filmGauge / Math.max( this.aspect, 1 );
};
/**
* Sets an offset in a larger frustum. This is useful for multi-window or
* multi-monitor/multi-machine setups.
......@@ -77,80 +152,65 @@ THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight
*
* Note there is no reason monitors have to be the same size or in a grid.
*/
THREE.PerspectiveCamera.prototype.setViewOffset = function( fullWidth, fullHeight, x, y, width, height ) {
THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {
this.aspect = fullWidth / fullHeight;
this.fullWidth = fullWidth;
this.fullHeight = fullHeight;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.view = {
fullWidth: fullWidth,
fullHeight: fullHeight,
offsetX: x,
offsetY: y,
width: width,
height: height
};
this.updateProjectionMatrix();
};
THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function() {
THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {
var near = this.near,
top = near * Math.tan(
THREE.Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
height = 2 * top,
width = this.aspect * height,
left = -0.5 * width,
view = this.view;
var fov = THREE.Math.RAD2DEG * ( 2 * Math.atan( Math.tan( THREE.Math.DEG2RAD * this.fov * 0.5 ) / this.zoom ) );
if ( view !== null ) {
if ( this.fullWidth ) {
var fullWidth = view.fullWidth,
fullHeight = view.fullHeight;
var aspect = this.fullWidth / this.fullHeight;
var top = Math.tan( THREE.Math.DEG2RAD * fov * 0.5 ) * this.near;
var bottom = - top;
var left = aspect * bottom;
var right = aspect * top;
var width = Math.abs( right - left );
var height = Math.abs( top - bottom );
left += view.offsetX * width / fullWidth;
top -= view.offsetY * height / fullHeight;
width *= view.width / fullWidth;
height *= view.height / fullHeight;
this.projectionMatrix.makeFrustum(
left + this.x * width / this.fullWidth,
left + ( this.x + this.width ) * width / this.fullWidth,
top - ( this.y + this.height ) * height / this.fullHeight,
top - this.y * height / this.fullHeight,
this.near,
this.far
);
} else {
}
this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far );
var skew = this.filmOffset;
if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
}
this.projectionMatrix.makeFrustum(
left, left + width, top - height, top, near, this.far );
};
THREE.PerspectiveCamera.prototype.copy = function ( source ) {
THREE.PerspectiveCamera.prototype.copy = function( source ) {
THREE.Camera.prototype.copy.call( this, source );
this.focalLength = source.focalLength;
this.zoom = source.zoom;
this.fov = source.fov;
this.aspect = source.aspect;
this.near = source.near;
this.far = source.far;
THREE.PerspectiveCamera._assignProps( this, source );
return this;
};
THREE.PerspectiveCamera.prototype.toJSON = function ( meta ) {
THREE.PerspectiveCamera.prototype.toJSON = function( meta ) {
var data = THREE.Object3D.prototype.toJSON.call( this, meta );
data.object.focalLength = this.focalLength;
data.object.zoom = this.zoom;
data.object.fov = this.fov;
data.object.aspect = this.aspect;
data.object.near = this.near;
data.object.far = this.far;
THREE.PerspectiveCamera._assignProps( data.object, this );
return data;
};
......@@ -24,20 +24,20 @@ THREE.StereoCamera.prototype = {
update: ( function () {
var focalLength, fov, aspect, near, far;
var focus, fov, aspect, near, far;
var eyeRight = new THREE.Matrix4();
var eyeLeft = new THREE.Matrix4();
return function update ( camera ) {
var needsUpdate = focalLength !== camera.focalLength || fov !== camera.fov ||
var needsUpdate = focus !== camera.focus || fov !== camera.fov ||
aspect !== camera.aspect * this.aspect || near !== camera.near ||
far !== camera.far;
if ( needsUpdate ) {
focalLength = camera.focalLength;
focus = camera.focus;
fov = camera.fov;
aspect = camera.aspect * this.aspect;
near = camera.near;
......@@ -48,7 +48,7 @@ THREE.StereoCamera.prototype = {
var projectionMatrix = camera.projectionMatrix.clone();
var eyeSep = 0.064 / 2;
var eyeSepOnProjection = eyeSep * near / focalLength;
var eyeSepOnProjection = eyeSep * near / focus;
var ymax = near * Math.tan( THREE.Math.DEG2RAD * fov * 0.5 );
var xmin, xmax;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册