记录下开发过程

  • mesh转OBJ格式
  • mesh转STL格式
    • 二进制格式(UG打开正常)
    • ASCII格式(UG打开报错)
  • 调用win窗口
    • 导入
    • 导出
    • 注意事项

背景:客户想在UG中打开编辑好的模型,UG不支持obj格式。mesh转曲面不太现实,折中取了个STL。

mesh转OBJ格式

设置导出模型的零点,例如设置底面中心为导出模型的零点。

        float offsetX = 0;float offsetY = 0;float offsetZ = 0;float minX = float.MaxValue;float maxX = float.MinValue;float minY = float.MaxValue;float maxY = float.MinValue;float minZ = float.MaxValue;float maxZ = float.MinValue;   foreach (var item in vertices ){Vector3 worldPos = trans.TransformPoint(item);if (minX > worldPos.x) minX = worldPos.x;if (minY > worldPos.y) minY = worldPos.y;if (minZ > worldPos.z) minZ = worldPos.z;if (maxX < worldPos.x) maxX = worldPos.x;if (maxY < worldPos.y) maxY = worldPos.y;if (maxZ < worldPos.z) maxZ = worldPos.z;}  offsetX = (minX + manX) / 2;offsetZ = (maxZ + minZ) / 2;offsetY = minY;

校验传入路径名称是否带.obj后缀。

   if (!name.Contains(".obj")){name = Path.Combine(name + ".obj");}

验证是否导出成功

  if (!File.Exists(name )){UnityEngine.Debug.LogError("导出失败!");}

