opengl教程2,你好顶点

来源:互联网 发布:c语言中arr 编辑:程序博客网 时间:2024/05/16 01:00

说明:本文翻译自http://ogldev.atspace.co.uk/www/tutorial02/tutorial02.html
我们只在本教程和下一篇教程使用了固定函数管道而不是可编程管道。实际上,在这两个教程中没有发生任何转换。我们只是依赖数据流过管道的方式。

教程2:

你好顶点

这是我们第一次遇到GLEW库,英文名全称为OpenGL Extension Wrangler Library,这是一个Opengl扩展库。GLEW能够帮助您处理在Opengl中不断出现的扩展包的管理问题。一旦初始化,它就可以查询操作系统上所有可用的扩展,动态加载它们,并通过一个头文件提供简单的访问。

在本教程中,我们将会看到VBOs(vertex buffer objects 顶点缓冲对象)的使用。顾名思义,它是用来缓冲顶点信息的。你试图可视化的3D场景中的对象,它可以是怪物,城堡或者是一个简单的旋转立方体,都是通过关联一组顶点来构建的。VBOs对象是把顶点加载到GPU的最有效的方法。VBOs缓冲对象可以存储在视频内存中,GPU对此内存的访问是最快的,所以推荐使用这种访问方式。

我们将会在下一个教程中对管道进行深入研究,我们需要理解的是,在光栅化阶段(实际上是使用屏幕坐标绘制点、线和三角形),可视化顶点有自己的X、Y和Z坐标,坐标的范围在[- 1.0,1.0]。光栅化会将这些坐标映射到屏幕上。例如,如果屏幕宽度是1024,那么X坐标的-1.0将被映射为0,而1.0将被映射为1。最后,光栅化会根据绘制命令来绘制最初始的图形(下面将会介绍)。如果我们没有绑定任何着色器(shader)到管道,我们的顶点不会发生转换。这意味着我们只需要给他们一个在[-1.0,1.0]之间的值,他们才会可见。事实上,我们需要将X和Y的零点置于两个轴的中点,也就是屏幕的中心。

安装GLEW:

我们可以从它的官网获取:http://glew.sourceforge.net/. 

大多数Linux发行版都提供了预构建包。在Ubuntu上,你可以通过运行以下命令来安装它:

apt-get install libglew1.6 libglew1.6-dev

一步一步看源码

#include <GL/glew.h>

这里我们包含了GLEW头文件,如果你还包含了其他Opengl头文件,你必须注意有没有其他扩展库,否则会报错。为了程序能够链接上GLEW,你需要在MakeFile文件中添加'-lGLEW'。

#include "math_3d.h"

在本教程中,我们需要使用一些辅助结构比如向量。需要此扩展包。

Glenum res = glewInit();

if(res != GLEW_OK)

{

fprintf(stderr,"Error:'%s'\n",glewGetErrorString(res));

return 1;

}

这里我们初始化了GLEW库并检查了有没有出现错误。

Vector3f Vertices[1];

Vertices[0] = Vector3f(0.0f,0.0f,0.0f);

我们创建了一个由Vector3f构成的数组并且初始化XYZ的坐标为零(Vector3f这个类型定义在math_3d.h中)。这个点将会出现在屏幕的正中间位置。

GLuint VBO;

我们创建了一个GLuint类型的全局变量来记录VBO(顶点缓冲对象)的句柄。稍后你会看到,大部分的Opengl对象通过一个GLuint类型的变量来访问。

glGenBuffer(1,&VBO);

Opengl定义了许多glGen*类型的函数来生成不同类型的对象。它们通常采用两个参数,第一个参数指定要创建的对象的数量,第二个参数是驱动分配给你的句柄数组地址。(要确保地址足够大以存储句柄信息)。如果你在调用这个函数之前没有使用glDeleteBuffers来清楚缓存,这个调用不会不会产生相同的对象句柄。请注意,在这里你并没有指定你要用这个缓冲来做什么,它会默认为通用。下一个函数将会指定用缓冲来做什么。

glBindBuffer(GL_ARRAY_BUFFER,VBO);

Opengl有一个非常独特的使用句柄的方法。在许多API中,句柄简单的传递给相关函数并对该句柄进行操作。在Opengl中,我们将句柄绑定到目标名称,然后在该目标上执行命令。这些命令对这些已绑定的句柄进行操作,直到另一个句柄替换它的绑定或者上面的调用以0作为句柄。目标GL_ARRAY_BUFFER意味着缓冲区将会绑定一个顶点数组。另一个有用的目标是GL_ELEMENT_ARRAY_BUFFER,它意味着缓冲包含着顶点数组的索引。其他目标也是可用的,我们将在以后的教程中看到它们。

