【qt小系统】使用qt实现透明的3D魔方效果

打印 上一主题 下一主题

主题 982|帖子 982|积分 2946


   摘要:本文主要是利用 QOpenGLWidget
实现的3D魔方效果,可实现自动宣传及鼠标拖动,可根据自己喜好贴差异的配景图及编写内容。代码实现了一个带有旋转立方体的 OpenGL
小部件,立方体的六个面上分别绘制了一些笔墨。
  由于本人能力有限,难免有疏漏之处。
  文中源码文件【获取方式】:关注公众号:利哥AI实例探险,
  给公众号发送 “qt3D魔方” 获取下载方式,关注发送关键字即可获取下载方式,免费,无套路,关注即可!
  原文地址:【qt小系统】使用qt实现透明的3D魔方效果
系统演示


基本介绍



  • 初始化时,代码加载立方体多少形状和纹理,准备好 OpenGL 的基本配置和着色器。
  • 鼠标移动控制立方体的旋转,通过捕获鼠标事件计算旋转轴和速度。
  • 使用定时器逐步低沉旋转速度,模拟摩擦力的效果。
  • 在每一帧中,代码重新计算并设置投影矩阵,绑定纹理,并最终绘制立方体。
  • 立方体表面的纹理图像由 InitCube() 动态天生,使用 QPainter 绘制带有随机颜色和字体的笔墨。
    通过这些技术和逻辑,代码实现了一个可以根据鼠标输入旋转的立方体,每一面都表现了差异的图像和笔墨。

  • 使用 initializeGL() 方法初始化 OpenGL 上下文,包括设置深度测试和背面剔除。
  • 使用 paintGL() 方法进行绘制,负责绘制立方体的每一帧画面。
  • 通过重载 mousePressEvent 和 mouseMoveEvent 方法,代码捕获并处置惩罚鼠标按下和移动事件,以计算并更新立方体的旋转角度。
  • 计算鼠标移动的方向和距离,将其转化为旋转轴和旋转速度。
  • 使用 timerEvent() 方法每隔肯定时间触发一次,逐步减少旋转速度,实现类似摩擦力的效果,从而使立方体旋转逐渐停止。
  • 使用 initShaders() 方法加载和编译顶点着色器和片段着色器,构建并绑定着色器程序。这一步为后续在 OpenGL 管线中使用着色器进行绘制做了准备。
  • 使用 initTextures() 方法加载纹理,将其绑定到立方体的各个面。设置纹理的缩小和放大过滤模式,以及纹理的包裹模式(Repeat)。
  • 使用 GeometryEngine 类管理立方体的多少形状,并在 paintGL() 方法中调用其 rawCubeGeometry() 方法绘制立方体。
  • InitCube() 方法将预定义的笔墨转换为图像,并将多个图像归并成一个纹理,用于立方体的表面。使用 QPainter 类在图像上绘制笔墨,笔墨的字体和颜色是随机天生的。
  • 使用 QMatrix4x4 进行模型视图变换和透视投影计算,在 resizeGL() 和 paintGL() 方法中设置合适的投影矩阵。
核心代码


vshader.glsl文件
  1. #ifdef GL_ES
  2. // Set default precision to medium
  3. precision mediump int;
  4. precision mediump float;
  5. #endif
  6. uniform mat4 mvp_matrix;
  7. attribute vec4 a_position;
  8. attribute vec2 a_texcoord;
  9. varying vec2 v_texcoord;
  10. //! [0]
  11. void main()
  12. {
  13.     // Calculate vertex position in screen space
  14.     gl_Position = mvp_matrix * a_position;
  15.     // Pass texture coordinate to fragment shader
  16.     // Value will be automatically interpolated to fragments inside polygon faces
  17.     v_texcoord = a_texcoord;
  18. }
  19. //! [0]
复制代码
fshader.glsl文件
  1. #ifdef GL_ES
  2. // Set default precision to medium
  3. precision mediump int;
  4. precision mediump float;
  5. #endif
  6. uniform sampler2D texture;
  7. varying vec2 v_texcoord;
  8. //! [0]
  9. void main()
  10. {
  11.     // Set fragment color from texture
  12.     gl_FragColor = texture2D(texture, v_texcoord);
  13. }
  14. //! [0]
复制代码
主要部门代码,代码比较长,有须要的可以到文章摘要中获取下载方式,免费下载使用。

  1. #include "DlgCube.h"
  2. #include <QMouseEvent>
  3. #include <math.h>
  4. #include <QPen>
  5. #include <QPainter>
  6. #include <QTime>
  7. DlgCube::DlgCube(int width, int height, QWidget *parent) :
  8.     QOpenGLWidget(parent),
  9.     geometries(0),
  10.     texture(0),
  11.     angularSpeed(0)
  12. {
  13.     this->setFixedSize(width, height);
  14. }
  15. DlgCube::~DlgCube()
  16. {
  17.     // Make sure the context is current when deleting the texture
  18.     // and the buffers.
  19.     makeCurrent();
  20.     delete texture;
  21.     delete geometries;
  22.     doneCurrent();
  23. }
  24. void DlgCube::mousePressEvent(QMouseEvent *e)
  25. {
  26.     // Save mouse press position
  27.     mousePressPosition = QVector2D(e->localPos());
  28. }
  29. void DlgCube::mouseMoveEvent(QMouseEvent *e)
  30. {
  31.     //qDebug()<<e->pos();
  32.     // Mouse release position - mouse press position
  33.     QVector2D diff = QVector2D(e->localPos()) - mousePressPosition;
  34.     // Rotation axis is perpendicular to the mouse position difference
  35.     // vector
  36.     QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
  37.     // Accelerate angular speed relative to the length of the mouse sweep
  38.     qreal acc = diff.length() / 100.0;
  39.     // Calculate new rotation axis as weighted sum
  40.     rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
  41.     // Increase angular speed
  42.     angularSpeed += acc;
  43.     mousePressPosition = QVector2D(e->localPos());
  44. }
  45. void DlgCube::timerEvent(QTimerEvent *)
  46. {
  47.     // Decrease angular speed (friction)
  48.     angularSpeed *= 0.95;
  49.     // Stop rotation when speed goes below threshold
  50.     if (angularSpeed < 0.01) {
  51.         angularSpeed = 0.0;
  52.     } else {
  53.         // Update rotation
  54.         rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;
  55.         // Request an update
  56.         update();
  57.     }
  58. }
  59. void DlgCube::initializeGL()
  60. {
  61.     initializeOpenGLFunctions();
  62.     //球 后 widget 的背景色
  63. //    glClearColor(1, 1, 1, 0);
  64.     initShaders();
  65.     initTextures();
  66.     // Enable depth buffer
  67.     glEnable(GL_DEPTH_TEST);
  68.     // Enable back face culling
  69.     glEnable(GL_CULL_FACE);
  70.     geometries = new GeometryEngine;
  71.     // Use QBasicTimer because its faster than QTimer
  72.     timer.start(12, this);
  73. }
  74. void DlgCube::initShaders()
  75. {
  76.     // Compile vertex shader
  77.     if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vshader.glsl"))
  78.         close();
  79.     // Compile fragment shader
  80.     if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fshader.glsl"))
  81.         close();
  82.     // Link shader pipeline
  83.     if (!program.link())
  84.         close();
  85.     // Bind shader pipeline for use
  86.     if (!program.bind())
  87.         close();
  88. }
  89. void DlgCube::initTextures()
  90. {
  91.     // Load cube.png image
  92.     texture = new QOpenGLTexture(myImage.mirrored());
  93.     // Set nearest filtering mode for texture minification
  94.     texture->setMinificationFilter(QOpenGLTexture::Nearest);
  95.     // Set bilinear filtering mode for texture magnification
  96.     texture->setMagnificationFilter(QOpenGLTexture::Linear);
  97.     // Wrap texture coordinates by repeating
  98.     // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
  99.     texture->setWrapMode(QOpenGLTexture::Repeat);
  100. }
  101. void DlgCube::resizeGL(int w, int h)
  102. {
  103.     // Calculate aspect ratio
  104.     qreal aspect = qreal(w) / qreal(h ? h : 1);
  105.     // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
  106.     //fov 可以调节大小
  107.     const qreal zNear = 2.5, zFar = 7.0, fov = 45.0;
  108.     // Reset projection
  109.     projection.setToIdentity();
  110.     // Set perspective projection
  111.     projection.perspective(fov, aspect, zNear, zFar);
  112. }
  113. void DlgCube::paintGL()
  114. {
  115.     // Clear color and depth buffer
  116.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  117.     texture->bind();
  118.     // Calculate model view transformation
  119.     QMatrix4x4 matrix;
  120.     matrix.translate(0.0, 0.0, -5.0);
  121.     matrix.rotate(rotation);
  122.     // Set modelview-projection matrix
  123.     program.setUniformValue("mvp_matrix", projection * matrix);
  124.     // Use texture unit 0 which contains cube.png
  125.     program.setUniformValue("texture", 0);
  126.     // Draw cube geometry
  127.     geometries->drawCubeGeometry(&program);
  128. }
  129. void DlgCube::InitCube()
  130. {
  131.     m_which_color = 0;
  132.     tip_1.clear(); tip_2.clear(); tip_3.clear(); tip_4.clear(); tip_5.clear(); tip_6.clear();
  133.     tip_1.push_back("<静夜思>");
  134.     tip_1.push_back("床前明月光");
  135.     tip_1.push_back("疑是地上霜");
  136.     tip_1.push_back("举头望明月");
  137.     tip_1.push_back("低头思故乡");
  138.     tip_2.push_back("<江雪>");
  139.     tip_2.push_back("千山鸟飞绝");
  140.     tip_2.push_back("万径人踪灭");
  141.     tip_2.push_back("孤舟蓑笠翁");
  142.     tip_2.push_back("独钓寒江雪");
  143.     tip_3.push_back("<闻乐天授江州司马>");
  144.     tip_3.push_back("残灯无焰影幢幢");
  145.     tip_3.push_back("此夕闻君谪九江");
  146.     tip_3.push_back("垂死病中惊坐起");
  147.     tip_3.push_back("暗风吹雨入寒窗");
  148.     tip_4.push_back("问世间情是何物");
  149.     tip_4.push_back("直教生死相许");
  150.     tip_4.push_back("天南地北双飞客");
  151.     tip_4.push_back("老翅几回寒暑");
  152.     tip_4.push_back("欢乐趣");
  153.     tip_5.push_back("离别苦");
  154.     tip_5.push_back("就中更有痴儿女");
  155.     tip_5.push_back("君应有语");
  156.     tip_6.push_back("渺万里层云,千山暮雪,只影向谁去?");
  157.     //merge
  158.     QString str = QString(":image/edge.png");
  159.     QImage resultImg(str);
  160.     //
  161.     QPainter painter;
  162.     painter.begin(&resultImg);
  163.     //在新区域画图
  164.     painter.drawImage(  0,   0, Text_To_Image(0));
  165.     painter.drawImage(396,   0, Text_To_Image(1));
  166.     painter.drawImage(792,   0, Text_To_Image(2));
  167.     painter.drawImage(  0, 400, Text_To_Image(3));
  168.     painter.drawImage(396, 400, Text_To_Image(4));
  169.     painter.drawImage(792, 400, Text_To_Image(5));
  170.     painter.end();
  171.     QString strResultImg = QString("./tiledball.png");
  172.     resultImg.save(strResultImg);
  173.     myImage = resultImg;
  174. }
  175. void DlgCube::MoveLittle()
  176. {
  177.     //move 初始位置露出一个角
  178.     QVector2D diff = QVector2D(QPoint(180,180));
  179.     QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
  180.     qreal acc = diff.length() / 100.0;
  181.     rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
  182.     angularSpeed += acc;
  183. }
  184. QImage DlgCube::Text_To_Image(int count)
  185. {
  186.     QVector <QString> tip;
  187.     QImage img;
  188.     switch(count)
  189.     {
  190.     case 0:tip = tip_1; img.load(":image/11.png");break;
  191.     case 1:tip = tip_2; img.load(":image/22.png");break;
  192.     case 2:tip = tip_3; img.load(":image/33.png");break;
  193.     case 3:tip = tip_4; img.load(":image/44.png");break;
  194.     case 4:tip = tip_5; img.load(":image/55.png");break;
  195.     case 5:tip = tip_6; img.load(":image/66.png");break;
  196.     default:break;
  197.     }
  198.     QPainter painter;
  199.     painter.begin(&img);
  200.     QFont font;
  201.     font.setBold(true);
  202.     int tip_size = tip.size()>8?8:tip.size();
  203.     for(int i=0;i<tip_size;i++)
  204.     {
  205.         switch (m_which_color%2)
  206.         {
  207.         case 0:font.setFamily("Noto Sans S Chinese Thin");break;
  208.         case 1:font.setFamily("Noto Sans S Chinese Bold");break;
  209.         default:break;
  210.         }
  211.         font.setPixelSize(random_fontpixsize(tip[i].length()));
  212.         painter.setFont(font);
  213.         QPen pen = random_Color();
  214.         painter.setPen(pen);
  215.         //左右各留20px
  216.         int x = 20 + qrand()%((360 - tip[i].length()*font.pixelSize())+1);
  217.         if(x<0)
  218.             x = 5;
  219.         //y会在实际图上向下偏移10个坐标
  220.         int y = 380/tip_size*i + qrand()%((380/tip_size - font.pixelSize())+1);
  221.         painter.drawText(QRect(x, y, 380,380), Qt::AlignLeft|Qt::AlignTop,tip[i]);
  222.     }
  223.     painter.end();
  224.     return img;
  225. }
  226. QPen DlgCube::random_Color()
  227. {
  228.     QPen pen;
  229.     switch (m_which_color % 4) {
  230.     case 0:pen.setColor(QColor(151,255,244));
  231.         break;
  232.     case 1:pen.setColor(QColor(255,195,109));
  233.         break;
  234.     case 2:pen.setColor(QColor(124,204,255));
  235.         break;
  236.     case 3:pen.setColor(QColor(255,255,255));
  237.         break;
  238.     default:
  239.         break;
  240.     }
  241.     m_which_color++;
  242.     return pen;
  243. }
  244. int DlgCube::random_fontpixsize(int fontlen)
  245. {
  246.     if(0 == fontlen)
  247.         return 1;
  248.     int size = (380 / fontlen / 2) + qrand()%(380 / fontlen / 2);
  249.     //字体大小 25<size<38
  250.     if (size > 38)
  251.         size = 33 + qrand() % 6;
  252.     if(size < 25)
  253.         size = 25 + qrand() % 6;
  254.     return  size;
  255. }
