(本文是LearnOpenGL的学习笔记,教程中文翻译地址https://learnopengl-cn.github.io/)
0.前言
LearnOpenGL教程目前使用的是glfw+glad的方式来使用OpenGL,而在Qt Widgets框架中也封装了相应的类,并且配合其他工具类,操作起来更加方便。
1.如何实现
在Qt旧版本中,提供有QGLWidget类,从Qt5.4开始提供了QOpenGLWidget类,我们只需要继承并实现相应接口,就可以使用OpenGL绘制一个Qt组件(其中使用OpenGL函数还要借助QOpenGLFunctions相关的类):
class GLTriangle : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{}
继承之后,只需要实现三个虚函数接口,就可以实现绘制:
//设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
void initializeGL() override;
//渲染OpenGL场景,每当需要更新小部件时使用
void paintGL() override;
//设置OpenGL视口、投影等,每当尺寸大小改变时调用
void resizeGL(int width, int height) override;
QOpenGLWidget是继承自QWidget的,所以做好的组件类像其他Widget类那样使用就行了。
在教程中,是自己封装着色器程序类,Qt已经封装好了一个 QOpenGLShaderProgram,我们可以直接用它。此外还提供了QOpenGLVertexArrayObject、QOpenGLBuffer等封装好的类供我们使用,不过目前主要是简易移植教程代码,尽量使用原有的代码就行了。
剩下的,就是把LearnOpenGL代码移植到QtWidgets中。
2.实现代码
(项目git链接:https://github.com/gongjianbo/OpenGLwithQtWidgets.git)
我的GLTriangle类和GLElement类效果图:
其中三角形的实现代码:
#ifndef GLTRIANGLE_H
#define GLTRIANGLE_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
//绘制三角形
class GLTriangle : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit GLTriangle(QWidget *parent = nullptr);
~GLTriangle();
protected:
//设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
void initializeGL() override;
//渲染OpenGL场景,每当需要更新小部件时使用
void paintGL() override;
//设置OpenGL视口、投影等,每当尺寸大小改变时调用
void resizeGL(int width, int height) override;
private:
QOpenGLShaderProgram _shaderProgram;
GLuint _VAO;
GLuint _VBO;
};
#endif // GLTRIANGLE_H
#include "GLTriangle.h"
GLTriangle::GLTriangle(QWidget *parent)
: QOpenGLWidget(parent)
{
}
GLTriangle::~GLTriangle()
{
glDeleteVertexArrays(1, &_VAO);
glDeleteBuffers(1, &_VBO);
}
void GLTriangle::initializeGL()
{
//为当前上下文初始化OpenGL函数解析
initializeOpenGLFunctions();
//着色器代码
//in输入,out输出,uniform从cpu向gpu发送
const char *vertex_str=R"(#version 330 core
layout (location = 0) in vec3 vertices;
void main() {
gl_Position = vec4(vertices,1.0);
})";
const char *fragment_str=R"(#version 330 core
uniform vec3 myColor;
void main() {
gl_FragColor = vec4(myColor,1.0);
})";
//将source编译为指定类型的着色器,并添加到此着色器程序
if(!_shaderProgram.addCacheableShaderFromSourceCode(
QOpenGLShader::Vertex,vertex_str)){
qDebug()<<"compiler vertex error"<<_shaderProgram.log();
}
if(!_shaderProgram.addCacheableShaderFromSourceCode(
QOpenGLShader::Fragment,fragment_str)){
qDebug()<<"compiler fragment error"<<_shaderProgram.log();
}
//使用addShader()将添加到该程序的着色器链接在一起。
if(!_shaderProgram.link()){
qDebug()<<"link shaderprogram error"<<_shaderProgram.log();
}
//从LearnOpenGL移植过来
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
glGenVertexArrays(1, &_VAO);
glGenBuffers(1, &_VBO);
glBindVertexArray(_VAO);
glBindBuffer(GL_ARRAY_BUFFER, _VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void GLTriangle::paintGL()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
_shaderProgram.bind();
//传递值
_shaderProgram.setUniformValue("myColor", QVector3D(0.0f,1.0f,0.0f));
//绘制三角
glBindVertexArray(_VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
_shaderProgram.release();
}
void GLTriangle::resizeGL(int width, int height)
{
glViewport(0,0,width,height);
}