Skip to content

⬅️ Back to Table of Contents

📄 CameraUtils.js

📊 Analysis Summary

Metric Count
🔧 Functions 1
📦 Imports 3
📊 Variables & Constants 19

📚 Table of Contents

🛠️ File Location:

📂 examples/jsm/utils/CameraUtils.js

📦 Imports

Name Source
MathUtils three
Quaternion three
Vector3 three

Variables & Constants

Name Type Kind Value Exported
_va any let/var new Vector3()
_vb any let/var new Vector3()
_vc any let/var new Vector3()
_vr any let/var new Vector3()
_vu any let/var new Vector3()
_vn any let/var new Vector3()
_vec any let/var new Vector3()
_quat any let/var new Quaternion()
pa Vector3 let/var bottomLeftCorner
pb Vector3 let/var bottomRightCorner
pc Vector3 let/var topLeftCorner
pe any let/var camera.position
n any let/var camera.near
f any let/var camera.far
d number let/var - _va.dot( _vn )
l number let/var _vr.dot( _va ) * n / d
r number let/var _vr.dot( _vb ) * n / d
b number let/var _vu.dot( _va ) * n / d
t number let/var _vu.dot( _vc ) * n / d

Functions

frameCorners(camera: PerspectiveCamera, bottomLeftCorner: Vector3, bottomRightCorner: Vector3, topLeftCorner: Vector3, estimateViewFrustum: boolean): void

JSDoc:

/**
 * Set projection matrix and the orientation of a perspective camera
 * to exactly frame the corners of an arbitrary rectangle.
 * NOTE: This function ignores the standard parameters;
 * do not call `updateProjectionMatrix()` after this.
 *
 * @param {PerspectiveCamera} camera - The camera.
 * @param {Vector3} bottomLeftCorner - The bottom-left corner point.
 * @param {Vector3} bottomRightCorner - The bottom-right corner point.
 * @param {Vector3} topLeftCorner - The top-left corner point.
 * @param {boolean} [estimateViewFrustum=false] - If set to `true`, the function tries to estimate the camera's FOV.
 */

Parameters:

  • camera PerspectiveCamera
  • bottomLeftCorner Vector3
  • bottomRightCorner Vector3
  • topLeftCorner Vector3
  • estimateViewFrustum boolean

Returns: void

Calls:

  • _vr.copy( pb ).sub( pa ).normalize
  • _vu.copy( pc ).sub( pa ).normalize
  • _vn.crossVectors( _vr, _vu ).normalize
  • _va.copy( pa ).sub
  • _vb.copy( pb ).sub
  • _vc.copy( pc ).sub
  • _va.dot
  • _vr.dot
  • _vu.dot
  • _quat.setFromUnitVectors
  • _vec.set
  • camera.quaternion.setFromUnitVectors( _vec.set( 0, 0, 1 ).applyQuaternion( _quat ), _vn ).multiply
  • camera.projectionMatrix.set
  • camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert
  • Math.min
  • Math.atan
  • _vec.copy( pb ).sub( pa ).length
  • _vec.copy( pc ).sub( pa ).length
  • _va.length

Internal Comments:

// Set the camera rotation to match the focal plane to the corners' plane (x4)
// Set the off-axis projection matrix to match the corners (x5)
// FoV estimation to fix frustum culling
// Set fieldOfView to a conservative estimate (x4)
// to make frustum tall/wide enough to encompass it (x4)

Code
function frameCorners( camera, bottomLeftCorner, bottomRightCorner, topLeftCorner, estimateViewFrustum = false ) {

    const pa = bottomLeftCorner, pb = bottomRightCorner, pc = topLeftCorner;
    const pe = camera.position; // eye position
    const n = camera.near; // distance of near clipping plane
    const f = camera.far; //distance of far clipping plane

    _vr.copy( pb ).sub( pa ).normalize();
    _vu.copy( pc ).sub( pa ).normalize();
    _vn.crossVectors( _vr, _vu ).normalize();

    _va.copy( pa ).sub( pe ); // from pe to pa
    _vb.copy( pb ).sub( pe ); // from pe to pb
    _vc.copy( pc ).sub( pe ); // from pe to pc

    const d = - _va.dot( _vn ); // distance from eye to screen
    const l = _vr.dot( _va ) * n / d; // distance to left screen edge
    const r = _vr.dot( _vb ) * n / d; // distance to right screen edge
    const b = _vu.dot( _va ) * n / d; // distance to bottom screen edge
    const t = _vu.dot( _vc ) * n / d; // distance to top screen edge

    // Set the camera rotation to match the focal plane to the corners' plane
    _quat.setFromUnitVectors( _vec.set( 0, 1, 0 ), _vu );
    camera.quaternion.setFromUnitVectors( _vec.set( 0, 0, 1 ).applyQuaternion( _quat ), _vn ).multiply( _quat );

    // Set the off-axis projection matrix to match the corners
    camera.projectionMatrix.set( 2.0 * n / ( r - l ), 0.0,
        ( r + l ) / ( r - l ), 0.0, 0.0,
        2.0 * n / ( t - b ),
        ( t + b ) / ( t - b ), 0.0, 0.0, 0.0,
        ( f + n ) / ( n - f ),
        2.0 * f * n / ( n - f ), 0.0, 0.0, - 1.0, 0.0 );
    camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();

    // FoV estimation to fix frustum culling
    if ( estimateViewFrustum ) {

        // Set fieldOfView to a conservative estimate
        // to make frustum tall/wide enough to encompass it
        camera.fov =
            MathUtils.RAD2DEG / Math.min( 1.0, camera.aspect ) *
            Math.atan( ( _vec.copy( pb ).sub( pa ).length() +
                            ( _vec.copy( pc ).sub( pa ).length() ) ) / _va.length() );

    }

}