项目实战:Qt+OSG爆破动力学仿真三维引擎测试工具v1.1.0(加载.K模型,子弹轨迹模拟动画,支持windows、linux、国产麒麟系统)
若该文为原创文章,转载请注明出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/142454993
长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…
Qt开发专栏:项目实战(点击传送门)
OSG开发专栏(点击传送门)
需求
1.使用osg三维引擎进行动力学模型仿真性能测试;
2.打开动力学仿真模型文件,.k后缀的模型文件,测试加载解析过程;
3.解决第三方company的opengl制作的三维引擎,绘制面较多与弹丸路径模拟较卡顿的问题;
4.测试时,使用的模型为公开模型,基础面数量达到160多万个;
5.测试时,模拟动画使用的时100万条弹丸路径平行飞射出去;
相关博客
《OSG开发笔记(三十):OSG加载动力学仿真K模型文件以及测试Demo》:该博文也有针对性性能测试过程
Demo V1.1.0
1.新增打开双模型,第一个模型在原来的位置,第二个模型在偏移后的位置
2.优化打开关闭重新打开模型的过程
3.对于100万线动画射击,用于测试性能
4.当前模型为160万个面,双模型的时候为320多万个元素基础面
CSDN粉丝0积分下载:https://download.csdn.net/download/qq21497936/89786375
QQ群:博客技术大全文首行QQ技术群,点击“文件”搜索“osgKFile”,群内与博文同步更新)
Demo v1.0.0
测试交互流畅性,交互无延迟!!!
模块化部署
关键源码
OsgWidget.h
#ifndef OSGWIDGET_H
#define OSGWIDGET_H#include <QWidget>
#include "OsgViewerWidget.h"
#include "MyManipulator.h"
#include "osg/PolygonMode"class AnimationPathCameraMainpulator;namespace Ui {
class OsgWidget;
}class OsgWidget : public QWidget
{Q_OBJECT
public:// 模型结构体struct Element_Shell // *ELEMENT_SHELL{Element_Shell() {}qint64 eid; // 单元idqint64 pid; // 材料idqint64 n1; // 节点1,定义几何形状qint64 n2; // 节点2,定义几何形状qint64 n3; // 节点3,定义几何形状qint64 n4; // 节点4,定义几何形状qint64 n5; // 厚度,额外的节点在标准的LS-DYNA四边形壳单元定义中是没有意义的。qint64 n6; // 积分点数,额外的节点在标准的LS-DYNA四边形壳单元定义中是没有意义的。qint64 n7; // 额外的节点在标准的LS-DYNA四边形壳单元定义中是没有意义的。qint64 n8; // 额外的节点在标准的LS-DYNA四边形壳单元定义中是没有意义的。};struct Part // *PART{Part() {}qint64 pid; // 部件的id号,唯一qint64 secid; // 有*section关键字定义的section的id号QList<Element_Shell> listElementShell; // 部件片元qint64 mid; // 部件的材料号qint64 eosid; // 部件所属材料涉及的状态方程号,由*EOS关键字定义qint64 hgid; // 沙漏或体积粘性参数编号,由*HOURGLASS关键字定义,取0表示将采用默认的数值:qint64 grav; // 仅对实体单元有效,取0表示对所有PART进行重力初始化,取1表示仅对当前材料初始化qint64 adpopt; // 标识该部件是否采用自适应网格划分,取0表示不采用qint64 tmid; // 标识该部件是否采用自适应网格划分,取0表示不采用};struct Node {Node() {}qint64 nid; // 结点号,唯一double x; // 三维x坐标(全局)double y; // 三维y坐标(全局)double z; // 三维z坐标(全局)int tc; // 平动自由度受约束状态,枚举值:0-无平动约束,1-X方向平动约束,2-Y方向平动约束int rc; // 转动自由度收约束状态,枚举值:0-无转动约束,1-X方向转动约束,2-Y方向转动约束};struct K_Mode{K_Mode() {}QList<Part> listPart;QList<Node> listNode;QHash<int, Node> hashNid2Node;};// 添加模型K_Mode kMode;public:explicit OsgWidget(QWidget *parent = 0);~OsgWidget();public:bool getFixXAxis() const; // 获取X轴固定状态bool getFixYAxis() const; // 获取Y轴固定状态bool getFixZAxis() const; // 获取Z轴固定状态void getCenter(double &x, double &y, double &z);// 获取引擎中心点坐标void getPersonPoint(double &x, double &y, double &z);// 获取初始化人眼的角度(看向引擎中心点)public:void setFixXAxis(bool fixXAxis); // 设置固定X轴void setFixYAxis(bool fixYAxis); // 设置固定Y轴void setFixZAxis(bool fixZAxis); // 设置固定Z轴void setCenter(double x, double y, double z);// 设置引擎中心点坐标void setPersonPoint(double x, double y, double z);void setEnablePolygonMode(bool enable);void startAnimation();void pauseAnimation();void stopAnimation();public:bool loadKFile(QString filePath);bool loadK2File(QString filePath, int num, int x, int y, int z);void clear();void resetCoordinate();protected:void initOsg(); // osg初始化void loadNode(osg::ref_ptr<osg::Node> pNode);// 加载场景根节点protected:osg::ref_ptr<osg::Node> createScene(); // 创建总场景osg::ref_ptr<osg::Node> createAnimation(); // 创建动画protected:void resizeEvent(QResizeEvent *event);void keyPressEvent(QKeyEvent* event);void keyReleaseEvent(QKeyEvent* event);void mousePressEvent(QMouseEvent* event);void mouseReleaseEvent(QMouseEvent* event);void mouseDoubleClickEvent(QMouseEvent* event);void mouseMoveEvent(QMouseEvent* event);void wheelEvent(QWheelEvent* event);void timerEvent(QTimerEvent *event);private:Ui::OsgWidget *ui;private:OsgViewerWidget *_pViewer; // osg场景嵌入Qt核心类osg::ref_ptr<osg::MatrixTransform> _pRoot; // osg场景根节点private:float _xDistance; // x轴单个tick间距int _xTickNumber; // x轴tick数(例如:5的时候,是6个,0~5)float _yDistance; // y轴单个tick间距int _yTickNumber; // y轴tick数(例如:5的时候,是6个,0~5)float _zDistance; // z轴单个tick间距int _zTickNumber; // z轴tick数(例如:5的时候,是6个,0~5)QString _zUnit; // z轴单位float _zTickLabelOffset; // z轴坐标偏移QString _yUnit; // y轴单位float _zTickUnitLabelOffset; // z轴坐标偏移QColor _gridColor; // 轴颜色QColor _labelColor; // 轴tickLabel的颜色osg::ref_ptr<osg::Node> _pNode; // 模型osg::ref_ptr<osg::Node> _pNode2; // 子弹osg::ref_ptr<MyManipulator> _pManipulator; // 自定义漫游器osg::Vec3d _eyeVect3D; // 原始坐标,用于复位原始视角osg::Vec3d _centerVect3D; // 原始坐标,用于复位原始视角osg::Vec3d _upVect3D; // 原始坐标,用于复位原始视角K_Mode _kMode;int _timerId;osg::ref_ptr<osg::StateSet> _pStateSet;osg::ref_ptr<osg::PolygonMode> _pPolygonMode;osg::ref_ptr<osg::Vec3Array> _pVec3Array; // 炮弹bool _animationPausing;};#endif // OSGWIDGET_H
OsgWidget.cpp
bool OsgWidget::loadK2File(QString filePath, int num, int x, int y, int z)
{if(!QFile::exists(filePath)){LOG << "Not exist file:" << filePath;QMessageBox::information(0, "错误", QString("Not exist file: %1").arg(filePath));return false;}QFile file(filePath);if(!file.open(QIODevice::ReadOnly)){LOG << "Failed to open file:" << filePath;QMessageBox::information(0, "错误", QString("Failed to open file: %1").arg(filePath));return false;}kMode = K_Mode();QTextStream textStream(&file);QString context;qint64 rowIndex = -1;context = textStream.readLine();rowIndex++;LOG;...file.close();LOG;osg::ref_ptr<osg::Group> pGroup = new osg::Group;for(int index = 0; index < num; index++){LOG << index;// 绘图{for(int partIndex = 0; partIndex < kMode.listPart.size(); partIndex++){// 创建一个用户保存几何信息的对象osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;// 创建四个顶点的数组osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;// 添加四个顶点pGeometry->setVertexArray(pVec3Array.get());// 创建四种颜色的数据osg::ref_ptr<osg::Vec4Array> pVec4Array = new osg::Vec4Array;// 添加四种颜色pGeometry->setColorArray(pVec4Array.get());// 绑定颜色pGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);double r, g, b;r = qrand() % 100 * 1.0f / 100;g = qrand() % 100 * 1.0f / 100;b = qrand() % 100 * 1.0f / 100;for(int elementShellIndex = 0; elementShellIndex < kMode.listPart.at(partIndex).listElementShell.size(); elementShellIndex++){// x y zpVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).x + index * x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).y + index * y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).z + index * z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).x + index * x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).y + index * y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).z + index * z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).x + index * x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).y + index * y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).z + index * z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).x + index * x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).y + index * y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).z + index * z));// r g b a(a设置无效,估计需要其他属性配合)pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));}// 注意:此处若不绑定画笔,则表示使用之前绑定的画笔// 为唯一的法线创建一个数组 法线: normalosg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;pGeometry->setNormalArray(pVec3ArrayNormal.get());pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);pVec3ArrayNormal->push_back(osg::Vec3(0.0, -1.0, 0.0));// 由保存的数据绘制四个顶点的多边形pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, kMode.listPart.at(partIndex).listElementShell.size() * 4));// pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));// 向Geode类添加几何体(Drawable)osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;pGeode->addDrawable(pGeometry.get());
#if 0{_pStateSet = pGeometry->getOrCreateStateSet();// _pPolygonMode = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);_pPolygonMode = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL);_pStateSet->setAttribute(_pPolygonMode, osg::StateAttribute::ON);}
#endifpGroup->addChild(pGeode.get());}}}// 始终是灰色,这里需要设置关闭光照:OFF,同时旋转都能看到了(光照关闭,法向量不起作用){osg::StateSet *pStateSet = pGroup->getOrCreateStateSet();// pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);}_pNode = pGroup.get();if(_pNode.get() == 0){return false;}_pRoot->addChild(_pNode);return true;
}
工程模板v1.1.0
相关文章:

项目实战:Qt+OSG爆破动力学仿真三维引擎测试工具v1.1.0(加载.K模型,子弹轨迹模拟动画,支持windows、linux、国产麒麟系统)
若该文为原创文章,转载请注明出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/142454993 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、Op…...

CSS开发全攻略
目录 一、CSS基础入门(一)CSS概述1.CSS的定义与作用2.CSS的历史与发展3.CSS的核心概念(1)选择器(Selector)(2)声明(Declaration)(3)规…...

OpenCV运动分析和目标跟踪(3)计算图像序列的加权平均值函数accumulateWeighted()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 更新一个运行平均值。 该函数计算输入图像 src 和累积器 dst 的加权和,使得 dst 成为帧序列的运行平均值: dst ( x , y…...

vue3中echarts柱状图横轴文字太多放不下怎么解决
问题:在做数据展示的时候,使用的是echarts,遇到了个问题,就是数据过多,但是设置的x轴的文字名称又太长,往往左边第一个或右边最后一个的名称展示不全,只有半个。 从网上找到了几种办法ÿ…...

Web 开发安全与最佳实践:MVC、会话管理与常见攻击防御
1. 引言 随着 Web 应用的普及,安全问题变得尤为重要。从小型个人网站到复杂的企业级系统,安全漏洞可能导致数据泄露、服务中断甚至经济损失。因此,在 Web 开发中,采用良好的架构设计、会话管理和安全防护机制至关重要。本文将探讨…...

Segformer双显卡推理速度测试
1、4080单显卡和双显卡同步并行推理平均耗时分别为360ms、600ms;双显卡速度明显比单显卡的速度快 2、两个相机间隔500ms的并行推理耗时,单双显卡推理平均耗时为340ms 3、4080双显卡和4070双显卡同步并行推理平均耗时分别为360ms、380ms;4080比4070的速度快20ms...

使用在线电子模拟器 Wokwi 运行 ESP32 示例(Arduino IDE、ESP32C3)
文章目录 Wokwi安装客户端(Mac/Linux)创建 Token ESP32C3 示例demo.ino创建模拟器运行模拟器 Wokwi Wokwi 是一款在线电子模拟器。您可以使用它来模拟 Arduino、ESP32、STM32 以及许多其他流行的主板、部件和传感器。 Github: https://gith…...

vue3+element-plus icons图标选择组件封装
一、最终效果 二、参数配置 1、代码示例 <t-select-icon v-model"selectVlaue" />2、配置参数(Attributes)继承 el-input Attributes 参数说明类型默认值v-model绑定值string-prefixIcon输入框前缀iconstringSearchisShowSearch是否显…...

Spring validation校验框架
第1步:导入依赖 <!-- 校验框架--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency> 第2步:为需要校验的参数&…...

UBUNTU20.04安装CH384串口卡驱动
继续上文:统信UOS安装CH384串口卡驱动-CSDN博客 统信UOS系统成功安装CH384串口驱动后,继续在ubuntu20.04下安装驱动,发现一直报错,原因是内核驱动不一致。 解决办法: 1. 下载最新的驱动。CH35XCH384驱动源文件资源-C…...

JWT(JSON Web Tokens) 详细介绍
文章目录 什么是JWT?JWT的组成部分JWT的使用场景优点缺点 Java中如何实现JWT编解码引入JJWT依赖编码JWT解码JWT使用示例 什么是JWT? JWT(JSON Web Tokens)是一种用于双方之间安全传输信息的简洁的、URL安全的令牌标准。JWT可以传递信息,这…...

数据结构练习题————(二叉树)——考前必备合集!
今天在牛客网和力扣上带来了数据结构中二叉树的进阶练习题 1.二叉搜索树与双向链表———二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com) 2.二叉树遍历————二叉树遍历_牛客题霸_牛客网 (nowcoder.com) 3.二叉树的层序遍历————102. 二叉树的层序遍历 - 力扣&am…...

一天认识一个硬件之鼠标
今天来给大家分享一下鼠标的相关内容,先来分享一下什么是鼠标: 鼠标是一种计算机输入设备,用于控制屏幕上的光标移动和进行各种操作。它最早由道格拉斯恩格尔巴特在1963年发明,并在1968年12月9日制成了世界上第一个鼠标。介绍完了…...

Django 请求配置
http请求配置 请求流程 urls.py配置 from first_app import viewsurlpatterns [path(admin/, admin.site.urls),path(test/,views.first_test), ] views.py配置 from django.shortcuts import render,HttpResponse# Create your views here. def first_test(request):prin…...

轮播图组件更加完善版
依然是基于微博语法开发,使用时请注意标签替换 优化了滑动的效果,默认的索引,滑动距离等, 使用方式和以前一样没变,主要修改了组件内部 <template><wbx-view class"" style"width: 100vw;heig…...

cpu路、核、线程
路:主板插口实际插入的 CPU 个数,也可以理解为主板上支持的CPU的数量。每个CPU插槽可以插入一个物理处理器芯片。例如,一台服务器可能有2路或4路插槽,这意味着它最多可以安装2个或4个物理处理器。 核:单块 CPU 上面能…...

鸿蒙开发(NEXT/API 12)【硬件(注册出行业务事件监听)】车载系统
注册出行业务事件监听,用于接收业务发送事件的通知。 接口说明 接口名描述[on] (type: ‘smartMobilityEvent’, smartMobilityTypes: SmartMobilityType[],callback: Callback): void应用注册出行业务事件监听。 开发步骤 导入Car Kit模块。 import { smartMobi…...

安卓中有main函数吗?
在标准的Android应用程序开发中,并不直接使用类似于传统Java或C程序中的main函数入口点。Android应用程序是基于组件的架构,它依赖于几个关键组件来执行不同的任务,这些组件包括Activity、Service、Broadcast Receiver和Content Provider。 …...

js-17-对数组、对象进行浅拷贝和深拷贝
目录 数组一、浅拷贝1. 展开运算符...2. Array.prototype.slice() 二、深拷贝1. JSON方法2. 递归函数 对象一、浅拷贝1. Object.assign()2. 展开运算符... 二、深拷贝1. JSON方法2. 递归函数 自己总结的一些方法,可能有不到位的地方,欢迎指出 数组 一、…...

Ubuntu24.04中安装Electron
1. 安装Nodejs 使用代理服务从github下载并执行Nodejs安装脚本(假设代理服务器为192.168.2.150:10792) curl -x 192.168.2.150:10792 -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash #注意,Nodejs官网的安装命令少了下面这一行: …...

CPU中也应用到了缓存:CPU3层高速缓存,以及它的缓存一致性问题、MESI协议和Java的一些应用
为什么需要cpu高速缓存? 缓存,一般是为了用来协调两端的数据传输效率差(也可以归纳为性能差),提升响应速度。那么CPU的高速缓存是用来协调什么之间的速度差呢? CPU在处理一条指令的时候,会读写…...

如何使用开发者工具捕获鼠标右键点击事件
要使用浏览器的开发者工具捕获鼠标右键点击事件,请按照以下步骤操作: 打开开发者工具 在大多数浏览器中,您可以按 F12 键或右键单击页面并选择"检查"或"检查元素"。 切换到 Console 标签页 在开发者工具中,找到并点击 “Console” 标签。 添加事件监听器…...

【几何】个人练习-Leetcode-1453. Maximum Number of Darts Inside of a Circular Dartboard
题目链接:https://leetcode.cn/problems/maximum-number-of-darts-inside-of-a-circular-dartboard/description/ 题目大意:给出一系列点和一个圆的半径,(寻找一个圆心)求这个半径的圆最多能覆盖多少个点。 思路&…...

啤酒:从饮品到文化的演变
在人类饮品的长河中,啤酒以其不同的魅力走过了一段漫长的历史旅程。它不仅仅是一种简单的饮品,更是一种文化的象征,一种生活的态度。今天,我们将一起追溯啤酒从单一的饮品到丰富文化的演变过程,并感受Fendi Club精酿啤…...

Java 中 Map 常用类和数据结构详解
1. 引言 在Java编程中,Map是一种重要的数据结构,广泛应用于各种场景,Map实现了键值对(key-value)的存储方式,使得开发者能够快速检索、更新和操作数据。本篇文章将详细讲解Java中常用的Map类及其底层数据结…...

实时监控,动态调整 —— 淘宝商品详情API助力商家实现灵活经营
在讨论实时监控和动态调整的策略时,虽然我不能直接提供淘宝商品详情API的具体代码(因为这通常涉及商业机密和API密钥等敏感信息),但我可以给出一个概念性的示例,说明如何使用这类API来辅助商家实现灵活经营。 概念性示…...

WebGL常用接口和事件
目录 初始化WebGL上下文清除缓冲区缓冲区对象着色器和程序属性指针渲染事件监听错误处理纹理映射...

Golang | Leetcode Golang题解之第429题N叉树的层序遍历
题目: 题解: func levelOrder(root *Node) (ans [][]int) {if root nil {return}q : []*Node{root}for q ! nil {level : []int{}tmp : qq nilfor _, node : range tmp {level append(level, node.Val)q append(q, node.Children...)}ans append(a…...

数据库的全透明加密和半透明加密主要是针对数据存储安全的不同处理方式
数据库的全透明加密和半透明加密主要是针对数据存储安全的不同处理方式。 全透明加密(也称作无损加密或自动加密)就像是给文字戴上了一层无形的面具。在用户看来,他们在数据库中输入的是明文(比如姓名、密码)…...

MySQL的登录、访问、退出
一、登录: 访问MySQL服务器对应的命令:mysql.exe ,位置:C:\Program Files\MySQL\MySQL Server 8.0\bin (mysql.exe需要带参数执行,所以直接在图形界面下执行该命令会自动结束) 执行mysql.exe命令的时候出…...