开发者

在Qt中使用OpenGL绘制三角形指南

目录
  • 前言
  • QOpenGLFunctions
    • Windows 下加载(wglGetProcAddress)
    • linux 下加载(glXGetProcAddress )
  • QOpenGLWidget
    • initializeGL
    • paintGL
    • resizeGL
  • 完整代码

    本文只介绍基本的 QOpenGLWidget 和 QOpenGLFunctions 的使用,想要学习 OpenGL 的朋友,建议访问经典 OpenGL 学习网站:LearnOpenGL CN

    本篇文章,我们将以绘制一个经典的三角形为例,讲一讲,怎么在 Qt 中使用 OpenGL 来进行 GPU 绘制。

    前言

    在高性能渲染场景中,CPU资源常被过度消耗,导致界面卡顿。而OpenGL作为业界标准的图形API,能通过GPU硬件加速显著降低CPU负载。本文将以绘制三角形为例,教你如何通过Qt的QOpenGLWidget和QOpenGLFunctions实现跨平台GPU渲染。

    QOpenGLFunctions

    OpenG编程客栈L函数在不同平台(Windows/Linux/MAC)的实现存在差异。例如:

    平台函数加载方式
    WindowswglGetProcAddress
    LinuxglXGetProcAddress

    Qtjavascript通过QOpenGLFunctions封装了这些底层差异,开发者只需继承此类,即可用glClear() 等统一接口调用OpenGL函数,无需编写平台特定代码。通过这样,我们就可以用一套代码,在不同平台下使用 OpenGL 相。要使用这个类也很简单,让我们的类直接继承 QOpenGLFuntions 就好了。同时也可以配合 QOpenGLWidget 来使用,在 initializeGL 函数里,调用 initializeOpenGLFunctions 后,就可以直接使用 OpenGL 的函数

    Windows 下加载(wglGetProcAddress)

    例如在 Windows 下,我们使用 wglGetProcAddress来动态加载这些函数(例如 glClear),下面是加载代码:

    包含必要的头文件

    #include <windows.h>
    #include <GL/gl.h>
    #include <GL/glext.h>  // 提供 OpenGL 扩展声明

    定义函数指针类型

    // 示例:定义 glClear 的函数指针类型
    typedef void (APIENTRY *PFNGLCLEARPROC)(GLbitfield);
    PFNGLCLEARPROC glClear;

    加载 OpenGL 函数

    // 初始化 OpenGL 函数
    void initOpenGLFunctions() {
        // 1. 加载 OpenGL 1.1 函数(由 opengl32.dll 提供)
        glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear");
        // 2. 检查是否加载成功
        if (!glClear) {
            // 如果失败,可能是驱动不支持该函数
            MessageBoxA(NULL, "Failed to load glClear", "Error", MB_OK);
            exit(1);
        }
        // 3. 类似方式加载其他函数...
        // glDrawArrays = (PFNGLDRAWARRAYSPROC)wglGetProcAddress("glDrawArrays");
        // ...
    }

    使用加载的函数

    glClear(GL_COLOR_BUFFER_BIT);  // 现在可以正常调用

    Linux 下加载(glXGetProcAddress )

    而在 linux 下,加载的函数变成了:glXGetProcAddress ,对应的代码是:

    包含必要的头文件

    #include <GL/gl.h>
    #include <GL/glx.h>  // X11 的php OpenGL 扩展
    #include <GL/glext.h>

    定义函数指针类型

    // 示例:定义 glClear 的函数指针类型
    typedef void (*PFNGLCLEARPROC)(GLbitfield);
    PFNGLCLEARPROC glClear;

    加载 OpenGL 函数

    void initOpenGLFunctions() {
        // 1. 加载 glClear
        glClear = (PFNGLCLEARPROC)glXGetProcAddress((const GLubyte*)"glClear");
        // 2. 检查是否加载成功
        if (!glClear) {
            fprintf(stderr, "Failed to load glClear\n");
            exit(1);
        }
        // 3. 类似方式加载其他函数...
        // glDrawArrays javascript= (PFNGLDRAWARRAYSPROC)glXGetProcAddress((const GLubyte*)"glDrawArrays");
        // ...
    }

    使用加载的函数

    glClear(GL_COLOR_BUFFER_BIT);  // 现在可以正常调用

    QOpenGLWidget

    QOpenGLWidget 是 Qt 提供的一个 widget 类,用于在 Qt 应用程序中嵌入 OpenGL 渲染内容。它继承自 QWidget,内部管理了一个 OpenGL 上下文(例如 windows 下调用 wglMakeCurrent / wglDoneCurrent)和帧缓冲区,并提供了与 Qt 窗口系统无缝集成的能力。详细内容可看:QOpenGLWidget Class

    我们可以创建自己的窗口,并继承 QOpenGLWidget,然后重写下面三个函数,来处理一些 OpenGL 相关的工作。

    initializeGL

    初始化一些 OpenGL 相关的资源或者状态。这个函数在在第一次调用 resizeGL或者 paintGL之前被调用。

    paintGL

    渲染 OpenGL 的场景,类似于我们平常使用的 QWidget::paintEvent,在窗口需要更新时调用。

    resizeGL

    调整 OpenGL Viewport 的大小或者投影等,在窗口需要调整大小时调用。

    完整代码

    #pragma once
    #include <QOpenGLBuffer>
    #include <QOpenGLWidget>
    #include <QOpenGLShaderProgram>
    #include <QOpenGLFunctions>
    #include "FrameObserver.h"
    class COpenGLRenderWidget : public QOpenGLWidget, protected QOpenGLFunctions
    {
        Q_OBJECT
    public:
        explicit COpenGLRenderWidget(QWidget *parent = nullptr);
        ~COpenGLRenderWidget() override;
    private:
        void InitShaders();
    private:
        void initializeGL() override;
        void paintGL() override;
        void resizeGL(int w, int h) override;
    private:
        QOpenGLShaderProgram m_shaderProgram;
        QOpenGLBuffer m_vbo;
    };
    #include "OpenGLRenderWidget.h"
    static const GLfloat coordinateBasic[] = {
        // 顶点坐标,存储3个xyz坐标
        // x     y     z
        -0.5f, -0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
         0.0f,  0.5f, 0.0f,
    };
    constexpr auto VERTEX_SHADER_BASIC = R"(
    attribute vec3 vertexIn; 
    varying vec2 textureOut; 
    void main(void)
    {
        gl_Position = vec4(vertexIn, 1.0);
    }
    )";
    constexpr auto FRAGMENT_SHADER_BASIC = R"(
    varying vec2 textureOut;
    void main(void) 
    { 
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
    }
    )";
    COpenGLRenderWidget::COpenGLRenderWidget(QWidget *parent)
        : QOpenGLWidget(parent)
    {}
    COpenGLRenderWidget::~COpenGLRenderWidget()
    {}
    void COpenGLRenderWidget::initializeGL()
    {
     http://www.devze.com   initializeOpenGLFunctions();
        glDisable(GL_DEPTH_TEST);
        m_vbo.create();
        m_vbo.bind();
        m_vbo.allocate(coordinateBasic, sizeof(coordinateBasic));
        InitShaders();
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    }
    void COpenGLRenderWidget::paintGL()
    {
        m_shaderProgram.bind();
        glDrawArrays(GL_TRIANGLES, 0, 3);
        m_shaderProgram.release();
    }
    void COpenGLRenderWidget::resizeGL(int w, int h)
    {
        glViewport(0, 0, w, h);
        update();
    }
    void COpenGLRenderWidget::InitShaders()
    {
        QOpenGLShader vertexShader(QOpenGLShader::Vertex);
        if (!vertexShader.compileSourceCode(VERTEX_SHADER_BASIC))
        {
            qDebug() << "Vertex shader compilation failed. Error: " << vertexShader.log();
            return;
        }
        QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
        if (!fragmentShader.compileSourceCode(FRAGMENT_SHADER_BASIC))
        {
            qDebug() << "Fragment shader compilation failed. Error: " << fragmentShader.log();
            return;
        }
        m_shaderProgram.addShader(&vertexShader);
        m_shaderProgram.addShader(&fragmentShader);
        m_shaderProgram.link();
        m_shaderProgram.bind();
        m_shaderProgram.setAttributeBuffer("vertexIn", GL_FLOAT, 0, 3, 3 * sizeof(float));
        m_shaderProgram.enableAttributeArray("vertexIn");
    }

    到此这篇关于在Qt中使用OpenGL绘制指南的文章就介绍到这了,更多相关Qt使用OpenGL绘制指南内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