
com.flowpowered.commons.ViewFrustum Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of flow-commons Show documentation
Show all versions of flow-commons Show documentation
A library for Java that provides re-usable components commonly used by Flow libraries.
The newest version!
/*
* This file is part of Flow Commons, licensed under the MIT License (MIT).
*
* Copyright (c) 2013 Flow Powered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.flowpowered.commons;
import com.flowpowered.math.matrix.Matrix3f;
import com.flowpowered.math.matrix.Matrix4f;
import com.flowpowered.math.vector.Vector3f;
import com.flowpowered.math.vector.Vector4f;
/**
* A view frustum defined by the camera view and projection. Used to check for intersection with object to determine whether or not they're visible.
*/
public class ViewFrustum {
private final float[][] frustum = new float[6][4];
private Vector3f[] vertices;
private Vector3f position;
private float nearPlane = -1, farPlane = -1;
/**
* Updates the frustum to match the view and projection matrix.
*
* @param projection The projection matrix
* @param view The view matrix
*/
public void update(Matrix4f projection, Matrix4f view) {
// http://www.crownandcutlass.com/features/technicaldetails/frustum.html
final float[] clip = projection.mul(view).toArray(true);
// Extract the numbers for the RIGHT plane
frustum[0][0] = clip[3] - clip[0];
frustum[0][1] = clip[7] - clip[4];
frustum[0][2] = clip[11] - clip[8];
frustum[0][3] = clip[15] - clip[12];
// Extract the numbers for the LEFT plane
frustum[1][0] = clip[3] + clip[0];
frustum[1][1] = clip[7] + clip[4];
frustum[1][2] = clip[11] + clip[8];
frustum[1][3] = clip[15] + clip[12];
// Extract the BOTTOM plane
frustum[2][0] = clip[3] + clip[1];
frustum[2][1] = clip[7] + clip[5];
frustum[2][2] = clip[11] + clip[9];
frustum[2][3] = clip[15] + clip[13];
// Extract the TOP plane
frustum[3][0] = clip[3] - clip[1];
frustum[3][1] = clip[7] - clip[5];
frustum[3][2] = clip[11] - clip[9];
frustum[3][3] = clip[15] - clip[13];
// Extract the FAR plane
frustum[4][0] = clip[3] - clip[2];
frustum[4][1] = clip[7] - clip[6];
frustum[4][2] = clip[11] - clip[10];
frustum[4][3] = clip[15] - clip[14];
// Extract the NEAR plane
frustum[5][0] = clip[3] + clip[2];
frustum[5][1] = clip[7] + clip[6];
frustum[5][2] = clip[11] + clip[10];
frustum[5][3] = clip[15] + clip[14];
// Compute the position
// http://www.opengl.org/discussion_boards/showthread.php/178484-Extracting-camera-position-from-a-ModelView-Matrix
final Vector4f nPos = view.invert().getColumn(3);
position = nPos.div(nPos.getW()).toVector3();
// Invalidate the caches
vertices = null;
farPlane = -1;
nearPlane = -1;
}
/**
* Returns a new array containing the vertices of the frustum. They are in the following order, given by the intersection of the planes:
*
* RIGHT - TOP - NEAR
*
* RIGHT - TOP - FAR
*
* RIGHT - BOTTOM - NEAR
*
* RIGHT - BOTTOM - FAR
*
* LEFT - TOP - NEAR
*
* LEFT - TOP - FAR
*
* LEFT - BOTTOM - NEAR
*
* LEFT - BOTTOM - FAR
*
* @return An array containing the frustum vertices
*/
public Vector3f[] getVertices() {
if (vertices == null) {
// Recalculate the points if the cache is invalid
computeVertices();
}
return vertices.clone();
}
private void computeVertices() {
vertices = new Vector3f[8];
// RIGHT - TOP - NEAR
vertices[0] = getIntersection(0, 3, 5);
// RIGHT - TOP - FAR
vertices[1] = getIntersection(0, 3, 4);
// RIGHT - BOTTOM - NEAR
vertices[2] = getIntersection(0, 2, 5);
// RIGHT - BOTTOM - FAR
vertices[3] = getIntersection(0, 2, 4);
// LEFT - TOP - NEAR
vertices[4] = getIntersection(1, 3, 5);
// LEFT - TOP - FAR
vertices[5] = getIntersection(1, 3, 4);
// LEFT - BOTTOM - NEAR
vertices[6] = getIntersection(1, 2, 5);
// LEFT - BOTTOM - FAR
vertices[7] = getIntersection(1, 2, 4);
}
private Vector3f getIntersection(int p1, int p2, int p3) {
/*
Intersection of 3 planes
p1: ax + by + cz + d = 0
p2: ex + fy + gz + h = 0
p3: ix + jy + kz + l = 0
|a b c||x| |-d|
|e f g||y| = |-h|
|i j k||z| |-l|
A * r = b
r = (A^-1) * b
r is our point of intersection
*/
final Matrix3f a = new Matrix3f(
frustum[p1][0], frustum[p1][1], frustum[p1][2],
frustum[p2][0], frustum[p2][1], frustum[p2][2],
frustum[p3][0], frustum[p3][1], frustum[p3][2]
);
final Vector3f b = new Vector3f(
-frustum[p1][3], -frustum[p2][3], -frustum[p3][3]
);
final Matrix3f aInv = a.invert();
if (aInv == null) {
return null;
}
return aInv.transform(b);
}
/**
* Returns the position of the frustum.
*
* @return The frustum position
*/
public Vector3f getPosition() {
return position;
}
/**
* Returns the near plane distance of the frustum.
*
* @return The near plane
*/
public float getNearPlane() {
if (nearPlane == -1) {
// Recalculate the distance if the cache is invalid
final Vector3f nearPos = vertices[0].add(vertices[2]).add(vertices[4]).add(vertices[6]).div(4);
nearPlane = nearPos.sub(position).length();
}
return nearPlane;
}
/**
* Returns the far plane distance of the frustum.
*
* @return The far plane
*/
public float getFarPlane() {
if (farPlane == -1) {
// Recalculate the distance if the cache is invalid
final Vector3f farPos = vertices[1].add(vertices[3]).add(vertices[5]).add(vertices[7]).div(4);
farPlane = farPos.sub(position).length();
}
return farPlane;
}
/**
* Compute the distance between a point and the given plane.
*
* @param i The id of the plane
* @param x The x coordinate of the point
* @param y The y coordinate of the point
* @param z The z coordinate of the point
* @return The distance
*/
private float distance(int i, float x, float y, float z) {
return frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3];
}
/**
* Checks if the frustum of this camera intersects the given cuboid vertices.
*
* @param vertices The cuboid local vertices to check the frustum against
* @param position The position of the cuboid
* @return Whether or not the frustum intersects the cuboid
*/
public boolean intersectsCuboid(Vector3f[] vertices, Vector3f position) {
return intersectsCuboid(vertices, position.getX(), position.getY(), position.getZ());
}
/**
* Checks if the frustum of this camera intersects the given cuboid vertices.
*
* @param vertices The cuboid local vertices to check the frustum against
* @param x The x coordinate of the cuboid position
* @param y The y coordinate of the cuboid position
* @param z The z coordinate of the cuboid position
* @return Whether or not the frustum intersects the cuboid
*/
public boolean intersectsCuboid(Vector3f[] vertices, float x, float y, float z) {
if (vertices.length != 8) {
throw new IllegalArgumentException("A cuboid has 8 vertices, not " + vertices.length);
}
planes:
for (int i = 0; i < 6; i++) {
for (Vector3f vertex : vertices) {
if (distance(i, vertex.getX() + x, vertex.getY() + y, vertex.getZ() + z) > 0) {
continue planes;
}
}
return false;
}
return true;
}
/**
* Checks if the frustum contains the given point.
*
* @param point The point to check if the frustum contains
* @return True if the frustum contains the point
*/
public boolean contains(Vector3f point) {
return contains(point.getX(), point.getY(), point.getZ());
}
/**
* Checks if the frustum contains the given point.
*
* @param x The x coordinate of the point
* @param y The y coordinate of the point
* @param z The z coordinate of the point
* @return True if the frustum contains the point
*/
public boolean contains(float x, float y, float z) {
for (int i = 0; i < 6; i++) {
if (distance(i, x, y, z) <= 0) {
return false;
}
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy