Introduction

I have always been interested in computer graphics and their applications. Data representation and visualization is one of the main areas of HCI (Human Computer Interaction), and the better you make the interaction between a machine and a human, the more productivity will be generated by both the human and the machine. I had some experience with OpenGL during my undergraduate studies while attending the California Polytechnic University. Unfortunately, I never got a chance to pursue the more advanced features of the OpenGL library, given my time and work responsibilities.

You can find more about OpenGL at www.opengl.org. There are also a bunch of good literature available on the topic of Computer Graphics and OpenGL that you can refer for further advancements. Please check the Background/Reference section for a list of some reference material that I have used, in general, for computer graphics.

The following project is a very simple example demonstrating how to generate a terrain based on a bitmap file. The objective of the project is to generate a three dimensional terrain based on some data file. Please note, that this could have been any data file, but for the purpose of our example, we are going to be using a 32x32 dimensional bitmap file. We could have easily used a text file, and defined logic for each word or letter to represent it graphically.

The project also contains a good Windows framework that can be used for your other OpenGL applications. The current project allows you to rotate the camera using your mouse.

Once again, this is a simple approach to terrain generation, which can be a very difficult task in complex environments.

Background/Reference

Since Computer Graphics is kind of an advanced topic, it is necessary to have at least some king of understanding and exposure to the concepts and theories in the field. However, this does not mean that you will not be able to use the following code or understand it. I have made it as simple as possible, and hopefully, it will give you a good start, or some additional source of information that you can use for your projects. Also, please note that you will need to have a good understanding of C/C++ programming.

Some books I have used for learning Computer Graphics and OpenGL programming:

Books I used while attending the California Polytechnic University:

OpenGL Programming Guide, or better know as the Red Book.

Computer Graphics Using OpenGL, 2nd Edition.

Books I used while attending the California Lutheran University:

What is a Terrain?

Some background information on a terrain and their uses in a game application: A terrain in an environment is one of the most critical components in the scene that is being rendered. It could easily be the largest 3D object in the project. Rendering the terrain can become a daunting task, taking the most time to render in a scene. To keep the terrain engine running in real time can be a difficult task, and it requires some thought out processes and modeling for it to be sufficient.

To be effective, the terrain needs to meet a number of requirements, many of which can be contradicting each other. A terrain should appear to be continuous to the end user, yet the mesh should be simplified or culled where possible, to reduce the load on the graphics card.

In a gaming system, for example, some engines draw the terrain just beyond the point a player can reach, and then use a terrain drawn onto a skybox to simulate hills or mountains in the distance. The terrain should appear realistic to the setting for the environment, yet this can be taxing on the video card, and a balance needs to be maintained. Detail textures are often used close to the camera, allowing the areas further off to be rendered more quickly.

What is a Height Map?

The first thing required for terrain rendering is a representation of the terrain's shape. While there are a number of structures that can be used to perform the job, the most widely used is the height map. Others include: NURBS, which can be maintained through a number of control points, and voxels, which allow for overhangs and caves.

There is one drawback to a height map, and that is, for every point on the XZ-plane, there can only be one height value. You can see that this limits the representation of overhangs and caves by a height map. This can be overcome by using two separate models.

Another drawback is that height maps take a large amount of memory, as each height must be represented. On the other hand, height maps lend themselves to the creation of regular meshes easily. It is also easy to determine the height at any given location, which is useful for collision against the terrain as well as laying dynamic shadows onto the terrain.

A height map is represented by a 2D array of values, where for any point (X, Y, Z), the X and Z are the indexes into the array, and the value of the array is the Y value which is equivalent to the height value.

The Approach!

There are many advanced algorithms to generate terrains; I am using a very simple solution for the purpose of this project.

In a nutshell, I used a 32 x 32 grayscale bitmap to represent a height-field that is used to generate the terrain. The terrain itself is divided into a grid of height values, the result of which is a mesh representing the terrain in the scene.

We create a grid of vertices that are spaced evenly apart but have varying heights, based on the height-field data. The color value of each bit is used to determine the height value of each grid location; in this case, for a 24-bit grayscale bitmap, the values for the color range from 0 to 255.

Once the bitmap has been read and the values loaded in memory, we have the data needed to represent the terrain. We also use a variable called a MAP_SCALE to allow us to scale the map up or down. This is a scale factor; we use this to set the distance between each height vertex. This allows us to increase or decrease the size of the terrain.

When we actually assign the vertex coordinates for each grid location, we need to apply the MAP_SCALE factor, which is multiplying it with the grid location index based on the coordinate element, i.e.:

The terrain map is represented in a grid of height values, which is internally stored in a 2D array of vertex coordinates. It extends along the X and Z-axis, with the Y-Axis representing the terrain height.

To render the terrain map, we use GL_TRIANGLE_STRIP for each row of grid values along the Z-axis. To render the terrain correctly, we need to specify the point in a specific order.

This requires us to start at the end of the row and move along the positive X-axis by drawing the vertices in a Z pattern:

The following is a sample of the bitmap used to generate the height-field:

The following is the output of the generated terrain based on the bitmap file:

Using the Code

I will only list the code that deals with the terrain generation here. There is more code in the project that you can look at. It is well documented, so you shouldn't have any problems. The solution was compiled using MS Visual Studio 2003, so you should be able to compile and run it easily. You will need to have the OpenGL libraries and DLL, which I will also provide as a download option just in case you do not have them. Make life a little easier so you do not have to search for them online.

So the majority of the code is for preparing the windows to render the scene properly. As you can see below, the code for generating and rendering the terrain is very short. To give an overview, the first thing that happens is for the windows to get created, and then we initialize OpenGL, and read in the BMP file and assign it to the 2D array we discussed above. Then, the texture is applied to the surface of the mesh, and the scene rendered to the screen.

Without further ado, the following listing is the the portion of the code which initializes and generates the terrain:

The code above is the implementation of what we discussed about applying MAP_SCALE, which allows us to scale the terrain to our likings. So, it basically assigns the vertex coordinates for each grid location, the MAP_SCALE factor, which is multiplying it with the grid location index based on the coordinate element. It extends along the X and Z-axis, with the Y-Axis representing the terrain height.

The function is called after the bitmap has been loaded into the memory from the Initialize() function.

The first thing you see in the Render() function is the conversion of the angle into radians, by using the formula: radians = float(PI*(angle-90.0f)/180.0f);. This makes it easier to compute the cameraX, cameraY, and cameraZ positions using the sin() and cos() functions.

The next block of code sets the look-at coordinates of the camera at the center of the terrain. Then, we clear the screen and depth buffer using glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);. We set the camera position based on the camera (X, Y, Z) values and the look-at we computed.

We then bind the texture using the glBindTexture(GL_TEXTURE_2D, texture); function. This tells OpenGL that we are going to use that particular texture to apply to our surfaces that will be drawn.

So far, all the code was just to setup the camera position and bind the texture, the next block of code is what actually draws the terrain and applies the texture to the surface. We have two for loops which go through the 2D array we have created that stores the terrain data, and as we discussed earlier, we process four vertices at a time. In the process, we calculate the grayscale shade color, we set the texture, and then we draw the vertex.

That is pretty much all you need to do to generate a terrain, given a 24-bit bitmap file.

Points of Interest

If you are reading this, you most likely are interested in computer graphics and want to learn more about the techniques available to do really cool stuff. Computer graphics can be very complex in theory, but thanks to libraries such as OpenGL, the implementation of complex models/scenes can be done easily. Upon writing this article, I got the latest issue of Dr. Dobb's Journal (June 2006, Issue No. 385), and to my surprise, there is an article about OpenGL and Mobile Devices. It is under the name of OpenGL ES and it is a subset of OpenGL 1.3. That will make it possible to do real time 3D graphics on hand-held devices. Imagine the kind of nice looking applications/games that can be developed for your PDA or cell phones! Not all the functionality is available due to the limitations of the hand-held hardware. But I assume, in the near term future, you will be able to create as fascinating graphics on the handhelds as you can on your regular desktop machines.

On another note, I am going to start working on a new article which will describe the LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader) function. I am looking forward to hearing your comments and input, for future articles.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

I have been programming since the age of 15. Started with BASIC on Apple II computers then moved on to Pascal. I wrote the game of Tetris using both languages on Apple II. At the age of 16 I got my first computer, and I started transferring the code over to Quick Basic. I then moved into C/C++ and have been developing in C/C++, until the introduction of the .Net Framework, when I switched over to C# and have been doing most of my development in C#.

Recently I left the corporate world, to start my own software consulting firm located in Los Angeles, California, specializing in the .Net Framework and technologies.

I'm not trying to be rude but... You should never do this ! The codebase goes obsolete to quickly and it can't be maintained.
Hybird coding is slouchy ART where correct engineering is called for.
Just because somthing can be done, dosent mean it should be!

Bad, very Bad Habbit !

There is a valid stopping point for ART and a starting point for Engineering.
Art is an expression of an Analog, NOT a Digital Design.

When you use OpenGL you should always write portable code that does not have a message loop, and
that will compile under gcc or MinGW etc. Without Modification.

The onlytime you should use Windows specific code is if you are using DirectX. That's what it was made for.

You might say that it dosent matter, but look at the intent of the software API's you are using.

It's sloppy and incorrect to cross your arch tools for many reasons, it can't be maintained, it's really kinda worthless for anything opensource, and can cause $$$$$ failures for any company.
I could list many, many more bad reasons to do this. It's even bad to teach this.

hi
i am new developer of asp.net.. i am student of degree engineering in information technology....
and i am making a project of online gaming........ so for that i want to devlop one game so please give me suggetions how to develop a game.... i am work on c# .net... which one will easy? activeX or openGL to develop the game.........
thank you

hi vahe
i want to develop a game in dotet using c# with either directX or OpenGL... i have not much more practical knowledge about both this that is why i want to develope a game using these..... can you give me some idea about some simple type of game...... and some attention points required for making a game........ i will have to make a game and i have to put it on website....
this is my academic project so i have to develope it fast so please tell me fast and easy development technique .
thank you .......

Hello, it is possible to do this, but I do not have the time for the implementation as of today. Maybe in the future I can look into it. Please feel free to improve the code, and share with the rest of us.

Vahe

I have little patience with scientists who take a
board of wood, look for its thinnest part, and drill a
great number of holes where drilling is easy.

I'm doing a game to a school project and i'd really like to integrate some terrain in it. this code is simple and smooth but i just cant use other images. i'm using a bmp 256x256 and i change the MAP_X and MAP_Z to 256 but i get a memory error in this line :

I'm doing a game to a school project and i'd really like to integrate some terrain in it. this code is simple and smooth but i just cant use other images. i'm using a bmp 256x256 and i change the MAP_X and MAP_Z to 256 but i get a memory error in this line :

In my project i need to show the combined view of several 3d scenes at diff positions....
like i need to show the terrain generated frm a lot of 32X32 bitmaps on the screen ...
can any oe suggest a method to do this ....
plzz do me this favour ... its urgent ..... need to complete my proj bu next week

It is great and simple to understand!! I was playing around with it and the decide to try with different sizes bitmap like 544 x 390 and 390 x 544.
For first size, I changed the MAP_X to 544 and MAP_Z to 390 and somehow it did not display the generation correctly - it seemed that part was broken down or part was missing. For the second problem, i could not even ran because it break at initializeTerrain() function for imageData.
Am I missing anything??

How do Iget to view image from top bottom and lower the z plane shorter - not to sharp/tall??

Did you rescaled map to power of two?If didn't use gluScaleImage, or better gluBuild2DMipmaps to correct it.Please note, if you use ScaleImage, only downsampling will work, even it returns good on upsampling.

"As far as the laws of mathematics refer to reality, they are not
certain; and as far as they are certain, they do not refer to reality." Albert Einstein

the code is so useful and easy to understand. i like to implement in my student project. my image is of bigger size( and not being 32 X 32) where should i change exactly.
i tried resampling the bmp to 32 X 32 but there is enormous data lose..!! can you please help

Hey jqt, sure. I am not sure if you have gone over the code yet or not, but if you open the source code and go thru it, you will understand what is happening. But, let me give it to you in a nut shell.

When initializing OpenGl in the void Initialize() function, you will notice the following line:

imageData = LoadBitmapFile( "terrain2.bmp", &bitmapInfoHeader );

The LoadBitmapFile is a function defined in vkgllib.h file. This function is used to return a pointer to the bitmap image file with the header information. imageData is a pointer to the image file which holds the high-map of our terrain.

MAP_Z is defined as 32 which indicate the number of pixels among the z-axis, in this case the image is a 32x32 dimension, so we have MAP_X and MAP_Z defined as 32 a constant. If the image was of different dimensions, these values should be changes appropriately.

So the line you are referring to assigns the height/elevation to the terrain based on the value in the imageData which is pointing to the bitmap loaded into memory.

Hope this gives you a little bit explanation.

Sincerely,
Vahe Karamian

I have little patience with scientists who take a
board of wood, look for its thinnest part, and drill a
great number of holes where drilling is easy.

This is a simplification of that work with explanation for others who are interested in terrain generation. The algorithm described is also explained in the book by the authors Kevin Hawkins and Dave Astle. The question is; did this article make the subject easier to understand? If so, it has accomplished its objective. Thank you for your comment.

I have little patience with scientists who take a
board of wood, look for its thinnest part, and drill a
great number of holes where drilling is easy.

Please read my comments carefully. The intention of this article is to make it easier for people to understand the concept. If you agree that it has simplified the process, then my objective has been met.

I have little patience with scientists who take a
board of wood, look for its thinnest part, and drill a
great number of holes where drilling is easy.

I need your code to make simple application - support program for my main project. I need to visualize 256x256 3D surfaces that may have floating point vertical values. But all must be in a 3D cube: 256x256x256 I have a file with 256x256 double matrix. I suppose can use your code, but it only makes 32x32 bits 3D surface plot, so I need to extend it to 256x256 ) is it possible?

Hmmm, probably because if you had more experience in C, you would have found out that this source file is *NOT* C at all, but GFA basic, which existed on the Atari ST line of computers... This is not yet a port to VC++ and OpenGL, this is full software rendered fractal mountain generator