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

17. OPenGL实现旋转移动物体

1. 说明:

整体思路:如果想实现动态,可以使用一个矩阵和我们给定的坐标值进行相乘,实时的改变坐标值
类似于坐标的齐次变换,然后使用一个定时器,在规定时间内触发重新绘制的函数。
实际效果:

OPenGL移动旋转图形

2. 实现步骤:

第一步:
在MyOpenGLWidget.h文件中添加一个定时器变量,用来实时的调用更新函数,让画布在规定的间隔时间内重绘:

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H#include <QObject>
#include <QWidget>
#include <QTimer>
#include <QTime>#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{Q_OBJECT
public:enum Shape{None,Rect,Circle,Triangle};explicit MyOpenGLWidget(QWidget *parent = nullptr);void drawShape(Shape shape);void clearGraphic();void setWireFrame(bool wireFrame);protected:virtual void initializeGL() override;virtual void resizeGL(int w, int h) override;virtual void paintGL() override;signals:public slots:void on_timeout();private:Shape m_shape;QOpenGLShaderProgram shaderProgram;QOpenGLTexture *textureStar;QTimer timer;	//在之前的基础上再添加一个 定时器 变量
};
#endif // MYOPENGLWIDGET_H

第二步:
在MyOpenGLWidget.cpp文件中的paintGL()函数内部声明一个矩阵,使这个矩阵位移一段距离,然后随着时间不停的做旋转,最后将这个矩阵作用在顶点着色器的位置坐标上,即可实现物体的平移和旋转。
注意:矩阵要用左乘,且矩阵matrix在代码的体现上应该先平移,再旋转,否则会乱掉
paintGL()函数代码如下:

