Ios 在GLKit/OpenGL ES中自动计算法线

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

我正在基于苹果的示例代码在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);
我很难理解为什么我必须手动执行此操作。我确信有些情况下,除了垂直于曲面的向量之外,你还需要其他东西,但我也确信这是目前为止最流行的用例,所以难道没有更简单的方法吗?我错过了什么明显的东西吗?glcalculationormals()就太好了

//这里有一个答案 传入一个您希望用法线填充的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;
    }
}
-(void)计算曲面法线:(GLKVector3*)顶点法线:(GLKVector3*)入顶点计数:(int)numoftexts
{
对于(int i=0;i
答案是: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行代码,这并不复杂。

我原以为我的情况是大多数情况,但如果不是通常的情况,那么我可以理解这是一项手工工作。我主要是想要块,所以我可能会坚持我的系统。使用平均顶点法线方法,您描述了我如何告诉OpenGL,尽管我有12个多边形和36个顶点,但我只计算了8条法线?我是否需要一个包含36条法线的数组来匹配顶点,并以相同的顺序放置法线?这意味着当两个多边形共享一个顶点时,某些多边形会重复,或者有没有办法将法线和顶点链接起来?@Craig每个顶点都有一条法线。如果按您的方式(每个面)计算法线,则必须为面的每个顶点重复每个面法线。如果计算逐顶点法线,则每个顶点法线都会对顶点所属的每个面重复,就像实际的顶点一样。从概念上讲,顶点是其所有属性的整体,而不仅仅是位置,不幸的是,在OpenGL中也被称为顶点。@Craig但逐顶点法线(关于存储效率)的优点是,您可以使用索引数组(和
gldrawerelements
)并完全减少重复,因为每个唯一顶点都有相同的法线。对于每面法线,索引不会为你买任何东西,因为你无论如何都需要复制顶点,因为每个具有唯一位置的顶点可能有多个不同的法线。@Craig所以基本上你说的就是这样做的,因为如果你有36个顶点,你也有36个顶点法线,而不仅仅是8个。它怎么可能是8,你甚至事先都不知道你只有8个唯一的法线,因为你还没有计算任何法线。因此,是的,法线数组(以及每一个其他属性数组)总是与顶点数组相匹配,不管它包含哪些值。8条法线用于一个立方体,其中有8个顶点和一个索引数组。在这个索引数组中,它类似于{0,1,2,0,2,3)表示每个多边形使用哪个顶点,一次三个。然后我会使用相同的索引数组来排序(并重复)八条法线,每个多边形上的每个顶点一条。如果我想平均,我不需要。叉积非常适合我的块。谢谢