3. Terrain Rendering
Jump To:
heightfield.h Source
heightfield.cpp Source
main.cpp Source
Heightfield.H File:
In our heightfield.h file, we are going to declare some private variables inside our class, these are going to hold the height and the width of our heightfield, globally within the class:
// private:
// int hmHeight;
// int hmWidth;
1. 2. 3. 4. 5. 14. |
#include <windows.h>
class SwiftHeightField { int hmWidth; }; |
Heightfield.CPP File:
To render our terrain, we are going to need to call OpenGL commands from within this source file, so we need include gl.h:
// #include <gl/gl.h>
To get the height and width of our heightfield, we then copy the height and width inside the Create function, to our global variables:
// hmHeight = hHeight;
// hmWidth = hWidth;
Now we move onto our Render function. Yay, we are about to start seeing some results 🙂
To start off, I am going to just render our terrain as a bunch of points in space. To do this, we need our glBegin(GL_POINTS) and glEnd() Inside of thse calls, I am placing a loop that will create a vertex at every point along the X and the Z axis at their respective Y positions. So our code goes from nothing, to this:
// void SwiftHeightField::Render(void){
// glBegin(GL_POINTS);
// glEnd();
// }
And then to this:
// void SwiftHeightField::Render(void){
// glBegin(GL_POINTS);
// for (int hMapX = 0; hMapX < hmWidth; hMapX++){
// for (int hMapZ = 0; hMapZ < hmHeight; hMapZ++){
// glVertex3f(hMapX, hHeightField[hMapX][hMapZ], hMapZ);
// }
// }
// glEnd();
// }
Upon running this program, you should find that a window is displayed with a black background, and a bunch of white spots in space. These spots are the vertices of our terrain and are the building blocks of everything to come 🙂
1.
2. 11. 20. 29. |
#include <stdio.h> #include <gl\gl.h> #include “heightfield.h” bool SwiftHeightField::Create(char *hFileName, const int hWidth, hmHeight = hHeight; void SwiftHeightField::Render(void){ glBegin(GL_POINTS); for (int hMapZ = 0; hMapZ < hmHeight; hMapZ++){ } |
Main.CPP File:
Hehe, this is a simple change. All we need to do here is change our Create call to load in the file, heightfield.raw. So our Create line looks like:
// hField.Create("heightfield.raw", 1024, 1024);
Check out the next tutorial on rendering the heightfield with triangle strips instead of points here 🙂
If you have any questions, just email me at swiftless@gmail.com
1. 2. 3. 4. 5. 6. 15. 24. 33. 42. 51. 60. 69. 78. 87. 96. 105. 114. 123. |
#include <GL/glew.h>
#include <GL/gl.h> #include <math.h> #include <windows.h> #include <string.h> #include “heightfield.h” #pragma comment(lib,“glew32.lib”) float xpos = 851.078, ypos = 351.594, zpos = 281.033, xrot = 758, yrot = 238, float lastx, lasty; float bounce; SwiftHeightField hField; void camera (void) { int posZ = (int)zpos; glTranslated(–xpos,–ypos,–zpos); void display (void) { glClearColor (0.0,0.0,0.0,1.0); glLoadIdentity(); glutSwapBuffers(); void Init (void) { void mouseMovement(int x, int y) { int diffx=x–lastx; lasty=y; } void keyboard (unsigned char key, int x, int y) { yrotrad = (yrot / 180 * 3.141592654f); xpos += float(sin(yrotrad)) * cScale; ypos –= float(sin(xrotrad)) ; } yrotrad = (yrot / 180 * 3.141592654f); xpos –= float(sin(yrotrad)) * cScale; ypos += float(sin(xrotrad)); } yrotrad = (yrot / 180 * 3.141592654f); zpos += float(sin(yrotrad)) * cScale; yrotrad = (yrot / 180 * 3.141592654f); zpos –= float(sin(yrotrad)) * cScale; } void reshape (int w, int h) { glMatrixMode (GL_PROJECTION); glMatrixMode (GL_MODELVIEW); int main (int argc, char **argv) { glutInit(&argc, argv); glutInitWindowSize(500, 500); Init(); glutReshapeFunc(reshape); glutMainLoop (); |
Download:
Download heightfield.h Source Code for this Tutorial
Download heightfield.cpp Source Code for this Tutorial
glVertex3f(hMapX, hHeightField[hMapX][hMapZ], hMapZ);
The .RAW-file saves the date like an array[height][width] (two-dimensional) or array[height*width] ( 1D ). So we get the conclusion that the raw file writes every CHAR/BYTE in sequences and “puts” it into our Array;
Hey Kagulos,
Each pixel in the height file, in this case the .raw file, is an integer value between 0 and 254 (inclusive). In this case, my .raw file is made up of R values, each ranging from 0 to 254. Where 254 is white and 0 is black. Effectively a grayscale image. Therefore a value of 0 is a height of 0 and a value of 254 is a height of 254.
So at pixel (x,y) in the file, we get a value from 0 to 254 according to the grayscale value.
This does have the limitation that the landscape be of the same dimensions of the image file. But you can also branch out and use R, G and B values independently.
For example, you could store all the height values in just the R portion of the colour. And then use G and B to store extra information, such as object placement or water table or plant data.
I hope this clears it up a little bit.
Cheers,
Swiftless
Okay,
this stuff is a little bit harder then the other tutorials 🙂
I’ve got a question:
How do we create the points?
You’ve wrote:
“I am placing a loop that will create a vertex at every point along the X and the Z axis at their respective Y positions”
i’ve understood that we get the positions of the vertex from the .raw-file.
Now i’m not quite sure how the .raw-file saved the hight’s.
Can you explain it, please?