// 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