基于OpenCASCADE自制三维建模软件(十一)使用ASSIMP导入导出

2019年08月06日 23:54:20 Jelly_Lee2 阅读数 73 文章标签: 三维建模CADOpenCASCADEOCC 更多

分类专栏: 基于OpenCASCADE自制三维建模软件

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/jelatine/article/details/98611472

文章目录

  • 一、导入模型
  • 二、导出模型
  • 项目仓库

一、导入模型

  1. 打开导入对话框
    首先从Assimp::Importer中获取ASSIMP支持导入的文件格式,然后用QFileDialog::getOpenFileName函数弹出文件对话框。
// cmainwindow.cpp
void CMainWindow::on_actionImport_triggered()
{// 获取ASSIMP支持的导入格式Importer t_importer;std::string szOut;t_importer.GetExtensionList(szOut); // ASSIMP支持的导入格式// 筛选文件格式QString t_assimp=tr("ASSIMP (") +QString::fromStdString(szOut) +tr(")");QString all_filter;all_filter+=t_assimp;// 获取被打开的文件路径QString filename = QFileDialog::getOpenFileName(this,tr("open file"),"D:/models",all_filter);...
}

其中Assimp::Importer的成员函数 GetExtensionList原型如下,通过它获取ASSIMP支持的所有文件扩展名的完整列表,输出到szOut中,比如"*.3ds;*.obj;*.dae

inline void GetExtensionList(std::string& szOut) const;

使用QFileDialog::getOpenFileName函数显示导入文件框。

显示结果:

  1. 获取模型内容

构造函数

// cmodel.cpp
// CModel::CModel
{...//从外部文件中加载模型Importer t_importer;const aiScene *t_scene=t_importer.ReadFile(_filepath.toStdString(),aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);if(!t_scene || t_scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !t_scene->mRootNode) // if is Not Zero{qDebug() << "ERROR::ASSIMP:: " << t_importer.GetErrorString();return;}// 构造根节点及所有子节点m_process_nodes(t_scene->mRootNode, t_scene, true);
}

将模型的文件路径输入到Assimp::Importer的成员函数ReadFile中,返回场景aiScene结构体。把结构体放入m_process_nodes函数中处理场景的节点。

  1. 处理节点

获取坐标信息

// cmodel.cpp
// CModel::m_process_nodesaiMatrix4x4 t_matrix=_node->mTransformation;    // 获取转换坐标系// 获取旋转矩阵的缩放比例ai_real t_scaling_x = aiVector3D(t_matrix.a1,t_matrix.a2,t_matrix.a3).Length();ai_real t_scaling_y = aiVector3D(t_matrix.b1,t_matrix.b2,t_matrix.b3).Length();ai_real t_scaling_z = aiVector3D(t_matrix.c1,t_matrix.c2,t_matrix.c3).Length();// 从 aiMatrix4x4 转换成 gp_Trsf 形式gp_Trsf t_transfer;t_transfer.SetValues(t_matrix.a1 / t_scaling_x, t_matrix.a2 / t_scaling_x, t_matrix.a3 / t_scaling_x, t_matrix.a4,t_matrix.b1 / t_scaling_y, t_matrix.b2 / t_scaling_y, t_matrix.b3 / t_scaling_y, t_matrix.b4,t_matrix.c1 / t_scaling_z, t_matrix.c2 / t_scaling_z, t_matrix.c3 / t_scaling_z, t_matrix.c4);

遍历节点的所有网格(Mesh)

// cmodel.cpp
// void CModel::m_process_nodes(const aiNode *_node, const aiScene *_scene, bool _is_root)for(unsigned int imesh = 0; imesh < _node->mNumMeshes; imesh++){aiMesh* t_mesh = _scene->mMeshes[_node->mMeshes[imesh]];    // 获取当前网格// 遍历网格的所有面for(unsigned int iface = 0; iface < t_mesh->mNumFaces; iface++){t_mesh->mMaterialIndex;aiFace t_face = t_mesh->mFaces[iface];BRepBuilderAPI_MakePolygon t_polygon;// 遍历面的所有顶点for(unsigned int ivertex = 0; ivertex < t_face.mNumIndices; ivertex++){// 转换顶点储存模式gp_Pnt t_pnt=gp_Pnt(t_mesh->mVertices[t_face.mIndices[ivertex]].x,t_mesh->mVertices[t_face.mIndices[ivertex]].y,t_mesh->mVertices[t_face.mIndices[ivertex]].z);t_polygon.Add(t_pnt);   // 添加顶点}t_polygon.Close();  // 闭合顶点t_topo_face = BRepBuilderAPI_MakeFace (t_polygon); // 通过闭合的线构造面if(!t_topo_face.IsNull()){t_build_tool.Add (t_compound, t_topo_face);  // 将面加入到复合体中}}//! 材质信息aiMaterial* material = _scene->mMaterials[t_mesh->mMaterialIndex];   //通过索引获取网格在环境中的材质t_occ_material = m_material_transfer(material); // 从ASSIMP格式转换到OCC材质格式}

