Ogl Step2 Hello Dot!

原文地址 PS:我是使用VS来编译这些项目。并非纯粹的翻译,翻译中带有个人观点和文章。如有错误请指正。

背景

在这个课题我们需要使用到GLEW。可以在这里下载http://sourceforge.net/projects/glew/files/glew/1.8.0/%E3%80%82%E4%B8%8B%E8%BD%BD%E4%B9%8B%E5%90%8E%E8%A7%A3%E5%8E%8B%EF%BC%8C%E8%A7%A3%E5%8E%8B%E4%B9%8B%E5%90%8E%E6%8A%8A 把bin目录下的dll放到System32的目录下。lib的目录和include目录拷到你当前的项目中,并在vs的项目中进行引用。在此声明此篇文章需要opengl1.5以上的版本,如果你的显卡不支持就没办法编译通过(只要不是集显都会支持)。独显的如果你好久没更新驱动了,赶紧去更新驱动吧。

在这篇指南中。我们将会第一次使用到顶点缓冲区对象(vertex buffer objects VBOs)。顾名思义,它们是用来存储顶点源的。在3D世界中的怪物,城堡或者一个简单的四方形,都是通过一组顶点源构造出来的。VBOs是把顶点源加载到GPU的最有效方式。VBOs可以被存储在图像存储器中,提供最短的访问GPU的时间。

这一篇指南和下一篇是此系列中唯一依赖于固定管线模式,而不是可编程模式的例子。在这些例子中没有变换发生。我们仅仅是简单的方式让数据流过管道。后面的例子会带您深入的了解管道。但在此处我们还没有必要去深入光栅化程序。 可视化的顶点源中有[x,y,z]坐标,范围在[-1.0, 1.0]。光栅化程序负责把这些坐标映射到屏幕空间中(例如,如果屏幕宽度是1024.则X坐标-1.0对应的是0,1.0对应的是1023)。最后光栅化程序才更具制定的拓扑顺序去渲染元素。由于我们没有绑定任何的渲染器到管道中,也没有用到变换。所以我们只是简单地给出坐标,并让这些坐标点可见。

代码漫游

1
#include <GL/glew.h>

包含GLEW的头文件。如果你需要包含其他的OpenGl头文件,你要小心。把这个头文件放在后面包含进去。编译时,记得引入glew的lib文件。

1
#include "math_3d.h"

这个头文件定义了辅助的结构体。

1
2
3
4
5
6
GLenum res = glewInit();
if (res != GLEW_OK)
{
  fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
  return 1;
}

上面的代码要放在glut初始化之后,用于初始化GLEW并检查错误。

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

创建一个Vector3f的结构体数组,并初始化为0。这个点是屏幕的中心点。

1
GLuint VBO;

我们用一个全局变量来存储顶点缓冲区对象。大部分的OpenGL对象是通过GLunit类型的变量来访问的。

1
glGenBuffers(1, &VBO);

OpenGL定义了一些glGen* 函数用于产生各种类型的对象。它们通常带两个参数——第一个代表你要创建多少个对象。第二个参数是存储这些对象的句柄是 驱动给你分配的一组GLuint类型的数组。之后再调用这个函数不会产生相同的句柄,除非你嫌调用glDeleteBuffers删除它们。目前产生的这个缓冲区被视为默认的缓冲区,供下面的函数使用。

1
glBindBuffer(GL_ARRAY_BUFFER, VBO);

OpenGL用一个相当独特的方式来使用这些句柄。在许多的API中都是直接操作句柄,把句柄作为参数传给函数进行使用。在OpenGL中我们需要为句柄绑定一个目标名称(target name)然后再基于这个目标名称执行命令。这些命令会一直影响被绑定的句柄,直到有另外一个句柄替换它或者使用glBindBuffer(*,0)来释放绑定。参数GL_ARRAY_BUFFER意味着缓冲区将包含一组顶点源。另一个有用的目标名称GL_ELEMENT_ARRAY_BUFFER则是使用另一个缓冲区存储着顶点源的索引,通过这些索引来使用顶点源。

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

在绑定这些对象之后,我们往里面填充数据。第一个参数是目标名称(我们刚才绑定的),第二个参数是绑定顶点源的数据大小以字节为单位,第三个参数是顶点源数组的地址。最后一个参数指明我们对此数据使用什么样的DRAW模式。因为我们没必要修改缓冲区的内容所以我们指定了GL_STATIC_DRAW模式。相反地,是GL_DYNAMIC_DRAW模式。这只是给OpenGL一个指示,如何使用这些缓冲区。显卡驱动会根据这些标志进行优化。(例如:在内存中找到最佳位置存储该缓冲区)。

1
glEnableVertexAttribArray(0);
在渲染器的指南中,你将会看到顶点的属性用于渲染。在渲染器中,这些属性有对应的索引值建立c\C++数据与属性名称的绑定。另外你需要让这些顶点的属性可用通过一些Enalbe的方法。在此例中,我们没有用到任何渲染器,我们只是把顶点的位置加载到缓冲区中。在固定函数管道(当没有渲染器被绑定时,默认激活)中默认的顶点属性索引为0。你必须让每个顶点属性可用否则数据将不能被管道访问。
1
glBindBuffer(GL_ARRAY_BUFFER, VBO);
调用绘画函数之前我们需要重新绑定缓冲。在我们这个简单的程序中略显多余,但在复杂的程序中,将有多个缓冲区存储着多样的数据模型。你必须指定你要使用的缓冲区,更新管道的状态。
1
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
这个函数告诉管道如何解释缓冲区里的数据。第一个参数指定属性的索引,我们只使用了0. 第二个参数指明属性的组织形式(3 for X,Y and Z)。第三个参数代表没一维的数据类型。第四个参数指明在被管道使用之前是否将属性标准化。我们的数据不需要标准化。第五个参数代表在缓冲区中两个属性实例之间的步幅。而此例中只有一个属性参数。最后一个参数指定属性在数据中的偏移量。
1
glDrawArrays(GL_POINTS, 0, 1);
最终,我们调用glDrawArrays函数画几何图形。之前的命令都是为了这个函数调用做准备。到这里GPU才开始工作。GPU会结合已经通过参数设置好的状态,在屏幕上渲染点。

OpenGL提供了许多种函数调用,每一种适用于不同的情况。一般你可以把它们分为两类,顺序绘制索引绘制。顺序绘制很简单就是遍历你的顶点缓冲区,逐一绘制。例如:如果你指定的是GL_TRIANGLES,则顶点缓冲区里的0-2绘制第一个三角形。

索引绘制更复杂需要引入额外的缓冲区(索引缓冲区)。该索引缓冲区包含所有顶点的索引,我们可以通过索引来取的顶点。编辑索引缓冲区,我们可以重复绘制顶点。实现更复杂的绘制效果。

在这篇指南中我们只是简单的调用了glDrawArray.顺序绘制。第一个参数指定点的拓扑结构,GL_POINTS代表每个顶点都是单独的点。第二个代表第一个顶点的索引。最后一个参数代表要绘制的顶点的个数。

1
glDisableVertexAttribArray(0);
在不使用时,disable顶点属性是良好的编程习惯。

Comments