opengl教程翻译 #2你好!点!

背景知识:
这是我们第一次遇到GLEW(OpenGL Extension Wrangler Library)。GLEW可以帮助我们处

理那些伴随着OpenGL拓展管理出现的头疼问题。一经初始化,它便会在你的平台上查询所有能

得到的拓展,动态的加载它们,而且可以通过一个简单的头文件轻易地访问它们。

在这个教程中我们会第一次看到顶点缓冲对象(VBOs)的用法。正如其名字所隐含的,它们常

常用作存储顶点。那些你能想象到的存在于3D世界中的物体,不管是怪物、城堡,还是一个简

单的旋转着的立方体,都总是通过把一组顶点连接在一起。VBOs是把顶点加载进GPU中最有效

的方式。他们是一些能被存储在视频内存中的缓冲区,而且有着最短的访问GPU的时间,因此他

们毫无疑问备受推崇。

这一系列中,这一课和下一课,是仅有的依赖于固定管线而不是可编程管线的课程。事实上,

在这俩课程中一点儿变换都没用到。我们只是简单地看着数据流穿过管线。一个完整的管线学

习过程会继续通过后面的课程,但现在已经足够理解到达光栅化(真正根据屏幕坐标绘制点、

线、三角形)之前的概念了。可视顶点已经在范围[-1.0,1.0]中有X,Y,Z坐标,光栅化只是把

这些坐标映射到屏幕空间中(例如,如果屏幕宽度为1024像素,X坐标为-1.0会映射到第0个像

素, 1.0会映射到第1023个像素)。最后,光栅化根据在draw call中指定的拓扑绘制出几何

图元(在下面的课程实践中可以看到)。因为我们没有绑定任何着色器到管线程序,我们的顶

点不会经过任何变换。这意味着我们静静需要给他们一个上面范围的值,以便让它们可见。事

实上,给X和Y空间选择0,则顶点刚好在这两个轴的中点--换句话说,这个屏幕的中点。
安装GLEW:GLEW在主要网站http://glew.sourceforge.net/上可获得。大多数Linux操作系

统为它提供了预编译包。在Ubuntu你可以通过运行下面的命令行安装它:apt-get install

libglew1.6 libglew1.6-dev

源码演练:
#include <GL/glew.h>
在这里我们包含一个单独的GLEW头文件。如果你要包含其他OpenGL头文件的话,就必须要小心

地在其他头文件之前包含它,否则GLEW会有关于它的报错。为了把GLEW链接到程序,你需要在

makefile中添加'-lGLEW'。

#include "math_3d.h"
在这个课程我们开始使用像向量这样的辅助结构体,随着课程深入我们会拓展这个头文件。

GLenum res = glewInit();
if (res != GLEW_OK)
{
fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
return 1;
}
这里我们初始化GLEW以及检查是否有错误。这是在GLUT初始化后必须要做的工作。


Vector3f Vertices[1];
Vertices[0] = Vector3f(0.0f, 0.0f, 0.0f);
我们创建了一个只有一个元素的、类型为Vector3f结构体的数组(这个类型是math_3d.h里定

义的)以及把XYZ值都初始化为0。这会让点出现在屏幕的中间。

GLuint VBO;
我们在程序的全局环境分配一个GLuint以存储顶点缓冲对象的句柄。稍后你会看到大多数OpenGL

都是通过一个可变化的GLuint类型访问的。

glGenBuffers(1, &VBO);
OpenGL定义了几个glGen*函数,用来产生不同类型的对象。它们通常带有2个参数-第1个指定

你想要创建的对象数量,第2个是一个GLuints类型的数组的地址,用来存驱动程序分配给你的

handles(请确认数组足够大,可以处理你的要求)。多次调用这个函数并不会产生相同的对

象句柄,除非你先用glDeleteBuffers删除它们。注意在这点你并没有对缓冲指定你想做的操

作,所以目前来看他们被认为是“通用”的。对它做事情是下个函数的工作。

glBindBuffer(GL_ARRAY_BUFFER, VBO);
OpenGL有一个相当独特的方式使用handles。在许多API中,句柄就是简单地传递到相应的函数

,而相关动作也是通过句柄来识别。在OpenGL我们把句柄绑定到一个目标名字,然后在目标上

执行命令。这些命令影响着这些绑定的句柄,知道另外一个目标名字绑定它,或者句柄取零(

置空)。目标GL_ARRAY_BUFFER意味着这个缓冲区包含的是一组顶点数据。另一个有用的目标

是GL_ELEMENT_ARRAY_BUFFER,它意味着缓冲区包含的是存在另一缓冲区中的顶点的索引。我

们将会在更多的教程中看到其他可用目标。

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
在绑定了我们的对象后,我们用数据填充它。上面的调用包含目标名字(跟我们用来绑定的一

样),数据的位长度,顶点数组的地址,和一个给数据表明使用状态的标记。因为我们不打算

改变缓冲中的内容,所以我们用GL_STATIC_DRAW。相反的则是GL_DYNAMIC_DRAW。同时这在“

暗示”OpenGL按照正确标记去“思考”。驱动程序可以依赖它来优化(诸如在内存中存缓冲区

最好的位置在哪)。

glEnableVertexAttribArray(0);
在这个渲染课程中,你将会看到在着色器中使用的顶点属性(位置、法向量等)都有一个索引