遍历子节点

// cmodel.cpp
// void CModel::m_process_nodes(const aiNode *_node, const aiScene *_scene, bool _is_root)for(unsigned int i = 0; i < _node->mNumChildren; i++){m_process_nodes(_node->mChildren[i], _scene , t_is_next_root);   // 构造子节点}
  1. 获取材质及转换

上一节中使用了m_material_transfer函数将ASSIMP的aiMaterial结构体内容转换到OpenCASCADE中的Graphic3d_MaterialAspect形式。

初始化OpenCASCADE材质

// cmodel.cpp
// Graphic3d_MaterialAspect CModel::m_material_transfer(aiMaterial *_material)Graphic3d_MaterialAspect t_result;t_result.SetMaterialType(Graphic3d_MATERIAL_PHYSIC);Quantity_Color t_occ_colors[Graphic3d_TypeOfReflection_NB];t_occ_colors[Graphic3d_TOR_AMBIENT]  = Quantity_Color (Graphic3d_Vec3 (0.2f, 0.2f, 0.2f));t_occ_colors[Graphic3d_TOR_DIFFUSE]  = Quantity_Color (Graphic3d_Vec3 (0.2f, 0.2f, 0.2f));t_occ_colors[Graphic3d_TOR_SPECULAR] = Quantity_Color (Graphic3d_Vec3 (1.0f, 1.0f, 1.0f));Standard_ShortReal t_occ_shininess = 0.039f;

获取各种数据,包括名称、环境光、漫反射、镜面光、反光度

// cmodel.cpp
// Graphic3d_MaterialAspect CModel::m_material_transfer(aiMaterial *_material)aiString name;  // 材质名称 原始数据if (AI_SUCCESS==aiGetMaterialString(_material,AI_MATKEY_NAME,&name)){t_result.SetMaterialName(name.C_Str());}// 环境光aiColor4D ambient;      // 环境光 原始数据if(AI_SUCCESS ==aiGetMaterialColor(_material, AI_MATKEY_COLOR_AMBIENT, &ambient)){t_occ_colors[Graphic3d_TOR_AMBIENT]=Quantity_Color(ambient.r,ambient.g,ambient.b,Quantity_TOC_RGB);t_result.SetAmbientColor(t_occ_colors[Graphic3d_TOR_AMBIENT]);}// 漫反射aiColor4D diffuse;      // 漫反射 原始数据if(AI_SUCCESS ==aiGetMaterialColor(_material, AI_MATKEY_COLOR_DIFFUSE, &diffuse)){t_occ_colors[Graphic3d_TOR_DIFFUSE]=Quantity_Color(diffuse.r,diffuse.g,diffuse.b,Quantity_TOC_RGB);t_result.SetDiffuseColor(t_occ_colors[Graphic3d_TOR_DIFFUSE]);}// 镜面光aiColor4D specular;     // 镜面光 原始数据if(AI_SUCCESS ==aiGetMaterialColor(_material, AI_MATKEY_COLOR_SPECULAR, &specular)){t_occ_colors[Graphic3d_TOR_SPECULAR]=Quantity_Color(specular.r,specular.g,specular.b,Quantity_TOC_RGB);t_result.SetSpecularColor(t_occ_colors[Graphic3d_TOR_SPECULAR]);}// 反光度float shininess;        // 反光度 原始数据if(AI_SUCCESS ==aiGetMaterialFloat(_material, AI_MATKEY_SHININESS, &shininess)){t_occ_shininess=shininess/128.0;    // 由OpenGL值转换成VRML97// OCC的反光度表示方式只接受0到1之间,否则报错t_occ_shininess = t_occ_shininess<1.0 ? t_occ_shininess:1.0;t_occ_shininess = t_occ_shininess<0.0 ? 0.0:t_occ_shininess;t_result.SetShininess(t_occ_shininess); // 设置反光度}
  1. 导入模型结果
    打开菜单栏File->Import,弹出文件对话框后选择模型文件并打开。

二、导出模型

  1. 打开导出对话框

首先判断是否有模型被选择,若无模型则提示框

