深入理解:顶点缓存对象(VBO)

顶点缓存对象(VBO)

  • 深入理解:顶点缓存对象(VBO)
  • 前言
  • 一、创建VBO
  • 二、绘制VBO
  • 更新VBO
  • 实例
  • 源码下载
  • 引用

前言

GL_ARB_vertex_buffer_object扩展致力于提供顶点数组与显示列表的优势来提升OpenGL效率,同时避免它们实现上的不足。顶点缓存对象(VBO)准许顶点数组数据存放在服务端的高性能显卡内存中,且提供高效数据传输。如果缓存对象用于保存像素数据,就被称为像素缓存对象(PBO)。

使用顶点数组可以降低函数调用次数与降低共享顶点的重复使用。然而,顶点数组的不足之处是顶点数组函数处在客户端状态中,且每次引用都须向服务端重新发送数据。

此外,显示列表为服务端函数,因此,它并不受限于数据传输的开销。不过,一旦显示列表编译完成,显示列表中的数据不能够修改。

顶点缓存对象(VBO)在服务器端高性能内存中为顶点属性创建“缓存对象”,并且提供引用这些数组的访问函数,这些函数与顶点数组中使用的函数相同,如glVertexPointer()、glNormalPointer()、glTexCoordPointer()等。

顶点缓存对象中的内存管理根据用户提示(“target”与“Usage”模式)将缓存对象放置在最合适内存位置。因此,内存管理能够通过在系统、AGP与显卡内存三种内存之间做出平衡的方式优化缓存。

与显示列表不同,可以通过映射缓存到客户端内存空间的方式读取与更新顶点缓存对象中的数据。

VBO的另一个重要优势是就像显示列表与纹理那样可以在多个客户端共享缓存数据。因为VBO处在服务器端,多个客户端可以通过相应的标示符访问同一个缓存。

一、创建VBO

创建VBO需要3个步骤:

使用glGenBuffers()生成新缓存对象。
使用glBindBuffer()绑定缓存对象。
使用glBufferData()将顶点数据拷贝到缓存对象中。
glGenBuffers()
glGenBuffers()创建缓存对象并且返回缓存对象的标示符。它需要2个参数:第一个为需要创建的缓存数量,第二个为用于存储单一ID或多个ID的GLuint变量或数组的地址。

1
void glGenBuffers(GLsizei n, GLuint* buffers)
glBindBuffer()
当缓存对象创建之后,在使用缓存对象之前,我们需要将缓存对象连接到相应的缓存上。glBindBuffer()有2个参数:target与buffer。

1
void glBindBuffer(GLenum target, GLuint buffer)
target告诉VBO该缓存对象将保存顶点数组数据还是索引数组数据:GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY。任何顶点属性,如顶点坐标、纹理坐标、法线与颜色分量数组都使用GL_ARRAY_BUFFER。用于glDraw[Range]Elements()的索引数据需要使用GL_ELEMENT_ARRAY绑定。注意,target标志帮助VBO确定缓存对象最有效的位置,如有些系统将索引保存AGP或系统内存中,将顶点保存在显卡内存中。

当第一次调用glBindBuffer(),VBO用0大小的内存缓存初始化该缓存,并且设置VBO的初始状态,如用途与访问属性。

glBufferData()
当缓存初始化之后,你可以使用glBufferData()将数据拷贝到缓存对象。

1
void glBufferData(GLenum target,GLsizeiptr size, const GLvoid* data, GLenum usage);
第一个参数target可以为GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY。size为待传递数据字节数量。第三个参数为源数据数组指针,如data为NULL,则VBO仅仅预留给定数据大小的内存空间。最后一个参数usage标志位VBO的另一个性能提示,它提供缓存对象将如何使用:static、dynamic或stream、与read、copy或draw。

VBO为usage标志指定9个枚举值:

1
2
3
4
5
6
7
8
9
GL_STATIC_DRAW
GL_STATIC_READ
GL_STATIC_COPY
GL_DYNAMIC_DRAW
GL_DYNAMIC_READ
GL_DYNAMIC_COPY
GL_STREAM_DRAW
GL_STREAM_READ
GL_STREAM_COPY
”static“表示VBO中的数据将不会被改动(一次指定多次使用),”dynamic“表示数据将会被频繁改动(反复指定与使用),”stream“表示每帧数据都要改变(一次指定一次使用)。”draw“表示数据将被发送到GPU以待绘制(应用程序到GL),”read“表示数据将被客户端程序读取(GL到应用程序),”copy“表示数据可用于绘制与读取(GL到GL)。

注意,仅仅draw标志对VBO有用,copy与read标志对顶点/帧缓存对象(PBO或FBO)更有意义,如GL_STATIC_DRAW与GL_STREAM_DRAW使用显卡内存,GL_DYNAMIC使用AGP内存。_READ_相关缓存更适合在系统内存或AGP内存,因为这样数据更易访问。

glBufferSubData()
1
void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
与glBufferData()类似,glBufferSubData()用于向VBO中拷贝数据,不过它仅仅将从给定offset开始的一定范围的数据替换到现存缓存中。(在使用glBufferSubData()之前,整个缓存必须由glBufferData()指定。)

glDeleteBuffers()
1
void glDrawBuffers(GLsizei n, const GLenum* bufs);
在VBO不再使用时,你可以使用glDeleteBuffers()删除一个VBO或多个VBO。在混存对象删除之后,它的内容将丢失。

下列代码是为顶点坐标创建单一VBO的实例。注意,在你拷贝数据到VBO之后,你可以应用程序中为顶点数组分配的内存。

#include "glew/glew.h"
#include "glfw/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"   // glm::translate, glm::rotate, glm::scale, glm::perspective
#include "glm/gtc/type_ptr.hpp"           // glm::value_ptr
#include "Utils.h"
#include <iostream>
#include <string>
#include <fstream>using namespace std;static const int Screen_Width = 800;
static const int Screen_Height = 600;
static const int NumberVAOs = 1;
static const int NumberVBOs = 2;
int width = 0;
int height = 0;Utils util = Utils();
float cameraX = 0.f, cameraY = 0.f, cameraZ = 0.f;
float cubeLocX = 0.f, cubeLocY = 0.f, cubeLocZ = 0.f;
GLuint renderingProgram = 0;
GLuint vao[NumberVAOs] = { 0 };
GLuint vbo[NumberVBOs] = { 0 };// variable allocation for display
GLuint mvLoc = 0, projLoc = 0;
float aspect = 0.f;
glm::mat4 pMat(1), vMat(1), mMat(1), mvMat(1);void setupVertices(void)
{float vertexPositions[108] = {-1.0f,  1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f, 1.0f,  1.0f, -1.0f, -1.0f,  1.0f, -1.0f,1.0f, -1.0f, -1.0f, 1.0f, -1.0f,  1.0f, 1.0f,  1.0f, -1.0f,1.0f, -1.0f,  1.0f, 1.0f,  1.0f,  1.0f, 1.0f,  1.0f, -1.0f,1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f, 1.0f,  1.0f,  1.0f,-1.0f, -1.0f,  1.0f, -1.0f,  1.0f,  1.0f, 1.0f,  1.0f,  1.0f,-1.0f, -1.0f,  1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,  1.0f,-1.0f, -1.0f, -1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f,  1.0f,-1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,-1.0f,  1.0f, -1.0f, 1.0f,  1.0f, -1.0f, 1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f, -1.0f};//生成顶点数组对象glGenVertexArrays(NumberVAOs, vao);glBindVertexArray(vao[0]);//生成顶点缓存对象,并返回缓存对象的标识符idglGenBuffers(NumberVBOs, vbo);//绑定/激活缓存对象,target告诉VBO该缓存对象将保存顶点数组数据还是索引数组数据:GL_ARRAY_BUFFER或GL_ELEMENT_ARRAYglBindBuffer(GL_ARRAY_BUFFER, vbo[0]);//glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);//将顶点数据拷贝到缓存对象中glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions),  vertexPositions, GL_STATIC_DRAW);    //有问题//glDrawArrays(GL_TRIANGLES, 0, 108);
}void init(GLFWwindow* window)
{renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");cameraX = 0.f;cameraY = 0.f;cameraZ = 8.f;cubeLocX = 0.f;cubeLocY = -2.f;cubeLocZ = 0.f;setupVertices();
}void display(GLFWwindow* window, double currentTime)
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(0.f, 1.f, 1.f, 1.f);glUseProgram(renderingProgram);/*Utils::printProgramLog(renderingProgram);*/   //printProgramLog()是私有函数mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");//glfwGetFramebufferSize(window, const_cast<int*>(&Screen_Width), const_cast<int*>(&Screen_Height));width = 800;height = 600;glfwGetFramebufferSize(window, &width, &height);aspect = (float)(Screen_Width) / (float)(Screen_Height);pMat = glm::perspective(glm::radians(60.f), aspect, 0.1f, 1000.f);  //有问题//pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);vMat = glm::translate(glm::mat4(1.f), glm::vec3(-cameraX, -cameraY, -cameraZ));mMat = glm::translate(glm::mat4(1.f), glm::vec3(cubeLocX, cubeLocY, cubeLocZ));mvMat = vMat * mMat;glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);//glBufferData(GL_ARRAY_BUFFER, sizeof(vbo), vbo, GL_STATIC_DRAW);//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);   //有问题glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(0);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glDrawArrays(GL_TRIANGLES, 0, 36);}int main(int argc, char** argv)
{int glfwStatue = glfwInit();if (GLFW_FALSE == glfwStatue){cout << "GLFW initialize failed, invoke glfwInit().....Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;glfwTerminate();exit(EXIT_FAILURE);}glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);glfwWindowHint(GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_PROFILE);GLFWwindow* window = glfwCreateWindow(Screen_Width, Screen_Height, "Draw color cube", nullptr, nullptr);if (!window){cout << "GLFW create window failed, invoke glfwCreateWindow().......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;glfwTerminate();exit(EXIT_FAILURE);}glfwMakeContextCurrent(window);int glewSatue = glewInit();if (GLEW_OK != glewSatue){cout << "GLEW initialize failed, invoke glewInit().....Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;exit(EXIT_FAILURE);}//由于这些原因,应用程序通常希望将交换间隔设置为1。可以将其设置为更高的值,但通常不建议这样做,因为这样会导致输入延迟。glfwSwapInterval(1);init(window);while (!glfwWindowShouldClose(window)){display(window, glfwGetTime());glfwSwapBuffers(window);glfwPollEvents();}glfwDestroyWindow(window);glfwTerminate();exit(EXIT_SUCCESS);return 0;
}

二、绘制VBO

由于VBO基于现有的顶点数组实现之上,渲染VBO与使用顶点数组渲染几乎一致。仅有的不同是顶点数组指针现在作为当前绑定缓存对象的偏移值。因此,绘制VBO时除了glBindBuffer()之外不需别的API。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 为顶点数组与索引数组绑定VBO
glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId1); // 顶点坐标
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, vboId2); // 索引坐标

// 除了指针都与顶点数组一致
glEnableClientState(GL_VERTEX_ARRAY); // 开启顶点坐标数组
glVertexPointer(3, GL_FLOAT, 0, 0); // 最后一个参数为offset,而非ptr

// 使用索引数组偏移绘制6个四边形
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0);

glDisableClientState(GL_VERTEX_ARRAY); // 禁用顶点数组

// 用0绑定,因此,切换到标准指针操作
glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
使用0绑定缓存对象将关闭VBO操作。在使用完VBO之后,最好将之关闭,因此具有绝对指针的顶点数组操作将重新开启。

更新VBO

VBO相对于显示列表的优势在于客户端可以读取与编辑缓存对象数据,而显示列表不能这样做。更新VBO的最简便方法是使用glBufferData()或glBufferSubData()将新数据重新拷贝到绑定的VBO中。这种情况下,你的应用程序需要始终拥有一个有效的顶点数组。也就是说,你必须始终拥有2份顶点数据:一份在应用程序中,另一份在VBO中。

修改缓存对象的另一个方式是将缓存对象映射到客户端内存,客户端可以使用映射缓存的指针更新数据。下文描述如何将VBO映射到客户端内存以及如何访问映射数据。

glMapBuffer()
VBO提供glMapBuffer()以将缓存对象绑定到客户端内存。

