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

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

文章目录

  • 前言
  • 一、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 += widgetsHEADERS += \myopenglwidget.hSOURCES += \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_OBJECTpublic: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(一)

相关文章:

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

文章目录 前言一、Qt下使用OpenGL绘制图形介绍二、示例完整代码总结 前言 文章中引用的内容均来自这本书中的原文&#xff1a;【Qt Creator快速入门_霍亚飞编著】&#xff0c;本文的示例也是在书中代码的基础上进行编写的&#xff08;其中部分代码使用原文编译不过&#xff0c…...

在chrom浏览器安装Vue.js devtools插件,遇到恶意扩展程序字样,附百度网盘下载链接

遇到的问题 拖拽下载好的 Vue.js devtools 插件到谷歌扩展程序&#xff0c; 百度网盘下载地址 链接&#xff1a;https://pan.baidu.com/s/1FeK6pwc2UzRUUlMFN3rW5w?pwdw361 提取码&#xff1a;w361 提示&#xff1a; 解决办法 将Vue.js devtools 插件的后缀从.crx改为.zi…...

WSL2的安装与配置(创建Anaconda虚拟环境、更新软件包、安装PyTorch、VSCode)

1. WSL2 安装 以管理员身份打开 PowerShell&#xff08;“开始”菜单 >“PowerShell” >单击右键 >“以管理员身份运行”&#xff09;&#xff0c;然后输入以下命令&#xff1a; dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /a…...

【鸿蒙软件开发】ArkTS常见组件之单选框Radio和切换按钮Toggle

文章目录 前言一、Radio单选框1.1 创建单选框1.2 添加Radio事件1.3 场景示例二、切换按钮Toggle2.1 创建切换按钮2.2 创建有子组件的Toggle2.3 自定义样式selectedColor属性switchPointColor属性 2.4 添加事件2.5 示例代码 总结 前言 Radio是单选框组件&#xff0c;通常用于提…...

今年阿里云双十一服务器优惠价格讨论_看看大家怎么说?

2023阿里云双十一云服务器大概会降到什么区间&#xff1f;阿里云服务器网认为会在当前的优惠价格基础上&#xff0c;降价10%左右&#xff0c;可以在阿里云CLUB中心领券&#xff1a;aliyun.club 云服务器专用满减优惠券。阿里云服务器网从各个渠道了解到大家对今年阿里云双十一服…...

LC-1402. 做菜顺序(记忆化搜索 ==> 动态规划、贪心)

1402. 做菜顺序 困难 一个厨师收集了他 n 道菜的满意程度 satisfaction &#xff0c;这个厨师做出每道菜的时间都是 1 单位时间。 一道菜的 「 like-time 系数 」定义为烹饪这道菜结束的时间&#xff08;包含之前每道菜所花费的时间&#xff09;乘以这道菜的满意程度&#x…...

泰森多边形

泰森多边形 93 泰森多边形又叫沃洛诺伊图&#xff08;Voronoi diagram&#xff09;&#xff0c;得名于Georgy Voronoi&#xff0c;是一组由连接两邻点线段的垂直平分线组成的连续多边形。一个泰森多边形内的任一点到构成该多边形的控制点的距离小于到其他多边形控制点的距离。…...

YOLOV8 进行docker环境配置

修改docker文件 原docekerfile中ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/下载很慢&#xff0c;可以在外部下载好&#xff0c;放入docker文件夹中&#xff0c;再将源代码改为ADD Arial.ttf…...

sealos一键部署K8S环境(sealos3.0时代教程过时了,目前已经4.0了,请移步使用Sealos一键安装K8S)

1 安装Sealos(4.0版本) sealos部署k8s贼方便&#xff0c;只需要一条init命令即可&#xff0c;3分钟部署完&#xff08;下载安装包的时间不算&#xff09;。 官方教程&#xff1a;https://www.sealyun.com/instructions/1st #主机名&#xff1a; hostnamectl set-hostname mas…...

【C++】stackqueue

适配器是一种设计模式 &#xff0c; 该种模式是将一个类的接口转换成客户希望的另外一个接口 。 虽然 stack 和 queue 中也可以存放元素&#xff0c;但在 STL 中并没有将其划分在容器的行列&#xff0c;而是将其称为 容器适配 器 &#xff0c;这是因为 stack 和队列只是对其他容…...

