【问题标题】:Weird normal generation on height map based terrain基于高度图的地形上的奇怪法线生成
【发布时间】:2014-04-30 14:24:32
【问题描述】:

我正在使用 libnoise 和 OpenGL 进行地形生成。我做了一个看起来有点复杂的正常生成算法:

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();

所以,如您所见,我正在生成法线,方法是对周围六个面的法线进行平均,从而实现平滑着色。问题是在某些地方(尤其是地形的较低部分),钻头仍然是黑色的,有奇怪的阴影。 这是一张照片:

我的正常一代是如何工作的:

注意!!!!我画了 Y,我的意思是 Z,对不起!

这是一张图片:

绿色是第一个顶点。
红色是第二个顶点(x 轴上的第一个 + 1)
黄色是相邻三角形的点。

X 是外循环。
Z 是内环。

由于我使用的是GL_TRIANGLE_STRIP,所以下一次迭代只需要2个顶点就可以构造一个三角形。

所以...每个三角形都被构造出来:
p1 = (x, 图像高度, z)
p2 = (x + 1, 图像高度, z)

在下一次迭代中(z++)

p3 = (x, 图像高度, z + 1)
p4 = (x + 1, 图像高度, z + 1)

...等等。

【问题讨论】:

    标签: c++ opengl terrain normals heightmap


    【解决方案1】:

    我没有彻底检查所有代码,但我注意到您在此行末尾附近缺少一个“z”:

    t2 = Vector3(x + 1, image.GetValue(x + 1, z - 1).red / div, - 1);
    

    v4的计算中(两次)。

    另外,在这一行:

    Vector3 normal1 = Vector3::Normalize((v1 + v2 + v3 + v4 + v5 + v6) / 6);
    

    在标准化之前不需要除以 6。实际上,您可以尝试在求和之前不对单个交叉产品进行标准化。这将使法线向中心更靠近顶点的三角形加权。

    【讨论】:

    • 试过了,变得更糟了。就像由小三角形组成的跳棋。我在某处读到,由于_STRIP 存在双向排序,我需要翻转正常。但是我不知道反向法线到底是在哪里生成的,或者如何测试它。
    • @Arctic:对于每个奇数三角形,您都会翻转生成的法线。当以条带顺序排列时,每个三角形交替缠绕。如果您按照条带顺序计算三角形的法线并且未能对此进行补偿,那么如果您平均每个三角形的法线,其中一半将面向错误的方向。这是一个really good example,就是因为这个而发生的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多