本系列文章主要是记录学习OpenGL的过程,旨在驱动学习理解OpenGL,最终达到能够使用相关接口解决实际项目问题,学习流程参考《LearnOpenGL》。主要展现形式是"代码示例+接口分析"的形式,编码主要是基于Qt封装的OpenGL模块展开,这样对于我来说更加熟悉。
引言
前一章讲过了使用QOpenGLWidget进行纹理的加载,在QML下则需要其他方式实现,效果如下:
核心代码
void FrameBufferRenderer::render()
{
// 背景颜色
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
m_shaderProgram.bind();
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
m_wallTexture->bind();
// 设定顶点属性指针
glVertexAttribPointer(0 ,3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1 ,2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 绘制
glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_INT, nullptr);
m_shaderProgram.release();
}
主要就是将原本的QOpenGLWidget中的paintGL代码,迁移到QQuickFramebufferObject::Renderer中的render函数中,其他的初始化可以放入构造函数中完成。
这里需要使用到两个对象QQuickFramebufferObject以及QQuickFramebufferObject::Renderer,QQuickFramebufferObject可以说是一个壳子,用于Qml中使用,实际gl的代码是在Renderer中实现,通过createRenderer返回渲染对象即可。
完整代码
#ifndef FRAMEBUFFEROBJECT_H
#define FRAMEBUFFEROBJECT_H
#include <QQuickItem>
#include <QQuickFramebufferObject>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
class FrameBufferObject : public QQuickFramebufferObject
{
Q_OBJECT
public:
FrameBufferObject(QQuickItem *parent = nullptr);
QQuickFramebufferObject::Renderer *createRenderer() const override;
};
class QOpenGLTexture;
class FrameBufferRenderer : public QQuickFramebufferObject::Renderer, QOpenGLFunctions_3_3_Core
{
public:
FrameBufferRenderer();
~FrameBufferRenderer();
void render() override;
private:
QOpenGLShaderProgram m_shaderProgram;
QOpenGLTexture* m_wallTexture;
QOpenGLTexture* m_faceTexture;
QOpenGLShaderProgram program;
};
#endif // FRAMEBUFFEROBJECT_H
#include "framebufferobject.h"
#include <QOpenGLTexture>
#include <QOpenGLFramebufferObject>
FrameBufferObject::FrameBufferObject(QQuickItem *parent)
: QQuickFramebufferObject(parent)
{
}
QQuickFramebufferObject::Renderer *FrameBufferObject::createRenderer() const
{
return new FrameBufferRenderer;
}
static unsigned int VBO, VAO, EBO;
static float vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, // 右下角
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // 左下角
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, // 左上角
};
static unsigned int indices[] = {
0, 1, 2, 3
};
FrameBufferRenderer::FrameBufferRenderer()
{
initializeOpenGLFunctions();
m_wallTexture = new QOpenGLTexture(QImage(":/skin/images/wall.jpg"));
m_faceTexture = new QOpenGLTexture(QImage(":/skin/images/awesomeface.png"));
m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes.vert");
m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes.frag");
m_shaderProgram.link();
m_shaderProgram.bind();
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 绑定顶点数组对象
glBindVertexArray(VAO);
// 把我们的顶点数组复制到一个顶点缓冲中,供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 复制我们的索引数组到一个索引缓冲中,供OpenGL使用
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
m_shaderProgram.release();
}
FrameBufferRenderer::~FrameBufferRenderer()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
void FrameBufferRenderer::render()
{
// 背景颜色
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
m_shaderProgram.bind();
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
m_wallTexture->bind();
// 设定顶点属性指针
glVertexAttribPointer(0 ,3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1 ,2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 绘制
glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_INT, nullptr);
m_shaderProgram.release();
}