/**
* Copyright 2012 Jason Sorensen (sorensenj@smert.net)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.smert.frameworkgl.math;
/**
*
* @author Jason Sorensen <sorensenj@smert.net>
*/
public class ClipPlanes {
// Bottom
float bpW;
float bpX;
float bpY;
float bpZ;
// Far
float fpW;
float fpX;
float fpY;
float fpZ;
// Left
float lpW;
float lpX;
float lpY;
float lpZ;
// Near
float npW;
float npX;
float npY;
float npZ;
// Right
float rpW;
float rpX;
float rpY;
float rpZ;
// Top
float tpW;
float tpX;
float tpY;
float tpZ;
// Thresholds
float bpThreshold;
float fpThreshold;
float lpThreshold;
float npThreshold;
float rpThreshold;
float tpThreshold;
public ClipPlanes() {
reset();
}
public boolean planeAABBEquation(Vector3f aabbMin, Vector3f aabbMax) {
// This will fail if the AABB is larger than the frustum
// Vertex minX minY minZ (0)
float npXMinX = npX * aabbMin.x;
float npYMinY = npY * aabbMin.y;
float npZMinZ = npZ * aabbMin.z;
float fpXMinX = fpX * aabbMin.x;
float fpYMinY = fpY * aabbMin.y;
float fpZMinZ = fpZ * aabbMin.z;
float lpXMinX = lpX * aabbMin.x;
float lpYMinY = lpY * aabbMin.y;
float lpZMinZ = lpZ * aabbMin.z;
float rpXMinX = rpX * aabbMin.x;
float rpYMinY = rpY * aabbMin.y;
float rpZMinZ = rpZ * aabbMin.z;
float bpXMinX = bpX * aabbMin.x;
float bpYMinY = bpY * aabbMin.y;
float bpZMinZ = bpZ * aabbMin.z;
float tpXMinX = tpX * aabbMin.x;
float tpYMinY = tpY * aabbMin.y;
float tpZMinZ = tpZ * aabbMin.z;
if (((npXMinX + npYMinY + npZMinZ + npW) > npThreshold)
&& ((fpXMinX + fpYMinY + fpZMinZ + fpW) > fpThreshold)
&& ((lpXMinX + lpYMinY + lpZMinZ + lpW) > lpThreshold)
&& ((rpXMinX + rpYMinY + rpZMinZ + rpW) > rpThreshold)
&& ((bpXMinX + bpYMinY + bpZMinZ + bpW) > bpThreshold)
&& ((tpXMinX + tpYMinY + tpZMinZ + tpW) > tpThreshold)) {
return true;
}
// Vertex minX minY maxZ (1)
float npZMaxZ = npZ * aabbMax.z;
float fpZMaxZ = fpZ * aabbMax.z;
float lpZMaxZ = lpZ * aabbMax.z;
float rpZMaxZ = rpZ * aabbMax.z;
float bpZMaxZ = bpZ * aabbMax.z;
float tpZMaxZ = tpZ * aabbMax.z;
if (((npXMinX + npYMinY + npZMaxZ + npW) > npThreshold)
&& ((fpXMinX + fpYMinY + fpZMaxZ + fpW) > fpThreshold)
&& ((lpXMinX + lpYMinY + lpZMaxZ + lpW) > lpThreshold)
&& ((rpXMinX + rpYMinY + rpZMaxZ + rpW) > rpThreshold)
&& ((bpXMinX + bpYMinY + bpZMaxZ + bpW) > bpThreshold)
&& ((tpXMinX + tpYMinY + tpZMaxZ + tpW) > tpThreshold)) {
return true;
}
// Vertex minX maxY minZ (2)
float npYMaxY = npY * aabbMax.y;
float fpYMaxY = fpY * aabbMax.y;
float lpYMaxY = lpY * aabbMax.y;
float rpYMaxY = rpY * aabbMax.y;
float bpYMaxY = bpY * aabbMax.y;
float tpYMaxY = tpY * aabbMax.y;
if (((npXMinX + npYMaxY + npZMinZ + npW) > npThreshold)
&& ((fpXMinX + fpYMaxY + fpZMinZ + fpW) > fpThreshold)
&& ((lpXMinX + lpYMaxY + lpZMinZ + lpW) > lpThreshold)
&& ((rpXMinX + rpYMaxY + rpZMinZ + rpW) > rpThreshold)
&& ((bpXMinX + bpYMaxY + bpZMinZ + bpW) > bpThreshold)
&& ((tpXMinX + tpYMaxY + tpZMinZ + tpW) > tpThreshold)) {
return true;
}
// Vertex minX maxY maxZ (3)
if (((npXMinX + npYMaxY + npZMaxZ + npW) > npThreshold)
&& ((fpXMinX + fpYMaxY + fpZMaxZ + fpW) > fpThreshold)
&& ((lpXMinX + lpYMaxY + lpZMaxZ + lpW) > lpThreshold)
&& ((rpXMinX + rpYMaxY + rpZMaxZ + rpW) > rpThreshold)
&& ((bpXMinX + bpYMaxY + bpZMaxZ + bpW) > bpThreshold)
&& ((tpXMinX + tpYMaxY + tpZMaxZ + tpW) > tpThreshold)) {
return true;
}
// Vertex maxX minY minZ (4)
float npXMaxX = npX * aabbMax.x;
float fpXMaxX = fpX * aabbMax.x;
float lpXMaxX = lpX * aabbMax.x;
float rpXMaxX = rpX * aabbMax.x;
float bpXMaxX = bpX * aabbMax.x;
float tpXMaxX = tpX * aabbMax.x;
if (((npXMaxX + npYMinY + npZMinZ + npW) > npThreshold)
&& ((fpXMaxX + fpYMinY + fpZMinZ + fpW) > fpThreshold)
&& ((lpXMaxX + lpYMinY + lpZMinZ + lpW) > lpThreshold)
&& ((rpXMaxX + rpYMinY + rpZMinZ + rpW) > rpThreshold)
&& ((bpXMaxX + bpYMinY + bpZMinZ + bpW) > bpThreshold)
&& ((tpXMaxX + tpYMinY + tpZMinZ + tpW) > tpThreshold)) {
return true;
}
// Vertex maxX minY maxZ (5)
if (((npXMaxX + npYMinY + npZMaxZ + npW) > npThreshold)
&& ((fpXMaxX + fpYMinY + fpZMaxZ + fpW) > fpThreshold)
&& ((lpXMaxX + lpYMinY + lpZMaxZ + lpW) > lpThreshold)
&& ((rpXMaxX + rpYMinY + rpZMaxZ + rpW) > rpThreshold)
&& ((bpXMaxX + bpYMinY + bpZMaxZ + bpW) > bpThreshold)
&& ((tpXMaxX + tpYMinY + tpZMaxZ + tpW) > tpThreshold)) {
return true;
}
// Vertex maxX maxY minZ (6)
if (((npXMaxX + npYMaxY + npZMinZ + npW) > npThreshold)
&& ((fpXMaxX + fpYMaxY + fpZMinZ + fpW) > fpThreshold)
&& ((lpXMaxX + lpYMaxY + lpZMinZ + lpW) > lpThreshold)
&& ((rpXMaxX + rpYMaxY + rpZMinZ + rpW) > rpThreshold)
&& ((bpXMaxX + bpYMaxY + bpZMinZ + bpW) > bpThreshold)
&& ((tpXMaxX + tpYMaxY + tpZMinZ + tpW) > tpThreshold)) {
return true;
}
// Vertex maxX maxY maxZ
if (((npXMaxX + npYMaxY + npZMaxZ + npW) > npThreshold)
&& ((fpXMaxX + fpYMaxY + fpZMaxZ + fpW) > fpThreshold)
&& ((lpXMaxX + lpYMaxY + lpZMaxZ + lpW) > lpThreshold)
&& ((rpXMaxX + rpYMaxY + rpZMaxZ + rpW) > rpThreshold)
&& ((bpXMaxX + bpYMaxY + bpZMaxZ + bpW) > bpThreshold)
&& ((tpXMaxX + tpYMaxY + tpZMaxZ + tpW) > tpThreshold)) {
return true;
}
// AABB is not in the frustum or it is bigger than so we do a proximity
// test. This gives us false positives but does not ruin the user
// experience by having objects that pop in and out of the frustum.
Vector3f center = new Vector3f(aabbMin).add(aabbMax).multiply(.5f);
Vector3f extent = new Vector3f(aabbMax).subtract(aabbMin).multiply(.5f);
float maxExtent = MathHelper.Sqrt(extent.dot(extent));
return planePointEquation(center, maxExtent);
}
public boolean planePointEquation(float x, float y, float z, float threshold) {
boolean result;
result = ((npX * x + npY * y + npZ * z + npW) > (-threshold + npThreshold));
if (!result) {
return result;
}
result = ((fpX * x + fpY * y + fpZ * z + fpW) > (-threshold + fpThreshold));
if (!result) {
return result;
}
result = ((lpX * x + lpY * y + lpZ * z + lpW) > (-threshold + lpThreshold));
if (!result) {
return result;
}
result = ((rpX * x + rpY * y + rpZ * z + rpW) > (-threshold + rpThreshold));
if (!result) {
return result;
}
result = ((bpX * x + bpY * y + bpZ * z + bpW) > (-threshold + bpThreshold));
if (!result) {
return result;
}
result = ((tpX * x + tpY * y + tpZ * z + tpW) > (-threshold + tpThreshold));
return result;
}
public boolean planePointEquation(Vector3f v, float threshold) {
return planePointEquation(v.x, v.y, v.z, threshold);
}
public void normalize() {
float invMag;
// W component must NOT be a part of the inverse magnitude
invMag = 1f / MathHelper.Sqrt(npX * npX + npY * npY + npZ * npZ);
npW *= invMag; // We still normalize it though
npX *= invMag;
npY *= invMag;
npZ *= invMag;
invMag = 1f / MathHelper.Sqrt(fpX * fpX + fpY * fpY + fpZ * fpZ);
fpW *= invMag;
fpX *= invMag;
fpY *= invMag;
fpZ *= invMag;
invMag = 1f / MathHelper.Sqrt(lpX * lpX + lpY * lpY + lpZ * lpZ);
lpW *= invMag;
lpX *= invMag;
lpY *= invMag;
lpZ *= invMag;
invMag = 1f / MathHelper.Sqrt(rpX * rpX + rpY * rpY + rpZ * rpZ);
rpW *= invMag;
rpX *= invMag;
rpY *= invMag;
rpZ *= invMag;
invMag = 1f / MathHelper.Sqrt(bpX * bpX + bpY * bpY + bpZ * bpZ);
bpW *= invMag;
bpX *= invMag;
bpY *= invMag;
bpZ *= invMag;
invMag = 1f / MathHelper.Sqrt(tpX * tpX + tpY * tpY + tpZ * tpZ);
tpW *= invMag;
tpX *= invMag;
tpY *= invMag;
tpZ *= invMag;
}
public final void reset() {
bpW = 0f;
bpX = 0f;
bpY = 0f;
bpZ = 0f;
fpW = 0f;
fpX = 0f;
fpY = 0f;
fpZ = 0f;
lpW = 0f;
lpX = 0f;
lpY = 0f;
lpZ = 0f;
npW = 0f;
npX = 0f;
npY = 0f;
npZ = 0f;
rpW = 0f;
rpX = 0f;
rpY = 0f;
rpZ = 0f;
tpW = 0f;
tpX = 0f;
tpY = 0f;
tpZ = 0f;
bpThreshold = 0f;
fpThreshold = 0f;
lpThreshold = 0f;
npThreshold = 0f;
rpThreshold = 0f;
tpThreshold = 0f;
}
}