完整代码

  public static void Export(Transform trans, Mesh mesh, string name){if (mesh == null) return;Vector3[] vertices = mesh.vertices;Vector3[] normals = mesh.normals;int[] triangles = mesh.triangles;StringBuilder sb = new StringBuilder();float offsetX = 0;float offsetY = 0;float offsetZ = 0;float minX = float.MaxValue;float maxX = float.MinValue;float minY = float.MaxValue;float maxY = float.MinValue;float minZ = float.MaxValue;float maxZ = float.MinValue;         foreach (var item in vertices ){Vector3 worldPos = trans.TransformPoint(item);if (minX > worldPos.x) minX = worldPos.x;if (minY > worldPos.y) minY = worldPos.y;if (minZ > worldPos.z) minZ = worldPos.z;if (maxX < worldPos.x) maxX = worldPos.x;if (maxY < worldPos.y) maxY = worldPos.y;if (maxZ < worldPos.z) maxZ = worldPos.z;}offsetX = minX;offsetZ = (maxZ + minZ) / 2;offsetY = (minY + maxY) / 2;//sb.Append("#为模型导出的obj,不带材质\n\n");     for (int i = 0; i < vertices.Length; i++){Vector3 worldVertices = trans.TransformPoint(vertices[i]);sb.Append("v " + (worldVertices.x - offsetX) + " " + (worldVertices.y - offsetY) + " " + (worldVertices.z - offsetZ) + "\n");}sb.Append("\n");for (int i = 0; i < normals.Length; i++){//反转法线过后sb.Append("vn " + -(normals[i].y) + " " + (normals[i].x) + " " + (normals[i].z) + "\n");}sb.Append("\n");for (int i = 0; i < triangles.Length; i += 3){sb.Append("f " + (triangles[i] + 1) + "//" + (triangles[i] + 1) + " " + (triangles[i+1] + 1) + "//" + (triangles[i+1] + 1) + " " + (triangles[i + 2] + 1) + "//" + (triangles[i + 2] + 1) + "\n");}
//校验导出名称if (!name.Contains(".obj")){name = Path.Combine(name + ".obj");}       File.WriteAllText(name, sb.ToString());if (!File.Exists(name )){UnityEngine.Debug.LogError("导出失败!");}}

mesh转STL格式

二进制格式(UG打开正常)

 public static void STLExportBinary(Transform trans,, Mesh mesh, string name){if (mesh == null) return;Vector3[] vertices = mesh.vertices;Vector3[] normals = mesh.normals;int[] triangles = mesh.triangles;StringBuilder sb = new StringBuilder();float offsetX = 0;float offsetY = 0;float offsetZ = 0;float minX = float.MaxValue;float maxX = float.MinValue;float minY = float.MaxValue;float maxY = float.MinValue;float minZ = float.MaxValue;float maxZ = float.MinValue;         foreach (var item in vertices ){Vector3 worldPos = trans.TransformPoint(item);if (minX > worldPos.x) minX = worldPos.x;if (minY > worldPos.y) minY = worldPos.y;if (minZ > worldPos.z) minZ = worldPos.z;if (maxX < worldPos.x) maxX = worldPos.x;if (maxY < worldPos.y) maxY = worldPos.y;if (maxZ < worldPos.z) maxZ = worldPos.z;}offsetX = minX;offsetZ = (maxZ + minZ) / 2;offsetY = (minY + maxY) / 2;int trianglesCount = triangles.Length;//计算出stl的大小int stlSize = 80 + 4 + (trianglesCount + 360) * (4 * 12 + 2);byte[] stl = new byte[stlSize];//创建一个文件流用于将数据写入到本地MemoryStream ms = new MemoryStream(stl);BinaryWriter writer = new BinaryWriter(ms);byte[] header = new byte[80];short _short = 0;header[0] = 73;header[1] = 99;header[2] = 101;header[3] = 109;header[4] = 97;header[5] = 110;writer.Write(header);writer.Write(trianglesCount);//循环遍历顶点,并将数据写入到文件中for (int i = 0; i < trianglesCount; i += 3){writer.Write(0.0f);writer.Write(0.0f);writer.Write(0.0f);Vector3 worldPos1 = (vertices[triangles[i]]) ;Vector3 worldPos2 = (vertices[triangles[i + 2]]) ;Vector3 worldPos3 = (vertices[triangles[i + 1]]);writer.Write(worldPos1.x-offsetX );writer.Write(worldPos1.z-offsetZ );writer.Write(worldPos1.y-offsetY );writer.Write(worldPos2.x-offsetX );writer.Write(worldPos2.z-offsetZ );writer.Write(worldPos2.y-offsetY );writer.Write(worldPos3.x-offsetX );writer.Write(worldPos3.z-offsetZ );writer.Write(worldPos3.y-offsetY );writer.Write(_short);}writer.Close();ms.Close();ms.Dispose();//将数据保存到本地File.WriteAllBytes(name , stl);if (!File.Exists(name)){UnityEngine.Debug.LogError("导出失败!");}else{UnityEngine.Debug.Log("导出完成");}

ASCII格式(UG打开报错)

基础框架和导出obj一致,区别在于写入了大量的标志信息。

  public static void STLExportASCII(Transform trans, Mesh mesh, string name){  if (mesh == null) return;Vector3[] vertices = mesh.vertices;Vector3[] normals = mesh.normals;int[] triangles = mesh.triangles;StringBuilder sb = new StringBuilder();float offsetX = 0;float offsetY = 0;float offsetZ = 0;float minX = float.MaxValue;float maxX = float.MinValue;float minY = float.MaxValue;float maxY = float.MinValue;float minZ = float.MaxValue;float maxZ = float.MinValue;         foreach (var item in vertices ){Vector3 worldPos = trans.TransformPoint(item);if (minX > worldPos.x) minX = worldPos.x;if (minY > worldPos.y) minY = worldPos.y;if (minZ > worldPos.z) minZ = worldPos.z;if (maxX < worldPos.x) maxX = worldPos.x;if (maxY < worldPos.y) maxY = worldPos.y;if (maxZ < worldPos.z) maxZ = worldPos.z;}offsetX = minX;offsetZ = (maxZ + minZ) / 2;offsetY = (minY + maxY) / 2;sb.Append("\nsolid " + "导出工件" + "\n");for (int i = 0; i < triangles.Length / 3; i++){try{Vector3 curPos1 = vertices[triangles[i * 3]];Vector3 curPos2 = vertices[triangles[i * 3 + 1]];Vector3 curPos3 = vertices[triangles[i * 3 + 2]];Vector3 nor1 = trans.TransformDirection(normals[triangles[i * 3]]);Vector3 nor2 = trans.TransformDirection(normals[triangles[i * 3 + 1]]);Vector3 nor3 = trans.TransformDirection(normals[triangles[i * 3 + 2]]);//顶点变换到世界空间Vector3 worldPos1 = trans.TransformPoint(curPos1);Vector3 worldPos2 = trans.TransformPoint(curPos2);Vector3 worldPos3 = trans.TransformPoint(curPos3);Vector3 normal = (nor1 + nor2 + nor3) / 3;sb.Append("facet normal " + normal.x + " " + normal.y + " " + normal.z);sb.Append("outer loop\n");sb.Append("\tvertex " + worldPos1.x-offsetX  + " " + worldPos1.y-offsetY + " " + worldPos1.z-offsetZ  + "\n");sb.Append("\tvertex " + worldPos2.x-offsetX  + " " + worldPos2.y-offsetY + " " + worldPos2.z-offsetZ  + "\n");sb.Append("\tvertex " + worldPos3.x -offsetX + " " + worldPos3.y-offsetY + " " + worldPos3.z-offsetZ  + "\n");sb.Append("\tendloop\n");sb.Append("\tendfacet\n");               }catch (Exception e){UnityEngine.Debug.Log("缺少顶点重用信息,索引为:" + triangles[i * 3] + "\n" + e);}}sb.Append("endsolid " + name);File.WriteAllText(name, sb.ToString());if (!File.Exists(name)){UnityEngine.Debug.LogError("导出失败!");}else{UnityEngine.Debug.Log("导出完成");       }

调用win窗口

调用dll及基础参数定义,直接拷贝就行。

public class OpenFileName
{public int structSize = 0;public IntPtr dlgOwner = IntPtr.Zero;public IntPtr instance = IntPtr.Zero;public String filter = null;public String customFilter = null;public int maxCustFilter = 0;public int filterIndex = 0;public String file = null;public int maxFile = 0;public String fileTitle = null;public int maxFileTitle = 0;public String initialDir = null;public String title = null;public int flags = 0;public short fileOffset = 0;public short fileExtension = 0;public String defExt = null;public IntPtr custData = IntPtr.Zero;public IntPtr hook = IntPtr.Zero;public String templateName = null;public IntPtr reservedPtr = IntPtr.Zero;public int reservedInt = 0;public int flagsEx = 0;
}
///2.系统函数调用类, 如下:
public class LocalDialog
{//链接指定系统函数       打开文件对话框[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);public static bool GetOFN([In, Out] OpenFileName ofn){return GetOpenFileName(ofn);}//链接指定系统函数        另存为对话框[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);public static bool GetSFN([In, Out] OpenFileName ofn){return GetSaveFileName(ofn);}
}

导入

导入参考图

  /// <summary>/// 选择导入路径/// </summary>public void InputFile(){      file = "";OpenFileName openFileName = new OpenFileName();openFileName.structSize = Marshal.SizeOf(openFileName);      openFileName.filter = "模型文件(*.obj)\0*.obj";openFileName.file = new string(new char[256]);openFileName.maxFile = openFileName.file.Length;openFileName.fileTitle = new string(new char[64]);openFileName.maxFileTitle = openFileName.fileTitle.Length;openFileName.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//默认路径openFileName.title = "导入";openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;if (LocalDialog.GetOpenFileName(openFileName)){file = openFileName.file;}}

导出

设置格式 \0*.obj\0 和 \0*.stl\0,这种形式是分开显示格式,下图所示; \0*.obj *.stl\0 这种显示在一起,导入参考图所示。

  /// <summary>/// 选择导出路径/// </summary>void OutputFile(){if (Manager3.instance.cylinder==null ){textTips.text = "未加载工件!";return;}file = "";       OpenFileName openFileName = new OpenFileName();openFileName.structSize = Marshal.SizeOf(openFileName);openFileName.filter = "模型文件(*.obj)\0*.obj\0模型文件(*.stl)\0*.stl\0";openFileName.file = new string(new char[256]);openFileName.maxFile = openFileName.file.Length;openFileName.fileTitle = new string(new char[64]);openFileName.maxFileTitle = openFileName.fileTitle.Length;openFileName.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//默认路径openFileName.title = "导出";openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;openFileName.defExt = ".obj";if (LocalDialog.GetSaveFileName(openFileName)){file = openFileName.file;}}

注意事项

1.不建议在编辑器中频繁调用win。可能引起Library错误,导致资源全部丢失,需要删除Library,重新加载场景。
2. openFileName.defExt = “.obj”; 这个重点,选择格式后,自动在输入框中追加后缀。不设置defExt 值时,需要自己追加。

mesh导出OBJ、STL格式和win窗口调用相关推荐

  1. matlab生成面导出stl格式,如何将MATLAB中的网格导出为stl或obj?

    我已经编写了MATLAB代码(如下所示),它创建了一个边,然后构建了从该边延伸的网格.我可以将3D模型看作网格物体,但无法将此模型导出为3d对象,例如stl或obj.如何将MATLAB中的网格导出为s ...

  2. 2.5 使用SolidWorks转换STL格式为OBJ文件格式

    1. 说明: 使用SW进行三维模型建模,一般应用在机械工程领域中.将模型保存成STL格式后,转换为.obj文件,才能进一步转换为mesh文件,供QT中的3D控件进行使用,本文章记录一些格式转换步骤和关 ...

  3. 使用blender做一个地球模型,贴上UV纹理,导出Obj格式

    使用blender做一个地球模型,贴上UV纹理,导出Obj格式 Table of Contents 1 blender 1.1 图文教程 1.2 export to objloader, coordi ...

  4. blender 导出 obj 格式,3dsmax 导入3ds max obj 格式数据

    blender 导出 obj 格式,3dsmax 导入3ds max obj 格式数据 blender 导出 3dsmax 导入

  5. obj文件编辑软件_工程动画制作 | MAX文件导出obj、fbx格式在Bentley软件中应用

    一.利用3dmax打开max模型,利用材质球吸取材质. 看材质是否为标准材质(standard),如若是,继续下一步操作.如若不是,修改材质球属性,保留贴图为子材质,更改为标准材质. 二.处理模型面数 ...

  6. 点云文件常用格式转换(pcd,txt,ply,obj,stl)

    目录 pcd转txt txt转pcd pcd转ply pcd转ply(三角网格化) ply转pcd obj/ply转pcd(均匀采样) pcd转obj stl转ply ply转stl pcd转txt ...

  7. ply格式转为obj,stl等格式

    ply格式转为obj,stl等格式 一般方法是使用meshlab或matlab等软件工具进行转化,需要配置环境,调试程序等一系列准备工作,工作量大,一般人只是使用一下,并不准备研究这些工具. 在这里推 ...

  8. Three.js加载.stl格式模型

    .stl格式模型加载 本文是Three.js电子书的14.2节 基本所有的三维软件都支持导出.stl格式的三维模型文件,.stl格式的三维模型不包含材质Material信息,只包含几何体顶点数据的信息 ...

  9. jsonhandle主界面没有显示格式_怎么将图纸导出成图片格式保存

    怎么将图纸导出成图片格式保存呢?接下来将与大家分享一下有关CAd图纸转换成图片进行保存的方法. 方法/步骤 为了实现CAd转图片操作,首先我们需要在电脑上安装一个CAD编辑软件,如图所示: 待CAD编 ...

最新文章

  1. DongLiORM 第二次更新
  2. 自动运维PXE安装系统和DNS缓存解析
  3. JavaScript面向对象的支持(7)
  4. 缕一缕c#可null类型
  5. 编译安装Mysql5.6.36
  6. 云图说丨初识数据工坊DWR
  7. @程序员,多写点“坏”代码吧!
  8. SVN删除某版本解决办法
  9. 利用计算机进行国际贸易的弊端,国际贸易中的计算机应用体系建设浅析
  10. PHP面向对象知识点
  11. 苏浪浪 201771010120 第三周 Java基本程序设计总结
  12. 系统字体大小导致rem布局变大
  13. psd效果预览转成网站首页(html+css)
  14. java计算机毕业设计工会会员管理系统MyBatis+系统+LW文档+源码+调试部署
  15. 六自由度机械臂研究(3)- 机械臂DH参数表建立
  16. python小程序源码合集
  17. android 分辨率转换器,Nevercenter Pixelmash(图片像素转换器) v202010 官方版
  18. 嵌入式系统开发-麦子学院(10)——arm汇编基础
  19. 第九次java课堂笔记
  20. 8.Redis主从复制

热门文章

  1. 基于高德离线地图数据实现GPS经纬度逆解析城市信息
  2. tftp 服务器linux,CentOS 7 下 TFTP服务器安装
  3. C语言编写学生籍贯信息记录簿
  4. 在微信里点击链接无跳转
  5. 网页游戏开发入门教程二(游戏模式+系统)
  6. 广州地震了!地震到底离我们有多近,Python 爬虫带你了解
  7. 定义求x的n次幂的函数,并返回计算结果
  8. Triangle Peg Solitaire(孔明棋)
  9. 【附源码】计算机毕业设计SSM社区居家养老服务管理系统
  10. 书单:书籍、论坛、网站