diff --git a/docs/api/cameras/PerspectiveCamera.html b/docs/api/cameras/PerspectiveCamera.html
index ca4b1e1e83d7a16767af1652ffc18104e3425aa7..4f97c9ce77f3d0005901cace9583e52a0f7a0ce8 100644
--- a/docs/api/cameras/PerspectiveCamera.html
+++ b/docs/api/cameras/PerspectiveCamera.html
@@ -42,14 +42,11 @@ scene.add( camera );
Properties
- [property:number zoom]
- Gets or sets the zoom factor of the camera.
-
[property:Float fov]
Camera frustum vertical field of view, from bottom to top of view, in degrees.
- [property:Float aspect]
- Camera frustum aspect ratio, window width divided by window height.
+ [property:number zoom]
+ Gets or sets the zoom factor of the camera.
[property:Float near]
Camera frustum near plane.
@@ -57,18 +54,60 @@ scene.add( camera );
[property:Float far]
Camera frustum far plane.
+ [property:Float focus]
+ Object distance used for stereoscopy and depth-of-field effects. This parameter does not influence the projection matrix unless a StereoCamera is being used.
+
+ [property:Float aspect]
+ Camera frustum aspect ratio, window width divided by window height.
+
+ [property:Object view]
+ Frustum window specification or null.
+
+ [property:Float filmGauge]
+ 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.
+
+ [property:Float filmOffset]
+ Horizontal off-center offset in the same unit as .filmGauge.
Methods
- [method:null setLens]( [page:Float focalLength], [page:Float frameSize] )
+ [method:Float getEffectiveFOV]()
+
+ Returns the current vertical field of view angle in degrees considering .zoom.
+
+
+ [method:Float getFocalLength]()
+
+ Returns the focal length of the current .fov in respect to .filmGauge.
+
+
+ [method:Float getFilmWidth]()
+
+ Returns the width of the image on the film. If .aspect is greater than or equal to one (landscape format), the result equals .filmGauge.
+
+
+ [method:Float getFilmHeight]()
+
+ Returns the height of the image on the film. If .aspect is less than or equal to one (portrait format), the result equals .fimlGauge.
+
+
+ [method:null setFocalLength]( [page:Float focalLength] )
+
+ Sets the FOV by focal length in respect to the current .filmGauge.
+
+
+ By default, the focal length is specified for a 35mm (full frame) camera.
+
+
+ [method:null setLens]( [page:Float focalLength], [page:Float filmGauge] )
focalLength — focal length
- frameSize — frame size
+ frameGauge — film gauge
- Uses focal length (in mm) to estimate and set FOV 35mm (fullframe) camera is used if frame size is not specified.
- 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.
[method:null setViewOffset]( [page:Float fullWidth], [page:Float fullHeight], [page:Float x], [page:Float y], [page:Float width], [page:Float height] )
diff --git a/docs/api/examples/cameras/CombinedCamera.html b/docs/api/examples/cameras/CombinedCamera.html
index 52100341206ac750840ca960ca3557df1e149e4d..d3347673d0aaaaa4f0c3425ae5ae2253b249e8a6 100644
--- a/docs/api/examples/cameras/CombinedCamera.html
+++ b/docs/api/examples/cameras/CombinedCamera.html
@@ -130,10 +130,10 @@
Sets the zoomfactor.
- [method:null setLens]([page:number focalLength], [page:Number frameHeight])
+ [method:null setLens]([page:number focalLength], [page:Number filmGauge])
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.
- frameHeight -- the size of the frame in mm. (default is *35*)
+ filmGauge -- the size of the frame in mm. (default is *35*)
Sets the fov based on lens data.
diff --git a/examples/js/cameras/CinematicCamera.js b/examples/js/cameras/CinematicCamera.js
index cfc0fc4412c86d0ac669b936fa373f6af9888d9b..7007d90015e9bc0e9a20375794665ee1ee58d923 100644
--- a/examples/js/cameras/CinematicCamera.js
+++ b/examples/js/cameras/CinematicCamera.js
@@ -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 );
diff --git a/examples/js/cameras/CombinedCamera.js b/examples/js/cameras/CombinedCamera.js
index 797ba9a1748598a0c3d8083392e0cbb170348690..126f0513c4a1572d91b26476c935ebe7cf83829a 100644
--- a/examples/js/cameras/CombinedCamera.js
+++ b/examples/js/cameras/CombinedCamera.js
@@ -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 );
diff --git a/src/cameras/PerspectiveCamera.js b/src/cameras/PerspectiveCamera.js
index 9041bfadd111f6f48892c8e1791046f13c3fc730..328a0b7fe64aa2b6696305744e70f16d92bd8908 100644
--- a/src/cameras/PerspectiveCamera.js
+++ b/src/cameras/PerspectiveCamera.js
@@ -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;
};
diff --git a/src/cameras/StereoCamera.js b/src/cameras/StereoCamera.js
index 8df58ff9287f5591c9480a3d5e2fe0a59343c54c..57a795d1f4ab9a67e7a033de8db409f056ced584 100644
--- a/src/cameras/StereoCamera.js
+++ b/src/cameras/StereoCamera.js
@@ -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;