// math.gl // SPDX-License-Identifier: MIT and Apache-2.0 // Copyright (c) vis.gl contributors import { assert, Vector2 } from '@math.gl/core'; import { PerspectiveOffCenterFrustum } from "./perspective-off-center-frustum.js"; const defined = (val) => val !== null && typeof val !== 'undefined'; /** * The viewing frustum is defined by 6 planes. * Each plane is represented by a {@link Vector4} object, where the x, y, and z components * define the unit vector normal to the plane, and the w component is the distance of the * plane from the origin/camera position. * * @alias PerspectiveFrustum * * @example * var frustum = new PerspectiveFrustum({ * fov : Math.PI_OVER_THREE, * aspectRatio : canvas.clientWidth / canvas.clientHeight * near : 1.0, * far : 1000.0 * }); * * @see PerspectiveOffCenterFrustum */ export class PerspectiveFrustum { constructor(options = {}) { this._offCenterFrustum = new PerspectiveOffCenterFrustum(); const { fov, aspectRatio, near = 1.0, far = 500000000.0, xOffset = 0.0, yOffset = 0.0 } = options; this.fov = fov; this.aspectRatio = aspectRatio; this.near = near; this.far = far; this.xOffset = xOffset; this.yOffset = yOffset; } /** * Returns a duplicate of a PerspectiveFrustum instance. */ clone() { return new PerspectiveFrustum({ aspectRatio: this.aspectRatio, fov: this.fov, near: this.near, far: this.far }); } /** * Compares the provided PerspectiveFrustum componentwise and returns * true if they are equal, false otherwise. */ equals(other) { if (!defined(other) || !(other instanceof PerspectiveFrustum)) { return false; } this._update(); other._update(); return (this.fov === other.fov && this.aspectRatio === other.aspectRatio && this.near === other.near && this.far === other.far && this._offCenterFrustum.equals(other._offCenterFrustum)); } /** * Gets the perspective projection matrix computed from the view this. */ get projectionMatrix() { this._update(); return this._offCenterFrustum.projectionMatrix; } /** * The perspective projection matrix computed from the view frustum with an infinite far plane. */ get infiniteProjectionMatrix() { this._update(); return this._offCenterFrustum.infiniteProjectionMatrix; } /** * Gets the angle of the vertical field of view, in radians. */ get fovy() { this._update(); return this._fovy; } /** * @private */ get sseDenominator() { this._update(); return this._sseDenominator; } /** * Creates a culling volume for this this.ion. * @returns {CullingVolume} A culling volume at the given position and orientation. * * @example * // Check if a bounding volume intersects the this. * var cullingVolume = this.computeCullingVolume(cameraPosition, cameraDirection, cameraUp); * var intersect = cullingVolume.computeVisibility(boundingVolume); */ computeCullingVolume( /** A Vector3 defines the eye position. */ position, /** A Vector3 defines the view direction. */ direction, /** A Vector3 defines the up direction. */ up) { this._update(); return this._offCenterFrustum.computeCullingVolume(position, direction, up); } /** * Returns the pixel's width and height in meters. * @returns {Vector2} The modified result parameter or a new instance of {@link Vector2} with the pixel's width and height in the x and y properties, respectively. * * @exception {DeveloperError} drawingBufferWidth must be greater than zero. * @exception {DeveloperError} drawingBufferHeight must be greater than zero. * * @example * // Example 1 * // Get the width and height of a pixel. * var pixelSize = camera.this.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, new Vector2()); * * @example * // Example 2 * // Get the width and height of a pixel if the near plane was set to 'distance'. * // For example, get the size of a pixel of an image on a billboard. * var position = camera.position; * var direction = camera.direction; * var toCenter = Vector3.subtract(primitive.boundingVolume.center, position, new Vector3()); // vector from camera to a primitive * var toCenterProj = Vector3.multiplyByScalar(direction, Vector3.dot(direction, toCenter), new Vector3()); // project vector onto camera direction vector * var distance = Vector3.magnitude(toCenterProj); * var pixelSize = camera.this.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, new Vector2()); */ getPixelDimensions( /** The width of the drawing buffer. */ drawingBufferWidth, /** The height of the drawing buffer. */ drawingBufferHeight, /** The distance to the near plane in meters. */ distance, /** The object onto which to store the result. */ result) { this._update(); return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result || new Vector2()); } // eslint-disable-next-line complexity, max-statements _update() { assert(Number.isFinite(this.fov) && Number.isFinite(this.aspectRatio) && Number.isFinite(this.near) && Number.isFinite(this.far)); // 'fov, aspectRatio, near, or far parameters are not set.' const f = this._offCenterFrustum; if (this.fov !== this._fov || this.aspectRatio !== this._aspectRatio || this.near !== this._near || this.far !== this._far || this.xOffset !== this._xOffset || this.yOffset !== this._yOffset) { assert(this.fov >= 0 && this.fov < Math.PI); // throw new DeveloperError('fov must be in the range [0, PI).'); assert(this.aspectRatio > 0); // throw new DeveloperError('aspectRatio must be positive.'); assert(this.near >= 0 && this.near < this.far); // throw new DeveloperError('near must be greater than zero and less than far.'); this._aspectRatio = this.aspectRatio; this._fov = this.fov; this._fovy = this.aspectRatio <= 1 ? this.fov : Math.atan(Math.tan(this.fov * 0.5) / this.aspectRatio) * 2.0; this._near = this.near; this._far = this.far; this._sseDenominator = 2.0 * Math.tan(0.5 * this._fovy); this._xOffset = this.xOffset; this._yOffset = this.yOffset; f.top = this.near * Math.tan(0.5 * this._fovy); f.bottom = -f.top; f.right = this.aspectRatio * f.top; f.left = -f.right; f.near = this.near; f.far = this.far; f.right += this.xOffset; f.left += this.xOffset; f.top += this.yOffset; f.bottom += this.yOffset; } } } //# sourceMappingURL=perspective-frustum.js.map