Hive篇面试题+详解

Hive篇面试题 1.什么是Hive&#xff1f;它的主要功能是什么&#xff1f; Hive是一个基于Hadoop的数据仓库工具&#xff0c;它提供了一个类SQL的查询语言&#xff08;HiveQL&#xff09;来查询和分析存储在Hadoop集群中的大规模数据。Hive的主要功能是将结构化数据映射到Hadoop…...

Mysql批量插入更新如何拆分大事务?

拆分大事务 一、解决方案二、遇到问题之前在运行Mysql任务的时候报错:binlog(1610646347 bytes) write threshold exceeded,原因是Mysql任务提交的是个大事务,超出binlog设定阈值,使得系统自动终止事务 一、解决方案 使用limit分页拆分大事务 CREATE PROCEDURE `split_tran…...

【计算机网络原理】初始网络基础

文章目录 1. 网络发展史1.1 单机时代1.2 网络互连局域网 LAN广域网 WAN 2. 网络通信基础2.1 IP 地址2.2 端口号2.3 协议2.4 五元组2.5 协议分层2.5.1 OSI七层模型2.5.2 TCP/IP五层模型 2.6 封装和分用2.6.1 数据封装(发送方情况)2.6.2 数据分用(接收方情况) 总结 1. 网络发展史…...

【sqlserver】配置管理器打不开

问题描述 无法连接到 WMI 提供程序。您没有权限或者该服务器无法访问。请注意&#xff0c;您只能使用SQL Server 配置管理器来管理 SQL Server 2005 和更高版本的服务 器。无效类[0x80041010] 解决方式: 命令提示符-右键-以管理员身份运行&#xff0c;再把以下代码执行一遍&…...

磁盘清理 | 已经卸载的软件还出现在应用和功能里怎么办?

一句话总结解决方法&#xff1a; 安装Geek Uninstaller,删除卸载残留。 问题描述&#xff1a; 最近磁盘满了&#xff0c;需要删除一些平时不常用的软件&#xff0c;但是发现一个问题。就是已经删除的软件&#xff0c;仍然会出现在“应用与功能”中。并且显示卸载图标为灰色&am…...

C++之异常

目录 一、C语言传统的处理错误的方式 二、C的异常 1、概念 2、关键字 3、基本格式 三、异常的抛出和捕获 1、异常的抛出和匹配原则 2、 在函数调用链中异常栈展开匹配原则 四、异常抛派生类&#xff0c;基类捕获 五、异常的重新抛出 六、异常安全 七、异常的优缺点…...

动态天气预报:Living Weather HD for Mac

Living Weather HD能够为Mac用户提供及时、准确、个性化的天气信息&#xff0c;并提供了丰富的定制选项&#xff0c;使用户能够更加方便地查看天气状况。 具有以下特点&#xff1a; 显示世界各地的准确天气预报和当地时间。自动探测出用户所在的首个地点&#xff0c;并通过搜…...

深度神经网络时与协方差矩阵

平时训练深度神经网络时&#xff0c;什么时候用到了协方差矩阵 在深度神经网络的平时训练过程中&#xff0c;一般情况下不直接使用协方差矩阵。然而&#xff0c;协方差矩阵的概念和相关性的考虑在某些情况下可以对网络的训练和优化起到一定的指导作用。 下面是一些与协方差矩…...

idea中java类属性(字段)链式赋值

很多人看到标题可能会想到 lombok 的 Builder&#xff0c;lombok 在国内用的挺多的&#xff0c;开源的组件中 mybatis-plus 中用到了这个&#xff0c;使用这个有一个问题就是通过对应 get 和 set 方法找不到对应的赋值方法&#xff0c;因为 lombok 使用了 apt 在编译期生成了相…...

vue通知(滚动)

1. li宽度不顾定 <template><div id"app"><div id"box" mouseover"clearLeft" mouseleave"setLeft"><ul :style"{ transform: translateX( left px) }" ref"cmdlist"><li v-for&qu…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...