Unity导入STL格式模型(二)
来源:互联网 发布:产品经理 原型软件 编辑:程序博客网 时间:2024/06/06 02:22
在群里一位朋友的提点下,以分成多个子网格的方式解决了导入慢以及目标模型顶点过多的问题,在此我要非常诚心的感谢他!
优化之后,目前针对二进制STL文件有比较良好的解析能力。
MeshCompression:是否使用压缩模式,Off为不使用,跳过压缩算法,导入模型的时间可以短到忽略不计。
On为使用,会为每个子网格单独压缩,也就是删掉所有他认为重复的顶点(位置相等他就认为重复)。
SingleTrianglesNumber:以此数量做为子网格的面数进行拆分,将模型分为多个子网格。
SaveMesh:是否保存模型的所有子网格至本地磁盘?在CreateInstance至Scene中之后。
照例,贴所有核心代码:
/// <summary> /// 创建STL模型实例 /// </summary> private void CreateInstance() { if (_singleTrianglesNumber < 1000 || _singleTrianglesNumber > 20000) { Debug.LogError("Single Triangles Number: this value is unreasonable!"); return; } if (int.Parse(_trianglescount) > 200000) { Debug.LogError("Triangles Count: this value is too much!"); return; } string fullPath = Path.GetFullPath(AssetDatabase.GetAssetPath(target)); _total = int.Parse(_trianglescount); _number = 0; _binaryReader = new BinaryReader(File.Open(fullPath, FileMode.Open)); //抛弃前84个字节 _binaryReader.ReadBytes(84); _vertices = new List<Vector3>(); _normals = new List<Vector3>(); _triangles = new List<int>(); //读取顶点信息 Thread t = new Thread(ReadVertex); t.Start(); while (_number < _total) { EditorUtility.DisplayProgressBar("读取信息", "正在读取顶点信息(" + _number + "/" + _total + ")......", (float)_number / _total); } CreateGameObject(); _binaryReader.Close(); EditorUtility.ClearProgressBar(); }
/// <summary> /// 读取顶点信息 /// </summary> private void ReadVertex() { while (_number < _total) { byte[] bytes; bytes = _binaryReader.ReadBytes(50); if (bytes.Length < 50) { _number += 1; continue; } Vector3 vec0 = new Vector3(BitConverter.ToSingle(bytes, 0), BitConverter.ToSingle(bytes, 4), BitConverter.ToSingle(bytes, 8)); Vector3 vec1 = new Vector3(BitConverter.ToSingle(bytes, 12), BitConverter.ToSingle(bytes, 16), BitConverter.ToSingle(bytes, 20)); Vector3 vec2 = new Vector3(BitConverter.ToSingle(bytes, 24), BitConverter.ToSingle(bytes, 28), BitConverter.ToSingle(bytes, 32)); Vector3 vec3 = new Vector3(BitConverter.ToSingle(bytes, 36), BitConverter.ToSingle(bytes, 40), BitConverter.ToSingle(bytes, 44)); _normals.AddNormal(vec0); _triangles.AddTriangle(_vertices.AddGetIndex(vec1), _vertices.AddGetIndex(vec2), _vertices.AddGetIndex(vec3)); _number += 1; } }
/// <summary> /// 创建GameObject /// </summary> private void CreateGameObject() { string path = AssetDatabase.GetAssetPath(target); string fullPath = Path.GetFullPath(path); string assetPath = path.Substring(0, path.LastIndexOf("/")) + "/"; GameObject root = new GameObject(Path.GetFileNameWithoutExtension(fullPath)); root.transform.localPosition = Vector3.zero; root.transform.localScale = Vector3.one; int count = _total / _singleTrianglesNumber; count += (_total % _singleTrianglesNumber > 0) ? 1 : 0; for (int i = 0; i < count; i++) { GameObject tem = new GameObject(Path.GetFileNameWithoutExtension(fullPath) + "Sub" + i); tem.transform.SetParent(root.transform); tem.transform.localPosition = Vector3.zero; tem.transform.localScale = Vector3.one; MeshFilter mf = tem.AddComponent<MeshFilter>(); MeshRenderer mr = tem.AddComponent<MeshRenderer>(); int startIndex = i * _singleTrianglesNumber * 3; int length = _singleTrianglesNumber * 3; if ((startIndex + length) > _vertices.Count) { length = _vertices.Count - startIndex; } List<Vector3> vertices = _vertices.GetRange(startIndex, length); List<Vector3> normals = _normals.GetRange(startIndex, length); List<int> triangles = _triangles.GetRange(0, length); //压缩网格 if (_meshCompression.IsOn()) { MeshCompression(tem.name, vertices, normals, triangles); } Mesh m = new Mesh(); m.name = tem.name; m.vertices = vertices.ToArray(); m.normals = normals.ToArray(); m.triangles = triangles.ToArray(); m.RecalculateNormals(); mf.mesh = m; mr.material = new Material(Shader.Find("Standard")); Debug.Log("Create done! " + tem.name + ": Vertex Number " + m.vertices.Length); } }
/// <summary> /// 压缩网格 /// </summary> /// <param name="meshName">网格名称</param> /// <param name="vertices">需要压缩的网格顶点数组</param> /// <param name="normals">与之对应的法线数组</param> /// <param name="triangles">与之对应的三角面数组</param> private void MeshCompression(string meshName, List<Vector3> vertices, List<Vector3> normals, List<int> triangles) { //移位补偿,当顶点被标记为待删除顶点时 int offset = 0; //需要删除的顶点索引集合 List<int> removes = new List<int>(); for (int i = 0; i < vertices.Count; i++) { EditorUtility.DisplayProgressBar("压缩网格", "正在压缩网格[ " + meshName + " ](" + i + "/" + vertices.Count + ")......", (float)i / vertices.Count); if (removes.Contains(i)) { offset += 1; continue; } triangles[i] = i - offset; for (int j = i + 1; j < vertices.Count; j++) { if (vertices[i] == vertices[j]) { removes.Add(j); triangles[j] = triangles[i]; } } } removes.Sort(); removes.Reverse(); for (int i = 0; i < removes.Count; i++) { vertices.RemoveAt(removes[i]); normals.RemoveAt(removes[i]); } }
测试:使用不压缩网格模式,点击CreateInstance,导入的时间快到可以忽略不计,而且目标已被拆分为多个网格,再多顶点的模型也不用担心超过上限:
没有经过压缩的顶点数量分别为:
测试:然后我们使用压缩网格模式,点击CreateInstance,注意,这里勾选SaveMesh,以便于将网格保存在本地,便可重复使用,毕竟压缩模式导入比较慢,不用每次使用都重新压缩网格:
压缩之后的结果:
可以看到顶点几乎被压缩掉了四分之三,如果要考虑性能的话,还是使用压缩网格比较好,而且因为他替换掉的都是位置重复顶点,这些在视觉上是看不出任何差异的(没有贴图的话),而且我们保存在本地的Mesh文件之后便可以直接通过拖拽给MeshFilter组件使用,方便了很多。
github源码链接:https://github.com/SaiTingHu/ImportSTL
阅读全文
0 0
- Unity导入STL格式模型(二)
- Unity导入STL格式模型(一)
- stl格式模型导入osg后旋转操作
- unity,跟着大佬做第一个游戏(二,模型导入和游戏基本代码编写)
- Unity导入模型UnityPacket
- unity导入模型无色
- unity导入模型相关
- Unity将内部模型转换成stl格式模型,用于3D打印机进行打印
- Unity模型导入的若干问题
- Unity 导入贴图和模型
- unity 模型导入不显示
- Unity 导入 fbx 模型文件
- Unity模型导入的Check
- 3Dmax中的模型生成FBX格式的模型导入unity中,会出现支离破碎的现象,怎么解决?
- unity导入模型昏暗(对比度低)解决办法
- 【Unity闲谈】关于制作 Voxel(体素,3D像素)模型并导入Unity
- Unity中导入的模型,第一(三)人称可以穿插模型,该怎么解决?
- unity基础开发----导入模型碰撞检测
- [bzoj 1103] 大都市meg(树状数组和dfs序)
- 蓝桥杯----生成回文数
- android 四大组件只------BroadCastReceiver(广播)
- C语言基础-指针深入16
- 一道题看透函数柯里化(currying)
- Unity导入STL格式模型(二)
- RecyclerView做ListView的效果,Recyclerview带分隔线的使用
- Tour UVA
- iOS 第三方应用中打开自己的文件(UIDocumentInteractionController)
- 鸡啄米:添加控件变量
- 一、Servlet基础
- jQuery选择器之表单元素选择器
- graph确定是否有循环
- AWT如何关闭窗口