3
votes

I'm trying to calculate the vertex normals for a wave, but I'm getting a chequered effect instead of the desired smooth shading.

enter image description here

I'm not sure if I'm passing the correct vector into the calcNormal() function or if something else is wrong.

Here is my wave code

Vector3 wave1(Sea::seaGrid[i][j].x, Sea::sinVals[k], Sea::seaGrid[i][j].z);
Vector3 wave2(Sea::seaGrid[i][j+1].x, Sea::sinVals[k], Sea::seaGrid[i][j+1].z);
Vector3 wave3(Sea::seaGrid[i+1][j+1].x, Sea::sinVals[nextK], Sea::seaGrid[i+1][j+1].z);
Vector3 wave4(Sea::seaGrid[i+1][j].x, Sea::sinVals[nextK], Sea::seaGrid[i+1][j].z);

Vector3 waveNorm1 = wave1.calcNormal(wave2);
Vector3 waveNorm2 = wave2.calcNormal(wave3);
Vector3 waveNorm3 = wave3.calcNormal(wave4);
Vector3 waveNorm4 = wave4.calcNormal(wave1);

//rest of wave
glBegin(GL_POLYGON);    
glNormal3f(waveNorm1.x, waveNorm1.y, waveNorm1.z);glTexCoord2f(0.0, 1.0);glVertex3f(Sea::seaGrid[i][j].x, Sea::sinVals[k], Sea::seaGrid[i][j].z);
glNormal3f(waveNorm2.x, waveNorm2.y, waveNorm2.z);glTexCoord2f(0.0, 0.0);glVertex3f(Sea::seaGrid[i][j+1].x, Sea::sinVals[k], Sea::seaGrid[i][j+1].z);
glNormal3f(waveNorm3.x, waveNorm3.y, waveNorm3.z);glTexCoord2f(1.0, 0.0);glVertex3f(Sea::seaGrid[i+1][j+1].x, Sea::sinVals[nextK], Sea::seaGrid[i+1][j+1].z);
glNormal3f(waveNorm4.x, waveNorm4.y, waveNorm4.z);glTexCoord2f(1.0, 1.0);glVertex3f(Sea::seaGrid[i+1][j].x, Sea::sinVals[nextK], Sea::seaGrid[i+1][j].z);
glEnd();

This is the calcNormal() function

Vector3& Vector3::calcNormal(const Vector3 &other){

Vector3 normal = crossProduct(*this, other);

//normalises vector
float vecLength = sqrt(pow(normal.x,2)+pow(normal.y,2)+pow(normal.z,2));// length();

normal.x = normal.x / vecLength;
normal.y = normal.y / vecLength;
normal.z = normal.z / vecLength;

return normal;
}

and this is the crossProduct() function

Vector3 Vector3::crossProduct( const Vector3 &v1,  const Vector3 &v2 )
{
Vector3 vCrossProduct;

vCrossProduct.x = v1.y * v2.z - v1.z * v2.y;
vCrossProduct.y = v1.z * v2.x - v1.x * v2.z;
vCrossProduct.z = v1.x * v2.y - v1.y * v2.x;

return vCrossProduct;
}

any ideas?

1
Surely the normal at i,j doesn't exclusively depend on the points at i,j and i+1,j, similarly at the other wave points?.user786653
are you saying that for waveNorm1 it should be wave4.calcNormal(wave2) instead?Chris
No, that the normal at point (i,j) probably depends on more and other variables than the points at (i,j) and (i+1,j) and probably other points than (i+1,j) and (i,j+1) that you also have. With the disclaimer that I might have misread your question I think you might want to look at something like en.wikipedia.org/wiki/Finite_difference_methoduser786653
By the way, don't draw polygons! Just draw quads (GL_QUADS), or even better triangles (GL_TRIANGLES). That way you can even wrap the whole wave mesh into a single glBegin/glEnd block and the transition to vertex arrays is also much easier.Christian Rau

1 Answers

5
votes

Those make no sense:

Vector3 waveNorm1 = wave1.calcNormal(wave2);
Vector3 waveNorm2 = wave2.calcNormal(wave3);
Vector3 waveNorm3 = wave3.calcNormal(wave4);
Vector3 waveNorm4 = wave4.calcNormal(wave1);

By that you're calculating the cross product of the position vectors. But what you actually want are the cross products of the local differentials, i.e. differences.

I.e. (wave2 - wave1) × (wave3 - wave1)