当前位置: 首页 > article >正文

完整例子和调用关系qt OpenGL

项目结构

        首先,你需要在 Qt 项目中创建一个类,继承自 QOpenGLWidget 来进行 OpenGL 渲染。文件结构如下:
- main.cpp
- MyOpenGLWidget.h
- MyOpenGLWidget.cpp
- vertex_shader.glsl
- fragment_shader.glsl

1. main.cpp

        这是 Qt 项目的入口文件,创建一个 QApplication 实例并显示一个包含 QOpenGLWidget 的窗口。
// 包含 Qt 应用程序的核心类,用于管理 Qt 应用程序的控制流。
#include <QApplication>
 // 包含 Qt 的主窗口类,可以创建一个包含菜单、工具栏等常见组件的窗口。
#include <QMainWindow>
 // 包含我们自定义的 OpenGL 渲染窗口类。
#include "MyOpenGLWidget.h"


int main(int argc, char *argv[]) {
    /* 初始化 Qt 应用程序。argc 和 argv 是命令行参数,通常用来传递命令行参数到程序中。
        QApplication 是所有 Qt 应用程序的基础,它管理应用程序的生命周期和事件循环。
    */
    QApplication app(argc, argv);
    // 创建一个主窗口对象 window,它是应用程序的主界面。
    QMainWindow window;
    
    // 创建自定义的 OpenGL 渲染窗口 glWidget。
    // &window 将主窗口 window 作为父窗口传递给 glWidget。
    MyOpenGLWidget *glWidget = new MyOpenGLWidget(&window);
    // 将 glWidget 设为 window 的中心部件。
    // QMainWindow 中的中心部件通常占据主窗口的最大区域。
    window.setCentralWidget(glWidget);
    // 设置窗口大小
    window.resize(800, 600);
    // 显示窗口
    window.show();
    
    return app.exec();
}

2. MyOpenGLWidget.h

        这是声明文件,继承自 QOpenGLWidget 和 QOpenGLFunctions, 用于处理 OpenGL 渲染。在这里,我们声明必要的 OpenGL 初始化、绘制和清理函数。
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

// 包含 Qt 的 OpenGL 小部件类,这样我们可以创建一个 OpenGL 渲染窗口。
#include <QOpenGLWidget>
// 包含 OpenGL 功能的接口。我们可以通过这个类访问 OpenGL 的核心功能。
#include <QOpenGLFunctions>
// 包含 OpenGL 着色器程序类,负责加载、编译、链接和管理着色器程序。
#include <QOpenGLShaderProgram>
// 包含 OpenGL 缓冲区类,负责创建和管理顶点缓冲对象(VBO)和索引缓冲对象(EBO)。
#include <QOpenGLBuffer>

/* 声明一个名为 MyOpenGLWidget 的类,继承自 QOpenGLWidget 和 QOpenGLFunctions。
   QOpenGLWidget 是 Qt 提供的 OpenGL 渲染窗口基类,QOpenGLFunctions 提供了 OpenGL 的基本功能。
   protected QOpenGLFunctions 是为了能够访问 OpenGL 的函数接口。
*/
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
    Q_OBJECT

public:
    MyOpenGLWidget(QWidget *parent = nullptr);
    ~MyOpenGLWidget();

protected:
    // 初始化 OpenGL 环境的函数。
    // 在这里你会设置 OpenGL 的状态,例如开启深度测试、设置视口、加载着色器等。
    void initializeGL() override;
    // 当窗口大小改变时自动调用。你可以在这里设置 OpenGL 视口以及投影矩阵。
    void resizeGL(int w, int h) override;
    // 每次需要重新绘制时调用。在这里绘制 OpenGL 图形。
    void paintGL() override;

private:
    // 用于初始化并编译着色器的函数。
    void initializeShaders();
    // 用于初始化顶点数据和缓冲区的函数。
    void initializeBuffers();

    // 指向 OpenGL 着色器程序的指针。用于管理着色器的加载、编译、链接和绑定。
    QOpenGLShaderProgram *shaderProgram;
    // 一个 QOpenGLBuffer 对象,用于存储顶点数据的缓冲区(VBO)。
    QOpenGLBuffer vertexBuffer;        
    // 顶点数组对象的句柄。VAO 用于管理顶点属性和缓冲区对象。
    GLuint VAO, VBO;                          
};

#endif // MYOPENGLWIDGET_H

3. MyOpenGLWidget.cpp

        这是实现文件,包含了 OpenGL 初始化、着色器编译、数据传输和渲染的具体代码。
#include "MyOpenGLWidget.h"
// 包含 OpenGL 着色器类,负责加载着色器代码并编译它们。
#include <QOpenGLShader>
#include <QOpenGLBuffer>
#include <QDebug>

MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent),shaderProgram(nullptr) 
{
}

MyOpenGLWidget::~MyOpenGLWidget() {
    // 销毁 shaderProgram,释放着色器程序的内存。
    delete shaderProgram;
}

void MyOpenGLWidget::initializeGL() {
    // 1. 初始化 OpenGL 函数,确保可以使用 OpenGL 的所有函数。
    initializeOpenGLFunctions();
    // 启用深度测试,确保物体在 3D 场景中的正确显示(即前面物体遮挡后面物体)。
    glEnable(GL_DEPTH_TEST);  

    // 2. 初始化着色器程序
    initializeShaders();

    // 3. 初始化顶点数据
    initializeBuffers();
}

void MyOpenGLWidget::initializeShaders() {
    // 2.1 创建并编译顶点着色器
    // 创建一个新的着色器程序对象。
    shaderProgram = new QOpenGLShaderProgram();
    // 加载并编译顶点着色器,QOpenGLShader::Vertex 指明这是顶点着色器,文件路径为 :/vertex_shader.glsl。
    shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex_shader.glsl");
    // 加载并编译片段着色器,QOpenGLShader::Fragment 指明这是片段
    shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment_shader.glsl");

    // 2.2 链接着色器程序
    shaderProgram->link();
    shaderProgram->bind();
}

void MyOpenGLWidget::initializeBuffers() {
    // 3.1 顶点数据(一个简单的三角形)
    GLfloat vertices[] = {
        -1.0f,  1.0f, 0.0f,   // 顶点1
        -1.0f, -1.0f, 0.0f,   // 顶点2
         1.0f, -1.0f, 0.0f    // 顶点3
    };

    // 3.2 创建 VAO 和 VBO
    glGenVertexArrays(1, &VAO);  // 创建 VAO
    glBindVertexArray(VAO);      // 绑定 VAO
    
    glGenBuffers(1, &VBO);       // 创建 VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);  // 绑定 VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 分配数据给 VBO

    // 3.3 设置顶点属性(位置)
    // 启用顶点属性(位置属性)
    shaderProgram->enableAttributeArray(0);
    // 设置位置数据的格式
    shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 3 * sizeof(GLfloat));

    vertexBuffer.release();  // 释放 VBO
    glBindVertexArray(0);  // 解绑 VAO
}

void MyOpenGLWidget::resizeGL(int w, int h) {
    // 4. 设置视口大小
    glViewport(0, 0, w, h);

    // 4.1 设置投影矩阵(透视投影)
    glMatrixMode(GL_PROJECTION); // 设定当前矩阵为投影矩阵
    glLoadIdentity();  // 重置当前矩阵
    // 设置透视投影
    gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.1, 100.0);
    // 切换回模型视图矩阵
    glMatrixMode(GL_MODELVIEW);
}

void MyOpenGLWidget::paintGL() {
    // 5. 清空屏幕并准备绘制
    // 清空颜色和深度缓冲
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // 5.1 使用着色器程序
    shaderProgram->bind();
    glBindVertexArray(VAO);

    // 5.2 绘制三角形
    // 使用顶点数据绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindVertexArray(0);
    shaderProgram->release();
}

4. vertex_shader.glsl

        顶点着色器(将顶点位置传递给片段着色器):
#version 330 core
layout(location = 0) in vec3 position;
void main() {
    gl_Position = vec4(position, 1.0);  // 直接输出位置
}

5. fragment_shader.glsl

        片段着色器(指定最终颜色):
#version 330 core
out vec4 color;
void main() {
    color = vec4(1.0, 0.0, 0.0, 1.0);  // 输出红色
}


函数作用说明

  • initializeGL():负责 OpenGL 环境的初始化工作,包括启用深度测试、初始化着色器和顶点数据。这个函数会在 QOpenGLWidget 创建后自动调用。
  • initializeShaders():编译顶点和片段着色器,并将它们链接成一个 OpenGL 程序。着色器代码通常存储在外部文件中,这里用 addShaderFromSourceFile() 来加载。
  • initializeBuffers():创建并初始化顶点缓冲对象(VBO)和顶点数组对象(VAO)。VBO 存储顶点数据,而 VAO 用于管理 VBO 的状态。顶点数据传送到 GPU 后,OpenGL 会使用它来绘制物体
  • resizeGL(int w, int h):用于处理 OpenGL 上下文的大小变化,设置视口以及投影矩阵,使得绘制的图形不会在窗口大小变化时失真。
  • paintGL():这个函数每次需要重新绘制时都会被调用。这里,我们清空屏幕,使用着色器程序,并通过 glDrawArrays() 绘制三角形。

调用关系和逻辑

  1. 在程序启动时,QOpenGLWidget 的构造函数会被调用。QOpenGLWidget 会创建一个 OpenGL 上下文,并在需要时调用 initializeGL()。
  2. 在 initializeGL() 中,我们初始化 OpenGL 状态(如深度测试),然后调用 initializeShaders() 来加载并编译着色器程序,接着调用 initializeBuffers() 初始化顶点数据。
  3. 每当窗口大小改变时,resizeGL() 会被自动调用来调整视口大小和设置合适的投影矩阵。
  4. 每次需要绘制时(例如每帧刷新时),paintGL() 会被调用。在此函数中,我们绑定着色器程序、顶点数组对象(VAO),并通过 glDrawArrays() 来绘制三角形。

总结

  • initializeGL() -> 调用 initializeShaders() 初始化着色器,调用 initializeBuffers() 初始化顶点数据。
  • paintGL() -> 每次绘制时使用着色器和顶点数据。
  • resizeGL() -> 当窗口大小变化时调整视口和投影矩阵。

疑惑补充:

QOpenGLShaderProgram 对象-CSDN博客

OpenGL疑惑-CSDN博客


http://www.kler.cn/a/579067.html

相关文章:

  • Electron-Forge + Vue3 项目初始化
  • Qt常用控件之表格QTableWidget
  • 【leetcode100】组合总和Ⅱ
  • 【MySQL】事务|概念|如何回滚|基本特性|MySQL事务隔离性具体怎么实现的
  • 如何不重启,生效windows环境变量
  • 高效Android MQTT封装工具:简化物联网开发,提升性能与稳定性
  • 基于Linux环境部署和使用ElasticSearch搜索引擎
  • C# 开发工具Visual Studio下载和安装
  • ubuntu20.04已安装 11.6版本 cuda,现需要通过源码编译方式安装使用 cuda 加速的 ffmpeg 步骤
  • 【MySQL】(4) 表的操作
  • Spring Boot 内置工具类,功能齐全!!
  • MoonSharp 文档一
  • 2025年最新可用!Docker/DockerHub 国内镜像源/加速列表
  • 【蓝桥杯每日一题】3.8
  • Vue.js框架设计核心要素解析
  • 【GPT入门】第8课 大语言模型的自洽性
  • 安固软件指南:确保外发文件安全的全面策略
  • 腾讯云大模型知识引擎LKE+DeepSeek结合工作流升级智能客服
  • ESP8266TCP单连接透传
  • RabbitMQ从入门到实战-2