Qt学习:使用OpenGL绘制3D图形

news2024/10/7 6:41:04

文章目录

  • 前言
  • 一、Qt下使用OpenGL绘制图形介绍
  • 二、示例完整代码
  • 总结


前言

文章中引用的内容均来自这本书中的原文:【Qt Creator快速入门_霍亚飞编著】,本文的示例也是在书中代码的基础上进行编写的(其中部分代码使用原文编译不过,进行了修正),这里对相关知识进行了学习总结,想要了解更加详细的内容可见原文。

OpenGL是一个跨平台的、用来渲染3D图形的标准API,Qt对OpenGL提供了强大的支持。Qt4时代的QtOpenGL模块在Qt5中已经不再建议使用,OpenGL相关的类被移到了QtGUI模块。QtWidgets模块中的QOpenGLWidget类提供了一个可以渲染OpenGL图形的部件,通过该部件可以轻松地将OpenGL图形整合到Qt应用程序中。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、Qt下使用OpenGL绘制图形介绍

QOpenGLWidget类是一个用来渲染OpenGL图形的部件,它提供了在Qt应用程序中显示 OpenGL图形的功能。这个类使用起来很简单,只需要继承该类,然后像使用其他QWidget 部件一样来使用它即可。QGLWidget 提供了3个方便的虚函数,可以在子类中重新实现它们来执行典型的 OpenGL任务:
initializeGL():设置 OpenGL资源和状态,该函数只在第一次调用resizeGL()或paintGL()前被调用一次;
resizeGL():设置OpenGL的视口投影等,每次部件改变大小时都会调用该函数;
paintGL():渲染OpenGL 场景,每当部件需要更新时都会调用该函数。

这里介绍下Qt下一些类的使用和OpenGL中重要的概念或名称,详情可见参考文章:
QOpenGLShader:用来创建和编译着色器。着色器是使用 OpenGL着色语言(OpenGL Shading Language,GLSL)编写的一个小型函数。绘图时需要至少指定两个着色器;顶点着色器(vertexshader)和片段着色器(fragmentshader,也称为片元着色器)

QOpenGLShaderProgram:用来创建并设置着色器程序,可以链接多个着色器,并在OpenGL当前环境(current context,也称为当前上下文)中绑定着色器程序

QAbstractOpenGLFunctions:是一个类族的基类,类族中的类涉及了所有 OpenGL 版本,并为相应版本 OpenGL 的所有函数提供了访问接口

QOpenGLBuffer:用来创建并管理OpenGL缓存对象

QOpenGLTexture:封装了一个OpenGL纹理对象,可以使用该类来设置纹理

二、示例完整代码

1.MyOpenGL.pro

QT += widgets

HEADERS += \
    myopenglwidget.h

SOURCES += \
    main.cpp \
    myopenglwidget.cpp

2.myopenglwidget.h

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLShaderProgram>
#include <QKeyEvent>

class QOpenGLTexture;
class QOpenGLShaderProgram;
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit MyOpenGLWidget(QWidget *parent = 0);

protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int width,int height);

    void keyPressEvent(QKeyEvent *event);

private:
    QOpenGLShaderProgram *program;
    QOpenGLBuffer vbo;
    QOpenGLTexture *textures[2];
    GLfloat translate,xRot,yRot,zRot;
};

#endif // MYOPENGLWIDGET_H

3.myopenglwidget.cpp

#include "myopenglwidget.h"

MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    //初始化变量
    translate = -6.0;
    xRot = zRot = 0.0;
    yRot = -30.0;
}

