UNPKG

trackasia-gl

Version:

BSD licensed community fork of mapbox-gl, a WebGL interactive maps library

59 lines (48 loc) 2.2 kB
import {type mat4, vec3, vec4} from 'gl-matrix'; import {Aabb} from './aabb'; export class Frustum { constructor(public points: vec4[], public planes: vec4[], public aabb: Aabb) { } public static fromInvProjectionMatrix(invProj: mat4, worldSize: number = 1, zoom: number = 0): Frustum { const clipSpaceCorners = [ [-1, 1, -1, 1], [1, 1, -1, 1], [1, -1, -1, 1], [-1, -1, -1, 1], [-1, 1, 1, 1], [1, 1, 1, 1], [1, -1, 1, 1], [-1, -1, 1, 1] ]; const scale = Math.pow(2, zoom); // Transform frustum corner points from clip space to tile space, Z to meters const frustumCoords = clipSpaceCorners.map(v => { v = vec4.transformMat4([] as any, v as any, invProj) as any; const s = 1.0 / v[3] / worldSize * scale; return vec4.mul(v as any, v as any, [s, s, 1.0 / v[3], s] as vec4); }); const frustumPlanePointIndices = [ [0, 1, 2], // near [6, 5, 4], // far [0, 3, 7], // left [2, 1, 5], // right [3, 2, 6], // bottom [0, 4, 5] // top ]; const frustumPlanes = frustumPlanePointIndices.map((p: number[]) => { const a = vec3.sub([] as any, frustumCoords[p[0]] as vec3, frustumCoords[p[1]] as vec3); const b = vec3.sub([] as any, frustumCoords[p[2]] as vec3, frustumCoords[p[1]] as vec3); const n = vec3.normalize([] as any, vec3.cross([] as any, a, b)) as any; const d = -vec3.dot(n, frustumCoords[p[1]] as vec3); return n.concat(d); }); const min: vec3 = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY]; const max: vec3 = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY]; for (const p of frustumCoords) { for (let i = 0; i < 3; i++) { min[i] = Math.min(min[i], p[i]); max[i] = Math.max(max[i], p[i]); } } return new Frustum(frustumCoords, frustumPlanes, new Aabb(min, max)); } }