MCP 3D Printer Server
by DMontgomery40
Verified
- node_modules
- three
- src
- cameras
import { Camera } from './Camera.js';
import { RAD2DEG, DEG2RAD } from '../math/MathUtils.js';
import { Vector2 } from '../math/Vector2.js';
import { Vector3 } from '../math/Vector3.js';
const _v3 = /*@__PURE__*/ new Vector3();
const _minTarget = /*@__PURE__*/ new Vector2();
const _maxTarget = /*@__PURE__*/ new Vector2();
class PerspectiveCamera extends Camera {
constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
super();
this.isPerspectiveCamera = true;
this.type = 'PerspectiveCamera';
this.fov = fov;
this.zoom = 1;
this.near = near;
this.far = far;
this.focus = 10;
this.aspect = aspect;
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();
}
copy( source, recursive ) {
super.copy( source, recursive );
this.fov = source.fov;
this.zoom = source.zoom;
this.near = source.near;
this.far = source.far;
this.focus = source.focus;
this.aspect = source.aspect;
this.view = source.view === null ? null : Object.assign( {}, source.view );
this.filmGauge = source.filmGauge;
this.filmOffset = source.filmOffset;
return this;
}
/**
* 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.
*
* @param {number} focalLength - Values for focal length and film gauge must have the same unit.
*/
setFocalLength( focalLength ) {
/** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope );
this.updateProjectionMatrix();
}
/**
* Calculates the focal length from the current .fov and .filmGauge.
*
* @returns {number}
*/
getFocalLength() {
const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov );
return 0.5 * this.getFilmHeight() / vExtentSlope;
}
getEffectiveFOV() {
return RAD2DEG * 2 * Math.atan(
Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom );
}
getFilmWidth() {
// film not completely covered in portrait format (aspect < 1)
return this.filmGauge * Math.min( this.aspect, 1 );
}
getFilmHeight() {
// film not completely covered in landscape format (aspect > 1)
return this.filmGauge / Math.max( this.aspect, 1 );
}
/**
* Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction.
* Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle.
*
* @param {number} distance
* @param {Vector2} minTarget
* @param {Vector2} maxTarget
*/
getViewBounds( distance, minTarget, maxTarget ) {
_v3.set( - 1, - 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse );
minTarget.set( _v3.x, _v3.y ).multiplyScalar( - distance / _v3.z );
_v3.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse );
maxTarget.set( _v3.x, _v3.y ).multiplyScalar( - distance / _v3.z );
}
/**
* Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction.
*
* @param {number} distance
* @param {Vector2} target - Vector2 target used to store result where x is width and y is height.
* @returns {Vector2}
*/
getViewSize( distance, target ) {
this.getViewBounds( distance, _minTarget, _maxTarget );
return target.subVectors( _maxTarget, _minTarget );
}
/**
* Sets an offset in a larger frustum. This is useful for multi-window or
* multi-monitor/multi-machine setups.
*
* For example, if you have 3x2 monitors and each monitor is 1920x1080 and
* the monitors are in grid like this
*
* +---+---+---+
* | A | B | C |
* +---+---+---+
* | D | E | F |
* +---+---+---+
*
* then for each monitor you would call it like this
*
* const w = 1920;
* const h = 1080;
* const fullWidth = w * 3;
* const fullHeight = h * 2;
*
* --A--
* camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
* --B--
* camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
* --C--
* camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
* --D--
* camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
* --E--
* camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
* --F--
* camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
*
* Note there is no reason monitors have to be the same size or in a grid.
*
* @param {number} fullWidth
* @param {number} fullHeight
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
*/
setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
this.aspect = fullWidth / fullHeight;
if ( this.view === null ) {
this.view = {
enabled: true,
fullWidth: 1,
fullHeight: 1,
offsetX: 0,
offsetY: 0,
width: 1,
height: 1
};
}
this.view.enabled = true;
this.view.fullWidth = fullWidth;
this.view.fullHeight = fullHeight;
this.view.offsetX = x;
this.view.offsetY = y;
this.view.width = width;
this.view.height = height;
this.updateProjectionMatrix();
}
clearViewOffset() {
if ( this.view !== null ) {
this.view.enabled = false;
}
this.updateProjectionMatrix();
}
updateProjectionMatrix() {
const near = this.near;
let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom;
let height = 2 * top;
let width = this.aspect * height;
let left = - 0.5 * width;
const view = this.view;
if ( this.view !== null && this.view.enabled ) {
const fullWidth = view.fullWidth,
fullHeight = view.fullHeight;
left += view.offsetX * width / fullWidth;
top -= view.offsetY * height / fullHeight;
width *= view.width / fullWidth;
height *= view.height / fullHeight;
}
const skew = this.filmOffset;
if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem );
this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
}
toJSON( meta ) {
const data = super.toJSON( meta );
data.object.fov = this.fov;
data.object.zoom = this.zoom;
data.object.near = this.near;
data.object.far = this.far;
data.object.focus = this.focus;
data.object.aspect = this.aspect;
if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
data.object.filmGauge = this.filmGauge;
data.object.filmOffset = this.filmOffset;
return data;
}
}
export { PerspectiveCamera };