UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

102 lines (101 loc) 2.83 kB
import { Plane } from "./plane.js"; import { Vec3 } from "../math/vec3.js"; const _c23 = new Vec3(); const _c31 = new Vec3(); const _c12 = new Vec3(); const _corner = new Vec3(); function intersectPlanes(p1, p2, p3, out) { _c23.cross(p2.normal, p3.normal); const denom = p1.normal.dot(_c23); if (Math.abs(denom) < 1e-6) { return false; } _c31.cross(p3.normal, p1.normal); _c12.cross(p1.normal, p2.normal); const invDenom = -1 / denom; out.set( (p1.distance * _c23.x + p2.distance * _c31.x + p3.distance * _c12.x) * invDenom, (p1.distance * _c23.y + p2.distance * _c31.y + p3.distance * _c12.y) * invDenom, (p1.distance * _c23.z + p2.distance * _c31.z + p3.distance * _c12.z) * invDenom ); return isFinite(out.x) && isFinite(out.y) && isFinite(out.z); } class Frustum { planes = []; constructor() { for (let i = 0; i < 6; i++) { this.planes[i] = new Plane(); } } clone() { const cstr = this.constructor; return new cstr().copy(this); } copy(src) { for (let i = 0; i < 6; i++) { this.planes[i].copy(src.planes[i]); } return this; } setFromMat4(matrix) { const d = matrix.data; const m00 = d[0], m01 = d[1], m02 = d[2], m03 = d[3]; const m10 = d[4], m11 = d[5], m12 = d[6], m13 = d[7]; const m20 = d[8], m21 = d[9], m22 = d[10], m23 = d[11]; const m30 = d[12], m31 = d[13], m32 = d[14], m33 = d[15]; const planes = this.planes; planes[0].set(m03 - m00, m13 - m10, m23 - m20, m33 - m30).normalize(); planes[1].set(m03 + m00, m13 + m10, m23 + m20, m33 + m30).normalize(); planes[2].set(m03 + m01, m13 + m11, m23 + m21, m33 + m31).normalize(); planes[3].set(m03 - m01, m13 - m11, m23 - m21, m33 - m31).normalize(); planes[4].set(m03 - m02, m13 - m12, m23 - m22, m33 - m32).normalize(); planes[5].set(m03 + m02, m13 + m12, m23 + m22, m33 + m32).normalize(); } containsPoint(point) { for (let p = 0; p < 6; p++) { const { normal, distance } = this.planes[p]; if (normal.dot(point) + distance <= 0) { return false; } } return true; } add(other) { const planes = this.planes; const op = other.planes; for (let zi = 4; zi <= 5; zi++) { for (let xi = 0; xi <= 1; xi++) { for (let yi = 2; yi <= 3; yi++) { if (intersectPlanes(op[zi], op[xi], op[yi], _corner)) { for (let p = 0; p < 6; p++) { const plane = planes[p]; const d = plane.normal.dot(_corner) + plane.distance; if (d < 0) { plane.distance -= d; } } } } } } return this; } containsSphere(sphere) { const { center, radius } = sphere; let c = 0; for (let p = 0; p < 6; p++) { const { normal, distance } = this.planes[p]; const d = normal.dot(center) + distance; if (d <= -radius) { return 0; } if (d > radius) { c++; } } return c === 6 ? 2 : 1; } } export { Frustum };