I’m currently trying to render a terrain by loading one stored in a heightmap. I’m creating a class for loading and displaying it, but I’m having trouble displaying it (I assume that it’s being loaded correctly, but can’t be 100% sure until I get it displayed properly). I’m trying to find a way to display it using a VBO and triangle strips but can’t seem to get it working just right. The terrain looks awful. Images of the terrain along with the heightmap can be found at: Terrain Stuff(2) .
My code for loading and displaying the terrain looks like this:
void Terrain::Load(wchar_t* Image)
{
WritetoLog("Loading terrain from heightmap...");
Texture HeightMap;
HeightMap.LoadTexture(Image);
Width = HeightMap.Get_ImgWidth();
Depth = HeightMap.Get_ImgHeight();
Heights = new float*[Width];
for ( int i = 0; i < Width; i++ )
Heights[i] = new float[Depth];
for ( int x = 0; x < Width; x++ )
for ( int z = 0; z < Depth; z++ )
{
GLubyte Color = HeightMap.GetPixel(x, z)[0];
Heights[x][z] = (Color/255.f - .5f) * TERRAIN_MAX_HEIGHT * 2;
}
vec3 Normals[Width][Depth], SmoothNormals[Width][Depth];
for ( int x = 0; x < Width; x++ )
for ( int z = 0; z < Depth; z++ )
{
Normals[x][z] = vec3(0);
vec3 Front, Behind, Right, Left;
if ( z > 0 )
Front = vec3( 0, Heights[x][z] - Heights[x][z+1], -1 );
if ( z < Depth - 1 )
Behind = vec3( 0, Heights[x][z] - Heights[x][z-1], 1 );
if ( x > 0 )
Left = vec3( 1, Heights[x][z] - Heights[x-1][z], 0 );
if ( x < Width - 1 )
Right = vec3( -1, Heights[x][z] - Heights[x+1][z], 0 );
if ( x > 0 and z > 0 )
Normals[x][z] += normalize( cross(Front, Left) );
if ( x > 0 and z < Depth - 1 )
Normals[x][z] += normalize( cross(Behind, Left) );
if ( x < Width - 1 and z > 0 )
Normals[x][z] += normalize( cross(Front, Right) );
if ( x < Width - 1 and z < Depth - 1 )
Normals[x][z] += normalize( cross(Behind, Right) );
Normals[x][z] = Normals[x][z];
}
const float NeighborWeight = .75;
for ( int x = 0; x < Width; x++ )
for ( int z = 0; z < Depth; z++ )
{
SmoothNormals[x][z] = Normals[x][z];
if ( x > 0 )
SmoothNormals[x][z] += Normals[x-1][z] * NeighborWeight;
if ( z > 0 )
SmoothNormals[x][z] += Normals[x][z-1] * NeighborWeight;
if ( z < Depth - 1 )
SmoothNormals[x][z] += Normals[x][z+1] * NeighborWeight;
if ( x < Width - 1 )
SmoothNormals[x][z] += Normals[x+1][z] * NeighborWeight;
SmoothNormals[x][z] = normalize(SmoothNormals[x][z]);
}
vector<vec3> Verts;
vector<vec3> Norms;
vector<vec4> Cols;
vector<unsigned short> Indicies;
for ( int x = 0; x < Width; x++ )
for ( int z = 0; z < Depth; z++ )
{
Verts.push_back( vec3( x - Width/2.f, Heights[x][z] - TERRAIN_MAX_HEIGHT/2.f, -z + Depth/2.f ) ); ///Automatically translate terrain to be centered at (0,0,0)
Norms.push_back( SmoothNormals[x][z] );
if ( Verts.back().y >= TERRAIN_MAX_HEIGHT/2.f * .75 )
Cols.push_back( vec4( 242/255.f, 242/255.f, 242/255.f, 1 ) ); /// Simple snow capped mountain effect
else
Cols.push_back( vec4( 49/255.f, 150/255.f, 36/255.f, 1 ) );
}
for ( int x = 0; x < Width - 1; x++ )
for ( int z = 0; z < Depth; z++ )
{
Indicies.push_back( z + x*Depth );
Indicies.push_back( z + (x+1)*Depth );
}
glGenBuffers( 4, IDs );
glBindBuffer( GL_ARRAY_BUFFER, IDs[0] );
glBufferData( GL_ARRAY_BUFFER, Verts.size() * sizeof(vec3), &Verts[0], GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, IDs[1] );
glBufferData( GL_ARRAY_BUFFER, Cols.size() * sizeof(vec4), &Cols[0], GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, IDs[2] );
glBufferData( GL_ARRAY_BUFFER, Norms.size() * sizeof(vec3), &Norms[0], GL_STATIC_DRAW );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IDs[3] );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, Indicies.size() * sizeof(unsigned short), &Indicies[0], GL_STATIC_DRAW );
NumIndicies = Indicies.size();
WritetoLog("Terrain Loaded Successfully");
}
void Terrain::Draw(int Attributes[4])
{
int InitialFlags = BasicProgram.Get_Flags();
BasicProgram.SetFlags( USING_POINT_LIGHT | USING_SPOT_LIGHT | USING_VERTEX_COLOR | USING_NORMALIZED_NORMALS );
BasicProgram.UpdateFlags();
glEnableVertexAttribArray( Attributes[0] );
glBindBuffer(GL_ARRAY_BUFFER, IDs[0]);
glVertexAttribPointer(Attributes[0], 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );
glEnableVertexAttribArray( Attributes[1] );
glBindBuffer(GL_ARRAY_BUFFER, IDs[1]);
glVertexAttribPointer( Attributes[1], 4, GL_FLOAT, GL_FALSE, 0, (void*)0 );
glEnableVertexAttribArray( Attributes[3] );
glBindBuffer(GL_ARRAY_BUFFER, IDs[2]);
glVertexAttribPointer( Attributes[3], 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IDs[3]);
glDrawElements(GL_TRIANGLE_STRIP, NumIndicies, GL_UNSIGNED_SHORT, (void*)0 );
for ( int i = 0; i < 4; i++ )
glDisableVertexAttribArray( Attributes[i] );
BasicProgram.SetFlags(InitialFlags);
}
Do I just need to average my normals or is there more I need to do?
Edit:
I fixed everything myself