标准OPenGLes2.0还没有引进VAO,应该是OpenGL3.0以后才有。不过Qt封装的OPenGLes2.0可以使用VAO,它就是QOpenGLVertexArrayObject。其用法与OpenGL3.0中的VAO用法一样。本文假设您熟悉OpenGL的vao。接下来我们一起来学习这个类的用法。
一、QOpenGLVertexArrayObject的使用流程
和VBO用法(可参考博主另外一篇博文)一样首先要调用QOpenGLVertexArrayObject::create()创建该对象。创建成功您就可以对它绑定某个VBO的状态,需要绘制时将其绑定到OPenGL上下文,最后要销毁掉。做法如下:
1.初始化:
Bind the VAO ----> Set vertex data state for this visual object ---> Unbind (release()) the VAO
2.渲染:
Bind the VAO ----> Call a glDraw*() function ----> Unbind (release()) the VAO
二、示例代码
#ifndef OPENGL_WIDGET_H
#define OPENGL_WIDGET_H
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
class OpenGLWidget : public QOpenGLWidget,
protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit OpenGLWidget(QWidget *parent = nullptr);
~OpenGLWidget();
protected:
virtual void initializeGL() override;
virtual void resizeGL(int w, int h) override;
virtual void paintGL() override;
private:
void makeObject();
void makeObject_2();
void setVertexAttribute();
private:
QOpenGLShaderProgram *m_program;
QOpenGLBuffer m_vbo;
int m_matrixUniform;
QMatrix4x4 m_pMat;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo_2;
QOpenGLVertexArrayObject m_vao_2;
};
#endif // OPENGL_WIDGET_
/
#include "opengl_widget.h"
OpenGLWidget::OpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent),
m_program(nullptr),
m_vbo(QOpenGLBuffer::VertexBuffer),
m_matrixUniform(0),
m_pMat(),
m_vao(),
m_vbo_2(QOpenGLBuffer::VertexBuffer),
m_vao_2()
{
}
OpenGLWidget::~OpenGLWidget()
{
m_vbo.destroy();
m_vbo_2.destroy();
m_vao.destroy();
m_vao_2.destroy();
}
void OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
makeCurrent();
m_vbo.create();
m_vbo_2.create();
m_program = new QOpenGLShaderProgram(this);
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex,
":/vertex_shader.glsl");
m_program->addShaderFromSourceFile(QOpenGLShader::Fragment,
":/fragment_shader.glsl");
if (!m_program->link())
close();
m_matrixUniform = m_program->uniformLocation("matrix");
makeObject();
makeObject_2();
}
void OpenGLWidget::resizeGL(int w, int h)
{
float aspect = float(w)/float(h?h:1);
float fov = 45.0f, zNear = 0.1f, zFar = 100.f;
m_pMat.setToIdentity();
m_pMat.perspective(fov, aspect, zNear, zFar);
}
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
m_program->bind();
QMatrix4x4 mvMat;
mvMat.translate(0.0f, 0.0f, -3.0f);
m_program->setUniformValue(m_matrixUniform, m_pMat*mvMat);
{
QOpenGLVertexArrayObject::Binder vaoBind(&m_vao_2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
}
{
QOpenGLVertexArrayObject::Binder vaoBind(&m_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
}
m_program->release();
}
void OpenGLWidget::makeObject()
{
makeCurrent();
float arrVertex[] {
// position color
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
QOpenGLVertexArrayObject::Binder vaoBind(&m_vao);
m_vbo.bind();
m_vbo.allocate(arrVertex, sizeof(arrVertex));
int attr = -1;
attr = m_program->attributeLocation("posAttr");
m_program->setAttributeBuffer(attr, GL_FLOAT, 0,
3, sizeof(float) * 6);
m_program->enableAttributeArray(attr);
attr = m_program->attributeLocation("colAttr");
m_program->setAttributeBuffer(attr, GL_FLOAT, 3 * sizeof(float),
3, sizeof(float) * 6);
m_program->enableAttributeArray(attr);
m_vbo.release();
}
void OpenGLWidget::makeObject_2()
{
makeCurrent();
float arrVertex[] {
// position color
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
QOpenGLVertexArrayObject::Binder vaoBind(&m_vao_2);
m_vbo_2.bind();
m_vbo_2.allocate(arrVertex, sizeof(arrVertex));
int attr = -1;
attr = m_program->attributeLocation("posAttr");
m_program->setAttributeBuffer(attr, GL_FLOAT, 0,
3, sizeof(float) * 6);
m_program->enableAttributeArray(attr);
attr = m_program->attributeLocation("colAttr");
m_program->setAttributeBuffer(attr, GL_FLOAT, 3 * sizeof(float),
3, sizeof(float) * 6);
m_program->enableAttributeArray(attr);
m_vbo_2.release();
}
/v s///
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
attribute vec4 posAttr;
attribute vec4 colAttr;
varying vec4 col;
uniform mat4 matrix;
void main()
{
col = colAttr;
gl_Position = matrix * posAttr;
}
/f s/
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
varying vec4 col;
void main()
{
gl_FragColor = col;
}
三、运行结果
程序运行结果如下图所示是两个挨一起的三角形
四、总结
QOpenGLVertexArrayObject的使用很简单。就像Qt文档所说:This class(QOpenGLVertexArrayObject::Binder) is to QOpenGLVertexArrayObject as QMutexLocker is to QMutex.这句话的要表达的意思是:借助Binder类绑定时,Binder对象析构时会调用vao.release();
之前一直有个疑问,我要在一个场景中使用多个VBO,绘制多个物体如何实现。没错就是VAO。