Qt OpenGL中VAO&VBO

483 阅读2分钟

代码环境:Qt + OpenGL

Qt支持OpenGL,实现了自己的接口,但是在VAO、VBO的管理上好像有些小问题。印象中原生OpenGL的一个VAO可以管理多个VBO,如下所示。使用一个vao对象管理两个vbo,不用每次绘制时都向GPU解释缓冲区中的数据要如何组织。

//init
int vao,vbo[2];
glGenVertexArrays(1,&vao);
glGenBuffers(2,vbo);

glBindVertexArray(vao);

glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,size0,data0,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ARRAY_BUFFER,size1,data1,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glEnableVertexAttribArray(0);

/*-------------------draw------------------------*/
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
//draw model
glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
//draw another model 

而在Qt中,用QOpenGLVertexArrayObject创建vao对象,用QOpenGLBuffer创建vbo或者ebo对象,如下所示。

QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo; //默认是顶点数组缓冲
QOpenGLBuffer m_ebo(QOpenGLBuffer::IndexBuffer);

m_vao.create();
m_vbo.create();
m_ebo.create();

m_vao.bind();
m_vbo.bind();
m_vbo.allocate(const void *data, int count);
m_ebo.bind();
m_ebo.allocate(const void *data, int count);

m_ebo.release();
m_vbo.release();
m_vao.release();

虽然该vao对象仍然可以管理vbo或者ebo,但貌似不能创建多个vbo或者多个ebo (vbo和ebo类型不同)。如果有多个相同类型的QOpenGLBuffer对象,后面调用allocate()函数的对象会移除先前调用该函数的对象所拥有的内容。

我本来想实现的一个功能大致是:当前场景已经有一个模型存在,通过按钮或者菜单动作触发一个事件,可以用一个新的QOpenGLBuffer对象为场景中再添加另一个模型。因为allocate()的特性,绘制已有模型的glDrawElements(...)函数出现一些问题,导致场景内容发生突变,达不到想要的效果。无奈之下,只能换一种解决思路,同时使用allocate()函数和write()函数。如下所示:

m_vao.bind();

m_vbo.bind();
m_vbo.allocate(count1+count2);//void allocate(int count);
m_vbo.write(0,&originalData[0],count1);
m_vbo.write(count1,&newData[0],count2);

m_ebo.bind();
m_ebo.allocate(count3+count4);
m_vbo.write(0,&originalIndices[0],count3);
m_vbo.write(count3,&newIndices[0],count4);
m_ebo.release();
m_vbo.release();
m_vao.release();

/*-------------------PaintGL------------------------*/
m_vao.bind();//上面有release()的话这里要再次bind()
m_ebo.bind();//vao对象不记录索引信息,也要bind()
glDrawElements(GL_TRIANGLES,originalIndices.size(),GL_UNSIGNED_INT,0);
glDrawElements(GL_TRIANGLES,newIndices.size(),GL_UNSIGNED_INT,(void*)(originalIndices.size()*sizeof(unsigned)));

m_ebo.release();
m_vao.release();

早知道一开始就用原生的OpenGL,搞得现在两边都不清晰了。