VAO和VBO API备忘

  • 概述

OpenGL从OpenGL 3.0开始将API分成了两种类型:即旧式的OpenGL(Legacy OpenGL)和新式的OpenGL(Core Profile),OpenGL3.3 的官方API文档完整地描述了新式的OpenGL API,旧式的OpenGL API可以在OpenGL 2.1中查看。

对于OpenGL渲染的的第一站:也就是把顶点数据(包括顶点位置、顶点法线、顶点颜色、纹理坐标等)传入到OpenGL,旧式的OpenGL中有以下几种方式实现:

  1. 立即模式(glBegin/glEnd) 这种方式恐怕是学习OpenGL最早接触到的API吧,至少我是这样。不过很遗憾它已经被新式OpenGL抛弃了
  2. 顶点数组(VA:Vertex Array)相比立即模式减少了函数的调用开销。目前也被新式OpenGL抛弃
  3. 缓冲区对象(VBO:Vertex Buffer Object)相比较VA,将数据存储到服务器端(VA存储在客户端)。目前是新式OpenGL支持的唯一数据传入方式
  4. 显示列表(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}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )