# Geometric Approach – Implementation

Prev: Geometric Approach - Extracting the Planes | Next: Testing Points and Spheres |

A class to implement the frustum functionality is now presented. Note that the code itself is not optimized in any way, as the goal is only to serve as the tutorial companion. The class contains an array of six planes, plus other variables such as the 8 corners of the frustum and the camera definitions. Only the planes are needed for the culling operation, but the remaining variables are useful for debug and visualization purposes.

**The class header file**

class FrustumG { private: enum { TOP = 0, BOTTOM, LEFT, RIGHT, NEARP, FARP }; public: static enum {OUTSIDE, INTERSECT, INSIDE}; Plane pl[6]; Vec3 ntl,ntr,nbl,nbr,ftl,ftr,fbl,fbr; float nearD, farD, ratio, angle,tang; float nw,nh,fw,fh; FrustumG::FrustumG(); FrustumG::~FrustumG(); void setCamInternals(float angle, float ratio, float nearD, float farD); void setCamDef(Vec3 &p, Vec3 &l, Vec3 &u); int pointInFrustum(Vec3 &p); int sphereInFrustum(Vec3 &p, float raio); int boxInFrustum(AABox &b); };

**The Methods: setCamInternals**

This function takes exactly the same parameters as the function `gluPerspective`

. Each time the perspective definitions change, for instance when a window is resized, this function should be called as well.

#define ANG2RAD 3.14159265358979323846/180.0 void FrustumG::setCamInternals(float angle, float ratio, float nearD, float farD) { // store the information this->ratio = ratio; this->angle = angle; this->nearD = nearD; this->farD = farD; // compute width and height of the near and far plane sections tang = (float)tan(ANG2RAD * angle * 0.5) ; nh = nearD * tang; nw = nh * ratio; fh = farD * tang; fw = fh * ratio; }

The function stores all the information, and computes the width and height of the rectangular sections of the near and far plane and stores them in *nh* (near height), *nh* (near width), *fh* (far height), and *fw* (far width).

**The Methods: setCamDef**

This function takes three vectors that contain the information for the `gluLookAt`

function: the position of the camera, a point to where the camera is pointing and the up vector. Each time the camera position or orientation changes, this function should be called as well.

void FrustumG::setCamDef(Vec3 &p, Vec3 &l, Vec3 &u) { Vec3 dir,nc,fc,X,Y,Z; // compute the Z axis of camera // this axis points in the opposite direction from // the looking direction Z = p - l; Z.normalize(); // X axis of camera with given "up" vector and Z axis X = u * Z; X.normalize(); // the real "up" vector is the cross product of Z and X Y = Z * X; // compute the centers of the near and far planes nc = p - Z * nearD; fc = p - Z * farD; // compute the 4 corners of the frustum on the near plane ntl = nc + Y * nh - X * nw; ntr = nc + Y * nh + X * nw; nbl = nc - Y * nh - X * nw; nbr = nc - Y * nh + X * nw; // compute the 4 corners of the frustum on the far plane ftl = fc + Y * fh - X * fw; ftr = fc + Y * fh + X * fw; fbl = fc - Y * fh - X * fw; fbr = fc - Y * fh + X * fw; // compute the six planes // the function set3Points assumes that the points // are given in counter clockwise order pl[TOP].set3Points(ntr,ntl,ftl); pl[BOTTOM].set3Points(nbl,nbr,fbr); pl[LEFT].set3Points(ntl,nbl,fbl); pl[RIGHT].set3Points(nbr,ntr,fbr); pl[NEARP].set3Points(ntl,ntr,nbr); pl[FARP].set3Points(ftr,ftl,fbl); }

The function computed the eight corners of the frustum and the six planes according to the algorithm defined in the previous section.

The following (more efficient) alternative may be used to replace the computation of the eight corners and the six planes in the function above.

pl[NEARP].setNormalAndPoint(-Z,nc); pl[FARP].setNormalAndPoint(Z,fc); Vec3 aux,normal; aux = (nc + Y*nh) - p; aux.normalize(); normal = aux * X; pl[TOP].setNormalAndPoint(normal,nc+Y*nh); aux = (nc - Y*nh) - p; aux.normalize(); normal = X * aux; pl[BOTTOM].setNormalAndPoint(normal,nc-Y*nh); aux = (nc - X*nw) - p; aux.normalize(); normal = aux * Y; pl[LEFT].setNormalAndPoint(normal,nc-X*nw); aux = (nc + X*nw) - p; aux.normalize(); normal = Y * aux; pl[RIGHT].setNormalAndPoint(normal,nc+X*nw);

Prev: Geometric Approach - Extracting the Planes | Next: Testing Points and Spheres |

ive got a question for FrustumG::setCamDef(),

why is it that the Z axis points in the opposite direction from look direction?

i mean is it inverted or negated?

Thanks

OpenGL uses a right-hand coordinate system, see this page on wikipedia if handedness is new to you..

setCamDef code is not in paralled with your theory explanation.

It should be something like

X = l * u; // right vector

X.normalize();

nc = p + l * nearD;

fc = p + l * farD;

ntl = nc + u * nh/2 – X * nw/2;

ntr = nc + u * nh/2 + X * nw/2;

nbl = nc – u * nh/2 – X * nw/2;

nbr = nc – u * nh/2 + X * nw/2;

ftl = fc + u * fh/2 – X * fw/2;

ftr = fc + u * fh/2 + X * fw/2;

fbl = fc – u * fh/2 – X * fw/2;

fbr = fc – u * fh/2 + X * fw/2;

that was assuming u to be lookAt direction

Hi Hakan,

In the “theory” page, “up” is the real up vector. When using gluLookAt, the vector we call up is not necessarily the up vector, hence we have to compute it, and that’s what I do with Y.

I’m not sure if this was what you we’re pointing out, though. Please let me know if I did not get your comment right.

Seems I was a bit confused when I posted that, your implementation seems correct.

Thank you for the cool tutorial