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:

terrain.cpp

home Home   up Up   ( Download )


#include "terrain.h" /* * TerrainGrid class * ---------------------- * Creates a random terrain using the * diamond-square fractal algorithm. * ------------------------- * Tristan Aubrey-Jones 18/12/2007 */ // calculate a random float between // 0.0 and ran. inline GLfloat randf(GLfloat ran) { // calculate between 0 and 1 int ir = rand() % 1000; GLfloat v = ((float)(ir) / 1000.0f); // change to range return v * ran; } // calculates a midpoint value by averaging the 4 corners and adding // a random value inline RegularGridVertex calcMidpoint(RegularGridVertex v, RegularGridVertex v0, RegularGridVertex v1, RegularGridVertex v2, RegularGridVertex v3, RegularGridVertex r) { // calc average height, if not already set if (v.y < 0.0) { v.y = (v0.y + v1.y + v2.y + v3.y) / 4.0f; v.y += randf(r.y); } // return return v; } // performs the square step of the diamond-square algorithm // sqrSize - the length (in grid elements) of one size of the square // range - the range the height can be varies by void TerrainGrid::performSquareStep(int sqrSize, RegularGridVertex ran) { int half = sqrSize / 2; // for every row for (int z = half; z < depth(); z += sqrSize) { // for every col for (int x = 0; x < width(); x += sqrSize) { // update RegularGridVertex v = get(x,z); //printf("Square a step for (%i,%i)\n", x, z); v = calcMidpoint(v, get(x,z-half), get(x,z+half), get(x-half,z), get(x+half,z), ran); //printf("%f\n", v.y); set(x, z, v); } } // for every col for (int x = half; x < width(); x += sqrSize) { // for every row for (int z = 0; z < depth(); z += sqrSize) { // update RegularGridVertex v = get(x,z); //printf("Square b step for (%i,%i)\n", x, z); v = calcMidpoint(v, get(x,z-half), get(x,z+half), get(x-half,z), get(x+half,z), ran); set(x, z, v); } } } // performs the diamond step of the diamond-square algorithm // sqrSize - the length (in grid elements) of one size of the square // range - the range the height can be varies by void TerrainGrid::performDiamondStep(int sqrSize, RegularGridVertex ran) { // half square size int half = sqrSize / 2; // iterate over all squares int x0 = 0, x1 = sqrSize; while (x1 < width()) { int d0 = 0, d1 = sqrSize; while (d1 < depth()) { // calc center point int cx = x0 + half; int cd = d0 + half; // get center point RegularGridVertex v = get(cx,cd); // adjust by random amount v = calcMidpoint(v, get(x0,d0), get(x0,d1), get(x1,d0), get(x1,d1), ran); // set set(cx,cd,v); // next square d0 = d1; d1 += sqrSize; } x0 = x1; x1 += sqrSize; } } // generate, creates a new random landscape void TerrainGrid::generate() { computeNormals(); // seed random numbers srand(SDL_GetTicks()); // init random ranges RegularGridVertex ran; ran.y = height; float H = roughness; // perform diamond-square algorithm int sqrSize = 2< 1) { performDiamondStep(sqrSize, ran); performSquareStep(sqrSize, ran); ran.y *= pow(2, -H); H += 0.2; sqrSize /= 2; // 1/2 = 0 } // compute normals for landscape computeNormals(); } // check for collision, and if // one occurs provides the point of // collision // position - vertex to check // direction - direction of vertex as it approached // result - when returns true contains the point of collision bool TerrainGrid::collisionDetect(Vec3* position, Vec3* direction, Vec3* result) { return false; }