void MyOpenGLWidget::paintGL()
{QMatrix4x4 matrix;unsigned int time = QTime::currentTime().msec();matrix.translate(0.5,-0.5,0.0);//先写平移的代码matrix.rotate(time,0.0f,0.0f,1.0f);//再写旋转的代码glClearColor(0.5f,0.9f,0.4f,1.0f);glClear(GL_COLOR_BUFFER_BIT);shaderProgram.bind();textureStar->bind(0);//在渲染前只需开启对应的VAO即可glBindVertexArray(VAO);switch (m_shape) {case Rect://将变量matrix传输到顶点着色器中的变量theMatrix中shaderProgram.setUniformValue("theMatrix",matrix);glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,&indices);break;default:break;}}

第三步:
在顶点着色器文件中,定义变量theMatrix,用来接收来自外界数据的传入(matrix),并将变量theMatrix作用在顶点位置坐标上,注意是左乘,代码如下:

#version 330 corelayout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCord;out vec3 ourColor;
out vec2 texCord;uniform mat4 theMatrix;//定义变量,接收外界数据void main()
{//将矩阵变换作用在位置坐标上gl_Position = theMatrix * vec4(aPos.x,aPos.y,aPos.z,1.0f);ourColor = aColor;texCord = aTexCord;
}

MyOpenGLWidget.cpp整天代码:

#include "myopenglwidget.h"unsigned int VBO,VAO;//添加一个索引控制器
unsigned int EBO;float vertices[] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f
};float verticesColorTexture[] = {	//每一行数据的前三个是位置坐标,后三个是颜色值0.5f,0.5f,0.5f,1.0f,0.0f,0.0f,1.0f,1.0f,0.5f,-0.5f,0.0f,0.0f,1.0f,0.0f,1.0f,0.0f,-0.5f,-0.5f,0.0f,0.0f,0.0f,1.0f,0.0f,0.0f,-0.5f,0.5f,0.0f,0.5f,0.5f,0.5f,0.0f,1.0f
};//添加索引数据
unsigned int indices[]={0,1,3,1,2,3
};MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) :  QOpenGLWidget(parent)
{connect(&timer,SIGNAL(timeout()),this,SLOT(on_timeout()));//定时器触发连接槽函数timer.start(100);//启动定时器
}void MyOpenGLWidget::drawShape(MyOpenGLWidget::Shape shape)
{makeCurrent();m_shape = shape;update();doneCurrent();
}void MyOpenGLWidget::clearGraphic()
{makeCurrent();drawShape(MyOpenGLWidget::None);makeCurrent();glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);update();doneCurrent();
}void MyOpenGLWidget::setWireFrame(bool wireFrame)
{makeCurrent();if(wireFrame){glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);}else{glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);}update();doneCurrent();
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();//void glGenVertexArrays(GLsizei n, GLuint *arrays)生成顶点数组对象名称// n: 要产生的VAO对象的数量// arrays: 存放产生的VAO对象的名称glGenVertexArrays(1,&VAO);// void glGenBuffers(GLsizei n,GLuint *buffers)生成顶点缓冲对象// n: 要产生的VBO对象的数量// arrays: 存放产生的VBO对象的名称glGenBuffers(1,&VBO);//初始化索引器glGenBuffers(1,&EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof (indices),indices,GL_STATIC_DRAW);//绑定VAO和VBOglBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//在VBO中存入顶点数据glBufferData(GL_ARRAY_BUFFER,sizeof (verticesColorTexture),verticesColorTexture,GL_STATIC_DRAW);//告诉VAO怎么在VBO中拿数据(顶点位置数据)glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,8*sizeof (float),(void*)0);//开启第一个VAOglEnableVertexAttribArray(0);//告诉VAO怎么在VBO中拿数据(颜色数据)glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,8*sizeof (float),(void*)(3*sizeof(float)));//开启第二个VAOglEnableVertexAttribArray(1);//告诉VAO怎么在VBO中拿数据(纹理数据)glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,8*sizeof (float),(void*)(6*sizeof(float)));//开启第三个VAOglEnableVertexAttribArray(2);//用完之后解除绑定(信息已经被记录下来了)glBindBuffer(GL_ARRAY_BUFFER,0);glBindVertexArray(0);//添加着色器shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/Shaders/shape.vert");shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/Shaders/shape.frag");shaderProgram.link();//添加纹理数据textureStar = new QOpenGLTexture(QImage(":/img/images/water.jpg").mirrored());shaderProgram.setUniformValue("textureStar",0);
}void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);}void MyOpenGLWidget::paintGL()
{QMatrix4x4 matrix;unsigned int time = QTime::currentTime().msec();matrix.translate(0.5,-0.5,0.0);matrix.rotate(time,0.0f,0.0f,1.0f);glClearColor(0.5f,0.9f,0.4f,1.0f);glClear(GL_COLOR_BUFFER_BIT);shaderProgram.bind();textureStar->bind(0);//在渲染前只需开启对应的VAO即可glBindVertexArray(VAO);switch (m_shape) {case Rect:shaderProgram.setUniformValue("theMatrix",matrix);glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,&indices);break;default:break;}}
//定时器槽函数内,调用opengl的更新函数
void MyOpenGLWidget::on_timeout()
{update();
}

持续更新中,请大家多多关注…

相关文章:

17. OPenGL实现旋转移动物体

1. 说明&#xff1a; 整体思路&#xff1a;如果想实现动态&#xff0c;可以使用一个矩阵和我们给定的坐标值进行相乘&#xff0c;实时的改变坐标值 类似于坐标的齐次变换&#xff0c;然后使用一个定时器&#xff0c;在规定时间内触发重新绘制的函数。 实际效果&#xff1a; OP…...

《SQL基础》14. 存储过程 · 存储函数

存储过程 存储函数存储过程基本语法变量系统变量用户定义变量局部变量if判断参数case判断while循环repeat循环loop循环游标条件处理程序存储函数存储过程 存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合。调用存储过程可以简化应用开发人员的工作&#xff0c;减…...

NFT Insider #87:The Sandbox 收购游戏开发工作室 Sviper,GHST 大迁徙即将拉开帷幕

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members(https://twitter.com/WHALEMembers)、BeepCrypto&#xff08;https://twitter.com/beep_crypto&#xff09;联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周…...

html部分codewhy网课学习笔记

day1 网页显示的过程和服务器 浏览器内核,也称为渲染引擎 head标签描述网页的原数据&#xff0c;如title shifttab是向前缩进 div>ul>li可以快速生成 <div> <ul> <li></li> </ul> </div> 在早期,单标签如<input>也可写为&l…...

电脑出问题了怎么重装系统修好

电脑在使用过程中经常会出现各种各样的问题&#xff0c;如系统崩溃、蓝屏、病毒感染等。这些问题如果不能及时得到解决&#xff0c;将会给用户带来很多麻烦和损失。小白一键重装系统是一个功能强大的工具&#xff0c;可以帮助用户快速解决电脑常见问题。下面我们就来详细介绍如…...

Nginx国密支持问题记录

文章目录添加国密支持可能出现的问题国密不生效&#xff0c;查看 Nginx 可执行文件路径是否正确证书无法解析Nginx无法启动添加国密支持 NGINX添加国密支持 添加国密支持可以直接按照官网的操作顺序操作即可 参考网址&#xff1a;https://www.gmssl.cn/gmssl/index.jsp 可能出…...

基于ensp的小型局域网网络搭建及需求分析

一 需求分析本实验的目的在于建立小型局域网。由于公司由财政部、人事部、科技部三个部门组成&#xff0c;分布在同一个交换机下。设计以下网络&#xff1a;三个个部门使用两台交换机连接&#xff0c;然后连接到汇聚交换机&#xff0c;再通过路由器与外网以及其他部门网络相连。…...

Kubernetes学习(二)Pod

创建Pod kubectl创建nginx pod 编写 nginx pod的yaml文件 apiVersion: v1 kind: Pod metadata:name: my-nginxlabels:name: my-nginx spec:containers:- image: nginxname: my-nginxresources:limits:memory: "128Mi"cpu: "500m"ports:- name: nginx-po…...

【Docker】docker | 迁移docker目录

一、场景说明1、物理机磁盘空间不够用了2、docker的镜像、容器、卷等资料的默认路径为&#xff1a; /var/lib/docker3、增加了数据盘挂在&#xff0c;需要将docker的全部资料更换个目录二、操作确认是否满足切换条件1&#xff09;服务是否能够暂停&#xff0c;如果可以就OK2&am…...

day24_多线程进阶

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 创建线程的几种方式 1) 继承 2) 实现Runnable 3) calla…...

