Home Reference Source

src/Frustum.js

import { Plane } from "./Plane.js";
import { Vector3 } from "./Vector3.js";

/**
 * A vector.
 *
 * @type {Vector3}
 * @private
 */

const v = new Vector3();

/**
 * A frustum.
 */

export class Frustum {

	/**
	 * Constructs a new frustum.
	 *
	 * @param {Plane} [p0] - A plane.
	 * @param {Plane} [p1] - A plane.
	 * @param {Plane} [p2] - A plane.
	 * @param {Plane} [p3] - A plane.
	 * @param {Plane} [p4] - A plane.
	 * @param {Plane} [p5] - A plane.
	 */

	constructor(
		p0 = new Plane(),
		p1 = new Plane(),
		p2 = new Plane(),
		p3 = new Plane(),
		p4 = new Plane(),
		p5 = new Plane()
	) {

		/**
		 * The six planes that form the frustum.
		 *
		 * @type {Plane[]}
		 */

		this.planes = [p0, p1, p2, p3, p4, p5];

	}

	/**
	 * Sets the planes of this frustum.
	 *
	 * @param {Plane} [p0] - A plane.
	 * @param {Plane} [p1] - A plane.
	 * @param {Plane} [p2] - A plane.
	 * @param {Plane} [p3] - A plane.
	 * @param {Plane} [p4] - A plane.
	 * @param {Plane} [p5] - A plane.
	 * @return {Frustum} This frustum.
	 */

	set(p0, p1, p2, p3, p4, p5) {

		const planes = this.planes;

		planes[0].copy(p0);
		planes[1].copy(p1);
		planes[2].copy(p2);
		planes[3].copy(p3);
		planes[4].copy(p4);
		planes[5].copy(p5);

		return this;

	}

	/**
	 * Clones this frustum.
	 *
	 * @return {Frustum} The cloned frustum.
	 */

	clone() {

		return new this.constructor().copy(this);

	}

	/**
	 * Copies a given frustum.
	 *
	 * @param {Frustum} frustum - A frustum.
	 * @return {Frustum} This frustum.
	 */

	copy(frustum) {

		const planes = this.planes;

		let i;

		for(i = 0; i < 6; ++i) {

			planes[i].copy(frustum.planes[i]);

		}

		return this;

	}

	/**
	 * Sets this frustum based on a given projection matrix.
	 *
	 * @param {Matrix4} m - A matrix.
	 * @return {Frustum} This frustum.
	 * @deprecated Use setFromPerspectiveMatrix instead.
	 */

	setFromMatrix(m) {

		return this.setFromProjectionMatrix(m);

	}

	/**
	 * Sets this frustum based on a given projection matrix.
	 *
	 * @param {Matrix4} m - A matrix.
	 * @return {Frustum} This frustum.
	 */

	setFromProjectionMatrix(m) {

		const planes = this.planes;

		const me = m.elements;
		const me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
		const me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
		const me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
		const me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];

		planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize();
		planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize();
		planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize();
		planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize();
		planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize();
		planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize();

		return this;

	}

	/**
	 * Checks if this frustum intersects with the given sphere.
	 *
	 * @param {Sphere} sphere - A sphere.
	 * @return {Boolean} Whether this frustum intersects with the sphere.
	 */

	intersectsSphere(sphere) {

		const planes = this.planes;
		const center = sphere.center;
		const negativeRadius = -sphere.radius;

		let result = true;
		let i, d;

		for(i = 0; i < 6; ++i) {

			d = planes[i].distanceToPoint(center);

			if(d < negativeRadius) {

				result = false;
				break;

			}

		}

		return result;

	}

	/**
	 * Checks if this frustum intersects with the given sphere.
	 *
	 * @param {Box3} box - A box.
	 * @return {Boolean} Whether this frustum intersects with the box.
	 */

	intersectsBox(box) {

		const planes = this.planes;
		const min = box.min, max = box.max;

		let i, plane;

		for(i = 0; i < 6; ++i) {

			plane = planes[i];

			// Corner at max distance.
			v.x = (plane.normal.x > 0.0) ? max.x : min.x;
			v.y = (plane.normal.y > 0.0) ? max.y : min.y;
			v.z = (plane.normal.z > 0.0) ? max.z : min.z;

			if(plane.distanceToPoint(v) < 0.0) {

				return false;

			}

		}

		return true;

	}

	/**
	 * Checks if this frustum contains the given point.
	 *
	 * @param {Vector3} point - A point.
	 * @return {Boolean} Whether this frustum contains the point.
	 */

	containsPoint(point) {

		const planes = this.planes;

		let result = true;
		let i;

		for(i = 0; i < 6; ++i) {

			if(planes[i].distanceToPoint(point) < 0) {

				result = false;
				break;

			}

		}

		return result;

	}

}