映射到它们,使你能够在C/C++程序数据和着色器属性名称之间建立联系。此外,你必须开启

每一个顶点属性索引。在这一课中我们还未使用任何着色器,不过我们已经载入缓冲中的顶点

位置,在固定功能管线(当没有着色器绑定时开始启动)中已被当做索引为0的顶点属性。你

必须开启每一个顶点属性,否则数据将不能通过管线。

glBindBuffer(GL_ARRAY_BUFFER, VBO);
这里我们再次绑定了我们的缓冲区,用以draw call作准备。在这个小程序中我们仅仅有一个

顶点缓冲区,所以每帧都调用这句显得有点多余。但是在更复杂的程序中,有许多缓冲区存各

种模型,你必须在将要用哪种模型时及时通过缓冲区更新管线状态。

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
这句调用告诉管线以何种方式解析缓冲区中的数据。第一个参数指定了属性的索引。在这个例

子中我们默认设为0,但当我们开始使用着色器时,我们既需要明确地设置在着色器内部的索引也

要查询它。第二个参数是属性组合成员的个数(3个,分别是XYZ)。第三个参数是每个组合成

员的数据类型。下一个参数表明在使用之前,我们是否想在管线中标准化(译者注:归一化)

属性。在这个例子中,我们不做改变。第五个参数(被称为“跨步”),是在缓存区中两个属

性实例间的位数。当只有一个属性(例如缓冲区只包含一个顶点位置)且数据紧密封装时,我

们给这值设为0。如果我们有一个结构体数组,包含一个位置和一个法向量(每个都是一个

3floats的向量),我们就会赋予该值这个数据结构大小的位数(6*4=24位)。最后一个参数

对于前面这个例子很有用。我们需要指定在结构体中的偏移,当管线找到我们的属性时。在这

个包含位置和法向量的例子中,位置的偏移是0,法向量的偏移是12.

glDrawArrays(GL_POINTS, 0, 1);
最后,我们执行调用画出几何图形。目前为止我们已经看到的所有命令都非常重要,但这只是

为绘制指令准备舞台。这是GPU真正开始工作的地方。它现在将会结合draw call参数和已经为

点建立好的状态,然后在屏幕上渲染出结果。
OpenGL提供了几种形式的draw call,每种分别适用于不同的情况。通常我们把它们分为2种类

型-有序绘制和索引绘制。有序绘制更简单。GPU走一边顶点缓冲,逐一经过顶点,根据draw

call拓扑指令编译它们。例如,如果你指定了GL_TRIANGLES,则第0-2个顶点变成第一个三角

形,第3-5个顶点变成第二个,以此类推。如果你想用同样的顶点数据复刻出两个三角形,则

需要在顶点缓冲中指定它们两次,很浪费空间。
索引绘制比较复杂,涉及到一个额外的缓冲,被称作索引缓冲。索引缓冲包含在顶点缓冲中的

顶点的索引。GPU扫描索引缓冲,然后以与上面类似的方式描述它们,第0-2个变成第一个三角

形等等。而如果你想用相同的顶点数据出现两个三角形,只需简单地在索引缓冲中指定两次索

引。顶点缓冲仅仅需要包含一份拷贝。索引绘制在游戏中很普遍,因为大多数模型是由三角形

创建的,这意味着一些由大量顶点构成面(人物的皮肤,城堡的外墙等)可以共享这些顶点数

据。
这本课中,我们用了最简单的draw call -- glDrawArrays。这是一个有序绘制,所以并没有

索引缓冲。我们把拓扑指定为点表明每个顶点是一个点。下一个参数是所要绘制第一个顶点的

索引。在这个例子中我们想在缓冲的起始端开始,所以我们指定为0,但同时也允许我们把多

个模型存在同一缓冲中,通过缓冲的偏移选择其中一个来绘制。最后一个参数是用来绘制的顶

点数量。

glDisableVertexAttribArray(0);
应该养成这样一个好习惯,当顶点属性不是立刻使用时禁止它们。当一个着色器不用时却不禁

止它,很明显是在自找麻烦。

译者总结:
1.GLEW是一个管理OpenGL的扩展库,方便处理很多麻烦问题;
2.直接把数据传入GPU中效率不高,而先放入缓冲VBO中再传入GPU非常有效,生活中的例子是你每次开完发

票都去税局报税,不如公司每个月统计好一起报税效率高;
3.不用写着色器,用固定功能管线也是可以渲染的;
4.设置好数据和指令,光栅化就会他们输出到屏幕上;
5.快速开发一个程序需要引入外部辅助文件,如glew.h用于辅助管理,math_3d.h用于创建数据结构;
6.VBO、数据(Vertices)、目标名字(GL_ARRAY_BUFFER)之间的关系是:
VBO是编号,如001;数据是原材料;目标名字是代号。如,编号001,你的目标是从一滩海水中提炼出盐;
编号002,你的目标是从一滩海水中蒸馏出纯净水。这里编号即VBO,盐、纯净水即目标名字,海水即数据;
7.调用glDrawArrays,标志draw call开始;
8.vertex(顶点)和point(点)的区别。一个形象的比喻,相当于数字9和个位数9的区别。9可以组成9,

也可以组成99、999、9999。同理,vertex可以变编译成point,也可以被编译成triangle;
9.OpenGL中的拓扑,就是以point或以triangle这样形式。

转载于:https://www.cnblogs.com/alphaGo/p/9208520.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值