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;