Qt/QWidgets 中使用 OpenGL,画出第一个三角形(附工程)

在 LearnOpenGL 学习opengl的时候,示例中使用的是 glfw 这个应用框架去承载opengl,这个工具我们在工作或学习中是不必要使用的,Qt 对opengl的支持相当完善,我们将学习在Qt中使用opengl。
在Qt5.4之前,Qt 使用 QGLWidget 类来承载opengl的渲染,在 QGLWidget的文档中有如下内容:

This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.
这个类已经过时了。提供它是为了保持旧源代码的工作。我们强烈建议不要在新代码中使用它。

Note: This class is part of the legacy Qt OpenGL module and, like the
other QGL classes, should be avoided in the new applications. Instead,
starting from Qt 5.4, prefer using QOpenGLWidget and the QOpenGL
classes.
注意:这个类是遗留Qt OpenGL模块的一部分,像其他QGL类一样,应该在新的应用程序中避免使用。相反,从Qt5.4开始,更喜欢使用QOpenGLWidget和QOpenGL类。

我们直接选择较为新颖的 QOpenGLWidget

首先,我们创建一个QWidgets工程,增加头文件,修改基类继承 QOpenGLWidgetQOpenGLFunctions_3_3_core
注意:继承于 QOpenGLFunctions 无法使用 gl3.h 中的功能

class Widget : public QOpenGLWidget, public QOpenGLFunctions_3_3_Core

实现以下三个虚函数:

void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;

paintGL() :渲染OpenGL场景,每当需要更新小部件时调用。
resizeGL() : 设置OpenGL视口,投影等。每当小部件被调整大小时(当它第一次显示时也会调用,因为所有新创建的小部件都会自动获得一个resize事件)。
initializeGL() : 设置OpenGL资源和状态。在第一次调用resizeGL()或paintGL()之前调用一次。

基本实现如下:

void Widget::initializeGL()
{
    initializeOpenGLFunctions();
}

void Widget::resizeGL(int w, int h)
{
    glViewport(0.0f, 0.0f, w, h);
}

void Widget::paintGL()
{
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);       //清屏
    glClear(GL_COLOR_BUFFER_BIT);               //清除颜色缓冲
}

此时运行的结果是一个红色的窗口:
在这里插入图片描述

按照LearnOpenGL的示例,画出第一个三角形,添加顶点和片段着色器,并在 paintGL实现:

const GLchar* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "void main()\n"
    "{\n"
    "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
    "}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
    "out vec4 color;\n"
    "void main()\n"
    "{\n"
    "color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

void Widget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);       //清屏
    glClear(GL_COLOR_BUFFER_BIT);               //清除颜色缓冲

    //顶点着色器
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    //检测编译错误
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        qDebug() << "error(vertex compile):" << infoLog;
    }

    // 片段着色器
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    //检测编译错误
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        qDebug() << "error(fragment compile):" << infoLog;
    }

    // 程序对象链接着色器
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    // 检查链接错误
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        qDebug() << "error(shader link):" << infoLog;
    }
    //删除,先行标记为删除
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 设置顶点数据(和缓冲区)和属性指针
    GLfloat vertices[] =
    {
        -0.5f, -0.5f, 0.0f, // Left
        0.5f, -0.5f, 0.0f, // Right
        0.0f,  0.5f, 0.0f  // Top
    };
    GLuint VBO, VAO;
    glGenBuffers(1, &VBO);

    // 首先绑定顶点数组对象,然后绑定和设置顶点缓冲区和属性指针
    glGenVertexArrays(1, &VAO);
    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(GLfloat), (GLvoid*)0);

    glEnableVertexAttribArray(0);

    //注意,这是允许的,调用glVertexAttribPointer将VBO注册为当前绑定的顶点缓冲区对象,这样之后我们就可以安全地解除绑定
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 画出第一个三角形
    glUseProgram(shaderProgram);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);

    // 适当地分配所有的资源,一旦它们超过了它们的作用
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
}

运行结果如下:
在这里插入图片描述
opengl的渲染也可以和 Qt 的自绘相结合,重写QOpenGLWidget 的paintEvent以实现组合功能:

void Widget::paintEvent(QPaintEvent *event)
{
    QOpenGLWidget::paintEvent(event);
    QPainter painter(this);
    painter.fillRect(0, 0, 100, 100, Qt::green);
}

运行如下:
在这里插入图片描述
需要注意的地方:
如重写 QOpenGLWidget::paintEvent, 需在paintEvent中调用 基类 QOpenGLWidget的 paintEvent,因为 paintGL 函数是在QOpenGLWidget::paintEvent中调用,如不主动调用会导致opengl渲染无效;

如果想要在opengl渲染层上添加Qt绘制的图形,需在手动调用 QOpenGLWidget::paintEvent之后进行绘制。

附完整工程:qt-opengl

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Qt使用OpenGLES画一个三角形的步骤如下: 1. 创建一个新的Qt Quick项目。 2. 在项目文件夹创建一个新的源文件,命名为“main.cpp”。 3. 在“main.cpp”文件添加以下代码: ```c++ #include <QGuiApplication> #include <QOpenGLContext> #include <QOpenGLFunctions> #include <QQuickWindow> #include <QSurfaceFormat> class MyTriangleRenderer : public QObject, protected QOpenGLFunctions { Q_OBJECT public: explicit MyTriangleRenderer(QObject *parent = nullptr) : QObject(parent) { connect(window, &QQuickWindow::beforeRendering, this, &MyTriangleRenderer::paint, Qt::DirectConnection); } void setWindow(QQuickWindow *w) { window = w; } public slots: void paint() { initializeOpenGLFunctions(); // 设置OpenGL视口 glViewport(0, 0, window->width(), window->height()); // 设置OpenGL清除颜色 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 清除OpenGL缓存 glClear(GL_COLOR_BUFFER_BIT); // 绘制三角形 glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(0.5f, -0.5f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(0.0f, 0.5f, 0.0f); glEnd(); // 交换OpenGL缓存 window->resetOpenGLState(); } private: QQuickWindow *window; }; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 创建OpenGL窗口 QSurfaceFormat format; format.setVersion(2, 0); format.setProfile(QSurfaceFormat::CoreProfile); QQuickWindow window; window.setFormat(format); // 设置OpenGL渲染器 MyTriangleRenderer renderer; renderer.setWindow(&window); window.show(); renderer.paint(); return app.exec(); } #include "main.moc" ``` 4. 编译并运行你的Qt项目,你应该能够看到一个红绿蓝三角形。 这样,你就成功地在Qt使用OpenGLES画了一个三角形

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为啥不吃肉捏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值