diff options
Diffstat (limited to 'lib/glfrustum.h')
-rw-r--r-- | lib/glfrustum.h | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/lib/glfrustum.h b/lib/glfrustum.h new file mode 100644 index 0000000..03a3827 --- /dev/null +++ b/lib/glfrustum.h @@ -0,0 +1,217 @@ +// GLFrustum.h +// Code by Richard S. Wright Jr. +// Encapsulates a frustum... works in conjunction +// with GLFrame + +#include "math3d.h" +#include "glframe.h" + +#ifndef __GL_FRAME_CLASS +#define __GL_FRAME_CLASS + +class GLFrustum +{ + public: + // Set some Reasonable Defaults + GLFrustum(void) + { Set(30.0f, 1.0, 1.0, 10.0); } + + // Set the View Frustum + GLFrustum(float fFov, float fAspect, float fNear, float fFar) + { Set(fFov, fAspect, fNear, fFar); } + + // Calculates the corners of the Frustum and sets the projection matrix. + // Switches to projection matrix before returning + void Set(float fFov, float fAspect, float fNear, float fFar) + { + float xmin, xmax, ymin, ymax; // Dimensions of near clipping plane + float xFmin, xFmax, yFmin, yFmax; // Dimensions of far clipping plane + + // Do the Math for the near clipping plane + ymax = fNear * float(tan( fFov * M3D_PI / 360.0 )); + ymin = -ymax; + xmin = ymin * fAspect; + xmax = -xmin; + + // Do the Math for the far clipping plane + yFmax = fFar * float(tan(fFov * M3D_PI / 360.0)); + yFmin = -yFmax; + xFmin = yFmin * fAspect; + xFmax = -xFmin; + + // Do the GL + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( xmin, xmax, ymin, ymax, fNear, fFar ); + glMatrixMode(GL_MODELVIEW); + + // Fill in values for untransformed Frustum corners + // Near Upper Left + nearUL[0] = xmin; nearUL[1] = ymax; nearUL[2] = -fNear; nearUL[3] = 1.0f; + + // Near Lower Left + nearLL[0] = xmin; nearLL[1] = ymin; nearLL[2] = -fNear; nearLL[3] = 1.0f; + + // Near Upper Right + nearUR[0] = xmax; nearUR[1] = ymax; nearUR[2] = -fNear; nearUR[3] = 1.0f; + + // Near Lower Right + nearLR[0] = xmax; nearLR[1] = ymin; nearLR[2] = -fNear; nearLR[3] = 1.0f; + + // Far Upper Left + farUL[0] = xFmin; farUL[1] = yFmax; farUL[2] = -fFar; farUL[3] = 1.0f; + + // Far Lower Left + farLL[0] = xFmin; farLL[1] = yFmin; farLL[2] = -fFar; farLL[3] = 1.0f; + + // Far Upper Right + farUR[0] = xFmax; farUR[1] = yFmax; farUR[2] = -fFar; farUR[3] = 1.0f; + + // Far Lower Right + farLR[0] = xFmax; farLR[1] = yFmin; farLR[2] = -fFar; farLR[3] = 1.0f; + } + + // Builds a transformation matrix and transforms the corners of the Frustum, + // then derives the plane equations + void Transform(GLFrame& Camera) + { + // Workspace + M3DMatrix44f rotMat; + M3DVector3f vForward, vUp, vCross; + M3DVector3f vOrigin; + + /////////////////////////////////////////////////////////////////// + // Create the transformation matrix. This was the trickiest part + // for me. The default view from OpenGL is down the negative Z + // axis. However, building a transformation axis from these + // directional vectors points the frustum the wrong direction. So + // You must reverse them here, or build the initial frustum + // backwards - which to do is purely a matter of taste. I chose to + // compensate here to allow better operability with some of my other + // legacy code and projects. RSW + Camera.GetForwardVector(vForward); + vForward[0] = -vForward[0]; + vForward[1] = -vForward[1]; + vForward[2] = -vForward[2]; + + Camera.GetUpVector(vUp); + Camera.GetOrigin(vOrigin); + + // Calculate the right side (x) vector + m3dCrossProduct(vCross, vUp, vForward); + + // The Matrix + // X Column + memcpy(rotMat, vCross, sizeof(float)*3); + rotMat[3] = 0.0f; + + // Y Column + memcpy(&rotMat[4], vUp, sizeof(float)*3); + rotMat[7] = 0.0f; + + // Z Column + memcpy(&rotMat[8], vForward, sizeof(float)*3); + rotMat[11] = 0.0f; + + // Translation + rotMat[12] = vOrigin[0]; + rotMat[13] = vOrigin[1]; + rotMat[14] = vOrigin[2]; + rotMat[15] = 1.0f; + + //////////////////////////////////////////////////// + // Transform the frustum corners + m3dTransformVector4(nearULT, rotMat, nearUL); + m3dTransformVector4(nearLLT, rotMat, nearLL); + m3dTransformVector4(nearURT, rotMat, nearUR); + m3dTransformVector4(nearLRT, rotMat, nearLR); + m3dTransformVector4(farULT, rotMat, farUL); + m3dTransformVector4(farLLT, rotMat, farLL); + m3dTransformVector4(farURT, rotMat, farUR); + m3dTransformVector4(farLRT, rotMat, farLR); + + //////////////////////////////////////////////////// + // Derive Plane Equations from points... Points given in + // counter clockwise order to make normals point inside + // the Frustum + // Near and Far Planes + m3dGetPlaneEquation(nearPlane, nearULT, nearLLT, nearLRT); + m3dGetPlaneEquation(farPlane, farULT, farURT, farLRT); + + // Top and Bottom Planes + m3dGetPlaneEquation(topPlane, nearULT, nearURT, farURT); + m3dGetPlaneEquation(bottomPlane, nearLLT, farLLT, farLRT); + + // Left and right planes + m3dGetPlaneEquation(leftPlane, nearLLT, nearULT, farULT); + m3dGetPlaneEquation(rightPlane, nearLRT, farLRT, farURT); + } + + // Allow expanded version of sphere test + bool TestSphere(float x, float y, float z, float fRadius) + { + M3DVector3f vPoint; + vPoint[0] = x; + vPoint[1] = y; + vPoint[2] = z; + + return TestSphere(vPoint, fRadius); + } + + // Test a point against all frustum planes. A negative distance for any + // single plane means it is outside the frustum. The radius value allows + // to test for a point (radius = 0), or a sphere. Possibly there might + // be some gain in an alternative function that saves the addition of + // zero in this case. + // Returns false if it is not in the frustum, true if it intersects + // the Frustum. + bool TestSphere(M3DVector3f vPoint, float fRadius) + { + float fDist; + + // Near Plane - See if it is behind me + fDist = m3dGetDistanceToPlane(vPoint, nearPlane); + if(fDist + fRadius <= 0.0) + return false; + + // Distance to far plane + fDist = m3dGetDistanceToPlane(vPoint, farPlane); + if(fDist + fRadius <= 0.0) + return false; + + fDist = m3dGetDistanceToPlane(vPoint, leftPlane); + if(fDist + fRadius <= 0.0) + return false; + + fDist = m3dGetDistanceToPlane(vPoint, rightPlane); + if(fDist + fRadius <= 0.0) + return false; + + fDist = m3dGetDistanceToPlane(vPoint, bottomPlane); + if(fDist + fRadius <= 0.0) + return false; + + fDist = m3dGetDistanceToPlane(vPoint, topPlane); + if(fDist + fRadius <= 0.0) + return false; + + return true; + } + + protected: + // Untransformed corners of the frustum + M3DVector4f nearUL, nearLL, nearUR, nearLR; + M3DVector4f farUL, farLL, farUR, farLR; + + // Transformed corners of Frustum + M3DVector4f nearULT, nearLLT, nearURT, nearLRT; + M3DVector4f farULT, farLLT, farURT, farLRT; + + // Base and Transformed plane equations + M3DVector4f nearPlane, farPlane, leftPlane, rightPlane; + M3DVector4f topPlane, bottomPlane; +}; + + +#endif + |