// cmainwindow.cpp
// void CMainWindow::on_actionExport_triggered()if(m_3d_widget->m_get_context()->NbSelected() == 0){// 无选择则弹出提示框QMessageBox::warning(this,tr("Export Error"),tr("There is no object selected!"));return; // 不执行操作}

通过Assimp::ExporterGetExportFormatCount函数获取支持格式的数量,然后遍历及通过GetExportFormatDescription函数获取所有格式的结构体,结构体内包含:①id唯一标识;②description格式描述;③fileExtension文件扩展名
另外通过哈希表储存文件过滤字符串与文件格式id的对应关系,以在后面用作区分用户选择的文件格式id

// cmainwindow.cpp
// void CMainWindow::on_actionExport_triggered()QString t_all_filter; // 所有文件过滤器QHash<QString,const char *> t_hash_format;  // 格式过滤器与文档描述哈希表Exporter t_export;  // 导出器for(int i=0; i<t_export.GetExportFormatCount(); i++)    // 遍历ASSIMP允许导出的格式{const aiExportFormatDesc *t_format_desc = t_export.GetExportFormatDescription(i);   // 获取每个文档描述// 文档过滤器QString t_single_format = QString(t_format_desc->description)+QString("(*.%1)").arg(t_format_desc->fileExtension);t_hash_format.insert(t_single_format,t_format_desc->id);    // 插入格式过滤器与文档描述哈希表t_all_filter += t_single_format;    // 添加单个文档过滤到整体过滤器if(i != t_export.GetExportFormatCount()-1)  // 最后一个不添加分行{t_all_filter+=";;"; // 分行}}

打开保存文件对话框,通过返回值filename获得保存的文件名,并通过t_selected_filter获取用户选择的过滤器

// cmainwindow.cpp
// void CMainWindow::on_actionExport_triggered()QString t_selected_filter; // 被选择的过滤器// 打开文件保存提示框QString filename = QFileDialog::getSaveFileName(this,tr("Save"),".",t_all_filter,&t_selected_filter);if(filename.isEmpty())  // 若文件名为空,则不执行操作{return; // 不执行操作}

在对话框点击保存后,进行实质的文件保存操作

// cmainwindow.cpp
// void CMainWindow::on_actionExport_triggered()   // 导出模型文件CModel::m_export_model(filename,t_hash_format.value(t_selected_filter),m_3d_widget->m_get_context());

运行结果:

  1. 导出操作

初始化参数

// cmodel.cpp
// static bool m_export_model(QString _filename , const char *_format_id,Handle(AIS_InteractiveContext) _context);Exporter exporter;// 定义场景aiScene *t_scene = new aiScene();// 单一材质// 创建根节点t_scene->mRootNode=new aiNode();// 创建子节点int t_NumChildrenNode = _context->NbSelected();aiNode **t_node_list=new aiNode*[t_NumChildrenNode];t_scene->mNumMaterials=t_NumChildrenNode;t_scene->mMaterials = new aiMaterial*[t_NumChildrenNode];// 定义场景所有网格t_scene->mNumMeshes = t_NumChildrenNode;t_scene->mMeshes = new aiMesh*[t_NumChildrenNode];int t_index = 0;

遍历所有选择的模型

// cmodel.cpp
// static bool m_export_model(QString _filename , const char *_format_id,Handle(AIS_InteractiveContext) _context);for ( _context->InitSelected(); _context->MoreSelected(); _context->NextSelected() ){aiNode *t_node = t_node_list[t_index] = new aiNode();t_node->mNumMeshes=1;   // 一个网格t_node->mNumChildren=0; // 无子节点t_node->mMeshes = new uint[1];  //一个网格地址t_node->mMeshes[0] = t_index; // 网格地址索引aiMesh* pMesh = t_scene->mMeshes[t_index] = new aiMesh(); // 创建地址0的网格pMesh->mMaterialIndex = t_index;  // 网格材质Standard_Integer aNbNodes = 0;Standard_Integer aNbTriangles = 0;Handle(AIS_InteractiveObject) obj = _context->SelectedInteractive();......}

在以上遍历模型的循环内,添加材质参数到ASSIMP中

