74 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			74 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									MathUtils,
							 | 
						||
| 
								 | 
							
									Quaternion,
							 | 
						||
| 
								 | 
							
									Vector3
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const _va = /*@__PURE__*/ new Vector3(), // from pe to pa
							 | 
						||
| 
								 | 
							
									_vb = /*@__PURE__*/ new Vector3(), // from pe to pb
							 | 
						||
| 
								 | 
							
									_vc = /*@__PURE__*/ new Vector3(), // from pe to pc
							 | 
						||
| 
								 | 
							
									_vr = /*@__PURE__*/ new Vector3(), // right axis of screen
							 | 
						||
| 
								 | 
							
									_vu = /*@__PURE__*/ new Vector3(), // up axis of screen
							 | 
						||
| 
								 | 
							
									_vn = /*@__PURE__*/ new Vector3(), // normal vector of screen
							 | 
						||
| 
								 | 
							
									_vec = /*@__PURE__*/ new Vector3(), // temporary vector
							 | 
						||
| 
								 | 
							
									_quat = /*@__PURE__*/ new Quaternion(); // temporary quaternion
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** Set a PerspectiveCamera's projectionMatrix and quaternion
							 | 
						||
| 
								 | 
							
								 * to exactly frame the corners of an arbitrary rectangle.
							 | 
						||
| 
								 | 
							
								 * NOTE: This function ignores the standard parameters;
							 | 
						||
| 
								 | 
							
								 * do not call updateProjectionMatrix() after this!
							 | 
						||
| 
								 | 
							
								 * @param {Vector3} bottomLeftCorner
							 | 
						||
| 
								 | 
							
								 * @param {Vector3} bottomRightCorner
							 | 
						||
| 
								 | 
							
								 * @param {Vector3} topLeftCorner
							 | 
						||
| 
								 | 
							
								 * @param {boolean} estimateViewFrustum */
							 | 
						||
| 
								 | 
							
								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() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { frameCorners };
							 |