glBufferData(GL_ARRAY_BUFFER,sizeof(Vertices),GL_STATIC_DRAW);

绑定我们的对象后,我们需要用数据来填充它。这个调用的参数包括目标名(也就是我们绑定的目标),数据的大小(以字节为单位),顶点数组的地址和一个数据使用模式的标志。因为我们不打算改变缓冲区的内容所以使用了GL_STATIC_DRAW模式。与它相反的模式是GL_DYNAMIC_DRAW.虽然这只是对Opengl的一个提示,但是考虑使用适当的标记是一件好事。驱动程序可以依靠它进行优化(例如内存中存储缓冲的最佳位置)。

glEnableVertexAttribArray(0);

在着色器教程中,你将会看到在着色器中使用的顶点属性有一个映射到它们的索引,使你能够在C/C++程序中的数据和着色器的属性名称之间创建绑定。此外,你还必须启用每个顶点属性索引。在本教程中,我们还没有使用任何着色器,但是我们已经加载到缓冲区的顶点位置被视为固定函数管道中的顶点属性索引0(在没有着色绑定的情况下,它会变的活跃)。你必须启用每个顶点属性否则数据将无法通过管道访问。

glBindBuffer(GL_ARRAY_BUFFER,VBO);

在这里,我们再次绑定缓冲区,准备进行绘制调用。在这个小程序中,我们只有一个顶点缓冲所以让这个调用每一帧都是多余的,但是在更复杂的程序中,这里有多个缓冲存储你的各种模型,你必须用你想要用的缓冲来跟新管道状态。

glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);

这个调用告诉管道如何解释缓冲区内的数据。第一个参数指定属性的索引。在我们的例子中,我们我们知道它在默认情况下是0,但当我们开始使用着色器时,我们需要显示地在着色器中设置索引或者查询它。第二个参数是属性中的构成部分的数量(3代表的是X,Y和Z)。第三个参数是每个构成部分的数据类型。下一个参数表示属性在管道中使用之前是否进行归一化处理(也就是将参数的范围限制在-1.0到1.0之间)。在我们的例子中我们不希望进行此操作。第五个参数(称之为间隔)是缓冲区中该属性的两个实例之间的字节数。当只有一个属性(例如缓冲区只包含顶点位置)时,数据是紧密连接的,我们就会传递值为0。如果我们有一个包含位置和法线的结构数组,我们将通过字节来传递结构的大小。最后一个参数在前面的示例中是有效的。我们需要在结构中指定偏移量,这样管道就能够从结构中找到我们的设置的属性。在示例的包含位置和法线的结构中,位置的偏移量为0,法线的偏移量为12.

glDrawArrays(GL_POINTS,0,1);

最后,我们调用此命令绘制图形。目前我们看到的所有命令都很重要,但是他们仅仅为绘制命令打基础。这里才是GPU真正开始工作的地方。现在它将结合绘图调用的参数和构建到这一点的状态,并将结果呈现到屏幕上。

Opengl提供几种类型的调用,每个类型都适用于不同的情况。一般来说,你可以将它们分为两类----命令绘制和索引绘制。命令绘制更简单。GPU遍历顶点缓存,逐个遍历顶点,并根据调用中指定的拓扑来解释他们。例如,如果你指定绘制参数为GL_TRIANGLES,那么顶点0-2将会成为第一个三角形,3-5会成为第二个,以此类推。如果你希望同一个顶点出现在多个三角形中,则需要在顶点缓冲区指定2次,这是对内存的浪费。

索引绘制更复杂,涉及额外的缓冲区,称为索引缓冲区,索引缓冲去包含顶点缓冲区中顶点的索引。GPU扫描索引缓冲区和以类似的方式来描述上述指标0-2成为第一个三角形等。如果希望两个三角形中的顶点相同,只需在索引缓冲区中指定它的索引两次。顶点缓冲区只需要包含一个副本。在游戏中,索引绘制更为常见,因为大多数模型都是由代表某些表面(皮肤、城堡墙壁等)的三角形创建的,它们之间有大量的顶点共享。

在本教程中,我们使用简单的绘图调用——glDrawArrays.这是一个命令绘制所以没有索引缓冲区。我们将拓扑定义为点,即每个顶点都是一个点。下一个参数是绘制第一个顶点的索引。在我们的例子中,我们希望从缓冲区的开头开始,所以我们指定了0,但是这允许我们在同一个缓冲区中存储多个模型,然后根据缓冲区中的偏移量选择一个模型。最后一个参数是要绘制的顶点数。

glDisableVertexAttribArray(0);

在不立即使用时禁用每个顶点属性是个好习惯。当着色器不使用它时启用它是一种自找麻烦的方法。





原创粉丝点击