// cmodel.cpp
// static bool m_export_model(QString _filename , const char *_format_id,Handle(AIS_InteractiveContext) _context);
// for ( _context->InitSelected(); _context->MoreSelected(); _context->NextSelected() )Handle(AIS_Shape) ais_shape = Handle(AIS_Shape)::DownCast(obj);Graphic3d_MaterialAspect shpae_material(ais_shape->Material());aiMaterial* pMaterial = t_scene->mMaterials[t_index] = new aiMaterial();Quantity_Color amb=shpae_material.AmbientColor();aiColor4D ambient(amb.Red(),amb.Green(),amb.Blue(),1.0);pMaterial->AddProperty(&ambient,1,AI_MATKEY_COLOR_AMBIENT);Quantity_Color diff=shpae_material.DiffuseColor();aiColor4D diffuse(diff.Red(),diff.Green(),diff.Blue(),1.0);pMaterial->AddProperty(&diffuse,1,AI_MATKEY_COLOR_DIFFUSE);Quantity_Color spec=shpae_material.SpecularColor();aiColor4D specular(spec.Red(),spec.Green(),spec.Blue(),1.0);pMaterial->AddProperty(&specular,1,AI_MATKEY_COLOR_SPECULAR);Standard_ShortReal shin=shpae_material.Shininess();pMaterial->AddProperty(&shin,1,AI_MATKEY_SHININESS);

分别计算模型中的节点和三角面的数量

// cmodel.cpp
// static bool m_export_model(QString _filename , const char *_format_id,Handle(AIS_InteractiveContext) _context);
// for ( _context->InitSelected(); _context->MoreSelected(); _context->NextSelected() )TopoDS_Shape theShape = ais_shape->Shape();// calculate total number of the nodes and trianglesfor (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next()){TopLoc_Location aLoc;Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);if (! aTriangulation.IsNull()){aNbNodes += aTriangulation->NbNodes ();aNbTriangles += aTriangulation->NbTriangles ();}}pMesh->mNumVertices = aNbNodes;pMesh->mNumFaces = aNbTriangles;

把所有三角面与定点信息添加到ASSIMP中

// cmodel.cpp
// static bool m_export_model(QString _filename , const char *_format_id,Handle(AIS_InteractiveContext) _context);
// for ( _context->InitSelected(); _context->MoreSelected(); _context->NextSelected() )int index=0;int face_index=0;// fill temporary triangulationStandard_Integer aNodeOffset = 0;for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next()){TopLoc_Location aLoc;Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes();const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles();// copy nodesgp_Trsf aTrsf = aLoc.Transformation();for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter){gp_Pnt aPnt = aNodes (aNodeIter);aPnt.Transform (aTrsf);qDebug()<<"nodes "<<aPnt.X()<<aPnt.Y()<<aPnt.Z();vp[index].Set(aPnt.X(),aPnt.Y(),aPnt.Z());vn[index].Set(0.0,0.0,1.0);index++;}// copy trianglesconst TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();for (Standard_Integer aTriIter = aTriangles.Lower(); aTriIter <= aTriangles.Upper(); ++aTriIter){Poly_Triangle aTri = aTriangles (aTriIter);Standard_Integer anId[3];aTri.Get (anId[0], anId[1], anId[2]);if (anOrientation == TopAbs_REVERSED){// Swap 1, 2.Standard_Integer aTmpIdx = anId[1];anId[1] = anId[2];anId[2] = aTmpIdx;}// Update nodes according to the offset.anId[0] += aNodeOffset;anId[1] += aNodeOffset;anId[2] += aNodeOffset;aiFace& face = pMesh->mFaces[face_index++];face.mIndices = new unsigned int[face.mNumIndices = 3];face.mIndices[0]=anId[0]-1;face.mIndices[1]=anId[1]-1;face.mIndices[2]=anId[2]-1;}aNodeOffset += aNodes.Size();}t_index++;

完善aiScene结构体的内容,使用Assimp::ExporterExport方法将t_scene对象的内容保存到文件中,文件格式以_format_id参数决定

// cmodel.cpp
// static bool m_export_model(QString _filename , const char *_format_id,Handle(AIS_InteractiveContext) _context);// 根节点加入子节点t_scene->mRootNode->addChildren(t_NumChildrenNode,t_node_list);exporter.Export(t_scene , _format_id , _filename.toStdString());
  1. 导出模型文件效果
    打开菜单栏File->Export,弹出文件对话框后选择文件路径、输入文件名并点击保存。

    输出后的文件内容

项目仓库

https://github.com/Jelatine/JellyCAD

