This page was last updated: February 9, 2009
You will be given a height field and an image, representing the terrain and satellite image of the state of Oregon (in low resolution to keep it simple). The graphical representation of the transparent cloud, and its motion, is up to you. Write a program to view this scenario.
The texture image is in ".bmp" format. Read the texture image file into your program by:
unsigned char *BmpToTexture( char *filename, int *widthp, int *heightp ); unsigned char *Texture; int Width, Height; Texture = BmpToTexture( "or.bmp", &Width, &Height );
Test to be sure Texture is not equal to NULL, and that Width and Height each come back as 256. Then,
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glTexImage2D( GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, Texture );
Click here to get a copy of BmpToTexture(). You can either treat this as a separate file, or easier, just copy it into your proj09.cpp program.
The dimensions of the data are:
// Longitude is west-to-east (x)
// Latitude is south-to-north (-z)
#define NUMLNGS 201
#define NUMLATS 105
The ranges of the data are (all units are kilometers):
const float LNGMIN = { -289.6f };
const float LNGMAX = { 289.6f };
const float LATMIN = { -197.5f };
const float LATMAX = { 211.2f };
const float HGTMIN = { 0.0f };
const float HGTMAX = { 2.891f };
The texture image consists of 256x256 texels, but only the bottom 256x184 (0-255, 0-183) actually have the Oregon image. The upper 256x72 are there to pad it out to a power of 2. So, to compute s and t from a longitude and latitude:
s = ( lng - LNGMIN ) / ( LNGMAX - LNGMIN ); /* 0. -> 1. */
t = ( lat - LATMIN ) / ( LATMAX - LATMIN ); /* 0. -> 1. */
t = t * ( 183. / 255. ); /* 0. -> 0.718 */
struct LngLatHgt
{
float lng, lat, hgt;
};
struct LngLatHgt Points[NUMLATS][NUMLNGS];
float lng, lat, hgt;
float dlat, dlng;
int x, z;
dlng = ???
dlat = ???
for( z = 0, lat = LATMAX; z < NUMLATS; z++, lat -= dlat )
{
for( x = 0, lng = LNGMIN; x < NUMLNGS; x++, lng += dlng )
{
Points[z][x].lng = lng;
Points[z][x].lat = lat;
fscanf( fp, "%f", &Points[z][x].hgt );
}
}
You can draw the terrain with GL_TRIANGLES or GL_TRIANGLE_STRIPs. (Anything with quadrilaterals is not recommended because of non-planarity.) However you do it, just be sure to:
Note that:
OpenGL has a real lighting feature where the pipeline hardware will compute a lighting intensity at each vertex for you. You can use it if you want (it's fun to put the light source on the cloud, so it appears to be a moving glow), or you can simulate it.
If we assume that the light is coming from straight overhead, then any triangle that has a perfectly vertical (+Z) surface normal will be brighter than any triangle that doesn't. So, to do lighting this way, take the cross product of two edge vectors and use the Z component of the unitized normal vector as the intensity:
x01 = x1 - x0;
y01 = y1 - y0;
z01 = HGTFACTOR*( z1 - z0 );
x02 = x2 - x0;
y02 = y2 - y0;
z02 = HGTFACTOR*( z2 - z0 );
Cross( x01, y01, z01, x02, y02, z02, &nx, &ny, &nz );
inten = fabs(nz) / sqrt( nx*nx + ny*ny + nz*nz );
glColor3f( inten, inten, inten );
The HGTFACTOR is there to make the difference in intensities more obvious. You can hardcode this value, or make it a slider or spinner so you can adjust it.
Don't remember how to do a cross product? Look at the "Determinant Formula" here.
Open up another graphics window and graph:
Open up another graphics window and display a 3D view of the scene while riding on the cloud. Pick a reasonable eye position and lookat position. Try not to make the grader motion sick!
| Item | Points |
| Display the terrain correctly | 20 |
| Correct lighting | 10 |
| Correct GL_REPLACE | 20 |
| Correct GL_MODULATE | 20 |
| Toggle Nearest/Linear filtering correctly | 10 |
| Draw the cloud | 15 |
| Make the cloud transparent | 10 |
| Animate the cloud | 15 |
| Graph Extra Credit | 5 |
| Cloud-riding Extra Credit | 5 |
| Potential Total | 130 |