OSG开发笔记(三十):OSG加载动力学仿真K模型文件以及测试Demo
前言
Osg需要打开模型文件,但是遇到显示动力学仿真的K模型文件,.k文件是一种描述材料属性的文件,比如密度、弹性模量等,该模型文件不是常规中间开放格式,无法直接支持,需要自定义解析并且重建三维模型。
Demo
实际非常流程,因为视频转gif导致部分看起来不行:



交互流畅性测试
实际研发需要用不同的策略进行在不影响视觉观感的前提下,进行模型展示优化处理,本次测试直接copy多份模型加载:
172万多个四边形,丝滑

344万多个四边形,丝滑

518万多个四边形,开始稍微有点卡顿了

691万多个四边形,开始更不利索了
此时翻倍就在加载场景崩溃,这个崩溃确认代码没问题,是运行内存较大了,加大运行时内存配置:
QMAKE_LFLAGS_WINDOWS += /LARGEADDRESSAWARE
运行成功,交互更卡一点。

更大又不行了:

注意
分析的是本文件解析,可能包含数据格式关键字不全。

实际遇到的为:*TITLE,*PART,*ELEMENT_SHELL,*NODE, *END。
(PS:以后项目上遇到了再另起篇章补充。)
K文件
概览
.k文件是一种描述材料属性的文件,比如密度、弹性模量等。
打开其的软件LS-DYNA和LSPREPOST
- LS-DYNA
LS-DYNA程序(最新版本17.2版)是功能齐全的几何非线性(大位移、大转动和大应变)、材料非线性(140多种材料动态模型)和接触非线性(50多种)程序。它以Lagrange算法为主,兼有ALE和Euler算法;以显式求解为主,兼有隐式求解功能;以结构分析为主,兼有热分析、流体-结构耦合功能;以非线性动力分析为主,兼有静力分析功能(如动力分析前的预应力计算和薄板冲压成型后的回弹计算);军用和民用相结合的通用结构分析非线性有限元程序,是显式动力学程序的鼻祖和先驱。 - LSPREPOST
lsprepost是一套专为LS-DYNA开发的高级有限元前后处理软件,上线时间是1976年1月1日。
文件内容概览
文件整体概览如下:

以上所知,分为六个关键字,分割为五个区域,归属关系如下:

关键字:*KEYWORK
关键字:*TITLE
关键字:*PART
PART关键字来定义部件及其相关特性

第一行为title属性,为标题,没有实际意义。

关键字:*ELEMENT_SHELL
SECTION系列关键字指定所采用的单元算法、积分分规则及各种几何参数(壳单元的厚度、梁单元的截面信息参数等),对不同的单元类型,或者需要相应的SECTION关键字段来定义单元的算法和参数。
*SECTION_SEHLL定义单壳体单元的特性。这些属性对于模拟如汽车碰撞、航空航天结构、以及任何涉及薄壳结构动态响应的模拟都至关重要。然而,具体到ELEMENT_SHELL属性在K文件中的详细内容和格式,可能因LS-DYNA的版本和具体应用而有所不同。


关键字:*NODE
*NODE关键字来定义结构模型的每一节点及其在总体直角坐标系中的坐标及受约束情况,该关键字段包含如下的变量信息:


然后部件与node的对应关系,通过索引对应:

解析文件即可。
关键字:*END
表示文件结束。
测试加载K文件


Demo关键源码
模型结构体
// 模型结构体
struct Element_Shell // *ELEMENT_SHELL
{
Element_Shell() {
}
qint64 eid; // 单元id
qint64 pid; // 材料id
qint64 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;
};
绘制部分
osg::ref_ptr<osg::Group> pGroup = new osg::Group;
// 绘图
{
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 z
#if 0
pVec3Array->push_back(osg::Vec3( 1.0, 0.0, 0.0));
pVec3Array->push_back(osg::Vec3( 3.0, 0.0, 0.0));
pVec3Array->push_back(osg::Vec3( 3.0, 0.0, 1.0));
pVec3Array->push_back(osg::Vec3( 1.0, 0.0, 1.0));
#endif
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).x,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).y,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).z));
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).x,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).y,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).z));
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).x,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).y,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).z));
pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).x,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).y,
kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).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));
}
// 注意:此处若不绑定画笔,则表示使用之前绑定的画笔
// 为唯一的法线创建一个数组 法线: normal
osg::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());
{
osg::ref_ptr<osg::StateSet> pStateSet = pGeometry->getOrCreateStateSet();
osg::ref_ptr<osg::PolygonMode> pPolygonMode = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
pStateSet->setAttribute(pPolygonMode);
}
pGroup->addChild(pGeode);
}
}
工程模板:对应版本号v1.32.0

入坑
入坑一:绑定颜色不出来
问题
去掉纹理后颜色不出来,显示一直灰色。
原理
开启光照,就颜色不出来,需要关闭
解决
// 始终是灰色,这里需要设置关闭光照:OFF
osg::StateSet *pStateSet = pGroup->getOrCreateStateSet();
pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
//pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);



入坑二:运行起来就崩溃
问题
数据都加载绘制时,运行就崩溃
解决过程
- 步骤一:先减少面数量,发现小于一档数量可以没问题,初步怀疑绘制太多,但是osg本身做深度测试相关很不错,除非时内存爆了,所以应然需要继续。
- 步骤二:使用绘制四边形的,绘制10000个也会崩,加重了内存怀疑。
- 步骤三:由于之前对于顶点颜色没有进行全部点绑定,其他的看纹理的方式都是重复的,所以这块就直接只设置了4个点,但本次去掉颜色之后,发现是可以的。
- 步骤四:将颜色给他赋值上,一个部件一个纯色,把对应绑定点都补上,发现没问题
原因
就是因为绑定颜色角点,只绑定了四个,按道理来说就算其越界也只是读取的乱值,颜色是乱的,但是点多了就不行了,所以这里还是需要一一对应,不偷懒。
解决
颜色单独,每一个部件一个颜色,然后循环内一一对应:

OSG开发笔记(三十):OSG加载动力学仿真K模型文件以及测试Demo的更多相关文章
- Android开发笔记——以Volley图片加载、缓存、请求及展示为例理解Volley架构设计
Volley是由Google开源的.用于Android平台上的网络通信库.Volley通过优化Android的网络请求流程,形成了以Request-RequestQueue-Response为主线的网 ...
- SpringBoot入门笔记(三)、热加载
1.配置热加载环境,在pom.xml添加如下代码 <build> <!--springloader plugin --> <plugins> <plugin& ...
- Away3D 学习笔记(一): 加载3DS格式的模型文件
加载外部的3DS文件分为两种: 1: 模型与贴图独立于程序的,也就是从外部的文件夹中读取 private function load3DSFile():Loader3D { loader = new ...
- Java开发学习(三十二)----Maven多环境配置切换与跳过测试的三种方式
一.多环境开发 我们平常都是在自己的开发环境进行开发, 当开发完成后,需要把开发的功能部署到测试环境供测试人员进行测试使用, 等测试人员测试通过后,我们会将项目部署到生成环境上线使用. 这个时候就有一 ...
- AngularJS进阶(三十)AngularJS项目开发技巧之图片预加载
AngularJS项目开发技巧之图片预加载 绪 项目(移动端采用Ionic 框架)开发完毕,测试阶段发现移动APP首页的广告图片(图片由服务器端返回相应url地址)很难加载,主要原因还是网速.如下图左 ...
- World Wind Java开发之十二——加载粗制三维模型(ExtrudedPolygon)(转)
ww可以根据DLG图批量生成假三维模型,这对于小区等特征相似的建筑物模型的构建是非常有用的.下面来看如何一步步实现假三维模型的加载: 1.Shp文件的制作 首先在arcmap下数字化几个建筑物,并新建 ...
- Android UI开发第三十九篇——Tab界面实现汇总及比较
Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...
- Java开发学习(三十六)----SpringBoot三种配置文件解析
一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...
- arcgis三维球中加载2000坐标系出现错误(The tiling scheme of this layer is not supported by SceneView)
目前我们国家测绘地理信息的坐标体系基准是国家2000坐标系CGCS2000.各类地图组件如OpenLayers.Mapbox.Cesuim和ArcGIS Javascrip等都主要是支持WGS84(w ...
- Unity开发实战探讨-资源的加载释放最佳策略简要心得
Unity开发实战探讨-资源的加载释放最佳策略简要心得 看过我另外一篇关于Unity资源释放随笔<Unity开发实战探讨-资源的加载释放最佳策略>如果觉得略微复杂,那么下面是一些比较简要的 ...
随机推荐
- CGI、FastCGI和PHP-FPM区别和关系详解
在搭建 LAMP/LNMP 服务器时,会经常遇到 PHP-FPM.FastCGI和CGI 这几个概念.如果对它们一知半解,很难搭建出高性能的服务器.接下来我们就以图形方式,解释这些概念之间的关系. 1 ...
- workman和swoole区别和异同
swoole是使用C语言实现的socket通信框架,workerman则是使用纯php实现的socket框架,二者进程模型上也存在很多的不同. 先说下swoole的进程模型,看一下以下解析图 mast ...
- oeasy教您玩转vim - 47 - # 使用标记
使用标记 回忆上节课内容 有了这个range.address我们可以做很多事情 跳转:44 复制和剪切 1,3d 3,$y %d o 配合搜索 /oeasy/,$y 5;/oeasy/d 其实还有 ...
- 《最新出炉》系列入门篇-Python+Playwright自动化测试-55- 上传文件 (非input控件)- 中篇
1.简介 在实际工作中,我们进行web自动化的时候,文件上传是很常见的操作,例如上传用户头像,上传身份证信息等.所以宏哥打算按上传文件的分类对其进行一下讲解和分享. 2.上传文件的API(非input ...
- 假期小结8XML之LXML
这桌我初步学习了爬虫相关知识的python库LXML的一些基本用法 以下是我的部分总结 lxml是Python中一个流行的第三方库,用于处理XML和HTML数据.它提供了高效且易于使用的工具,使你能够 ...
- python的Faker使用
import json from faker import Faker from faker_demo.CustomFaker import CustomProvider myfaker = Fake ...
- idea2020修改help的vm options之后导致idea打不开的问题
如图所示,如果你修改了VM参数,导致启动没反应,证明你的参数配置有误. 这个时候你可能会想着直接修改idea安装目录bin中的配置文件,但是这个文件并不是你在idea中修改的配置文件,所以你修改这里的 ...
- 【Java】Input,Output,Stream I/O流 04 对象流&序列化
对象流,序列化机制 ObjectInputStream ObjectOutputStream 序列化 对象 写入转 数据 持久化 反序列化 数据 读取转 对象 活化 - 任何实现了Serializab ...
- 【RabbitMQ】13 消息补偿 & 幂等保障
https://www.bilibili.com/video/BV15k4y1k7Ep?p=34 我靠,幂等保障就是乐观锁控制啊 https://www.bilibili.com/video/BV15 ...
- 【SVN】文件解锁
提交代码莫名其妙的把文件上锁了 然后找到文件右键的SVN的选项也不能解锁: 原来是这样解锁的: 对上锁文件的所在目录右键找到SVN选项 然后勾选第二项: 这样就解锁了.如果还说没有解锁,说明是对方自己 ...