Qt实现系统桌面目录下文件搜索的GUI:功能一:文件查找与现实

⭐️我叫恒心&#xff0c;一名喜欢书写博客的研究生在读生。 原创不易~转载麻烦注明出处&#xff0c;并告知作者&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。 功能点一&#xff1a;文件查找与…...

有关数据库的一级、二级、三级封锁协议

一级封锁协议 一级封锁协议是指&#xff0c;事务T在修改数据R之前必须先对其加X锁&#xff0c;直到事务结束才释放。事务结束包括正常结束&#xff08;COMMIT&#xff09;和非正常结束&#xff08;ROLLBACK).一级封锁协议可防止丢失修改&#xff0c;并保证事务T是可恢复的。在…...

【Android Studio】【学习笔记】【2023春】

文章目录零、常用一、界面布局疑问&报错零、常用 一、界面布局 Android——六大基本布局总结/CSDN小马 同学 【Android】线性布局&#xff08;LinearLayout&#xff09;最全解析/CSDNTeacher.Hu 一个不错的计算器界面&#x1f447; Android Studio App LinearLayout多层…...

window.open()下载文件重命名/js下载文件重命名/js跨域下载文件重命名

普通文件下载 // 1 var fileUrl https://xxxx.docx; window.open(fileUrl"?attname文档.docx");// 2 var a document.createElement(a); a.href https://xxxx.docx; a.download 文档.docx; a.target "_blank"; a.click();以上方式 attname 和 a.down…...

zookeeper:简介及常用命令

目录 一、Zookeeper简介 二、Zookeeper服务端常用命令 1、启动ZooKeeper服务 2、查看ZooKeeper服务状态 3、停止ZooKeeper服务 4、重启ZooKeeper服务 三、Zookeeper客户端常用命令 1、连接ZooKeeper服务端 2、断开连接&#xff1a;quit 3、查看命令帮助&#xff1a;help…...

与流程挖掘布道者熵评科技孙一鸣博士共话流程挖掘市场的起源与前景 | 爱分析访谈

调研&#xff1a;李进宝 陈元新 撰写&#xff1a;李进宝 陈元新 随着数字化转型持续深入&#xff0c;国内企业流程挖掘需求初露端倪。流程挖掘是指通过采集和分析企业数据&#xff0c;以可视化流程图还原企业实际发生的业务流程&#xff0c;进而评估流程运行状况、诊断流程运…...

第十一届蓝桥杯省赛——2解密

题目&#xff1a;【问题描述】小明设计了一种文章加密的方法&#xff1a;对于每个字母 c&#xff0c;将它变成某个另外的字符 Tc。下表给出了字符变换的规则&#xff1a;字母cTc字母cTc字母cTc字母cTcaynlAYNLbxogBXOGcmpoCMPOddquDDQUearfEARFfcssFCSSgitzGITZhkupHKUPinvwINV…...

ChatGPT解答:PYQT5 美化各种控件的方案和实例

ChatGPT解答&#xff1a;PYQT5 美化各种控件的方案和实例 修改按钮样式 button QPushButton(按钮, self) button.setStyleSheet(QPushButton{background-color: red; border-radius: 5px;})修改标签样式 label QLabel(标签, self) label.setStyleSheet(QLabel{color: blue; …...

js实现翻盘抽奖

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>礼物编辑</title><style>* {margin: 0;padding: 0;box-sizing: border-box;list-style-type: none;text-decoration: none;}.container {d…...

Qt QtCreator 安卓开发环境搭建

踩坑 我的qt是使用在线安装工具安装的&#xff0c;Qt版本使用的是5.15.2&#xff0c;QtCreator版本9.0.2 在网上很多教程都是如下步骤 1.安装qt 2.安装jdk 3.安装android-sdk 4.安装android-ndk 5.配置android设置 例如&#xff1a; https://blog.csdn.net/weixin_51363326/…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...