OpenGL从OpenGL 3.0开始将API分红了两种类型:即旧式的OpenGL(Legacy OpenGL)和新式的OpenGL(Core Profile),OpenGL3.3 的官方API文档完整地描述了新式的OpenGL API,旧式的OpenGL API能够在OpenGL 2.1中查看。html
对于OpenGL渲染的的第一站:也就是把顶点数据(包括顶点位置、顶点法线、顶点颜色、纹理坐标等)传入到OpenGL,旧式的OpenGL中有如下几种方式实现:数组
此外VBO在Legacy OpenGL中和Core Profile OpenGL中的使用也有着不一样的方式。服务器
(1) 开启和关闭VAide
//开启和关闭客户端状态 void glEnableClientState(GLenum cap); void glDisableClientState(GLenum cap); //参数cap取值 GL_VERTEX_ARRAY //顶点位置 GL_COLOR_ARRAY //顶点颜色 GL_EDGE_FLAG_ARRAY //顶点边界线标识 GL_FOG_COORD_ARRAY //顶点雾坐标 GL_INDEX_ARRAY //顶点索引 GL_NORMAL_ARRAY //顶点法线 GL_SECONDARY_COLOR_ARRAY //顶点辅助颜色 GL_TEXTURE_COORD_ARRAY //顶点纹理坐标
(2) 设置数据到顶点函数
////////////////////////////////////////////////////////////////////////// //如下是一系列设置顶点数据的API //参数取值(默认形参表明OpenGL中默认值): // size 描述数据的维度(2D\3D) // type 描述每一个数据的类型 // stride 描述每一个顶点数据的跨度 //pointer 指向实际数据 //设置顶点位置数据 void glVertexPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //设置顶点颜色数据 void glColorPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //设置顶点边界线标识数据 void glEdgeFlagPointer( GLsizei stride=0, const GLvoid *pointer=0); //设置顶点雾坐标数据 void glFogCoordPointer( GLenum type=GL_FLOAT, GLsizei stride=0, GLvoid *pointer=0); //设置顶点索引数据 void glIndexPointer( GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //设置顶点法线数据 void glNormalPointer( GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //设置顶点辅助颜色数据 void glSecondaryColorPointer( GLint size=3, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0); //设置顶点纹理坐标数据 void glTexCoordPointer( GLint size=4, GLenum type=GL_FLOAT, GLsizei stride=0, const GLvoid *pointer=0);
(3) VA绘制学习
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //经过设置好的顶点数据进行绘制:可使用下列API进行绘制 void glDrawArrays( GLenum mode, GLint first, GLsizei count); //参数描述 //mode 绘制几何图元类型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) //first 顶点数据的开始索引位置(对应(2)中pointer) //count 须要渲染的顶点数据数量 void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); //参数描述 //mode 绘制几何图元类型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) //count 第四个参数indices中参与渲染的索引数量 //type 第四个参数indices的数据类型 //indices 须要额外传入的一个索引数组指针 void glDrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices); //参数描述(与glDrawElements一致但多出两个参数) //mode 绘制几何图元类型(GL_POINTS, GL_LINE_STRIP, GL_TRIANGLE等) //count 第四个参数indices中参与渲染的索引数量 //type 第四个参数indices的数据类型 //indices 须要额外传入的一个索引数组指针 //start 索引数组indices中的最小值索引值 //end 索引数组indices中的最大值索引值
以上就是VA所涉及到的基本API,使用过程以下优化
首先开启客户端VertexArray状态,接着绑定数据到顶点状态,最后进行绘制:ui
static float vertices[][3] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f }; static float colors[][4] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; //绘制函数 void renderScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); ////////////////////////////////////////////////////////////////////////// //开启VA状态 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); //绑定数据 glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(4, GL_FLOAT, 0, colors); //绘制 glDrawArrays(GL_TRIANGLES, 0, 3); //关闭VA状态 glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); ////////////////////////////////////////////////////////////////////////// }
前文描述了VBO在Legacy 和Core Profile中有两种不一样的方式:spa
(1)建立(初始化)VBO对象指针
//建立VBO的API ////////////////////////////////////////////////////////////////////////// void glGenBuffers( GLsizei n, GLuint * buffers); //生成缓冲区ID //参数描述 // n 生成ID数量 // buffers 存储缓冲区ID的数组 void glBindBuffer( GLenum target, GLuint buffer); //设置缓冲区为当前操做的缓冲区,而且设置缓冲区的类型 //参数描述 //target 缓冲区类型(包括4种) GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER GL_PIXEL_PACK_BUFFER GL_PIXEL_UNPACK_BUFFER //buffer 使用glGenBuffers生成的缓冲区ID void glBufferData( GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage); //为缓冲区设置数据 //参数描述 //target 缓冲区类型(包括4种) GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER GL_PIXEL_PACK_BUFFER GL_PIXEL_UNPACK_BUFFER //size 缓冲区大小(多少字节) //data 实际指向数组的指针 //usage 当前缓冲区的使用模式[一种提示用来优化之用](取值以下9种) GL_STREAM_DRAW GL_STREAM_READ GL_STREAM_COPY GL_STATIC_DRAW GL_STATIC_READ GL_STATIC_COPY GL_DYNAMIC_DRAW GL_DYNAMIC_READ GL_DYNAMIC_COPY
(2)开启/关闭VBO
当建立完VBO以后,咱们并不知道VBO中存储的是顶点位置、仍是顶点颜色或者是顶点法线,因而使用下面的API来描述某一个VBO中究竟是顶点什么方面的数据
////////////////////////////////////////////////////////////////////////// //开启关闭VBO状态 void glEnableClientState(GLenum cap); void glDisableClientState(GLenum cap); //参考VA中的描述 void glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer); //参考VA中的描述: //可是pointer参数有所区别: //当使用了glBindBuffer将GL_ARRAY_BUFFER绑定到一个非0的VBO ID上以后,这时候的pointer //表明的是一个VBO ID对象中实际数据(glBufferData中data参数)的偏移值,也就是说这时候pointer //并非一个指针,仅仅是一个偏移值。同时GL_ARRAY_BUFFER_BINDING这个状态会保存在客户端 //综合上面VA中的解释:能够知道这个glVertexPointer中的pointer两种含义: //(1)当glBindBuffer绑定到非0的ID时: //pointer表明偏移,此时客户端glClientState中会保存GL_ARRAY_BUFFER_BINDING暗示如今在用VBO //(2)当glBindBuffer绑定到0的ID时: //pointer表明一个指向数组的指针,此时客户端glClientState中不会保存GL_ARRAY_BUFFER_BINDING暗示如今在用VA //同理,对于VA中用到的一系列函数都有一样的解释,再也不赘述: glColorPointer glEdgeFlagPointer glFogCoordPointer glIndexPointer glNormalPointer glSecondaryColorPointer glTexCoordPointer
(3)VBO绘制
////////////////////////////////////////////////////////////////////////// //绘制VBO void glDrawArrays( GLenum mode, GLint first, GLsizei count); //参考VA中描述 //所不一样的是数据如今在缓冲区之中,而不是VA所指向的pointer数组中了 void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); //参考VA中描述 //所不一样的是indices设置为NULL //由于缓冲区类型有一种是GL_ELEMENT_ARRAY_BUFFER(查看glGenBuffers中类型描述) //咱们会把indices索引值存储在GL_ELEMENT_ARRAY_BUFFER类型的Buffer中,不须要额外的数组了 //直接用两个缓冲区便可
以上即是旧式OpenGL中实现VBO的API,使用过程以下:
首先建立缓冲区并设置缓冲区类型和填满缓冲区,接着指定缓冲里面是什么(到底存的是位置仍是颜色或者是法线),最后绘制
static float vertices[][3] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f }; static float colors[][4] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; void renderScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); ////////////////////////////////////////////////////////////////////////// //建立VBO(通常放在初始化函数中) GLuint vertexBufferID, colorBufferID; glGenBuffers(1, &vertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glGenBuffers(1, &colorBufferID); glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); //开启VBO模式并设置VBO该怎么解析 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glVertexPointer(3, GL_FLOAT, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); glColorPointer(4, GL_FLOAT, 0, 0); //绘制 glDrawArrays(GL_TRIANGLES, 0, 3); //绘制完成以后关闭VBO状态 //将glBindBuffer设置为0,使得后续glVertexPointer相似函数起到VA的做用 glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); ////////////////////////////////////////////////////////////////////////// }
(1)建立VBO
参考Legacy VBO中内容,两者是同样的
(2)开启/关闭VBO
////////////////////////////////////////////////////////////////////////// void glEnableVertexAttribArray( GLuint index); void glDisableVertexAttribArray( GLuint index); //开启和关闭一个通用的缓冲区对象 //参数描述 //index 缓冲区对象索引值 void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer ); //设置如何解析缓冲区中的数据 //参数描述 //index 当前操做的缓冲区对象索引值 //size 数据的维度是2D/3D/4D //type 数据类型 GL_INT /GL_FLOAT //normalized 是否已经单位化 //stride 数据间距 //pointer 参考Legacy VBO中解释(在glBindBuffer未开启时是指针开启后是索引值)
(3)绘制
参考Legacy VBO中内容,两者是同样的
以上即是Core Profile 下的VBO,使用方式以下:
首先建立VBO对象,接着开启VBO而且用来讲明VBO中数据是什么样组织的(可是并无说明数据是顶点位置、顶点颜色仍是法线),这一点与 Legacy VBO不一样,由于它的说明部分(哪一个VBO存储着位置、哪一个VBO存储着颜色、哪一个VBO存储着法线等)是在着色语言Shader中指明的,最后仍是使用 一样的API绘制:
////////////////////////////////////////////////////////////////////////// GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f }; GLfloat vColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; ////////////////////////////////////////////////////////////////////////// void RenderWidget::paintGL() { ////////////////////////////////////////////////////////////////////////// //生成VBO glGenBuffers(1, &_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vVerts), vVerts, GL_STATIC_DRAW); glGenBuffers(1, &_colorBuffer); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vColors), vColors, GL_STATIC_DRAW); setShaders(); //开启VBO并设置VBO里面存储的数据模式 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 0, (void*)0 ); //绘制VBO glDrawArrays(GL_TRIANGLES, 0, 3); //关闭VBO glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); }
Shader部分:
顶点Shader
#version 330 layout(location = 0) in vec4 vertex; layout(location = 1) in vec4 color; out vec4 inFragColor; void main( void ) { gl_Position = vertex; inFragColor = color; }
片元Shader
#version 330 in vec4 inFragColor; out vec4 outFragColor; void main( void ) { outFragColor = inFragColor; }
经过顶点Shader能够知道索引值为0的VBO解释为顶点位置,它传给gl_Position,索引值为1的VBO解释为顶点的颜色
VAO的介绍能够参考 <<AB是一家?VAO与VBO>>
(1)初始化
////////////////////////////////////////////////////////////////////////// //初始化VAO void glGenVertexArrays(GLsizei n, GLuint *arrays); //建立VAO ID //参数描述 //n 产生VAO ID的数量 //arrays 保存VAO ID的数组 void glBindVertexArray(GLuint array); //设置当前操做的VAO对象 //参数描述 //array VAO的ID
(2)开启/关闭VAO
VAO的开启当使用glBindVertexArray时自动开启,使用glBindVertexArray(0),传入一个0值能够视为将VAO关闭
设置VAO的过程就是调用VBO中(2)的过程
(3) 绘制
同VBO中绘制(绘制以前先启用VAO)
以上就是VAO涉及到的API,使用过程以下:
首先建立VAO,接着设置VAO(在调用VBO的数据设置过程当中VAO自动完成了设置),最后开启VAO并绘制:
////////////////////////////////////////////////////////////////////////// GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f }; GLfloat vColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; ////////////////////////////////////////////////////////////////////////// void RenderWidget::paintGL() { ////////////////////////////////////////////////////////////////////////// //生成VBO glGenBuffers(1, &_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vVerts), vVerts, GL_STATIC_DRAW); glGenBuffers(1, &_colorBuffer); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vColors), vColors, GL_STATIC_DRAW); setShaders(); //初始化VAO GLuint vaoBuffer; glGenVertexArrays(1, &vaoBuffer); glBindVertexArray(vaoBuffer); //经过设置VBO里面存储的数据模式完成VAO设置 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer); glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); ////////////////////////////////////////////////////////////////////////// //上述全部的代码在初始化函数中调用 //只有绘制代码在渲染函数中调用 //使用VAO绘制 glBindVertexArray(vaoBuffer); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); }