1

我很难弄清楚如何计算法线,我想我有一些误解,所以我想举一个简单几何的例子,并找出法线,在这种情况下应该更清楚如何做更难的几何。

    glBegin(GL_QUADS);
       glVertex3f(1,1,-1);
       glVertex3f(1,1,1);
       glVertex3f(-1,1,1);
       glVertex3f(-1,1,-1);
    glEnd();

在我知道的每个顶点处,我需要输入一个正常值(我想点亮这个),所以这代表一个正面的正方形(2 x 2)。那么在每个顶点之前我会有一个法线(0、1.0、0)吗?

4

1 回答 1

13

当您需要计算四边形的法线时,您需要计算四边形的 4 个顶点的叉积

A = (1, 1, -1)
B = (1, 1, 1)
C = (-1, 1, 1)
D = (-1, 1, -1)

这就是四边形顶点的布局方式。我添加这个的原因是因为您计算以下顶点的顺序很重要!

A----B
|    |
|    |
D----C

所以现在当你想计算法线时,你只需要这样做。

normal = (C - A) x (D - B)

其中 x 表示叉积。

交叉产品

如果您不知道什么是叉积或如何计算它,那么在这里我将向您展示如何计算它。

V1 = (C - A)
V2 = (D - B)

然后我们通过执行以下操作来计算叉积。

normal.x = V1.y * V2.z - V1.z * V2.y
normal.y = V2.x * V1.z - V2.z * V1.x
normal.z = V1.x * V2.y - V1.y * V2.x

其中上面3行相当于写。

normal = V1 x V2

现在我们已经计算了叉积,在本例中是一个 3D 向量。

额外的

如果您不知道什么是交叉产品,并且想了解更多关于它的信息,那么您可以在这两个链接上阅读更多关于它的信息。

编辑

我做了叉积,它是正常的 = (0, 8, 0),如果我标准化它,我得到 (0, 1, 0)

x, y, z,只是为了澄清一些事情,我们需要对正态进行归一化的原因是因为我们正在计算之间的正态分布0 <-> 1

如果你想标准化一个向量,你会做以下事情。

length = sqrt(x * x + y * y + z * z)

if (length > 0) {
    x /= length
    y /= length
    z /= length
}

此外,如果您想检查是否需要对向量进行归一化,您可以执行以下操作。

if ((x * x + y * y + z * z) != 1) {
    // NORMALIZE THE VECTOR
}

现在这是否意味着我只需要在顶点上放置一次,或者我需要为四边形中的每个顶点提及它。

第一种方式

glBegin(GL_QUADS);
    glNormal3f(0, 1, 0);
    glVertex3f(1, 1, -1);
    glVertex3f(1, 1, 1);
    glVertex3f(-1, 1, 1);
    glVertex3f(-1, 1, -1);
glEnd();

第二种方式

glBegin(GL_QUADS);
    glNormal3f(0, 1, 0);
    glVertex3f(1, 1, -1);
    glNormal3f(0, 1, 0);
    glVertex3f(1, 1, 1);
    glNormal3f(0, 1, 0);
    glVertex3f(-1, 1, 1);
    glNormal3f(0, 1, 0);
    glVertex3f(-1, 1, -1);
glEnd();

你是用第一种还是第二种方式并不重要。只要你的四边形是平的,所以如果它完全是平的,你可以做第一种或第二种方法。

虽然如果你的四边形不是完全平坦的,那么你需要做第二种方式,因为这样四边形的每个顶点都会/可能有不同的法线。

许多资源说您需要计算每个顶点的法线。

这是真的,尽管正如我上面所说,如果你计算一个完全平坦的四边形的法线,那么每个顶点的法线将是相同的,因此你可以通过只计算一次法线来节省一些计算/时间/CPU尽可能长时间地对每个顶点使用它。

于 2013-11-05T17:59:49.500 回答