Home Reference Source

viewer/frustum.js

import * as mat4 from "./glmatrix/mat4.js";
import * as vec3 from "./glmatrix/vec3.js";

import {FrustumPlane} from "./frustumplane.js";

/**
 * Frustum for fast World-space frustum-AABB collision testing
 * 
 * @class Frustum
 */
export class Frustum {

    constructor() {
    	this.tempMat4 = mat4.create();
    	
        this.planes = [ // Allocate now, init when needed
            new FrustumPlane(),
            new FrustumPlane(),
            new FrustumPlane(),
            new FrustumPlane(),
            new FrustumPlane(),
            new FrustumPlane()
        ];
    }

    init(viewMatrix, projMatrix) { // Builds frustum planes} from view and projection matrices
        var m = this.tempMat4;
        mat4.multiply(m, projMatrix, viewMatrix);
        var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
        var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7];
        var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11];
        var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15];
        this.planes[0].init(m3 - m0, m7 - m4, m11 - m8, m15 - m12);
        this.planes[1].init(m3 + m0, m7 + m4, m11 + m8, m15 + m12);
        this.planes[2].init(m3 - m1, m7 - m5, m11 - m9, m15 - m13);
        this.planes[3].init(m3 + m1, m7 + m5, m11 + m9, m15 + m13);
        this.planes[4].init(m3 - m2, m7 - m6, m11 - m10, m15 - m14);
        this.planes[5].init(m3 + m2, m7 + m6, m11 + m10, m15 + m14);
    }

    // Tests for intersection with World-space AABB, which is assumed to be: [xmin, ymin, zmin, xwidth, ywidth, zwidth]
    intersectsWorldAABB(minmax) {
        var result = Frustum.INSIDE_FRUSTUM;
        var plane = null;
        var normal;
        var offset;
        var testVertex;
        for (var i = 0; i < 6; ++i) {
            plane = this.planes[i];
            normal = plane.normal;
            offset = plane.offset;
            testVertex = plane.testVertex;
            if (((normal[0] * minmax[testVertex[0]][0]) + (normal[1] * minmax[testVertex[1]][1]) + (normal[2] * minmax[testVertex[2]][2]) + (offset)) < 0.0) {
                return Frustum.OUTSIDE_FRUSTUM;
            }
            if (((normal[0] * minmax[1 - testVertex[0]][0]) + (normal[1] * minmax[1 - testVertex[1]][1]) + (normal[2] * minmax[1 - testVertex[2]][2]) + (offset)) < 0.0) {
                result = Frustum.INTERSECT_FRUSTUM; // May still become OUTSIDE_FRUSTUM
            }
        }
        return result;
    }
}

Frustum.OUTSIDE_FRUSTUM = 0;
Frustum.INTERSECT_FRUSTUM = 1;
Frustum.INSIDE_FRUSTUM = 2;