复制代码
往期文章回顾
【深度学习】物体检测/实例分割/物体追踪/姿态估计/定向边框/图像分类检测演示系统【含源码】【深度学习】YOLOV8数据标注及模型训练方法团体流程介绍及演示【深度学习】行人跌倒举动检测软件系统【深度学习】火警检测软件系统【深度学习】吸烟举动检测软件系统【深度学习】数竹签演示软件系统【深度学习】菜品目标检测软件系统QT5集成FTP实现文件及文件夹的下载QT集成开源日记库示例python源码加密之Cython方案简单示例【python源码加密】Cython针对python工程多层级目录处置惩罚办法http服务网络请求如何确保数据安全(含python示例源码)http请求数据传输时确保完整性和保密性方案(含源码)QT集成百度在线地图JS API实现交互及特定效果【qt小游戏】小老鼠闯迷宫小游戏(附源码)【qt小系统】传感器云平台3D散点图(附源码)【qt小系统】通过qt折线图实现论文内容-快餐店排队效能分析【qt小系统】使用qt实现透明的3D魔方效果 竣事语

由于本人能力有限,难免有疏漏之处!
文中源码文件【获取方式】:关注公众号:利哥AI实例探险
给公众号发送 “qt3D魔方” 获取下载方式,免费,无套路,关注即可!!!
原文地址:【qt小系统】使用qt实现透明的3D魔方效果

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户国营

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表