3D Underwater World (using OpenGL and SDL)

Copyright Tristan Aubrey-Jones January 2008.

This is an example OpenGL SDL application which creates an animated 3D underwater world (screenshot), with "Thunderbird 4" with headlights moving on a spline path, a randomly generated sand terrain, sunken ship/submarine/treasure chest models, and swaying fish and seaweed. It is designed to demonstrate basic OpenGL features, and the structure is as follows:

clipping.cpp

home Home   up Up   ( Download )


#include "clipping.h" // constructor that copies FrustrumClipper::FrustrumClipper(FrustrumClipper* f): nr(f->nr), fr(f->fr), left(f->left), right(f->right), top(f->top), bottom(f->bottom) { } // set to this value void FrustrumClipper::set(FrustrumClipper* f) { nr.set(&(f->nr)); fr.set(&(f->fr)); left.set(&(f->left)); right.set(&(f->right)); top.set(&(f->top)); bottom.set(&(f->bottom)); } // transform this using a transformation matrix void FrustrumClipper::transform(Mat4* t) { nr.transform(t); fr.transform(t); left.transform(t); right.transform(t); top.transform(t); bottom.transform(t); } // inside the frustrum? bool FrustrumClipper::inside(const Vec3* p) { return nr.side(p) > 0 && // beyond near fr.side(p) > 0 && // before far left.side(p) > 0 && // to the right of left right.side(p) > 0 && // to the left of right bottom.side(p) > 0 && // above bottom top.side(p) > 0; // below the top } // sets the frustrum's clipping planes // to the frustrum defined by these // parameters void FrustrumClipper::set(float viewingAngle, float aspectRatio, float nearD, float farD, const Vec3* pos, const Vec3* obj, const Vec3* above) { // calculate side // as the normal to the up, forward plane HyperPlane ufp(pos, obj, above); Vec3 side(&ufp.N); side.norm(); // up vector Vec3 up(above); up.subtract(pos); up.norm(); // direction vector Vec3 dir(obj); dir.subtract(pos); dir.norm(); // start point Vec3 cstart(&dir); cstart.multiply(nearD); cstart.add(pos); // end point Vec3 cend(&dir); cend.multiply(farD); cend.add(pos); // near (front) clipping plane nr.A.set(&cstart); nr.N.set(&dir); // far (back) clipping plane fr.A.set(&cend); fr.N.set(&dir); fr.N.multiply(-1); // calculate vert distance from far center // to vertical points float ha = (viewingAngle / 2) * (PI / 180.0); float fvh = farD * tan(ha); Vec3 vt(up); vt.multiply(fvh); // calcuate horizontal distance from center // based on aspect ratio float fhw = fvh * aspectRatio; Vec3 hz(&side); hz.multiply(fhw); // init points at other end to far center Vec3 ftr(&cend); ftr.add(&vt); ftr.add(&hz); Vec3 ftl(&cend); ftl.add(&vt); ftl.subtract(&hz); vt.multiply(2.0); // increase at bottom to solve weird hz.multiply(1.5); // lack of clipping at bottom Vec3 fbr(&cend); fbr.subtract(&vt); fbr.add(&hz); Vec3 fbl(&cend); fbl.subtract(&vt); fbl.subtract(&hz); // make side planes left.set(pos, &fbl, &ftl); right.set(pos, &ftr, &fbr); // make top and bottom planes top.set(pos, &ftl, &ftr); bottom.set(pos, &fbr, &fbl); } // constructor CameraView::CameraView(GLfloat viewingAngle, GLfloat aspectRatio, GLfloat nearD, GLfloat farD): viewingAngle(viewingAngle), aspectRatio(aspectRatio), nearD(nearD), farD(farD) { } // set location and orientation void CameraView::set(const Vec3* ppos, const Vec3* pobj, const Vec3* pabove) { // set params pos.set(ppos); obj.set(pobj); above.set(pabove); // calculate side // as the normal to the up, forward plane HyperPlane ufp(&pos, &obj, &above); side.set(&ufp.N); side.norm(); // initialize clipping frustrum // to slightly bigger than the actual // viewing perspective frust.set(viewingAngle, aspectRatio, nearD, farD, ppos, pobj, pabove); } // set the cammera orientation to the // camera's (should happen in MODEL_VIEW) void CameraView::lookAt() { // calculate up from above Vec3 up(&above); up.subtract(&pos); // move camera gluLookAt(pos.x, pos.y, pos.z, obj.x, obj.y, obj.z, up.x, up.y, up.z); } // rotate horizontally void CameraView::rotateHoriz(float angle) { // calculate up vector from above and pos Vec3 up(&above); up.subtract(&pos); // transformation matrix to rotate by // angle around the point pos in the // side/forward plane Mat4 m; m.translate(-pos.x, -pos.y, -pos.z); m.rotate(-angle, 0, 1, 0); m.translate(pos.x, pos.y, pos.z); // move object looked at m.transform(&obj); // pos stays the same // upward direction moves m.transform(&above); // transform frustrum //frust.transform(&m); frust.set(viewingAngle, aspectRatio, nearD, farD, &pos, &obj, &above); // calculate side // as the normal to the up, forward plane HyperPlane ufp(&pos, &obj, &above); side.set(&ufp.N); } // rotate vertically void CameraView::rotateVert(float angle) { // transformation matrix to rotate // by angle, around the point pos // in the up/forward plane Mat4 m; m.translate(-pos.x, -pos.y, -pos.z); m.rotate(-angle, &side); m.translate(pos.x, pos.y, pos.z); // move object looked at m.transform(&obj); // move upward direction m.transform(&above); // pos stays same // side stays the same // transform frustrum //frust.transform(&m); frust.set(viewingAngle, aspectRatio, nearD, farD, &pos, &obj, &above); } // move forward void CameraView::moveForward(float d) { // transformation matrix to translate // by distance d in the direction of // obj-pos Mat4 m; Vec3 dir(&obj); dir.subtract(&pos); dir.norm(); dir.multiply(d); m.translate(&dir); // move pos m.transform(&pos); // move obj m.transform(&obj); // move above m.transform(&above); // side stays the same // transform frustrum //frust.transform(&m); frust.set(viewingAngle, aspectRatio, nearD, farD, &pos, &obj, &above); } // move up void CameraView::moveUp(float dist) { // transformation matrix to translate // by distance d in the direction of // obj-pos Mat4 m; Vec3 dir(0.0, dist, 0.0); m.translate(&dir); // move pos m.transform(&pos); // move obj m.transform(&obj); // move above m.transform(&above); // side stays the same // transform frustrum frust.set(viewingAngle, aspectRatio, nearD, farD, &pos, &obj, &above); } // get position void CameraView::getPosition(Vec3* r) { r->set(&pos); } // get forward vector void CameraView::getForwardVector(Vec3* r) { r->set(&obj); r->subtract(&pos); }