分类: C/C++
2015-03-16 15:02:42
图元是构成复杂物体的基本绘图要素。在OpenGL ES中,你可以使用的图元有点,线,三角形。它们都有非常强的自我解释性,我觉得你需要有些例子让你看到它们。
首先,让我们来看看一些代码,然后我们可以谈论这是怎么回事,这样您就可以使用它来创建一些自己的代码。
图元 #1 - 三角形
三角形是最“复杂”的图元,但是很容易使用,并且非常实用,这将是你可以绘制的第一个OpenGL的图元。当我们绘制一个三角形的时候,我们需要告诉OpenGL在3d空间中的三角形的3系坐标,并且,OpenGL将非常顺利的渲染这个三角形。
在开始之前,复制00教程中的项目代码或者从这里下载下项目代码: AppleCoder-OpenGLES-00.tar.gz .在XCode中打开,开启EAGLView.m文件,找到drawView函数。这里就是施展魔法的地方。
首先,我们需要定义一个三角形。要做到这点,我们需要知道在我们要处理的坐标的两种类型:模型和世界。模型坐标是指我们正在绘制的实际图元,世界坐标告诉OpenGL观察者在哪里。(在世界坐标中,观察者一般在(0.0,0.0,0.0)的地方)
第一个例子将说明这点。首先,我们定义这个三角形在模型空间使用3 x 3d 坐标(x,y,z):
const GLfloat triangleVertices[] = {
0.0, 1.0, -6.0,// Triangle top centre
-1.0, -1.0, -6.0,// bottom left
1.0, -1.0, -6.0,// bottom right
};
如上所示,这里使用了3个坐标来表示一个三角形,需要注意的是,我们定义三角形顶点是逆时针来显示的。虽然描述三角形的可以用逆时针也可以用顺时针,但是我们必须和上述一样用逆时针来描述三角形。不过,我建议你用逆时针来描述三角形,因为我们以后可以用逆三角形来达到一些先进的功能。
(补充:逆三角形在3d中被认为是正面,而顺三角形则被认为是反面。在纹理渲染中被使用到)
虽然本教程应该是纯粹的iPhone OpenGL ES的,对于初学者来说,我会简要的描述三维坐标系统。看看这张图片:
对于我的绘画技巧,我深表遗憾。不过这个图代表了模型空间和世界空间。 试想一下,这是您的计算机屏幕, X和Y的横向和纵向的,你应该预料到, Z表示深入。这个中心位置就是(0.0,0.0,0.0).
所以,看我们的三角形中所描述的顶点上述情况,第一点( 0.0 , 1.0 , -6.0 )中心将在的Y轴,上涨1点,在屏幕的深度为6点。 第二个坐标是右边的Y轴1.0点,低于X轴(因此-1.0的Y值) ,仍然回到屏幕-6.0点。这同样适用于第三个坐标。
为此,我们确定目标在我们眼睛之前(z值是负的),所以这个目标是可见的(记得吗,观察者或者说照相机是在(0.0,0.0,0.0)的位置上)所以说OpenGL的深度测试是失败的并且它没有被渲染。
我可以听到你尖叫“嘿,我还以为你说,这是模型坐标不是世界坐标! ” 。 是的,这是对的,但是,当我们去渲染这个三角形之前, OpenGL的将只是把对象放在( 0.0 , 0.0 , 0.0 ) 的位置上。 因此,我们将它放到屏幕内才可见。当我们进入转换(移动,旋转等) ,您会看到,您将不必设置对象Z值为负,也可以使之可见。在此之前,让目标的Z坐标在-6.0的位置上。
绘制函数:
所以我们这样做是为了说明目前的三角形。我们现在需要告诉OpenGL,数据保存在哪里,以及如何去绘制它。这个过程只需要很少的几行代码。回到drawView函数,并且实行以下的代码:
- (void)drawView {
const GLfloat triangleVertices[] = {
0.0, 1.0, -6.0, // Triangle top centre
-1.0, -1.0, -6.0, // bottom left
1.0, -1.0, -6.0 // bottom right
};
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
// -- BEGIN NEW CODE
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glVertexPointer(3, GL_FLOAT, 0, triangleVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, 3);
// -- END NEW CODE
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
[self checkGLError:NO];
}
如你所见,这4行代码就是我们渲染一个三角形的。让我们从上往下一行行的打断这些代码来分析,你会发现它们是非常的简单。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
这行代码只是简单的清除了屏幕。这个控制位告诉OpenGL,我们使用上次教程里面setupView函数中设置的颜色(黑色)来清除屏幕,并且清除了深度缓冲。请注意,如果我们没有创建深度缓冲和开启深度缓冲(如我们应该做的),这个屏幕将不会渲染。如果我们不使用深度缓冲,我们将不需要通过glClear() 里的 GL_DEPTH_BUFFER_BIT.
因此,我们无论是清除以前绘制的这个缓冲区(请记住,这是双重缓冲动画;利用一个缓冲区而另一个缓冲区显示) 。
glVertexPointer(3, GL_FLOAT, 0, triangleVertices);
此 函数告诉OpenGL的情况下我们的数据是什么格式,它是有4个参数,这个功能是很简单细分:
1.Size-这个值表示了每个坐标有几个数字。我们现在是3,是因为是3d坐标(x,y,z).如果我们使用2d绘制,不加入深度(就是z),我们只要在这里写2就可以了。
2.Data Type- GL_FLOAT 意味着我们用float点值。 您也可以使用整数值,但如果你想你需要习惯于使用浮点值的3D世界的浮点运算。
3.Stride - 这个stride告诉OpenGL 在每个坐标之间忽略哪几个点。别对这个表示疑惑,保持它是0就行了。你使用它
当您载入顶点数据文件的格式有更多的填充数据或肤色的数据,也就是说,一个3D程序像搅拌机。
4.Pointer to the Data – 数据本身,正是因为它,三角形才会出现。
因此,我们告诉OpenGL清除缓冲区,告诉它的数据是我们的目标和它的格式,现在我们需要告诉OpenGL的东西很重要:
glEnableClientState(GL_VERTEX_ARRAY);
OpenGL 是一个状态机。 这意味着你打开和关闭功能的要求就是启用和禁用命令。之前,我们使用过glEnable(),这影响到OpenGL的服务。 glEnableClientState ()影响到我们的程序方面(就是客户端面)。所以我们要做的就是告诉OpenGL我们顶点数据是一个顶点数组并且转换到OpenGL的绘制顶点功能。在这个情况下,顶点可以是一个颜色数组,我们将呼叫 glEnableClientState (GL_COLOR_ARRAY)或者一个纹理坐标数组如同纹理映射。(别垂涎三尺,你需要掌握所有的基本知识包括纹理映射)
随着我们进一步的研究OpenGL ,我们会使用不同的客户端状态,这将使用变得更为清晰。
现在命令OpenGL渲染一个三角形。
glDrawArrays(GL_TRIANGLES, 0, 3);
一旦这个方法被调用,OpenGL将用我们之前的两个函数的信息开始执行。屏幕中间出现一个白色的实心的三角形(白色是默认的绘制颜色)。现在的三角形是一个实心的,如果你需要一个镂空的三角形,你将要用不同的绘制方法。
分析这个方法里的三个参数:
1.Drawing Method- 在这种情况下,我们已通过GL_TRIANGLES这似乎相当明显,因为我们画一个三角形。然而,这一方法的第一个参数将变得很明显,当我们使用此功能,来绘制一个平面体。
2.First Vertex- 我们阵列只有3点,所以我们想要的OpenGL提请第一坐标的数组,这里指定零就像进入一个标准数组。如果我们有多种原始的顶点数组,我们可以在这里处理。我会在以后的教程教你,当我告诉您该如何建立复杂的物体的时候。现在,这里只要使用0。
3.Vertex Count-这将告诉OpenGL在我们的数组中有多少顶点需要被绘制。比如说,我们绘制一个三角形,所以至少要3点,一个平方形需要4点,一个线需要2点(或更多),一个点需要一个(或者多点)
当你把这些代码都输入到你的drawView函数里面以后。点击“Build and Go”运行这个程序在模拟器里面。你的模拟器应该看起来象如下的图:
如我们所说的,有一个实心的白色的三角形出现在屏幕的中间。
在我们做其他的图元之前,尝试修改z值,你就会明白我所说的是什么意思。如果你把z改为0,你将什么也看不到。
如果你自己输入几行代码,我希望你可以来发现OpenGL ES 是如何工作的。如果你学习过“标准”的OpenGL的教程,我希望你可以发现OpenGL与OpenGL ES的不同。
期待。。。
下个教程将着重于扩大代码量并生产一个平方形。