1
void* glMapBuffer(GLenum target, GLenum access);
如果OpenGL能够将缓存对象映射到客户端地址空间,glMapBuffer()返回指向缓存的指针。否则它返回NULL。

第一个参数target早在glBindBuffer()中涉及,第二个参数access标志指定怎样使用映射数据:读取、改写或两者都。

1
2
3
GL_READ_ONLY
GL_WRITE_ONLY
GL_READ_WRITE
注意,glMapBuffer()引起同步问题。如果GPU任然工作于该缓存对象,glMapBuffer()将一直等待直到GPU结束对应缓存对象上的工作。

为了避免等待,你可以首先使用NULL调用glBufferData(),然后再调用glMapBuffer()。这样,前一个数据将被丢弃且glMapBuffer()立即返回一个新分配的指针,即使GPU任然工作于前一个数据。

然而,由于你丢弃了前一个数据,这种方法只有在你想更新整个数据集的时候才有效。如果你仅仅希望更改部分数据或读取数据,你最好不要释放先前的数据。

glUnmapBuffer()
1
GLboolean glUnmapBuffer(GLenum target)
在完成VBO数据的修改之后,必须将缓存对象从客户端内存解除映射。如果成功,glUnmapBuffer()返回GL_TRUE。如返回GL_FALSE,绑定之后的VBO缓存内容是坏的。腐坏现象源自显示器分辨率的改变或窗口系统的特定事件。此种情况,数据必须重发。

下面是使用绑定方式改变VBO的实例代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 绑定然后映射该VBO
glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId);
float* ptr = (float*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);

// 如果指针为空(映射后的),更新VBO
if (ptr)
{
updateMyVBO(ptr, …); // 修改缓存数据
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); // 使用之后解除映射
}

// 你可以绘制更新后的VBO

实例

代码2:

/** Copyright ?2012-2015 Graham Sellers** Permission is hereby granted, free of charge, to any person obtaining a* copy of this software and associated documentation files (the "Software"),* to deal in the Software without restriction, including without limitation* the rights to use, copy, modify, merge, publish, distribute, sublicense,* and/or sell copies of the Software, and to permit persons to whom the* Software is furnished to do so, subject to the following conditions:** The above copyright notice and this permission notice (including the next* paragraph) shall be included in all copies or substantial portions of the* Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER* DEALINGS IN THE SOFTWARE.*///#include <sb7.h>
#include "sb7.h"
#include "sb7color.h"
#include "vmath.h"class basicfbo_app : public sb7::application
{void init(){static const char title[] = "OpenGL SuperBible - Basic Framebuffer Object";sb7::application::init();memcpy(info.title, title, sizeof(title));}virtual void startup(){static const char * vs_source[] ={"#version 410 core                                                  \n""                                                                   \n""layout (location = 0) in vec4 position;                            \n""layout (location = 1) in vec2 texcoord;                            \n""                                                                   \n""out VS_OUT                                                         \n""{                                                                  \n""    vec4 color;                                                    \n""    vec2 texcoord;                                                 \n""} vs_out;                                                          \n""                                                                   \n""uniform mat4 mv_matrix;                                            \n""uniform mat4 proj_matrix;                                          \n""                                                                   \n""void main(void)                                                    \n""{                                                                  \n""    gl_Position = proj_matrix * mv_matrix * position;              \n""    vs_out.color = position * 2.0 + vec4(0.5, 0.5, 0.5, 0.0);      \n""    vs_out.texcoord = texcoord;                                    \n""}                                                                  \n"};static const char * fs_source1[] ={"#version 410 core                                                              \n""                                                                               \n""in VS_OUT                                                                      \n""{                                                                              \n""    vec4 color;                                                                \n""    vec2 texcoord;                                                             \n""} fs_in;                                                                       \n""                                                                               \n""out vec4 color;                                                                \n""                                                                               \n""void main(void)                                                                \n""{                                                                              \n""    color = sin(fs_in.color * vec4(40.0, 20.0, 30.0, 1.0)) * 0.5 + vec4(0.5);  \n""}                                                                              \n"};static const char * fs_source2[] ={"#version 420 core                                                              \n""                                                                               \n""uniform sampler2D tex;                                                         \n""                                                                               \n""out vec4 color;                                                                \n""                                                                               \n""in VS_OUT                                                                      \n""{                                                                              \n""    vec4 color;                                                                \n""    vec2 texcoord;                                                             \n""} fs_in;                                                                       \n""                                                                               \n""void main(void)                                                                \n""{                                                                              \n""    color = mix(fs_in.color, texture(tex, fs_in.texcoord), 0.7);               \n""}                                                                              \n"};program1 = glCreateProgram();GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fs, 1, fs_source1, NULL);glCompileShader(fs);GLuint vs = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vs, 1, vs_source, NULL);glCompileShader(vs);glAttachShader(program1, vs);glAttachShader(program1, fs);glLinkProgram(program1);glDeleteShader(vs);glDeleteShader(fs);program2 = glCreateProgram();fs = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fs, 1, fs_source2, NULL);glCompileShader(fs);vs = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vs, 1, vs_source, NULL);glCompileShader(vs);glAttachShader(program2, vs);glAttachShader(program2, fs);glLinkProgram(program2);glDeleteShader(vs);glDeleteShader(fs);mv_location = glGetUniformLocation(program1, "mv_matrix");proj_location = glGetUniformLocation(program1, "proj_matrix");mv_location2 = glGetUniformLocation(program2, "mv_matrix");proj_location2 = glGetUniformLocation(program2, "proj_matrix");glGenVertexArrays(1, &vao);glBindVertexArray(vao);static const GLushort vertex_indices[] ={0, 1, 2,2, 1, 3,2, 3, 4,4, 3, 5,4, 5, 6,6, 5, 7,6, 7, 0,0, 7, 1,6, 0, 2,2, 4, 6,7, 5, 3,7, 3, 1};static const GLfloat vertex_data[] ={// Position                 Tex Coord-0.25f, -0.25f,  0.25f,      0.0f, 1.0f,-0.25f, -0.25f, -0.25f,      0.0f, 0.0f,0.25f, -0.25f, -0.25f,      1.0f, 0.0f,0.25f, -0.25f, -0.25f,      1.0f, 0.0f,0.25f, -0.25f,  0.25f,      1.0f, 1.0f,-0.25f, -0.25f,  0.25f,      0.0f, 1.0f,0.25f, -0.25f, -0.25f,      0.0f, 0.0f,0.25f,  0.25f, -0.25f,      1.0f, 0.0f,0.25f, -0.25f,  0.25f,      0.0f, 1.0f,0.25f,  0.25f, -0.25f,      1.0f, 0.0f,0.25f,  0.25f,  0.25f,      1.0f, 1.0f,0.25f, -0.25f,  0.25f,      0.0f, 1.0f,0.25f,  0.25f, -0.25f,      1.0f, 0.0f,-0.25f,  0.25f, -0.25f,      0.0f, 0.0f,0.25f,  0.25f,  0.25f,      1.0f, 1.0f,-0.25f,  0.25f, -0.25f,      0.0f, 0.0f,-0.25f,  0.25f,  0.25f,      0.0f, 1.0f,0.25f,  0.25f,  0.25f,      1.0f, 1.0f,-0.25f,  0.25f, -0.25f,      1.0f, 0.0f,-0.25f, -0.25f, -0.25f,      0.0f, 0.0f,-0.25f,  0.25f,  0.25f,      1.0f, 1.0f,-0.25f, -0.25f, -0.25f,      0.0f, 0.0f,-0.25f, -0.25f,  0.25f,      0.0f, 1.0f,-0.25f,  0.25f,  0.25f,      1.0f, 1.0f,-0.25f,  0.25f, -0.25f,      0.0f, 1.0f,0.25f,  0.25f, -0.25f,      1.0f, 1.0f,0.25f, -0.25f, -0.25f,      1.0f, 0.0f,0.25f, -0.25f, -0.25f,      1.0f, 0.0f,-0.25f, -0.25f, -0.25f,      0.0f, 0.0f,-0.25f,  0.25f, -0.25f,      0.0f, 1.0f,-0.25f, -0.25f,  0.25f,      0.0f, 0.0f,0.25f, -0.25f,  0.25f,      1.0f, 0.0f,0.25f,  0.25f,  0.25f,      1.0f, 1.0f,0.25f,  0.25f,  0.25f,      1.0f, 1.0f,-0.25f,  0.25f,  0.25f,      0.0f, 1.0f,-0.25f, -0.25f,  0.25f,      0.0f, 0.0f,};glGenBuffers(1, &position_buffer);glBindBuffer(GL_ARRAY_BUFFER, position_buffer);glBufferData(GL_ARRAY_BUFFER,sizeof(vertex_data),vertex_data,GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), NULL);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);glGenBuffers(1, &index_buffer);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(vertex_indices),vertex_indices,GL_STATIC_DRAW);glEnable(GL_CULL_FACE);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glGenFramebuffers(1, &fbo);glBindFramebuffer(GL_FRAMEBUFFER, fbo);glGenTextures(1, &color_texture);glBindTexture(GL_TEXTURE_2D, color_texture);glTexStorage2D(GL_TEXTURE_2D, 9, GL_RGBA8, 512, 512);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glGenTextures(1, &depth_texture);glBindTexture(GL_TEXTURE_2D, depth_texture);glTexStorage2D(GL_TEXTURE_2D, 9, GL_DEPTH_COMPONENT32F, 512, 512);glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color_texture, 0);glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0);static const GLenum draw_buffers[] = { GL_COLOR_ATTACHMENT0 };glDrawBuffers(1, draw_buffers);}virtual void render(double currentTime){static const GLfloat blue[] = { 0.0f, 0.0f, 0.3f, 1.0f };static const GLfloat one = 1.0f;vmath::mat4 proj_matrix = vmath::perspective(50.0f,(float)info.windowWidth / (float)info.windowHeight,0.1f,1000.0f);float f = (float)currentTime * 0.3f;vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -4.0f) *vmath::translate(sinf(2.1f * f) * 0.5f,cosf(1.7f * f) * 0.5f,sinf(1.3f * f) * cosf(1.5f * f) * 2.0f) *vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *vmath::rotate((float)currentTime * 81.0f, 1.0f, 0.0f, 0.0f);glBindFramebuffer(GL_FRAMEBUFFER, fbo);glViewport(0, 0, 512, 512);glClearBufferfv(GL_COLOR, 0, sb7::color::Green);glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);glUseProgram(program1);glUniformMatrix4fv(proj_location, 1, GL_FALSE, proj_matrix);glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);glDrawArrays(GL_TRIANGLES, 0, 36);glBindFramebuffer(GL_FRAMEBUFFER, 0);glViewport(0, 0, info.windowWidth, info.windowHeight);glClearBufferfv(GL_COLOR, 0, blue);glClearBufferfv(GL_DEPTH, 0, &one);glBindTexture(GL_TEXTURE_2D, color_texture);glUseProgram(program2);glUniformMatrix4fv(proj_location2, 1, GL_FALSE, proj_matrix);glUniformMatrix4fv(mv_location2, 1, GL_FALSE, mv_matrix);glDrawArrays(GL_TRIANGLES, 0, 36);glBindTexture(GL_TEXTURE_2D, 0);}virtual void shutdown(){glDeleteVertexArrays(1, &vao);glDeleteProgram(program1);glDeleteProgram(program2);glDeleteBuffers(1, &position_buffer);glDeleteFramebuffers(1, &fbo);glDeleteTextures(1, &color_texture);}private:GLuint          program1;GLuint          program2;GLuint          vao;GLuint          position_buffer;GLuint          index_buffer;GLuint          fbo;GLuint          color_texture;GLuint          depth_texture;GLint           mv_location;GLint           proj_location;GLuint          mv_location2;GLuint          proj_location2;
};DECLARE_MAIN(basicfbo_app)


