4

我正在根据 Apple 的示例代码在 OpenGL-ES 中制作一些相当基本的形状。他们使用了一个点数组,在第一个数组中有一个索引数组,每组三个索引创建一个多边形。太好了,我可以做出我想要的形状。为了正确着色形状,我相信我需要计算每个多边形上每个顶点的法线。起初形状是长方体的,所以很容易,但现在我正在制作(稍微)更高级的形状,我想自动创建这些法线。如果我得到一个多边形的两条边的向量(这里所有的多边形都是三角形)并将它们的叉积用于该多边形上的每个顶点,这似乎很容易。之后,我使用下面的代码来绘制形状。

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices);

glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, 0, triangleColours);

glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 0, triangleNormals);

glDrawArrays(GL_TRIANGLES, 0, 48);

glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribColor);
glDisableVertexAttribArray(GLKVertexAttribNormal);

我无法理解的是为什么我必须手动执行此操作。我敢肯定在某些情况下,您需要的不仅仅是垂直于表面的矢量,但我也确信这是迄今为止最流行的用例,所以不应该有更简单的方法吗?我错过了什么明显的东西吗?glCalculateNormals() 会很棒。

//这是一个答案 传入一个您希望用法线填充的 GLKVector3[],另一个带有顶点(每三个被分组为多边形),然后是顶点数。

- (void) calculateSurfaceNormals: (GLKVector3 *) normals forVertices: (GLKVector3 *)incomingVertices count:(int) numOfVertices
{

    for(int i = 0; i < numOfVertices; i+=3)
    {
        GLKVector3 vector1 = GLKVector3Subtract(incomingVertices[i+1],incomingVertices[i]);
        GLKVector3 vector2 = GLKVector3Subtract(incomingVertices[i+2],incomingVertices[i]);        
        GLKVector3 normal = GLKVector3Normalize(GLKVector3CrossProduct(vector1, vector2));
        normals[i] = normal;
        normals[i+1] = normal;
        normals[i+2] = normal;
    }
}
4

1 回答 1

3

答案又是:OpenGL 既不是场景管理库也不是几何库,而只是一个在屏幕上绘制漂亮图片的绘图 API。对于照明,它需要法线,你给它法线。就这样。如果这只能由用户完成并且与实际绘图无关,它为什么要计算法线?

通常你不会在运行时计算它们,而是从文件中加载它们。计算法线的方法有很多种。你想要每个面法线还是每个顶点法线?您是否需要任何特定的硬边或任何特定的平滑补丁?如果你想平均面法线以获得顶点法线,你想如何平均这些?

随着着色器的出现以及在较新的 OpenGL 版本中删除了内置法线属性和光照计算,这整个问题无论如何都变得过时了,因为您可以以任何方式进行光照,并且不再需要传统的法线。

顺便说一句,听起来你正在使用每面法线,这意味着面的每个顶点都具有相同的法线。这会创建一个带有硬边的非常多面的模型,并且也不能很好地与索引一起使用。如果你想要一个平滑的模型(我不知道,也许你真的想要一个多面的外观),你应该平均每个顶点的相邻面的面法线来计算每个顶点的法线。这实际上是更常见的用例,而不是每个面的法线。

所以你可以做这样的伪代码:

for each vertex normal:
    intialize to zero vector

for each face:
    compute face normal using cross product
    add face normal to each vertex normal of this face

for each vertex normal:
    normalize

生成平滑的每个顶点法线。即使在实际代码中,这也会导致 10 到 20 行代码,这并不复杂。

于 2011-12-05T14:41:23.253 回答