2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > stl文件unity_Unity导入STL格式模型(二)

stl文件unity_Unity导入STL格式模型(二)

时间:2022-11-29 07:49:42

相关推荐

stl文件unity_Unity导入STL格式模型(二)

接上篇Unity导入STL格式模型(一),分成多个子网格的方式解决了导入慢以及目标模型顶点过多的问题,优化之后,目前针对二进制STL文件有比较良好的解析能力。

MeshCompression:是否使用压缩模式

Off为不使用,跳过压缩算法,导入模型的时间可以短到忽略不计。

On为使用,会为每个子网格单独压缩,也就是删掉所有他认为重复的顶点(位置相等他就认为重复)。

SingleTrianglesNumber:以此数量做为子网格的面数进行拆分,将模型分为多个子网格。

SaveMesh:是否保存模型的所有子网格至本地磁盘?在CreateInstance至Scene中之后。

核心代码如下:

///

/// 创建STL模型实例

///

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();

_normals = new List();

_triangles = new List();

//读取顶点信息

Thread t = new Thread(ReadVertex);

t.Start();

while (_number < _total)

EditorUtility.DisplayProgressBar("读取信息", "正在读取顶点信息(" + _number + "/" + _total + ")......", (float)_number / _total);

CreateGameObject();

_binaryReader.Close();

EditorUtility.ClearProgressBar();

///

/// 读取顶点信息

///

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;

///

/// 创建GameObject

///

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();

MeshRenderer mr = tem.AddComponent();

int startIndex = i * _singleTrianglesNumber * 3;

int length = _singleTrianglesNumber * 3;

if ((startIndex + length) > _vertices.Count)

length = _vertices.Count - startIndex;

List vertices = _vertices.GetRange(startIndex, length);

List normals = _normals.GetRange(startIndex, length);

List 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);

///

/// 压缩网格

///

/// 网格名称

/// 需要压缩的网格顶点数组

/// 与之对应的法线数组

/// 与之对应的三角面数组

private void MeshCompression(string meshName, List vertices, List normals, List triangles)

//移位补偿,当顶点被标记为待删除顶点时

int offset = 0;

//需要删除的顶点索引集合

List removes = new List();

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源码链接:/SaiTingHu/ImportSTL

来自:/qq992817263/article/details/72738344

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。