实例程序沿法线防线创建VBO抖动。它映射VBO并且使用指向映射缓存的指针每帧更新一次顶点数据。你可以与传统顶点数组实现方式继进行性能对比。

它使用2个顶点缓存:一个为了顶点坐标与法向量,另一个仅仅保存索引数组。

下载源文件与二进制文件:vbo.zip,vboSimple.zip。

vboSimple是使用VBO与顶点数组绘制立方体的简单例子。你可以很容易看出VBO与VA的相同点与不同点。
英文原文:http://www.songho.ca/opengl/gl_vbo.html

源码下载

源码下载1:
源码下载2:

引用

参考

深入理解:顶点缓存对象(VBO)相关推荐

  1. OpenGL缓存对象VBO

    VAO指的是顶点数组对象,你可以看成是C语言中的一个数组指针,它指向一个数组,这个数组里面的元素也是指针,而这些指针指向的就是缓存对象,相当与一片内存空间VBO. 缓存对象VBO有很多种类型,例如用来 ...

  2. GLES 顶点缓冲区对象(VBO)

    可能大家经常从别人口中听到VBO,不知道是什么意思,觉得高大上的样子,但是如果知道中文名称,应该能明白一二. VBO,即顶点缓冲区对象. 使用顶点数组时,指定的顶点数据保存在系统内存中,在进行glDr ...

  3. openGL 入门 2--顶点数组对象 VAO 和 缓存对象 VBO

    用户输入的数据 以 顶点数组对象表示 Vertex Array Object,VAO void glGenVertexArrays(GLsizei n, GLuint *arrays); 返回 n个 ...

  4. NeHe OpenGL教程 第四十五课:顶点缓存

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  5. 【Visual C++】游戏开发笔记三十七 浅墨DirectX提高班之五 顶点缓存的红颜知己 索引缓存的故事

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  6. 【Visual C++】游戏开发笔记三十七 浅墨DirectX提高班之五 顶点缓存的红颜知己:索引缓存的故事

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8304741 作者:毛星云(浅墨 ...

  7. 【Visual C++】游戏开发笔记三十六 浅墨DirectX提高班之四 顶点缓存的逆袭

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8276363 作者:毛星云(浅墨 ...

  8. opengles2.0 帧缓存对象(FBO)

    opengles2.0 帧缓存对象(FBO) 帧缓存对象(fbo)主要是用于做渲染到纹理. opengles2.0渲染到纹理的方法有三种: 第一,使用glCopyTexImage2D或者glCopyT ...

  9. OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)

    原文地址http://www.songho.ca/opengl/gl_fbo.html 但有改动. OpenGL Frame BufferObject(FBO) Overview: 在OpenGL渲染 ...

最新文章

  1. 上帝和面向对象的七天
  2. 如何用Dart写一个单例
  3. Web前端经典面试试题(二)
  4. javaweb学习总结二十三(servlet开发之线程安全问题)
  5. 图解Oracle 12c创建数据挖掘(Data Miner)用户dmuser
  6. javaweb宿舍管理系统源码_宿舍信息管理系统展示
  7. android 悬浮按钮 魅族,Android使用RecycleView实现魅族手机通讯录界面
  8. 图灵奖得主华人高徒发布首款AI芯片!64位RISC-V、高度可编程,低功耗
  9. java设计模式--创建模式--单例模式
  10. 渝粤题库 陕西师范大学 《语言学概论》 作业
  11. 职称计算机考试在线题库,职称计算机考试题库理论「附答案」
  12. 移动终端安全模块技术研究
  13. python图像数字识别
  14. 彻底理解线性代数; 特征值,特征向量; 线性代数的本质 矩阵的逆矩阵的实质: 行列式值为0的实质: Essense Of Linear Algebra的理解
  15. android开发跑步软件设计,计算机软件毕业设计 android跑步应用开发.doc
  16. VS2013附加包含目录,添加相对路径
  17. java word转html乱码怎么办,poi导出word 乱码 poi word转html 乱码
  18. 工信部等三部委:推进区块链等新一代信息技术在养老场景集成应用
  19. CAD教程:CAD联动模式的使用技巧
  20. 小程序开发特辑—小程序申请及开发环境搭建

热门文章

  1. 什么是Provisioning Profile
  2. 【高级React技术】当企业级项目采用Refs 转发和使用 HOC 解决横切关注点问题
  3. 增强学习在无人驾驶中的应用
  4. C语言教程Day01
  5. 简述Linux扩大LV的过程
  6. 蓝牙耳机运动无线耳机排名、运动蓝牙耳机排行榜
  7. 2022年软考考试时间安排
  8. 我被中国计算机教育的现实打败了
  9. 汉语言文学要学计算机课程吗,汉语言文学专业学什么 主要课程有哪些
  10. CSS3动画 animation