7. Terrain Level Of Detail

Jump To:

heightfield.h Source
heightfield.cpp Source

main.cpp Source
Download

Heightfield.H File:

This is a really simple change I am going to implement, which will give us a crisper looking terrain, while also giving us a constant 60 frames per second :-D I am going to add a variable here which will be called hLOD:

// int hLOD;

This is going to be a public variable which we are going to set before we create our terrain. It is going to be a number which is a power of 2. Eg: 2, 4, 8, 16. I am going to use it to draw every nth vertex, where n is the hLOD variable. So we are going to draw every hLOD vertex if that makes sense. The reason this speeds up the terrain rendering should be obvious, the less we have to draw, the faster it will go. But it makes it crisper as well, because if you run the previous tutorials and get up close to the terrain, you will find that it is really jagged. This also smooths out the terrain surface for us.

1.
2.
3.
4.

5.
6.
7.
8.
9.
10.
11.
12.
13.

14.
15.
16.
17.
18.
19.
20.
21.
22.

23.
24.
25.
26.
27.
28.
29.
30.
31.

32.
33.
34.
35.
36.
37.
38.
39.
40.

41.

    #include <windows.h>

class Vert{
public:
float x;

float y;
float z;
};

class TexCoord{

public:
float u;
float v;
};

class SwiftHeightField {

private:
int hmHeight;
int hmWidth;

int vhVertexCount;
Vert *vhVertices;

TexCoord *vhTexCoords;

unsigned int vhVBOVertices;
unsigned int vhVBOTexCoords;

unsigned int tID[2];

bool Init(void);

public:
bool Create(char *hFileName, const int hWidth, const int 
hHeight);

void Render(void);

int hLOD;

BYTE hHeightField[1024][1024];

};

Heightfield.CPP File:

In our heightfield.cpp file, all our changes are going to take place in the Create function. First, we need to change the vertex count that we will be using throughout to tell us how many vertices we need, we do this by changing the following line:

// vhVertexCount = (int)(hmHeight * hHeight * 6) / (1 * 1);

to:

// vhVertexCount = (int)(hmHeight * hHeight * 6) / (hLOD * hLOD);

The next change we need to make is to the increments in our loops. Instead of incrementing by 1 for every vertex, we need to increment by every hLOD to get every hLOD’th vertex like so:

for (int hMapX = 0; hMapX < hmWidth; hMapX+=hLOD){

for (int hMapZ = 0; hMapZ < hmHeight; hMapZ+=hLOD){

After we have our loop setup, we need to make sure that our polygons span over every hLOD vertex, so instead of incrementing our vertices X and Z positions by 1, we need to increment them by our hLOD value as follows:

flX = (float)hMapX + ((nTri == 1 || nTri == 2 || nTri == 5) ? hLOD : 0);
flZ = (float)hMapZ + ((nTri == 2 || nTri == 4 || nTri == 5) ? hLOD : 0);

Next we are going to move onto our main.cpp file and set a value for our hLOD variable.

1.
2.
3.
4.
5.
6.
7.

8.
9.
10.
11.
12.
13.
14.
15.
16.

17.
18.
19.
20.
21.
22.
23.
24.
25.

26.
27.
28.
29.
30.
31.
32.
33.
34.

35.
36.
37.
38.
39.
40.
41.
42.
43.

44.
45.
46.
47.
48.
49.
50.
51.
52.

53.
54.
55.
56.
57.
58.
59.
60.
61.

62.
63.
64.
65.
66.
67.
68.
69.
70.

71.
72.
73.
74.
75.
76.
77.
78.
79.

80.
81.
82.
83.
84.
85.
86.
87.
88.

89.
90.
91.
92.
93.
94.
95.

    #include <stdio.h>

#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glext.h>

#include “jpeg.h”
#include “heightfield.h”

bool SwiftHeightField::Init(void){

glGenBuffersARB(1, &vhVBOVertices);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOVertices);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vhVertexCount * 
* sizeof(float), vhVertices, GL_STATIC_DRAW_ARB);

glGenBuffersARB(1, &vhVBOTexCoords);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOTexCoords);

glBufferDataARB(GL_ARRAY_BUFFER_ARB, vhVertexCount * 
* sizeof(float), vhTexCoords, GL_STATIC_DRAW_ARB);

delete [] vhVertices;
vhVertices = NULL;

delete [] vhTexCoords;

vhTexCoords = NULL;

return true;
}

bool SwiftHeightField::Create(char *hFileName, const 
int hWidth, const int hHeight){

hmHeight = hHeight;
hmWidth = hWidth;

FILE *fp;

fp = fopen(hFileName, “rb”);

fread(hHeightField, 1, hWidth * hHeight, fp);

fclose(fp);

vhVertexCount = (int)(hmHeight * hHeight * 6) / (hLOD * hLOD
);

vhVertices = new Vert[vhVertexCount];
vhTexCoords = new TexCoord[vhVertexCount];

int nIndex = 0;
float flX;
float flZ;

for (int hMapX = 0; hMapX < hmWidth; hMapX+=hLOD){

for (int hMapZ = 0; hMapZ < hmHeight; hMapZ+=hLOD){
for (int nTri = 0; nTri < 6; nTri++){

flX = (float)hMapX + ((nTri == 1 || nTri == 2 || nTri == 5) ? hLOD : 0);

flZ = (float)hMapZ + ((nTri == 2 || nTri == 4 || nTri == 5) ? hLOD : 0);

vhVertices[nIndex].x = flX;
vhVertices[nIndex].y = hHeightField[(int)flX][(int)flZ];

vhVertices[nIn