void MyOpenGLWidget::initializeGL()
{
    //初始化纹理变量
    for(int i=0;i<2;i++)
    {
          textures[i] = new QOpenGLTexture(QImage(QString("../MyOpenGL/side%1.jpg").arg(i+1)).mirrored());
    }

    //为当前环境初始化OpenGL环境
    initializeOpenGLFunctions();

    //开启深度测试
    glEnable(GL_DEPTH_TEST);

    //下列着色器使用书中代码运行报错,进行了修正
    //创建顶点着色器
    QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex,this);
    const char *vsrc = "#version 330\n"
                       "in vec4 vPosition;\n"
                       "in vec2 vTexCoord;\n"
                       "out vec2 texCoord;\n"
                       "uniform mat4 matrix;\n"
                       "void main()\n"
                       "{\n"
                       "    texCoord = vTexCoord;\n"
                       "    gl_Position = matrix * vPosition;\n"
                       "}\n";
    vshader->compileSourceCode(vsrc);

    //创建片段着色器
    QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment,this);
    const char *fsrc = "#version 330\n"
                       "uniform sampler2D tex;\n"
                       "in vec2 texCoord;\n"
                       "out vec4 fColor;\n"
                       "void main()\n"
                       "{\n"
                       "    fColor = texture(tex,texCoord);\n"
                       "}\n";
    fshader->compileSourceCode(fsrc);

    //创建着色器程序
    program = new QOpenGLShaderProgram;
    program->addShader(vshader);
    program->addShader(fshader);
    program->link();
    program->bind();
}

void MyOpenGLWidget::paintGL()
{
    //设置视口为正方形
    int w = width();
    int h = height();
    int side = qMin(w,h);
    glViewport((w-side)/2,(h-side)/2,side,side);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //顶点位置
    GLfloat vertices[2][4][3] =
    {
        {{-0.8f,0.8f,0.8f},{-0.8f,-0.8f,0.8f},{0.8f,-0.8f,0.8f},{0.8f,0.8f,0.8f}},
        {{0.8f,0.8f,0.8f},{0.8f,-0.8f,0.8f},{0.8f,-0.8f,-0.8f},{0.8f,0.8f,-0.8f}}
    };

    //添加缓存
    vbo.create();
    vbo.bind();
    vbo.allocate(vertices,48*sizeof(GLfloat));
    GLuint vPosition = program->attributeLocation("vPosition");
    //glVertexAttribPointer(vPosition,2,GL_FLOAT,GL_FALSE,0,vertices);
    program->setAttributeBuffer(vPosition,GL_FLOAT,0,3,0);
    glEnableVertexAttribArray(vPosition);

    //顶点着色
    GLfloat coords[2][4][2] =
    {
        {{0.0f,1.0f},{0.0f,0.0f},{1.0f,0.0f},{1.0f,1.0f}},
        {{0.0f,1.0f},{0.0f,0.0f},{1.0f,0.0f},{1.0f,1.0f}}
    };
    vbo.write(24*sizeof(GLfloat),coords,16*sizeof(GLfloat));
    GLuint vTexCoord = program->attributeLocation("vTexCoord");
    program->setAttributeBuffer(vTexCoord,GL_FLOAT,24*sizeof(GLfloat),2,0);
    glEnableVertexAttribArray(vTexCoord);
    program->setUniformValue("tex",0);

    //顶点变换
    QMatrix4x4 matrix;
    matrix.perspective(45.0f,(GLfloat)w/(GLfloat)h,0.1f,100.0f);
    matrix.translate(0,0,translate);
    matrix.rotate(xRot,1.0,0.0,0.0);
    matrix.rotate(yRot,0.0,1.0,0.0);
    matrix.rotate(zRot,0.0,0.0,1.0);
    program->setUniformValue("matrix",matrix);

    //绘制函数
    for(int i=0;i<2;i++)
    {
        textures[i]->bind();
        glDrawArrays(GL_TRIANGLE_FAN,i*4,4);
    }
}

void MyOpenGLWidget::resizeGL(int,int)
{

}

//按键事件
void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Up:
        xRot -= 10;
        break;
    case Qt::Key_Down:
        xRot += 10;
        break;
    case Qt::Key_Left:
        yRot -= 10;
        break;
    case Qt::Key_Right:
        yRot += 10;
        break;
    case Qt::Key_PageUp:
        zRot -= 10;
        break;
    case Qt::Key_PageDown:
        zRot += 10;
        break;
    case Qt::Key_Space:
        translate += 1;
        break;
    case Qt::Key_Alt:
        translate -= 1;
        break;
    default:
        break;
    }
    update();
    QOpenGLWidget::keyPressEvent(event);
}

4.main.cpp

#include <QApplication>
#include "myopenglwidget.h"

int main(int argc,char *argv[])
{
    QApplication app(argc,argv);
    MyOpenGLWidget w;
    w.resize(400,300);
    w.show();
    return app.exec();
}

总结

通过对书上的3D绘图这一章节学习,我也对在Qt下使用OpenGL进行了初步的了解,本文仅仅将示例展示给大家,没有进行很详细的解释,详见学习书籍:【Qt Creator快速入门_霍亚飞编著】
这里也推荐一个关于OpenGL的学习网站:LearnOpenGL CN(https://learnopengl-cn.github.io/)


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

学习书籍:【Qt Creator快速入门_霍亚飞编著】
参考文章:
OpenGL 基本概念
在Qt中使用OpenGL(一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1119902.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于协作搜索优化的BP神经网络(分类应用) - 附代码

基于协作搜索优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于协作搜索优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.协作搜索优化BP神经网络3.1 BP神经网络参数设置3.2 协作搜索算法应用 4.测试结果…

自然语言处理---文本预处理概述

自然语言处理&#xff08;Natural Language Processing&#xff0c;简称NLP&#xff09;是计算机科学与语言学中关注于计算机与人类语言间转换的领域。其主要应用于&#xff1a;语音助手、机器翻译、搜索引擎、智能问答等。 文本预处理概述 文本语料在输送给模型前一般需要一…

【iOS】AFNetworking的基本使用

使用AFNetworking框架需要Cocoapods进行管理 所以要预先配置好Cocoapods&#xff0c;具体步骤见这篇文章&#xff1a;【iOS】CocoaPods的安装及其使用方法 简介 AFNetworking是一款cocoapods的网络请求库&#xff0c;在Foundation框架基础上&#xff0c;提供了一套简单易用的…

基于厨师优化的BP神经网络(分类应用) - 附代码

基于厨师优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于厨师优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.厨师优化BP神经网络3.1 BP神经网络参数设置3.2 厨师算法应用 4.测试结果&#xff1a;5.M…

C#,数值计算——分类与推理Phylo_clc的计算方法与源程序

1 文本格式 using System; using System.Collections.Generic; namespace Legalsoft.Truffer { public class Phylo_clc : Phylagglom { public override void premin(double[,] d, int[] nextp) { } public override double dminfn(double[…

Studio One 6.5新版本功能讲解及一键安装下载教程

Studio One 6.5 发布&#xff1a;整合 Dolby Atmos 全景声&#xff0c;跟 Bitwig 联合推出开放的 DAWproject 格式&#xff0c;支持 Linux&#xff01; PreSonus 的“.5”更新通常都有比较大的变化&#xff0c;这次也不例外。Studio One 6.5 增加了一种全新的工作方式&#xff…

基于人工蜂鸟优化的BP神经网络(分类应用) - 附代码

基于人工蜂鸟优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于人工蜂鸟优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.人工蜂鸟优化BP神经网络3.1 BP神经网络参数设置3.2 人工蜂鸟算法应用 4.测试结果…

【计网 EMail】计算机网络 EMail协议详解:中科大郑烇老师笔记 (五)

目录 0 引言1 电子邮件EMail1.1 组成1.2 SMTP协议1.3 案例&#xff1a;Alice给Bob发送报文1.4 SMTP总结1.5 邮件报文格式1.6 POP3协议和IMAP协议 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;计算机四大基础专栏&#x1f4dc; 其他章节&#xf…

【RocketMQ系列九】SpringCloudStream整合RocketMQ

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

2023-10-15 LeetCode每日一题(只出现一次的数字)

2023-10-15每日一题 一、题目编号 137. 只出现一次的数字 II二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并…

MySQL数据库查询实战操作

前置条件: 创建库:MySQL基本操作之创建数据库-CSDN博客 创建表:MySQL基本操作之创建数据表-CSDN博客 目录 常规查询常用函数union查询一、常规查询 1、查询所有姓名以 "张" 开头的学生: SELECT * FROM student WHERE name LIKE 张%; 这条语句使用 LIKE 运算…

Linux磁盘扩容(加硬盘法)

目录 ​编辑 1、虚拟机操作 2、查看当前分区 3、更新并重启虚拟机 4、对新磁盘分区 5、对新分区进行格式化 6、进行文件系统扩展 1、虚拟机操作 点击添加 2、查看当前分区 fdisk -l3、更新并重启虚拟机 shutdown -r now 然后虚拟机会重启 在此查看当前分区 fdisk -l…

Pycharm设置项目的python环境与界面上terminal的shell运行环境

1、首先打开左上角的file–>settings 2、设置项目运行环境如下所示&#xff1a; 3、设置ternimal的shell执行环境如下所示&#xff1a;

【试题000】C语言整型常量求平方根Sqrt函数

题目&#xff1a;设float x9&#xff0c;y2;&#xff0c;表达式(int) (sqrt (x) /y) 的值是&#xff1f; 代码解析&#xff1a;↓ #include <studio.h> #include <math.h> void main() {float x 9, y 2;printf("%d\n", (int)(sqrt(x) / y));//结果1/…

【解锁未来】探索Web3的无限可能性-01

文章目录 前言什么是Web3&#xff1f; 前言 还记得你第一次听说比特币吗&#xff1f;也许那只是一个关于新技术将改变一切的微弱嗡嗡声。也许你会有一种 "FOMO "的感觉&#xff0c;因为那些早早入场的人突然积累了一大笔财富–尽管你并不清楚这些 "钱 "可…

解决windows10、windows11故障:Microsoft-Windows-Kernel-Processor-Power 事件ID:37

一、现象 windows系统日志中出现大量的“Microsoft-Windows-Kernel-Processor-Power”错误。 经过分析&#xff1a;原因是windows配置的【使用电池】默认值是5%&#xff0c;按5%计算出来的功率与CPU的最小功率不兼容&#xff0c;如&#xff1a;本机CPU最高功率是25W&#xff0…

【Linux】文件IO基础知识——下篇, 什么是软硬链接?如何用别人的动静态库??

目录 一&#xff0c;stderr 2. errno全局变量 二&#xff0c;文件系统 1. 软链接 2. 硬链接 三&#xff0c;静态库 1. 制作静态库 2. 自动化生成静态库 & 自动发布库与头文件 3. 如何使用第三方库 法&#xff08;一&#xff09;&#xff1a;修改系统文件库 …

QT学习day5(QT实现TCP协议)

作业&#xff1a;利用TCP客户端和服务器实现网络聊天室&#xff08;简单版QQ&#xff09; 1.服务器代码 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器头文件 #include<QTcpSocket> …

2023-10-21 LeetCode每日一题(统计无向图中无法互相到达点对数)

2023-10-21每日一题 一、题目编号 2316. 统计无向图中无法互相到达点对数二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数 n &#xff0c;表示一张 无向图 中有 n 个节点&#xff0c;编号为 0 到 n - 1 。同时给你一个二维整数数组 edges &#xff0c;其中 ed…

Python Pandas数据处理作图——波尔共振实验

import matplotlib.pyplot as plt import pandas as pd from pylab import mplmpl.rcParams["font.sans-serif"] ["SimHei"]data {频率比例w/wr: [1.036, 1.030, 1.025, 1.020, 1.012, 1.007, 1.002,0.997,0.993,0.990,0.986,0.977,0.969],振幅测量值θ&…