# Vertex normal calculation for triangle strips?

This topic is 1828 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I understand that calculating a normal is a rather simple concept, but for some reason, I can't wrap my head around generating normals for a triangle strip.  What I have is a heightmap and I need normals for lighting.  The whole thing is rendered using triangle strips.

Just in case you need a visual, take a look at this code I used to generate vertices and texture coordinates.

void heightmap_t::build_vertices()
{
float X, Y;
float x, y, z;
bool switch_sides = No;

/* Sanity check */
if( !m_height_data )
return;

/*
* First Pass: determine total number of vertices needed
*/
m_vertex_count = 0;

for ( X = 0; X <= m_width; X += m_polygon_scale )
{
/* Are we switching sides? */
if( switch_sides )
{
for( Y = m_height; Y >= 0; Y -= m_polygon_scale )
{
m_vertex_count += 2;
}
}
else
{
for( Y = 0; Y <= m_height; Y += m_polygon_scale )
{
m_vertex_count += 2;
}
}

/* Switch the direction the columb renders to allow fluid tri-strips */
switch_sides = !switch_sides;
}

/*
* Second Pass: Allocate and generate vertices
*/

switch_sides = No;
m_vertices = new float[m_vertex_count*3];
m_texcoords = new float[m_vertex_count*2];
int v = 0;

for ( X = 0; X <= m_width; X += m_polygon_scale )
{
/* Are we switching sides? */
if( switch_sides )
{
/* Columns */
for( Y = m_height; Y >= 0; Y -= m_polygon_scale )
{
/* Bottom left vertex */
x = X;
y = get_height( X, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;

/* Bottom right vertex */
x = X + m_polygon_scale;
y = get_height( X + m_polygon_scale, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;
}
}
else
{
for( Y = 0; Y <= m_height; Y += m_polygon_scale )
{
/* Bottom right vertex */
x = X + m_polygon_scale;
y = get_height( X + m_polygon_scale, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;

/* Bottom left vertex */
x = X;
y = get_height( X, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;
}
}

/* Switch the direction the columb renders to allow fluid tri-strips */
switch_sides = !switch_sides;
}

/* Use the vertex data to generate a VBO */
glGenBuffers( 3, m_vbo );
glBindBuffer( GL_ARRAY_BUFFER, m_vbo[0] );
glBufferData( GL_ARRAY_BUFFER, m_vertex_count*3*sizeof(float), m_vertices, GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, m_vbo[1] );
glBufferData( GL_ARRAY_BUFFER, m_vertex_count*2*sizeof(float), m_texcoords, GL_STATIC_DRAW );
}


This is based off of an old tutorial from gametutorials.com.  A bit of a shame that they didn't calculate normals in the heightmap tutorial...

My initial idea was to take each triangle individually, and calculate face normals first.  Then I get confused after the 2nd part.  Do I like go each vertex and  match up vertices with matching coordinates, add the normals and re-normalize?  That's the part I'm having trouble wrapping my head around.  My brain is a bit fried at the moment, and I'm in a 24-hour coding competition right now.  Any ideas?  Thanks.

Shogun.

##### Share on other sites

Oh, and another thing, this is my attempt to calculate them here.  What I did was take each surrounding value and form triangles with them.  Then I calculate the face normals of the resulting 8 triangles, then add the normals together, then average them out.  It's buggy, but it's better than nothing, that's for sure.

void calculate_normal( int x, int y, int polygon_offset, float* n_out )
{
int tris = 0; /* Triangles formed */
float center[3];
float vertices[8][3];
float fnormals[8][3];

/*x = X;
y = get_height( X, Y );
z = Y;*/

/* Calculate the center */
center[0] = x;
center[1] = get_height( x, y );
center[2] = y;

/* Right */
vertices[0][0] = x+polygon_offset;
vertices[0][1] = get_height(x+polygon_offset, y);
vertices[0][2] = y;

/* Right bottom */
vertices[1][0] = x+polygon_offset;
vertices[1][1] = get_height(x+polygon_offset, y-polygon_offset);
vertices[1][2] = y-polygon_offset;

/* Bottom */
vertices[2][0] = x;
vertices[2][1] = get_height(x, y-polygon_offset);
vertices[2][2] = y-polygon_offset;

/* Left bottom */
vertices[3][0] = x-polygon_offset;
vertices[3][1] = get_height(x-polygon_offset, y-polygon_offset);
vertices[3][2] = y-polygon_offset;

/* Left */
vertices[4][0] = x-polygon_offset;
vertices[4][1] = get_height(x-polygon_offset, y);
vertices[4][2] = y;

/* Left top */
vertices[5][0] = x-polygon_offset;
vertices[5][1] = get_height(x-polygon_offset, y+polygon_offset);
vertices[5][2] = y+polygon_offset;

/* Top */
vertices[6][0] = x;
vertices[6][1] = get_height(x, y+polygon_offset);
vertices[6][2] = y+polygon_offset;

/* Right top */
vertices[7][0] = x+polygon_offset;
vertices[7][1] = get_height(x+polygon_offset, y+polygon_offset);
vertices[0][2] = y+polygon_offset;

/* Generate face normals */
for( int i = 0; i < 7; i++ )
{
float temp[3];
int i2 = (i+1) < 7 ? i : 0;

cross( center, vertices[i], vertices[i2], temp );
normalize( temp, fnormals[i] );
memcpy( n_out, fnormals[i], sizeof( float ) * 3 );
}

/* Average out normals */
n_out[0] /= 8.0f;
n_out[1] /= 8.0f;
n_out[2] /= 8.0f;
}


The results:

[attachment=19544:Screen Shot 2014-01-18 at 7.48.48 PM.png]

Any ideas?  Thanks.

Shogun.

##### Share on other sites

I understand that calculating a normal is a rather simple concept, but for some reason, I can't wrap my head around generating normals for a triangle strip.  What I have is a heightmap and I need normals for lighting.  The whole thing is rendered using triangle strips.

Just in case you need a visual, take a look at this code I used to generate vertices and texture coordinates.

void heightmap_t::build_vertices()
{
float X, Y;
float x, y, z;
bool switch_sides = No;

/* Sanity check */
if( !m_height_data )
return;

/*
* First Pass: determine total number of vertices needed
*/
m_vertex_count = 0;

for ( X = 0; X <= m_width; X += m_polygon_scale )
{
/* Are we switching sides? */
if( switch_sides )
{
for( Y = m_height; Y >= 0; Y -= m_polygon_scale )
{
m_vertex_count += 2;
}
}
else
{
for( Y = 0; Y <= m_height; Y += m_polygon_scale )
{
m_vertex_count += 2;
}
}

/* Switch the direction the columb renders to allow fluid tri-strips */
switch_sides = !switch_sides;
}

/*
* Second Pass: Allocate and generate vertices
*/

switch_sides = No;
m_vertices = new float[m_vertex_count*3];
m_texcoords = new float[m_vertex_count*2];
int v = 0;

for ( X = 0; X <= m_width; X += m_polygon_scale )
{
/* Are we switching sides? */
if( switch_sides )
{
/* Columns */
for( Y = m_height; Y >= 0; Y -= m_polygon_scale )
{
/* Bottom left vertex */
x = X;
y = get_height( X, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;

/* Bottom right vertex */
x = X + m_polygon_scale;
y = get_height( X + m_polygon_scale, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;
}
}
else
{
for( Y = 0; Y <= m_height; Y += m_polygon_scale )
{
/* Bottom right vertex */
x = X + m_polygon_scale;
y = get_height( X + m_polygon_scale, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;

/* Bottom left vertex */
x = X;
y = get_height( X, Y );
z = Y;

/* Set texture and vertex coordinates */
m_texcoords[(v*2)+0] = ( x / float( m_width ) ) * 50.0f;
m_texcoords[(v*2)+1] = -( z / float( m_height ) ) * 50.0f;
m_vertices[(v*3)+0] = x;
m_vertices[(v*3)+1] = y;
m_vertices[(v*3)+2] = z;
v++;
}
}

/* Switch the direction the columb renders to allow fluid tri-strips */
switch_sides = !switch_sides;
}

/* Use the vertex data to generate a VBO */
glGenBuffers( 3, m_vbo );
glBindBuffer( GL_ARRAY_BUFFER, m_vbo[0] );
glBufferData( GL_ARRAY_BUFFER, m_vertex_count*3*sizeof(float), m_vertices, GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, m_vbo[1] );
glBufferData( GL_ARRAY_BUFFER, m_vertex_count*2*sizeof(float), m_texcoords, GL_STATIC_DRAW );
}

This is based off of an old tutorial from gametutorials.com.  A bit of a shame that they didn't calculate normals in the heightmap tutorial...

My initial idea was to take each triangle individually, and calculate face normals first.  Then I get confused after the 2nd part.  Do I like go each vertex and  match up vertices with matching coordinates, add the normals and re-normalize?  That's the part I'm having trouble wrapping my head around.  My brain is a bit fried at the moment, and I'm in a 24-hour coding competition right now.  Any ideas?  Thanks.

Shogun.

IIRC, yes you take each face that connects the vertex, add them together, then normalize the result. however you have to be careful not to add a co-planar faces, as it skew's the results. Edited by slicer4ever

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 28
• 16
• 10
• 10
• 11
• ### Forum Statistics

• Total Topics
634111
• Total Posts
3015573
×