1、什么是VBO?
顶点缓冲区对象VBO(Vertex Buffer Object), 将顶点数组存储在高性能的显存中,提升的绘制的速度。
2、why?
顶点数组可以减少函数调用、去除冗余的共享顶点;但是顶点数组存在自身的缺点,顶点数组是在客户端,这样数组中的数据每次被访问的时候都要传输到服务器端。
另外,显示列表是服务器端的函数,它没有数据传输耗费的问题。但是,每当显示列表被编译以后,其中的数据就不能在改变了。
鉴于以上两个问题,提出了VBO,即在显存中创建顶点缓冲区对象,可以与顶点数组一样被glVertexPointer(), glNormalPointer(), glTexCoordPointer()等函数访问。
3、优点
(1)与显示列表不同的是:VBO中的数据是可读、可更新的,具体方法是讲VBO映射到客户端的存储空间。
(2)VBO的另一个优点是:多个用户共享同一个缓冲区对象。因为VBO是在服务端,多个用户可以通过相应的标示符访问到同一个缓冲区。
4、operations
(1)创建VBO
//生成一个新的缓冲区对象
void glGenBuffersARB(GLsizei n, GLuint* ids)
//绑定缓冲区对象,也即选择(或者激活)一个缓冲区对象,因为可能创建了好多缓冲区对象,这是需要选择一个成为活动的
void glBindBufferARB(GLenum target, GLuint id)
//将顶点数据复制到缓冲区对象
void glBufferDataARB(GLenum target, GLsizei size, const void* data, GLenum usage)
//删除缓冲区对象
void glDeleteBuffersARB(GLsizei n, const GLuint* ids)
(2)绘制VBO
// bind VBOs for vertex array and index array
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId1); // for vertex coordinates
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboId2); // for indices
// do same as vertex array except pointer
glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array
glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr
// draw 6 quads using offset of index array
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0);
glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array
// bind with 0, so, switch back to normal pointer operation
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
(3)更新VBO
void* glMapBufferARB(GLenum target, GLenum access)//将缓冲区对象映射到客户端存储区
GLboolean glUnmapBufferARB(GLenum target)
代码:
#include <iostream>
#include <gl/glew.h>
#include <gl/glut.h>
using namespace std;
// cube ///
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
// vertex coords array for glDrawArrays() =====================================
// A cube has 6 sides and each side has 2 triangles, therefore, a cube consists
// of 36 vertices (6 sides * 2 tris * 3 vertices = 36 vertices). And, each
// vertex is 3 components (x,y,z) of floats, therefore, the size of vertex
// array is 108 floats (36 * 3 = 108).
GLfloat vertices[] = {
1, 1, 1, -1, 1, 1, -1,-1, 1, // v0-v1-v2 (front)
-1,-1, 1, 1,-1, 1, 1, 1, 1, // v2-v3-v0
1, 1, 1, 1,-1, 1, 1,-1,-1, // v0-v3-v4 (right)
1,-1,-1, 1, 1,-1, 1, 1, 1, // v4-v5-v0
1, 1, 1, 1, 1,-1, -1, 1,-1, // v0-v5-v6 (top)
-1, 1,-1, -1, 1, 1, 1, 1, 1, // v6-v1-v0
-1, 1, 1, -1, 1,-1, -1,-1,-1, // v1-v6-v7 (left)
-1,-1,-1, -1,-1, 1, -1, 1, 1, // v7-v2-v1
-1,-1,-1, 1,-1,-1, 1,-1, 1, // v7-v4-v3 (bottom)
1,-1, 1, -1,-1, 1, -1,-1,-1, // v3-v2-v7
1,-1,-1, -1,-1,-1, -1, 1,-1, // v4-v7-v6 (back)
-1, 1,-1, 1, 1,-1, 1,-1,-1 }; // v6-v5-v4
// normal array
GLfloat normals[] = {
0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2 (front)
0, 0, 1, 0, 0, 1, 0, 0, 1, // v2-v3-v0
1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4 (right)
1, 0, 0, 1, 0, 0, 1, 0, 0, // v4-v5-v0
0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6 (top)
0, 1, 0, 0, 1, 0, 0, 1, 0, // v6-v1-v0
-1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7 (left)
-1, 0, 0, -1, 0, 0, -1, 0, 0, // v7-v2-v1
0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3 (bottom)
0,-1, 0, 0,-1, 0, 0,-1, 0, // v3-v2-v7
0, 0,-1, 0, 0,-1, 0, 0,-1, // v4-v7-v6 (back)
0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v6-v5-v4
// color array
GLfloat colors[] = {
1, 1, 1, 1, 1, 0, 1, 0, 0, // v0-v1-v2 (front)
1, 0, 0, 1, 0, 1, 1, 1, 1, // v2-v3-v0
1, 1, 1, 1, 0, 1, 0, 0, 1, // v0-v3-v4 (right)
0, 0, 1, 0, 1, 1, 1, 1, 1, // v4-v5-v0
1, 1, 1, 0, 1, 1, 0, 1, 0, // v0-v5-v6 (top)
0, 1, 0, 1, 1, 0, 1, 1, 1, // v6-v1-v0
1, 1, 0, 0, 1, 0, 0, 0, 0, // v1-v6-v7 (left)
0, 0, 0, 1, 0, 0, 1, 1, 0, // v7-v2-v1
0, 0, 0, 0, 0, 1, 1, 0, 1, // v7-v4-v3 (bottom)
1, 0, 1, 1, 0, 0, 0, 0, 0, // v3-v2-v7
0, 0, 1, 0, 0, 0, 0, 1, 0, // v4-v7-v6 (back)
0, 1, 0, 0, 1, 1, 0, 0, 1 }; // v6-v5-v4
GLuint vboId = 0;
//camera
float cameraAngleX;
float cameraAngleY;
float cameraDistance = -5.0;
//mouse
bool mouseLeftDown;
bool mouseRightDown;
float LastXPos;
float LastYPos;
void initGL()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices)+sizeof(normals)+sizeof(colors), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(normals), normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices)+sizeof(normals), sizeof(colors), colors);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
glTranslatef(0, 0, cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0);
glRotatef(cameraAngleY, 0, 1, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, (void*)sizeof(vertices));
glColorPointer(3, GL_FLOAT, 0, (void*)(sizeof(vertices)+sizeof(normals)));
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat)w/(GLfloat)h, 0.01f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouseLeftDown = true;
LastXPos = x;
LastYPos = y;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
{
mouseRightDown = true;
}
}
void mouseMotion(int x, int y)
{
if (mouseLeftDown)
{
cameraAngleX += GLfloat(y - LastYPos)/GLfloat(20.0);
cameraAngleY += GLfloat(x - LastXPos)/GLfloat(20.0);
LastYPos = y;
LastXPos = x;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(480, 640);
glutInitWindowPosition(100, 100);
glutCreateWindow("VBO");
glewInit();
if(!glewIsSupported("GL_VERSION_2_0"))
{
fprintf(stderr, "ERROR: Support for necessary OpengGL extensions missing.");
}
initGL();
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutMainLoop();
glDeleteBuffers(GL_ARRAY_BUFFER, &vboId);
return 0;
}