-
概述
OpenGL从OpenGL 3.0开始将API分成了两种类型:即旧式的OpenGL(Legacy OpenGL)和新式的OpenGL(Core Profile),OpenGL3.3 的官方API文档完整地描述了新式的OpenGL API,旧式的OpenGL API可以在OpenGL 2.1中查看。
对于OpenGL渲染的的第一站:也就是把顶点数据(包括顶点位置、顶点法线、顶点颜色、纹理坐标等)传入到OpenGL,旧式的OpenGL中有以下几种方式实现:
- 立即模式(glBegin/glEnd) 这种方式恐怕是学习OpenGL最早接触到的API吧,至少我是这样。不过很遗憾它已经被新式OpenGL抛弃了
- 顶点数组(VA:Vertex Array)相比立即模式减少了函数的调用开销。目前也被新式OpenGL抛弃
- 缓冲区对象(VBO:Vertex Buffer Object)相比较VA,将数据存储到服务器端(VA存储在客户端)。目前是新式OpenGL支持的唯一数据传入方式
- 显示列表(Display List)将若干条OpenGL命令编译好,直接由显卡调用。由于编译好的模块无法修改,丧失了灵活性。也被新式OpenGL抛弃
此外VBO在Legacy OpenGL中和Core Profile OpenGL中的使用也有着不同的方式。
-
VA API
(1) 开启和关闭VA
1//开启和关闭客户端状态 2 3void glEnableClientState(GLenum cap); 4 5void glDisableClientState(GLenum cap); 6 7 8 9//参数cap取值 10 11GL_VERTEX_ARRAY //顶点位置 12 13GL_COLOR_ARRAY //顶点颜色 14 15GL_EDGE_FLAG_ARRAY //顶点边界线标识 16 17GL_FOG_COORD_ARRAY //顶点雾坐标 18 19GL_INDEX_ARRAY //顶点索引 20 21GL_NORMAL_ARRAY //顶点法线 22 23GL_SECONDARY_COLOR_ARRAY //顶点辅助颜色 24 25GL_TEXTURE_COORD_ARRAY //顶点纹理坐标
(2) 设置数据到顶点
1////////////////////////////////////////////////////////////////////////// 2//以下是一系列设置顶点数据的API 3//参数取值(默认形参代表OpenGL中默认值): 4// size 描述数据的维度(2D\3D) 5// type 描述每个数据的类型 6// stride 描述每个顶点数据的跨度 7//pointer 指向实际数据 8 9 10//设置顶点位置数据 11void glVertexPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); 12//设置顶点颜色数据 13void glColorPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); 14//设置顶点边界线标识数据 15void glEdgeFlagPointer( GLsizei stride=0, const GLvoid *pointer=0); 16//设置顶点雾坐标数据 17void glFogCoordPointer( GLenum type=GL_FLOAT, GLsizei stride=0, GLvoid *pointer=0); 18//设置顶点索引数据 19void glIndexPointer( GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); 20//设置顶点法线数据 21void glNormalPointer( GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); 22//设置顶点辅助颜色数据 23void glSecondaryColorPointer( GLint size=3, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); 24//设置顶点纹理坐标数据 25void glTexCoordPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0);
(3) VA绘制
1/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2//通过设置好的顶点数据进行绘制:可以使用下列API进行绘制 3 4void glDrawArrays( GLenum mode, GLint first, GLsizei count); 5//参数描述 6//mode 绘制几何图元类型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) 7//first 顶点数据的开始索引位置(对应(2)中pointer) 8//count 需要渲染的顶点数据数量 9 10void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); 11//参数描述 12//mode 绘制几何图元类型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) 13//count 第四个参数indices中参与渲染的索引数量 14//type 第四个参数indices的数据类型 15//indices 需要额外传入的一个索引数组指针 16 17void glDrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices); 18//参数描述(与glDrawElements一致但多出两个参数) 19//mode 绘制几何图元类型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) 20//count 第四个参数indices中参与渲染的索引数量 21//type 第四个参数indices的数据类型 22//indices 需要额外传入的一个索引数组指针 23//start 索引数组indices中的最小值索引值 24//end 索引数组indices中的最大值索引值
以上就是VA所涉及到的基本API,使用过程如下
首先开启客户端VertexArray状态,接着绑定数据到顶点状态,最后进行绘制:
1static float vertices[][3] = { 2 1.0f, 0.0f, 0.0f, 3 0.0f, 1.0f, 0.0f, 4 -1.0f, 0.0f, 0.0f 5}; 6 7static float colors[][4] = { 8 1.0f, 0.0f, 0.0f, 1.0f, 9 0.0f, 1.0f, 0.0f, 1.0f, 10 0.0f, 0.0f, 1.0f, 1.0f 11}; 12 13//绘制函数 14void renderScene() 15{ 16 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 17 18 glMatrixMode(GL_MODELVIEW); 19 glLoadIdentity(); 20 glTranslatef(0.0f, 0.0f, -5.0f); 21 22 ////////////////////////////////////////////////////////////////////////// 23 //开启VA状态 24 glEnableClientState(GL_VERTEX_ARRAY); 25 glEnableClientState(GL_COLOR_ARRAY); 26 //绑定数据 27 glVertexPointer(3, GL_FLOAT, 0, vertices); 28 glColorPointer(4, GL_FLOAT, 0, colors); 29 //绘制 30 glDrawArrays(GL_TRIANGLES, 0, 3); 31 //关闭VA状态 32 glDisableClientState(GL_VERTEX_ARRAY); 33 glDisableClientState(GL_COLOR_ARRAY); 34 ////////////////////////////////////////////////////////////////////////// 35}
-
VBO API
前文描述了VBO在Legacy 和Core Profile中有两种不同的方式:
- Legacy OpenGL VBO API
(1)创建(初始化)VBO对象
1//创建VBO的API 2////////////////////////////////////////////////////////////////////////// 3void glGenBuffers( GLsizei n, GLuint * buffers); 4//生成缓冲区ID 5//参数描述 6// n 生成ID数量 7// buffers 存储缓冲区ID的数组 8 9void glBindBuffer( GLenum target, GLuint buffer); 10//设置缓冲区为当前操作的缓冲区,并且设置缓冲区的类型 11//参数描述 12//target 缓冲区类型(包括4种) 13GL_ARRAY_BUFFER 14GL_ELEMENT_ARRAY_BUFFER 15GL_PIXEL_PACK_BUFFER 16GL_PIXEL_UNPACK_BUFFER 17//buffer 使用glGenBuffers生成的缓冲区ID 18 19void glBufferData( GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage); 20//为缓冲区设置数据 21//参数描述 22//target 缓冲区类型(包括4种) 23GL_ARRAY_BUFFER 24GL_ELEMENT_ARRAY_BUFFER 25GL_PIXEL_PACK_BUFFER 26GL_PIXEL_UNPACK_BUFFER 27//size 缓冲区大小(多少字节) 28//data 实际指向数组的指针 29//usage 当前缓冲区的使用模式[一种提示用来优化之用](取值如下9种) 30GL_STREAM_DRAW 31GL_STREAM_READ 32GL_STREAM_COPY 33GL_STATIC_DRAW 34GL_STATIC_READ 35GL_STATIC_COPY 36GL_DYNAMIC_DRAW 37GL_DYNAMIC_READ 38GL_DYNAMIC_COPY
(2)开启/关闭VBO
当创建完VBO之后,我们并不知道VBO中存储的是顶点位置、还是顶点颜色或者是顶点法线,于是使用下面的API来描述某一个VBO中到底是顶点什么方面的数据
1////////////////////////////////////////////////////////////////////////// 2//开启关闭VBO状态 3void glEnableClientState(GLenum cap); 4void glDisableClientState(GLenum cap); 5//参考VA中的描述 6 7 8void glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer); 9//参考VA中的描述: 10//但是pointer参数有所区别: 11//当使用了glBindBuffer将GL_ARRAY_BUFFER绑定到一个非0的VBO ID上之后,这时候的pointer 12//代表的是一个VBO ID对象中实际数据(glBufferData中data参数)的偏移值,也就是说这时候pointer 13//并不是一个指针,仅仅是一个偏移值。同时GL_ARRAY_BUFFER_BINDING这个状态会保存在客户端 14 15//综合上面VA中的解释:可以知道这个glVertexPointer中的pointer两种含义: 16//(1)当glBindBuffer绑定到非0的ID时: 17//pointer代表偏移,此时客户端glClientState中会保存GL_ARRAY_BUFFER_BINDING暗示现在在用VBO 18//(2)当glBindBuffer绑定到0的ID时: 19//pointer代表一个指向数组的指针,此时客户端glClientState中不会保存GL_ARRAY_BUFFER_BINDING暗示现在在用VA 20 21//同理,对于VA中用到的一系列函数都有同样的解释,不再赘述: 22glColorPointer 23glEdgeFlagPointer 24glFogCoordPointer 25glIndexPointer 26glNormalPointer 27glSecondaryColorPointer 28glTexCoordPointer
(3)VBO绘制
1////////////////////////////////////////////////////////////////////////// 2//绘制VBO 3 4void glDrawArrays( GLenum mode, GLint first, GLsizei count); 5//参考VA中描述 6//所不同的是数据现在在缓冲区之中,而不是VA所指向的pointer数组中了 7 8void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); 9//参考VA中描述 10//所不同的是indices设置为NULL 11//因为缓冲区类型有一种是GL_ELEMENT_ARRAY_BUFFER(查看glGenBuffers中类型描述) 12//我们会把indices索引值存储在GL_ELEMENT_ARRAY_BUFFER类型的Buffer中,不需要额外的数组了 13//直接用两个缓冲区即可
以上便是旧式OpenGL中实现VBO的API,使用过程如下:
首先创建缓冲区并设置缓冲区类型和填满缓冲区,接着指定缓冲里面是什么(到底存的是位置还是颜色或者是法线),最后绘制
1static float vertices[][3] = { 2 1.0f, 0.0f, 0.0f, 3 0.0f, 1.0f, 0.0f, 4 -1.0f, 0.0f, 0.0f 5}; 6 7static float colors[][4] = { 8 1.0f, 0.0f, 0.0f, 1.0f, 9 0.0f, 1.0f, 0.0f, 1.0f, 10 0.0f, 0.0f, 1.0f, 1.0f 11}; 12 13void renderScene() 14{ 15 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 16 17 glMatrixMode(GL_MODELVIEW); 18 glLoadIdentity(); 19 glTranslatef(0.0f, 0.0f, -5.0f); 20 21 ////////////////////////////////////////////////////////////////////////// 22 //创建VBO(一般放在初始化函数中) 23 GLuint vertexBufferID, colorBufferID; 24 glGenBuffers(1, &vertexBufferID); 25 glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); 26 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 27 glGenBuffers(1, &colorBufferID); 28 glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); 29 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); 30 31 //开启VBO模式并设置VBO该怎么解析 32 glEnableClientState(GL_VERTEX_ARRAY); 33 glEnableClientState(GL_COLOR_ARRAY); 34 glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); 35 glVertexPointer(3, GL_FLOAT, 0, 0); 36 glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); 37 glColorPointer(4, GL_FLOAT, 0, 0); 38 39 //绘制 40 glDrawArrays(GL_TRIANGLES, 0, 3); 41 42 //绘制完成之后关闭VBO状态 43 //将glBindBuffer设置为0,使得后续glVertexPointer类似函数起到VA的作用 44 glDisableClientState(GL_VERTEX_ARRAY); 45 glDisableClientState(GL_COLOR_ARRAY); 46 glBindBuffer(GL_ARRAY_BUFFER, 0); 47 ////////////////////////////////////////////////////////////////////////// 48}
- Core Profile VBO
(1)创建VBO
参考Legacy VBO中内容,二者是一样的
(2)开启/关闭VBO
1////////////////////////////////////////////////////////////////////////// 2void glEnableVertexAttribArray( GLuint index); 3void glDisableVertexAttribArray( GLuint index); 4//开启和关闭一个通用的缓冲区对象 5//参数描述 6//index 缓冲区对象索引值 7 8void glVertexAttribPointer( GLuint index, 9 GLint size, 10 GLenum type, 11 GLboolean normalized, 12 GLsizei stride, 13 const GLvoid * pointer 14 ); 15//设置如何解析缓冲区中的数据 16//参数描述 17//index 当前操作的缓冲区对象索引值 18//size 数据的维度是2D/3D/4D 19//type 数据类型 GL_INT /GL_FLOAT 20//normalized 是否已经单位化 21//stride 数据间距 22//pointer 参考Legacy VBO中解释(在glBindBuffer未开启时是指针开启后是索引值)
(3)绘制
参考Legacy VBO中内容,二者是一样的
以上便是Core Profile 下的VBO,使用方式如下:
首先创建VBO对象,接着开启VBO并且用来说明VBO中数据是什么样组织的(但是并没有说明数据是顶点位置、顶点颜色还是法线),这一点与 Legacy VBO不同,因为它的说明部分(哪个VBO存储着位置、哪个VBO存储着颜色、哪个VBO存储着法线等)是在着色语言Shader中指明的,最后还是使用 同样的API绘制:
1////////////////////////////////////////////////////////////////////////// 2GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f, 30.5f, 0.0f, 0.0f, 40.0f, 0.5f, 0.0f }; 5 6GLfloat vColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 70.0f, 1.0f, 0.0f, 1.0f, 80.0f, 0.0f, 1.0f, 1.0f }; 9////////////////////////////////////////////////////////////////////////// 10 11void RenderWidget::paintGL() 12{ 13 ////////////////////////////////////////////////////////////////////////// 14 //生成VBO 15 glGenBuffers(1, &_vertexBuffer); 16 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); 17 glBufferData(GL_ARRAY_BUFFER, sizeof(vVerts), vVerts, GL_STATIC_DRAW); 18 19 glGenBuffers(1, &_colorBuffer); 20 glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); 21 glBufferData(GL_ARRAY_BUFFER, sizeof(vColors), vColors, GL_STATIC_DRAW); 22 23 setShaders(); 24 25 //开启VBO并设置VBO里面存储的数据模式 26 glEnableVertexAttribArray(0); 27 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); 28 glVertexAttribPointer( 29 0, 30 3, 31 GL_FLOAT, 32 GL_FALSE, 33 0, 34 (void*)0 35 ); 36 glEnableVertexAttribArray(1); 37 glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); 38 glVertexAttribPointer( 39 1, 40 4, 41 GL_FLOAT, 42 GL_FALSE, 43 0, 44 (void*)0 45 ); 46 47 //绘制VBO 48 glDrawArrays(GL_TRIANGLES, 0, 3); 49 50 //关闭VBO 51 glDisableVertexAttribArray(1); 52 glDisableVertexAttribArray(0); 53 glBindBuffer(GL_ARRAY_BUFFER, 0); 54}
Shader部分**:**
顶点Shader
1#version 330 2layout(location = 0) in vec4 vertex; 3layout(location = 1) in vec4 color; 4out vec4 inFragColor; 5 6void main( void ) 7{ 8 gl_Position = vertex; 9 inFragColor = color; 10}
片元Shader
1#version 330 2in vec4 inFragColor; 3out vec4 outFragColor; 4 5void main( void ) 6{ 7 outFragColor = inFragColor; 8}
通过顶点Shader可以知道索引值为0的VBO解释为顶点位置,它传给gl_Position,索引值为1的VBO解释为顶点的颜色
-
VAO API
VAO的介绍可以参考 <<AB是一家?VAO与VBO>>
(1)初始化
1////////////////////////////////////////////////////////////////////////// 2//初始化VAO 3 4void glGenVertexArrays(GLsizei n, GLuint *arrays); 5//创建VAO ID 6//参数描述 7//n 产生VAO ID的数量 8//arrays 保存VAO ID的数组 9 10void glBindVertexArray(GLuint array); 11//设置当前操作的VAO对象 12//参数描述 13//array VAO的ID
(2)开启/关闭VAO
VAO的开启当使用glBindVertexArray时自动开启,使用glBindVertexArray(0),传入一个0值可以视为将VAO关闭
设置VAO的过程就是调用VBO中(2)的过程
(3) 绘制
同VBO中绘制(绘制之前先启用VAO)
以上就是VAO涉及到的API,使用过程如下:
首先创建VAO,接着设置VAO(在调用VBO的数据设置过程中VAO自动完成了设置),最后开启VAO并绘制:
1////////////////////////////////////////////////////////////////////////// 2GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f, 30.5f, 0.0f, 0.0f, 40.0f, 0.5f, 0.0f }; 5 6GLfloat vColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 70.0f, 1.0f, 0.0f, 1.0f, 80.0f, 0.0f, 1.0f, 1.0f }; 9////////////////////////////////////////////////////////////////////////// 10 11void RenderWidget::paintGL() 12{ 13 ////////////////////////////////////////////////////////////////////////// 14 //生成VBO 15 glGenBuffers(1, &_vertexBuffer); 16 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); 17 glBufferData(GL_ARRAY_BUFFER, sizeof(vVerts), vVerts, GL_STATIC_DRAW); 18 19 glGenBuffers(1, &_colorBuffer); 20 glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); 21 glBufferData(GL_ARRAY_BUFFER, sizeof(vColors), vColors, GL_STATIC_DRAW); 22 23 setShaders(); 24 25 26 //初始化VAO 27 GLuint vaoBuffer; 28 glGenVertexArrays(1, &vaoBuffer); 29 glBindVertexArray(vaoBuffer); 30 31 //通过设置VBO里面存储的数据模式完成VAO设置 32 glEnableVertexAttribArray(0); 33 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); 34 glVertexAttribPointer( 35 0, 36 3, 37 GL_FLOAT, 38 GL_FALSE, 39 0, 40 (void*)0 41 ); 42 glEnableVertexAttribArray(1); 43 glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); 44 glVertexAttribPointer( 45 1, 46 4, 47 GL_FLOAT, 48 GL_FALSE, 49 0, 50 (void*)0 51 ); 52 glBindVertexArray(0); 53 glBindBuffer(GL_ARRAY_BUFFER, 0); 54 55 ////////////////////////////////////////////////////////////////////////// 56 //上述所有的代码在初始化函数中调用 57 //只有绘制代码在渲染函数中调用 58 //使用VAO绘制 59 glBindVertexArray(vaoBuffer); 60 glDrawArrays(GL_TRIANGLES, 0, 3); 61 glBindVertexArray(0); 62}