mesh导出OBJ、STL格式和win窗口调用
记录下开发过程
- 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窗口调用相关推荐
- matlab生成面导出stl格式,如何将MATLAB中的网格导出为stl或obj?
我已经编写了MATLAB代码(如下所示),它创建了一个边,然后构建了从该边延伸的网格.我可以将3D模型看作网格物体,但无法将此模型导出为3d对象,例如stl或obj.如何将MATLAB中的网格导出为s ...
- 2.5 使用SolidWorks转换STL格式为OBJ文件格式
1. 说明: 使用SW进行三维模型建模,一般应用在机械工程领域中.将模型保存成STL格式后,转换为.obj文件,才能进一步转换为mesh文件,供QT中的3D控件进行使用,本文章记录一些格式转换步骤和关 ...
- 使用blender做一个地球模型,贴上UV纹理,导出Obj格式
使用blender做一个地球模型,贴上UV纹理,导出Obj格式 Table of Contents 1 blender 1.1 图文教程 1.2 export to objloader, coordi ...
- blender 导出 obj 格式,3dsmax 导入3ds max obj 格式数据
blender 导出 obj 格式,3dsmax 导入3ds max obj 格式数据 blender 导出 3dsmax 导入
- obj文件编辑软件_工程动画制作 | MAX文件导出obj、fbx格式在Bentley软件中应用
一.利用3dmax打开max模型,利用材质球吸取材质. 看材质是否为标准材质(standard),如若是,继续下一步操作.如若不是,修改材质球属性,保留贴图为子材质,更改为标准材质. 二.处理模型面数 ...
- 点云文件常用格式转换(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 ...
- ply格式转为obj,stl等格式
ply格式转为obj,stl等格式 一般方法是使用meshlab或matlab等软件工具进行转化,需要配置环境,调试程序等一系列准备工作,工作量大,一般人只是使用一下,并不准备研究这些工具. 在这里推 ...
- Three.js加载.stl格式模型
.stl格式模型加载 本文是Three.js电子书的14.2节 基本所有的三维软件都支持导出.stl格式的三维模型文件,.stl格式的三维模型不包含材质Material信息,只包含几何体顶点数据的信息 ...
- jsonhandle主界面没有显示格式_怎么将图纸导出成图片格式保存
怎么将图纸导出成图片格式保存呢?接下来将与大家分享一下有关CAd图纸转换成图片进行保存的方法. 方法/步骤 为了实现CAd转图片操作,首先我们需要在电脑上安装一个CAD编辑软件,如图所示: 待CAD编 ...
最新文章
- DongLiORM 第二次更新
- 自动运维PXE安装系统和DNS缓存解析
- JavaScript面向对象的支持(7)
- 缕一缕c#可null类型
- 编译安装Mysql5.6.36
- 云图说丨初识数据工坊DWR
- @程序员,多写点“坏”代码吧!
- SVN删除某版本解决办法
- 利用计算机进行国际贸易的弊端,国际贸易中的计算机应用体系建设浅析
- PHP面向对象知识点
- 苏浪浪 201771010120 第三周 Java基本程序设计总结
- 系统字体大小导致rem布局变大
- psd效果预览转成网站首页(html+css)
- java计算机毕业设计工会会员管理系统MyBatis+系统+LW文档+源码+调试部署
- 六自由度机械臂研究(3)- 机械臂DH参数表建立
- python小程序源码合集
- android 分辨率转换器,Nevercenter Pixelmash(图片像素转换器) v202010 官方版
- 嵌入式系统开发-麦子学院(10)——arm汇编基础
- 第九次java课堂笔记
- 8.Redis主从复制