基于OpenCASCADE自制三维建模软件(十一)使用ASSIMP导入导出相关推荐

  1. 基于OpenCASCADE自制三维建模软件(六)瓶子模型例程

    文章目录 概述 预备知识 模型 规格 一.构建轮廓 定义支持点 定义几何图形 定义拓扑结构 完成轮廓 二.构建瓶身 拉伸轮廓 倒角 添加瓶颈 创造中空的实体 三.构建螺纹 创建表面 定义二维曲线 创建 ...

  2. 基于OpenCASCADE自制三维建模软件(三)搭建开发环境

    文章目录 一.参考环境 二.安装Qt与VS2015 三.OCC第三方库介绍 1. Tcl 2. FreeType 2 3. FreeImage 4. FFmpeg 5. TBB 6. VTK 四.安装 ...

  3. 基于OpenCASCADE自制三维建模软件(五)鼠标模式

    文章目录 一.选择导航模式 二.平移 三.缩放 四.旋转 五.实际效果 项目仓库 鼠标控制模式用于三维空间可视化导航,通过鼠标的按键及少数键盘按键的组合,可以实现对三维视图的平移.缩放.选择等操作. ...

  4. 基于OpenCASCADE自制三维建模软件(四)实现三维显示界面

    文章目录 一.配置系统变量及QMake文件 二.创建界面 三.编译并运行项目 四.问题处理 项目仓库 一.配置系统变量及QMake文件 在系统环境变量中添加CASROOT变量,将OpenCASCADE ...

  5. 基于OpenCASCADE自制三维建模软件(七)立方体、圆柱、球、圆锥、圆环

    文章目录 一.立方体 1.构造 2.实例 二.圆柱 1.构造 2.实例 三.球 1.构造 2.实例 四.圆锥 1.构造 2.实例 五.圆环 1.构造 2.实例 项目仓库 Open CASCADE有现成 ...

  6. 轻便易用的三维建模软件

    用python写了个简易的三维建模软件Draft,抛砖引玉一下,小伙伴们可以在此基础上完善功能.采用wxPython库和OpenGL,由于OpenGL只支持Linux,所以软件的编写调试运行都是在Li ...

  7. Rhinoceros mac版(犀牛三维建模软件)中文版

    犀牛Rhinoceros mac版是非常受欢迎的一款三维建模软件,rhinoceros mac 中文版可应用于三维动画制作.机械设计.建筑设计.工业制造等,具备全面的NURBS.网格.分析.制图等工具 ...

  8. 【第三课】UAV倾斜摄影测量三维建模软件

    前言 各大厂商的UAV管家软件可以直接将航拍影像下载到电脑,当我们获得航片之后,检查像片质量和数量是否和之前规划的一致,像片质量如何?是否存在质量较差的影像.如果存在大面积的航片质量不佳,那么需要补飞 ...

  9. 三维建模软件的插件安装教程——3D Max

    大家在使用三维建模软件3D Max的时候一定遇到过插件不知道如何安装的情况,今天我将把常用插件的类型和扩展名罗列如下方便大家安装收集也算抛砖引玉望各位高手查漏补缺不吝赐教. 3DSMAX的插件名后缀主 ...

最新文章

  1. Mysql4种方式避免重复插入数据!
  2. category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性
  3. node内存配置(--max-old-space-size)
  4. 用NPOI从DataBase到Excel '2
  5. 全球44家机构,55位大佬,历时两年,打造最强NLG评测基准!
  6. android 开发 佳博打印模板_电商在打印快递电子面单时的常见问题及解决方法
  7. CCS6的graph变灰解决办法
  8. 迈高图手机版_迈高图最新版
  9. 教你ogg怎么转mp3格式
  10. Firefox浏览器修改背景颜色为豆沙绿
  11. 计算机的认识文档,对计算机专业的认识.pdf
  12. Java验证图片格式
  13. Ubuntu14.04/16.0 安装N卡驱动
  14. 错误代码warning C4013: ‘sqrt‘ undefined; assuming extern returning int怎么解决?
  15. 解决方案的四种落地形态
  16. 关于在node项目使用ioredis遇到的几个坑
  17. “碳中和”研究为什么需要气象数据
  18. 力扣解题思路:488. 祖玛游戏
  19. OpenLayers 6.13 新特性
  20. mysql一列数除以一列数和_MySQL查询将列除以100?

热门文章

  1. CDMA 1X WAP2.0业务网 设备实施规范 (V1.0)
  2. 天下布魔新手的6点游戏建议 教你快速入门的攻略
  3. STM32启动文件的分析
  4. GD32F450创建工程模板
  5. type 和 interface的区别
  6. CVSS得分计算公式
  7. MySQL 8.0安装教程及数据库可视化
  8. (转)一些经典的计算机书籍
  9. 这份“插件英雄榜Top40”才是Chrome的正确打开方式!(Github7000+ Stars)
  10. 软件工程师应具备的素质