CameraUtils.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import {
  2. MathUtils,
  3. Quaternion,
  4. Vector3
  5. } from 'three';
  6. /**
  7. * @module CameraUtils
  8. * @three_import import * as CameraUtils from 'three/addons/utils/CameraUtils.js';
  9. */
  10. const _va = /*@__PURE__*/ new Vector3(), // from pe to pa
  11. _vb = /*@__PURE__*/ new Vector3(), // from pe to pb
  12. _vc = /*@__PURE__*/ new Vector3(), // from pe to pc
  13. _vr = /*@__PURE__*/ new Vector3(), // right axis of screen
  14. _vu = /*@__PURE__*/ new Vector3(), // up axis of screen
  15. _vn = /*@__PURE__*/ new Vector3(), // normal vector of screen
  16. _vec = /*@__PURE__*/ new Vector3(), // temporary vector
  17. _quat = /*@__PURE__*/ new Quaternion(); // temporary quaternion
  18. /**
  19. * Set projection matrix and the orientation of a perspective camera
  20. * to exactly frame the corners of an arbitrary rectangle.
  21. * NOTE: This function ignores the standard parameters;
  22. * do not call `updateProjectionMatrix()` after this.
  23. *
  24. * @param {PerspectiveCamera} camera - The camera.
  25. * @param {Vector3} bottomLeftCorner - The bottom-left corner point.
  26. * @param {Vector3} bottomRightCorner - The bottom-right corner point.
  27. * @param {Vector3} topLeftCorner - The top-left corner point.
  28. * @param {boolean} [estimateViewFrustum=false] - If set to `true`, the function tries to estimate the camera's FOV.
  29. */
  30. function frameCorners( camera, bottomLeftCorner, bottomRightCorner, topLeftCorner, estimateViewFrustum = false ) {
  31. const pa = bottomLeftCorner, pb = bottomRightCorner, pc = topLeftCorner;
  32. const pe = camera.position; // eye position
  33. const n = camera.near; // distance of near clipping plane
  34. const f = camera.far; //distance of far clipping plane
  35. _vr.copy( pb ).sub( pa ).normalize();
  36. _vu.copy( pc ).sub( pa ).normalize();
  37. _vn.crossVectors( _vr, _vu ).normalize();
  38. _va.copy( pa ).sub( pe ); // from pe to pa
  39. _vb.copy( pb ).sub( pe ); // from pe to pb
  40. _vc.copy( pc ).sub( pe ); // from pe to pc
  41. const d = - _va.dot( _vn ); // distance from eye to screen
  42. const l = _vr.dot( _va ) * n / d; // distance to left screen edge
  43. const r = _vr.dot( _vb ) * n / d; // distance to right screen edge
  44. const b = _vu.dot( _va ) * n / d; // distance to bottom screen edge
  45. const t = _vu.dot( _vc ) * n / d; // distance to top screen edge
  46. // Set the camera rotation to match the focal plane to the corners' plane
  47. _quat.setFromUnitVectors( _vec.set( 0, 1, 0 ), _vu );
  48. camera.quaternion.setFromUnitVectors( _vec.set( 0, 0, 1 ).applyQuaternion( _quat ), _vn ).multiply( _quat );
  49. // Set the off-axis projection matrix to match the corners
  50. camera.projectionMatrix.set( 2.0 * n / ( r - l ), 0.0,
  51. ( r + l ) / ( r - l ), 0.0, 0.0,
  52. 2.0 * n / ( t - b ),
  53. ( t + b ) / ( t - b ), 0.0, 0.0, 0.0,
  54. ( f + n ) / ( n - f ),
  55. 2.0 * f * n / ( n - f ), 0.0, 0.0, - 1.0, 0.0 );
  56. camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
  57. // FoV estimation to fix frustum culling
  58. if ( estimateViewFrustum ) {
  59. // Set fieldOfView to a conservative estimate
  60. // to make frustum tall/wide enough to encompass it
  61. camera.fov =
  62. MathUtils.RAD2DEG / Math.min( 1.0, camera.aspect ) *
  63. Math.atan( ( _vec.copy( pb ).sub( pa ).length() +
  64. ( _vec.copy( pc ).sub( pa ).length() ) ) / _va.length() );
  65. }
  66. }
  67. export { frameCorners };