OpenGL实践2之第一个三角形

OpenGL实践2之第一个三角形

DionysosLai20160223

引言:

        本章,我们将介绍 GLEW 、顶点数组对象(vertex array objects VAOs)和顶点缓存对象(vertex buffer objects VBOs) 相关知识。

 

准备工作

GLEW:

        随着OpenGL的更新,OpenGL出现了很多新的高级特性,同时很多显卡公司,也会发布一些只有自己家显卡才支持的扩展函数。因此,如果我们想使用这些函数,则必须寻找配置最新的glext.h。在众多厂家和特性之间,我们难免感到纷繁杂乱,一头乱绪。GLEW正是未解决此问题而诞生的。

       GLEW是一个跨平台的C++扩展库,基于OpenGL图形接口。使用GLEW,可以帮助我们解决OpenGL扩展问题。一旦我们初始化了GLEW,GLEW会自动匹配我们使用的平台(这些平台,包括Windows、Linux、Mac OS X 、FreeBSD、Irix 和 Solaris)可适用的扩展,然后动态加载。使用时,只需要添加单个头文件(glew.h),OpenCL 内核和扩展函数,就全部自动包含进来。

 

VBO:vertex buffer object,顶点缓存对象

        顶点缓存对象用于记录顶点信息,这些包括法线、坐标等几乎所有传入OpenGL的数据。对于VBO归根到底是显卡存储空间里的一块缓存区(Buffer),因此访问VBO的速度异常快速。

 

VAO:verte x array object,顶点数组对象

        顶点数组对象和顶点缓存对象名字很像,不过顶点数组对象不是一块buffer-object,也就是说顶点数组对象不是显卡存储空间中中的一块空间,因此,顶点数组对象并不负责存储数据,而是跟“顶点绘制”息息相关,即与顶点数据VBO息息相关。

        顶点数组对象,定位是一个state-object,状态对象,记录存储状态信息。VAO记录的是一次绘制中做需要的信息,这包括“数据在哪里-glBindBuffer(GL_ARRAY_BUFFER)”、“数据的格式是怎样的-glVertexAttribPointer”。

 

OpenGL 坐标:

        OpenGL坐标 范围在 [-1, 1] 范围内。如下图所示:

                                                                           

        左下角坐标为(-1.0, -1.0),中点坐标为(0,0),如果某一对象的坐标超出这个范围,OpenGL将自动裁剪,超出范围的部分会被裁剪出去。OpenGL拥有复杂的坐标系统,详细内容以后章节我们再讨论。

 

准备工作:配置glew

        1,下载:http://glew.sourceforge.net/

        2,配置:

        配置和freeglut同理,将相应的文件拷贝到相应位置[1]

                bin/glew32.dll        拷贝到     %SystemRoot%system32

                lib/glew32.lib        拷贝到     {VCRoot}/Lib

                include/GL/glew.h      拷贝到     {VCRoot}/Include/GL

                include/GL/wglew.h      拷贝到     {VCRoot}/Include/GL

 

