摘要:本文主要是利用 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文件
- #ifdef GL_ES
- // Set default precision to medium
- precision mediump int;
- precision mediump float;
- #endif
- uniform mat4 mvp_matrix;
- attribute vec4 a_position;
- attribute vec2 a_texcoord;
- varying vec2 v_texcoord;
- //! [0]
- void main()
- {
- // Calculate vertex position in screen space
- gl_Position = mvp_matrix * a_position;
- // Pass texture coordinate to fragment shader
- // Value will be automatically interpolated to fragments inside polygon faces
- v_texcoord = a_texcoord;
- }
- //! [0]
复制代码 fshader.glsl文件
- #ifdef GL_ES
- // Set default precision to medium
- precision mediump int;
- precision mediump float;
- #endif
- uniform sampler2D texture;
- varying vec2 v_texcoord;
- //! [0]
- void main()
- {
- // Set fragment color from texture
- gl_FragColor = texture2D(texture, v_texcoord);
- }
- //! [0]
复制代码 主要部门代码,代码比较长,有须要的可以到文章摘要中获取下载方式,免费下载使用。
- #include "DlgCube.h"
- #include <QMouseEvent>
- #include <math.h>
- #include <QPen>
- #include <QPainter>
- #include <QTime>
- DlgCube::DlgCube(int width, int height, QWidget *parent) :
- QOpenGLWidget(parent),
- geometries(0),
- texture(0),
- angularSpeed(0)
- {
- this->setFixedSize(width, height);
- }
- DlgCube::~DlgCube()
- {
- // Make sure the context is current when deleting the texture
- // and the buffers.
- makeCurrent();
- delete texture;
- delete geometries;
- doneCurrent();
- }
- void DlgCube::mousePressEvent(QMouseEvent *e)
- {
- // Save mouse press position
- mousePressPosition = QVector2D(e->localPos());
- }
- void DlgCube::mouseMoveEvent(QMouseEvent *e)
- {
- //qDebug()<<e->pos();
- // Mouse release position - mouse press position
- QVector2D diff = QVector2D(e->localPos()) - mousePressPosition;
- // Rotation axis is perpendicular to the mouse position difference
- // vector
- QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
- // Accelerate angular speed relative to the length of the mouse sweep
- qreal acc = diff.length() / 100.0;
- // Calculate new rotation axis as weighted sum
- rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
- // Increase angular speed
- angularSpeed += acc;
- mousePressPosition = QVector2D(e->localPos());
- }
- void DlgCube::timerEvent(QTimerEvent *)
- {
- // Decrease angular speed (friction)
- angularSpeed *= 0.95;
- // Stop rotation when speed goes below threshold
- if (angularSpeed < 0.01) {
- angularSpeed = 0.0;
- } else {
- // Update rotation
- rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;
- // Request an update
- update();
- }
- }
- void DlgCube::initializeGL()
- {
- initializeOpenGLFunctions();
- //球 后 widget 的背景色
- // glClearColor(1, 1, 1, 0);
- initShaders();
- initTextures();
- // Enable depth buffer
- glEnable(GL_DEPTH_TEST);
- // Enable back face culling
- glEnable(GL_CULL_FACE);
- geometries = new GeometryEngine;
- // Use QBasicTimer because its faster than QTimer
- timer.start(12, this);
- }
- void DlgCube::initShaders()
- {
- // Compile vertex shader
- if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vshader.glsl"))
- close();
- // Compile fragment shader
- if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fshader.glsl"))
- close();
- // Link shader pipeline
- if (!program.link())
- close();
- // Bind shader pipeline for use
- if (!program.bind())
- close();
- }
- void DlgCube::initTextures()
- {
- // Load cube.png image
- texture = new QOpenGLTexture(myImage.mirrored());
- // Set nearest filtering mode for texture minification
- texture->setMinificationFilter(QOpenGLTexture::Nearest);
- // Set bilinear filtering mode for texture magnification
- texture->setMagnificationFilter(QOpenGLTexture::Linear);
- // Wrap texture coordinates by repeating
- // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
- texture->setWrapMode(QOpenGLTexture::Repeat);
- }
- void DlgCube::resizeGL(int w, int h)
- {
- // Calculate aspect ratio
- qreal aspect = qreal(w) / qreal(h ? h : 1);
- // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
- //fov 可以调节大小
- const qreal zNear = 2.5, zFar = 7.0, fov = 45.0;
- // Reset projection
- projection.setToIdentity();
- // Set perspective projection
- projection.perspective(fov, aspect, zNear, zFar);
- }
- void DlgCube::paintGL()
- {
- // Clear color and depth buffer
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- texture->bind();
- // Calculate model view transformation
- QMatrix4x4 matrix;
- matrix.translate(0.0, 0.0, -5.0);
- matrix.rotate(rotation);
- // Set modelview-projection matrix
- program.setUniformValue("mvp_matrix", projection * matrix);
- // Use texture unit 0 which contains cube.png
- program.setUniformValue("texture", 0);
- // Draw cube geometry
- geometries->drawCubeGeometry(&program);
- }
- void DlgCube::InitCube()
- {
- m_which_color = 0;
- tip_1.clear(); tip_2.clear(); tip_3.clear(); tip_4.clear(); tip_5.clear(); tip_6.clear();
- tip_1.push_back("<静夜思>");
- tip_1.push_back("床前明月光");
- tip_1.push_back("疑是地上霜");
- tip_1.push_back("举头望明月");
- tip_1.push_back("低头思故乡");
- tip_2.push_back("<江雪>");
- tip_2.push_back("千山鸟飞绝");
- tip_2.push_back("万径人踪灭");
- tip_2.push_back("孤舟蓑笠翁");
- tip_2.push_back("独钓寒江雪");
- tip_3.push_back("<闻乐天授江州司马>");
- tip_3.push_back("残灯无焰影幢幢");
- tip_3.push_back("此夕闻君谪九江");
- tip_3.push_back("垂死病中惊坐起");
- tip_3.push_back("暗风吹雨入寒窗");
- tip_4.push_back("问世间情是何物");
- tip_4.push_back("直教生死相许");
- tip_4.push_back("天南地北双飞客");
- tip_4.push_back("老翅几回寒暑");
- tip_4.push_back("欢乐趣");
- tip_5.push_back("离别苦");
- tip_5.push_back("就中更有痴儿女");
- tip_5.push_back("君应有语");
- tip_6.push_back("渺万里层云,千山暮雪,只影向谁去?");
- //merge
- QString str = QString(":image/edge.png");
- QImage resultImg(str);
- //
- QPainter painter;
- painter.begin(&resultImg);
- //在新区域画图
- painter.drawImage( 0, 0, Text_To_Image(0));
- painter.drawImage(396, 0, Text_To_Image(1));
- painter.drawImage(792, 0, Text_To_Image(2));
- painter.drawImage( 0, 400, Text_To_Image(3));
- painter.drawImage(396, 400, Text_To_Image(4));
- painter.drawImage(792, 400, Text_To_Image(5));
- painter.end();
- QString strResultImg = QString("./tiledball.png");
- resultImg.save(strResultImg);
- myImage = resultImg;
- }
- void DlgCube::MoveLittle()
- {
- //move 初始位置露出一个角
- QVector2D diff = QVector2D(QPoint(180,180));
- QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
- qreal acc = diff.length() / 100.0;
- rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
- angularSpeed += acc;
- }
- QImage DlgCube::Text_To_Image(int count)
- {
- QVector <QString> tip;
- QImage img;
- switch(count)
- {
- case 0:tip = tip_1; img.load(":image/11.png");break;
- case 1:tip = tip_2; img.load(":image/22.png");break;
- case 2:tip = tip_3; img.load(":image/33.png");break;
- case 3:tip = tip_4; img.load(":image/44.png");break;
- case 4:tip = tip_5; img.load(":image/55.png");break;
- case 5:tip = tip_6; img.load(":image/66.png");break;
- default:break;
- }
- QPainter painter;
- painter.begin(&img);
- QFont font;
- font.setBold(true);
- int tip_size = tip.size()>8?8:tip.size();
- for(int i=0;i<tip_size;i++)
- {
- switch (m_which_color%2)
- {
- case 0:font.setFamily("Noto Sans S Chinese Thin");break;
- case 1:font.setFamily("Noto Sans S Chinese Bold");break;
- default:break;
- }
- font.setPixelSize(random_fontpixsize(tip[i].length()));
- painter.setFont(font);
- QPen pen = random_Color();
- painter.setPen(pen);
- //左右各留20px
- int x = 20 + qrand()%((360 - tip[i].length()*font.pixelSize())+1);
- if(x<0)
- x = 5;
- //y会在实际图上向下偏移10个坐标
- int y = 380/tip_size*i + qrand()%((380/tip_size - font.pixelSize())+1);
- painter.drawText(QRect(x, y, 380,380), Qt::AlignLeft|Qt::AlignTop,tip[i]);
- }
- painter.end();
- return img;
- }
- QPen DlgCube::random_Color()
- {
- QPen pen;
- switch (m_which_color % 4) {
- case 0:pen.setColor(QColor(151,255,244));
- break;
- case 1:pen.setColor(QColor(255,195,109));
- break;
- case 2:pen.setColor(QColor(124,204,255));
- break;
- case 3:pen.setColor(QColor(255,255,255));
- break;
- default:
- break;
- }
- m_which_color++;
- return pen;
- }
- int DlgCube::random_fontpixsize(int fontlen)
- {
- if(0 == fontlen)
- return 1;
- int size = (380 / fontlen / 2) + qrand()%(380 / fontlen / 2);
- //字体大小 25<size<38
- if (size > 38)
- size = 33 + qrand() % 6;
- if(size < 25)
- size = 25 + qrand() % 6;
- return size;
- }
复制代码 往期文章回顾
【深度学习】物体检测/实例分割/物体追踪/姿态估计/定向边框/图像分类检测演示系统【含源码】【深度学习】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企服之家,中国第一个企服评测及商务社交产业平台。 |