你可能已经早就听过VBO了,它是学习OpenGL最重要的东西之一。VBO是存储在GPU Ram上的任意数据,他们可以快速被访问,故可加速渲染。VBO可以任何东西,关键是告知OpenGL如何解释它们。例如,可以用一个VBO来存储顶点数据(x,y,z)值,可以用VBO来存储顶点颜色值,纹理坐标值,顶点颜色值。如果有多个VBO,可以将它们存入VAO(顶点数组对象),那么就可以在所有对象之间快速切换了。
老版本的OpenGL 使用glBegin() 和 glEnd(),这会导致CPU的瓶颈,它的问题是必须把每个参数传给GPU。但是现在,我们仅是加载我们的对象数据(或者场景数据)到GPU里面,告诉OpenGL 如何解释它们,就可以开始渲染了。本例中,我们渲染一个三角形和一个四边形,不使用颜色。在 initScene中,我们设置顶点数据,然后用他们创建两个VBO.
float fQuad[12]; // Data to render quad using triangle strips (4 vertices, each has 3 floats)
UINT uiVBO[2];
void initScene(LPVOID lpParam)
{
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
// Setup triangle vertices
fTriangle[0] = -0.4f; fTriangle[1] = 0.1f; fTriangle[2] = 0.0f;
fTriangle[3] = 0.4f; fTriangle[4] = 0.1f; fTriangle[5] = 0.0f;
fTriangle[6] = 0.0f; fTriangle[7] = 0.7f; fTriangle[8] = 0.0f;
// Setup quad vertices
fQuad[0] = -0.2f; fQuad[1] = -0.1f; fQuad[2] = 0.0f;
fQuad[3] = -0.2f; fQuad[4] = -0.6f; fQuad[5] = 0.0f;
fQuad[6] = 0.2f; fQuad[7] = -0.1f; fQuad[8] = 0.0f;
fQuad[9] = 0.2f; fQuad[10] = -0.6f; fQuad[11] = 0.0f;
// Now we create two VBOs
glGenBuffers(2, uiVBO);
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[0]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof( float), fTriangle, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]);
glBufferData(GL_ARRAY_BUFFER, 12*sizeof( float), fQuad, GL_STATIC_DRAW);
}
glGenBuffers中,第一个参数是VBO的个数,第二参数指向存储数据的地方(本例中就是uiVBO中)。这样在uiVBO中,存储了两个缓冲区域的ID,使用这两个ID就可以读取修改这些缓冲区域。接着告诉OpenGL,调用glBindBuffer来使用第一块缓冲区域,第一个参数指向使用哪种的缓冲区域类型,第二参数缓冲区域 ID,接着调用glBufferData,将数据加载到GPU.第一个参数是缓冲区域类型,第二个是缓冲区域字节大小,第三个参数是客户端内存中源数据,最后一个参数告诉OpenGL缓冲数据的作用。本例中,我们不会改变数据,它们是静态的,所以我们设为GL_STATIC_DRAW,其他类型如GL_DYNAMIC_DRAW,GL_STREAM_DRAW ,OpenGL根据它们做一些性能优化。四边形我们也使用这两个函数,现在有了数据集了,下面看下渲染函数。
{
// Typecast lpParam to COpenGLControl pointer
COpenGLControl* oglControl = (COpenGLControl*)lpParam;
// We just clear color
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
// Triangle render
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
// Quad render using triangle strip
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
oglControl->swapBuffers();
}
第一个函数glVertexAttribPointer(),用它来设置顶点属性,如之前所讲,顶点有很多属性,如位置、颜色等(shaders中,可以告知OpenGL如何使用这些属性),第一个参数是顶点属性索引,本例中是0既是顶点位置,由于没使用shader,顶点在渲染管道里没有任何改变,进入管道前后的数值是一样的。注意的是我们没告知OpenGL属性索引0表示位置,这是默认的,所以函数的参数的顺序是:属性集的索引,每个顶点属性的元素个数(本例是3,位置包含了x,y,z三个值),数据类型,数据是否要归一化,属性之间的字节偏移(我们把数据紧凑放在内存中,故是0),最后一个参数是个指针,指向第一个元素。
效果图如下: