Weird normal generation on height map based terrain
I'm working on terrain generation using libnoise and OpenGL. I have made a somewhat complex normal generation algorithm as it seems:
list = glGenLists(1);
glNewList(list, GL_COMPILE);
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_TEXTURE_2D);
glPushMatrix();
int h = 256;
int w = 256;
float h1 = 0.0f;
float h2 = 0.0f;
float h3 = 0.0f;
float div = 7.0f;
float lPos[] = { 128, image.GetHeight() + 15.0f, 128, 1.0f };
for (int x = 1; x < h; x++)
{
glColor3ub(139, 69, 19);
glLightfv(GL_LIGHT0, GL_POSITION, lPos);
glBegin(GL_TRIANGLE_STRIP);
for (int z = 1; z < w; z++)
{
h1 = image.GetValue(x, z).red / 7.0f;
h2 = image.GetValue(x + 1, z).red / 7.0f;
Vector3 t1, t2, t3;
Vector3 v1, v2, v3, v4, v5, v6;
t1 = Vector3(x, h1, z);
t2 = Vector3(x - 1, image.GetValue(x - 1, z).red / div, z);
t3 = Vector3(x, image.GetValue(x, z - 1).red / div, z - 1);
v1 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1, image.GetValue(x + 1, z).red / div, z);
t3 = Vector3(x, image.GetValue(x, z + 1).red / div, z + 1);
v2 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1, image.GetValue(x + 1, z).red / div, z);
t3 = Vector3(x + 1, image.GetValue(x + 1, z - 1).red / div, z - 1);
v3 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1, image.GetValue(x + 1, z - 1).red / div, - 1);
t3 = Vector3(x , image.GetValue(x, z - 1).red / div, z - 1);
v4 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x - 1, image.GetValue(x - 1, z + 1).red / div, z + 1);
t3 = Vector3(x - 1, image.GetValue(x - 1, z).red / div, z);
v5 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x - 1, image.GetValue(x - 1, z + 1).red / div, z + 1);
t3 = Vector3(x, image.GetValue(x, z + 1).red / div, z + 1);
v6 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
Vector3 normal1 = Vector3::Normalize((v1 + v2 + v3 + v4 + v5 + v6) / 6);
glNormal3f(normal1.X, normal1.Y, normal1.Z);
glVertex3f(x, h1, z);
t1 = Vector3(x + 1, h2, z);
t2 = Vector3(x + 1 - 1, image.GetValue(x + 1 - 1, z).red / div, z);
t3 = Vector3(x + 1, image.GetValue(x + 1, z - 1).red / div, z - 1);
v1 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1 + 1, image.GetValue(x + 1 + 1, z).red / div, z);
t3 = Vector3(x + 1, image.GetValue(x + 1, z + 1).red / div, z + 1);
v2 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1 + 1, image.GetValue(x + 1 + 1, z).red / div, z);
t3 = Vector3(x + 1 + 1, image.GetValue(x + 1 + 1, z - 1).red / div, z - 1);
v3 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1 + 1, image.GetValue(x + 1 + 1, z - 1).red / div, -1);
t3 = Vector3(x + 1, image.GetValue(x + 1, z - 1).red / div, z - 1);
v4 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1 - 1, image.GetValue(x + 1 - 1, z + 1).red / div, z + 1);
t3 = Vector3(x + 1 - 1, image.GetValue(x + 1 - 1, z).red / div, z);
v5 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
t2 = Vector3(x + 1 - 1, image.GetValue(x + 1 - 1, z + 1).red / div, z + 1);
t3 = Vector3(x + 1, image.GetValue(x + 1, z + 1).red / div, z + 1);
v6 = Vector3::Normalize(Vector3::Cross(t3 - t1, t2 - t1));
normal1 = Vector3::Normalize((v1 + v2 + v3 + v4 + v5 + v6) / 6);
glNormal3f(normal1.X, normal1.Y, normal1.Z);
glVertex3f(x + 1, h2, z);
}
glEnd();
}
glPopMatrix();
glPopAttrib();
glEndList();
So, as you can see I'm generating the normals, by averaging the normals from the six surrounding faces, thus achieving smooth shading. The problem is that in some parts (especially lower parts of the terrain) bits remain black-ish, weirdly shaded. Here's a pic:
How my normal generation works:
NOTE!!!! I drew Y and I meant Z, sorry!
Here's an image:
Green is the first vertex.
Red is the second vertex (first + 1 on x axis)
Yellow are the points of adjacent triangles.
X is the outer loop.
Z is the inner loop.
Since I'm using GL_TRIANGLE_STRIP
, I only need 2 vertices for the next iteration to construct a triangle.
So... each triangle is constructed:
p1 = (x, image height, z)
p2 = (x + 1, image height, z)
and on the next iteration (z++)
p3 = (x, image height, z + 1)
p4 = (x + 1, image height, z + 1)
...etc.
I haven't checked all the code thoroughly, but I noticed you're missing a "z" near the end of this line:
t2 = Vector3(x + 1, image.GetValue(x + 1, z - 1).red / div, - 1);
In the calculation of v4
(both times).
Also, in this line:
Vector3 normal1 = Vector3::Normalize((v1 + v2 + v3 + v4 + v5 + v6) / 6);
You do not need to divide by 6 before normalizing. In fact you could try not normalizing the individual cross products before summing them. This will weight the normals towards the triangles whose center is closer to the vertex.
链接地址: http://www.djcxy.com/p/37180.html上一篇: 如何纹理用三角形绘制的“完美立方体”?
下一篇: 基于高度图的地形上奇怪的正常世代