OpenGL ES 从零开始系列08:交叉存取顶点数据

in openglcode with 0 comment
Technote 2230提出了很多用OpenGL ES来提升iphone程序性能的建议。我们现在远远不能深刻理解OpenGL ES所以你需要学习以下内容。不信?是真的,试试看,我等着你的读后感。

好,就这样定了?副标题为“优化顶点数据”,这里有一些算法上的建议用来"submit strip-ordered indexed triangles with per vertex data interleaved"。当苹果给出这些建议的时候,他们通常有一些非常好的理由,让我们看看如何使用它。
首先让我们了解它的意思。让我们把这句话分解开来:

Strip Ordered:换句话说,如果你的模型有相邻的三角形,组成一个三角形带提交而不是分别提交每一个三角形。我们早期教程讲到过三角形带,你应该多少知道一点该怎么做。对于大多数物体来说你都可以使用这个方法,但不是所有时候都要用它。你什么时候能够使用?当你确定使用三角形带可以有效减少推入OpenGL ES每帧的顶点数据的时候。

indexed:这里仍然没有什么新内容。我们使用顶点索引有一段时间了。我们仅仅用12个顶点来创建旋转的20面体。glDrawElements()是基于索引绘制而不是基于顶点。
见鬼,我们目前已经做的很棒了,不是吗?我们眼下一直在做着正确的事情。让我们来看最后一个建议,然而:

with per vertex data interleaved:好的,恩。。。。它到底是什么意思?

好的,是时候考验你的记忆力了。你还记得在过去几个部分,也就是当我们讨论glVertexPointer(),glNormalPointer(),glColorPointer(),glTexCoordPointer()的时候吗?在前面的部分里,我告诉你不用关注参数stride并把它设置为0。
但是现在你要关注它(stride)了,因为它是用来交叉存取每个顶点数据的关键。

Per Vertex Data


你也许想知道“per vertex data”是什么,并且想知道如何交叉存取它。
你肯定知道,在OpenGL ES里我们用顶点数组来表示几何图形,每一个数组包含3个定义顶点的GLfloat变量,来创造我们的物体。除了这些,我们有时也使用其它数据。举例来说,如果我们用光效就需要顶点法线,我们不得不在法线数组里定义每一个顶点的法线。如果我们使用纹理坐标,我们不得不在纹理数组里定义每一个顶点的纹理坐标。如果我们用颜色数组,我们不得不指定每个点的颜色,你是否注意到我总是强调“per vertex data”?这些数据类型就是苹果公司在它们技术说明里提到的"per vertex data"。这就是你所有在OpenGL ES 中放入数组的任意一种适用于顶点的顶点数组。

Interleaving


这个系列到目前为止,我们已经创造一个数组来存放顶点数据,并把它们与法线数据、颜色数据、纹理坐标分开存在其他独立数组中,像这样:


我们将要学习如何把这所有的数据放在一起作为一个整体数据来存储: 


如果你读不懂上图解里面的代码请不要担心。 当那个变得重要的时候,我们会再次列出来讲解的,这个给出的代码列表仅仅是举例说明在一个独立的内存单元中我们可以存入所有的顶点数据。 我们所要做的只是把所有描述一个单一点的数据放在内存的同一个地方。 
这样做能够使OpenGL快速的获得读取到每个顶点的信息。 在今天的例子里面,我们要将交叉存储顶点,法线,颜色(vertices, normals, color data),同样的方法可以使用在纹理坐标中,或者仅交叉存储顶点和法线。事实上在一个Xcode工程里面,会附带着一些数据结构定义这三个交叉存储的情况。 

Defining a Vertex Node


为了让这个能够工作起来,我们需要一个新的数据结构。下面的数据结构能够让我们把上面提到的顶点, 法线,颜色 交叉存储到一起,
typedef struct {
    Vertex3D    vertex;
    Vector3D    normal;
    Color3D     color;
} ColoredVertexData3D;

啊哈哈,漂亮而简洁不是吗?你只用一个数据结构就包含了我们需要的一个顶点的所有属性。 
下一步,当然了,线面我们需要填充顶点数据,所以我们需要把三个static const数组合并成一个。这里是相同的二十面体数据,指定使用了我们自己定义的新数据类型:

static const ColoredVertexData3D vertexData[] = { { {0, -0.525731, 0.850651}, // Vertex |  {0.000000, -0.417775, 0.675974}, // Normal | Vertex 0  {1.0, 0.0, 0.0, 1.0} // Color  |  }, { {0.850651, 0, 0.525731}, // Vertex |  {0.675973, 0.000000, 0.417775}, // Normal | Vertex 1  {1.0, 0.5, 0.0, 1.0} // Color  |  }, { {0.850651, 0, -0.525731}, // Vertex |  {0.675973, -0.000000, -0.417775}, // Normal | Vertex 2  {1.0, 1.0, 0.0, 1.0} // Color  |  }, { {-0.850651, 0, -0.525731}, // Vertex |  {-0.675973, 0.000000, -0.417775}, // Normal | Vertex 3  {0.5, 1.0, 0.0, 1.0} // Color  |  }, { {-0.850651, 0, 0.525731}, // Vertex |  {-0.675973, -0.000000, 0.417775}, // Normal | Vertex 4  {0.0, 1.0, 0.0, 1.0} // Color  |  }, { {-0.525731, 0.850651, 0}, // Vertex |  {-0.417775, 0.675974, 0.000000}, // Normal | Vertex 5  {0.0, 1.0, 0.5, 1.0} // Color  |  }, { {0.525731, 0.850651, 0}, // Vertex |  {0.417775, 0.675973, -0.000000}, // Normal | Vertex 6  {0.0, 1.0, 1.0, 1.0} // Color  |  }, { {0.525731, -0.850651, 0}, // Vertex |  {0.417775, -0.675974, 0.000000}, // Normal | Vertex 7  {0.0, 0.5, 1.0, 1.0} // Color  |  }, { {-0.525731, -0.850651, 0}, // Vertex |  {-0.417775, -0.675974, 0.000000}, // Normal | Vertex 8  {0.0, 0.0, 1.0, 1.0}, // Color  |  }, { {0, -0.525731, -0.850651}, // Vertex |  {0.000000, -0.417775, -0.675973}, // Normal | Vertex 9  {0.5, 0.0, 1.0, 1.0} // Color  |  }, { {0, 0.525731, -0.850651}, // Vertex |  {0.000000, 0.417775, -0.675974}, // Normal | Vertex 10  {1.0, 0.0, 1.0, 1.0} // Color  |  }, { {0, 0.525731, 0.850651}, // Vertex |  {0.000000, 0.417775, 0.675973}, // Normal | Vertex 11  {1.0, 0.0, 0.5, 1.0} // Color  |  } };


下面是我们如何传递信息到OpenGL。我们传递在这个数组里面的每个数据成员的第一个顶点的地址,并且提供所传递的数据的长度大小作为步长参数,而不是传递指针到合适的数组。 
glVertexPointer(3, GL_FLOAT, sizeof(ColoredVertexData3D), &vertexData[0].vertex);
glColorPointer(4, GL_FLOAT, sizeof(ColoredVertexData3D), &vertexData[0].color);
glNormalPointer(GL_FLOAT, sizeof(ColoredVertexData3D), &vertexData[0].normal);

以上几个方法中,最后一个参数调用了数据里的第一个顶点,例如,&vertexData[0].color指向第一个顶点的颜色信息。stride(跨度)参数表明了在我们读取下一个相同类型的数据时,我们要跳过多少比特的数据。如果你看了下面的图解你也许就有那么一点点感觉了(不好意思它有点宽,你需要适当的调整你的浏览器以便于看到这个图解的所有部分) 

变简单了不是吗?如果你一点也不喜欢打字,那么你可以下载这个十二面的交叉存取版本spinning icosahedron。我也会使用新的数据类型更新我的OpenGL ES Xcode Template
我们现在依然没有使用triangle strips,但是混合三角形到triangle strips是下一步的教程,现在我要去参加WWDC了。

原文:iphonedevelopment,OpenGL ES from the Ground Up Part 8: Interleaving Vertex Data
iTyran翻译讨论地址:http://ityran.com/forum-36-1.html

licensed under  Creative Commons license.

Comments are closed.