代码大纲:

        #include <GL/glew.h>

        添加glew.h 头文件,这个文件必须在其他OpenGL头文件之前,否则会报错。

 

        #pragma comment(lib, "glew32.lib")

        为了能够链接GLEW库,我们必须手动加载glew.lib 库文件。

 

        GLenum res =glewInit();
        if (res != GLEW_OK)
        {

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

        初始化GLEW,同时确保初始化成功。初始化GLEW工作必须在GLUT初始化之后。

     

        GLuintvao;

        glGenVertexArrays(1,&vao);

        定义一个Gluint 类型数据,这个数据用来存储定点缓存对象。关于OpenGL参数数据类型,详见下表:

后缀

数据类型

对应C语音数据类型

对应OpenGL数据类型

B

8位整型

signed char

GLbyte

S

16位整型

signed char

GLshort

I

32位整型

Int

GLint、GLsizei

F

32位浮点型

Float

GLfloat、GLclampf

D

64位浮点型

Double

GLdouble、GLclampd

Ub

8位无符号整型

unsigned char

GLubyte

us

16位无符号整型

unsigned short

Glubyte

Ui

32我无符号整型

Unsigned int

GLuint、GLenum、Glbitfield

        在直接使用C语音数据类型直接表示OpenGL数据类型时,因为OpenGL自身的实现不同,可能会造成类型不匹配情况。因此,我们建议直接使用OpenGL定义的数据类型,这样当需要在不同的OpenGL实现之间移植代码时,就不会产生数据类型不匹配的问题了[2]。P7

        首先,我们定义一个顶点数组对象 ,并使用glGenVertexArray()函数创建顶点数组对象。第一个参数1表示创建一个顶点数组对象,第二个参数&vao表示顶点数组对象存储地址。

        在以后的教程中,我们会发现很多OpenGL命令都是glGen*的形式,分别负责分配不同类型的OpenGL对象名称。

      

        glBindVertexArray(vao);

        在创建顶点完数组对象之后,我们必须为其分配内存,这样我们创建的顶点数组对象才有意义。在OpenGL中,这个分配机制我们称之为绑定对象(binga object)。在这里,我们通过glBindVertexArray函数绑定了一个顶点数组对象。

 

        GLuint VBO;

        glGenBuffers(1, &VBO);

        glBindBuffer(GL_ARRAY_BUFFER,vbo);

        这里我们同样创建了一个缓存对象,这里与前面不同的是,绑定对象时,指定了绑定对象类型。

glBindBuffer函数第一个参数,为指定缓冲对象类型,类型分别有:GL_ARRAY_BUFFER、GL_ELEMENT_ARRAY_BUFFER、GL_PIXEL_PACK_BUFFER、GL_PIXEL_UNPACK_BUFFER、GL_COPY_READ_BUFFER、GL_COPY_WRITE_BUFFER、GL_TRANSFORM_FEEDBACK_BUFFER和GL_UNIFORM_BUFFER。这里,我们指定缓存对象类型为GL_ARRAY_BUFFER,即顶点数组缓存类型。


        GLfloat vertices[][3] = {

                { -1.0f, -1.0f, 0.0f },

                { 1.0f, -1.0f, 0.0f },

                { 0.0f, 1.0f, 0.0f}

        };

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

        分配完顶点缓存对象之后,我们就应该将数据载入缓存对象。我们为顶点缓存对象载入了一个三角形数据。glBufferData()函数主要做两件事情:首先分配顶点数据所需要的存储空间;其次将数据从应用程序的数组中拷贝到OpenGL服务端的内存中。(这里我们要说明OpenGL客户端和服务端区别)。

        glBufferData()函数最后一个参数用于设置分配数据之后的读取和写入方式。这里我们只需要一次性写入,因此采用GL_STATIC_DRAW参数。

 

      glEnableVertexAttribArray(0);

      在着色器中,我们将会看到很多在着色器中使用的顶点属性,比如位置、法线等。这些顶点属性都在着色器中有对应的索引,通过其索引我们就可以绑定c++程序中的数据和着色器内部的属性。同时,在这之前,我们必须使能顶点属性索引。

      在本章中,我们还没有使用任何一个着色器,但三角形顶点位置载入缓存中,这个顶点位置被当做顶点属性,索引为0(实际上,任何一个OpenGL程序,默认都会包含一个顶点着色器和片段着色器,详细内容,下一章见)。因此,这里我们必须使能顶点属性,否则数据不会传递到着色器中。

      

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

        接下来,我们要指定渲染时索引值为0的顶点属性数组的数据格式和位置。第一个参数0,指定了属性索引。第二个参数3,指定了顶点属性组件数量,这个值必须是1、2、3或者4其中的一个,3代表了x、y、z。第三个参数指定了每个组件数据类型,在这里是GL_FLOAT。第四个参数指定当数据被使用时,是否先进行归一化处理(GL_TRUE)或者使用固定值(GL_FALSE),由于,前面三角形数据已经进行了归一化处理,因此参数为GL_FALSE。第五个参数,叫做“stide”,指定缓存中连续属性之间的偏移量量,这里只一个属性(缓存中只包含了一个顶点位置),并且数据是紧密排列的,因此我们传递参数值为0。第六个参数,指定第一个组件在数组的第一个顶点属性中的偏移量,这里偏移量为0。


        voiddisplay()

        {

                glClear(GL_COLOR_BUFFER_BIT);

                glDrawArrays(GL_TRIANGLES, 0, 3);

                glutSwapBuffers();

                glFlush();

        }

        与上一章不同地方,在于多了glDrawArras(GL_TRIANGLES,0,3),这是一个绘制函数,第一个参数指定了位置图元类型。图元类型入下表所示。第二个参数,开始绘制数据的位置,这里从第一个数据开始绘制,因此参数为0.第三个参数指定绘制当个图元需要顶点数量,我们这里绘制的是三角形,每一个三角形需要顶点数量为3。

到此为止,本章教程结束了。下一章,我们讲解第一个着色器程序。祝大家工作愉快 

详细代码下载,在下一章给出。


[延伸阅读]:

[1] http://glew.sourceforge.net/install.html

[2] 《OpenGL 编程指南》第三版P7

[3] 《OpenGL 编程指南》第三版P12~P17


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值