我很难弄清楚如何计算正常,我想我有一些误解所以我想举一个简单几何的例子并找出正常情况,在这种情况下它应该更清楚如何用更硬的几何形状做到这一点。
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)?
答案 0 :(得分:12)
当您需要计算 quad 的 normal 时,您需要计算四边形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正常一次,并尽可能长时间地为每个顶点使用它。