在Unity中运行时解析具有超过65k顶点的网格

3
我正在使用Unity和C#在运行时加载OBJ模型。我使用Unity的维基解析器“FastOBJImporter”http://wiki.unity3d.com/index.php/FastObjImporter来解析OBJ文件。 由于是Unity的限制(http://answers.unity3d.com/questions/471639/mesh-with-more-than-65000-vertices.html),我无法加载超过65,534个顶点的网格。

我的想法是将一个大网格路径传递给FastOBJImporter,并生成具有少于65k个顶点的多个游戏对象,以便加载更大的模型。

有人知道如何安全地修改FastOBJimporter,以返回子网格列表而不是一个大网格吗?欢迎任何其他解决方案/想法。

更具体地说,我正在实现的是解析一个顶点的超级列表、一个三角形的超级列表等。然后,我使用少于64K个顶点生成子顶点列表A、子顶点列表B等。然后,我将从子顶点列表A生成子三角形列表A,以此类推...我的问题是:我应该如何生成子三角形列表,以便仅包含来自单个子顶点列表的顶点?我担心会有许多由来自不同子顶点列表的顶点组成的三角形,这将是一个问题。 - user3543240
2个回答

1

这个脚本 可以处理STL模型文件。它将模型导入,无论大小如何,每次达到65k个顶点时都会将网格分割成子网格。STL文件可以转换为OBJ文件,因此我想,使用简单的转换器或修改脚本就可以解决问题。

以下是代码(我不对代码负责)。

#pragma warning disable 0219

using UnityEngine;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Threading;

namespace Parabox.STL
{
    /*Import methods for STL files*/
    public class STL_ImportScript : MonoBehaviour
    {

        const int MAX_FACETS_PER_MESH = 65535 / 3;

        class Facet
        {
            public Vector3 normal;
            public Vector3 a, b, c;

            public override string ToString()
            {
                return string.Format("{0:F2}: {1:F2}, {2:F2}, {3:F2}", normal, a, b, c);
            }
        }

        /**
         * Import an STL file at path.
         */
        public static Mesh[] Import(string path)
        {
                try
                {
                    return ImportBinary(path);
                }
                catch (System.Exception e)
                {
                    UnityEngine.Debug.LogWarning(string.Format("Failed importing mesh at path {0}.\n{1}", path, e.ToString()));
                    return null;
                }
        }

        private static Mesh[] ImportBinary(string path)
        {
            List<Facet> facets = new List<Facet>();
            byte[] header;
            uint facetCount;

            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                using (BinaryReader br = new BinaryReader(fs, new ASCIIEncoding()))
                {
                    while (br.BaseStream.Position < br.BaseStream.Length)
                    {
                        // read header
                        header = br.ReadBytes(80);
                        facetCount = br.ReadUInt32();

                        for (uint i = 0; i < facetCount; i++)
                        {
                            try
                            {
                                Facet facet = new Facet();

                                facet.normal.x = br.ReadSingle();
                                facet.normal.y = br.ReadSingle();
                                facet.normal.z = br.ReadSingle();

                                facet.a.x = br.ReadSingle();
                                facet.a.y = br.ReadSingle();
                                facet.a.z = br.ReadSingle();

                                facet.b.x = br.ReadSingle();
                                facet.b.y = br.ReadSingle();
                                facet.b.z = br.ReadSingle();

                                facet.c.x = br.ReadSingle();
                                facet.c.y = br.ReadSingle();
                                facet.c.z = br.ReadSingle();

                                facets.Add(facet);


                                // padding
                                br.ReadUInt16();
                            }
                            catch (Exception e)
                            {
                                //Console.WriteLine(e.Message);
                                Debug.Log(e.Message);
                            }
                        }
                    }
                }
            }

            return CreateMeshWithFacets(facets);
        }

        const int SOLID = 1;
        const int FACET = 2;
        const int OUTER = 3;
        const int VERTEX = 4;
        const int ENDLOOP = 5;
        const int ENDFACET = 6;
        const int ENDSOLID = 7;
        const int EMPTY = 0;

        private static int ReadState(string line)
        {
            if (line.StartsWith("solid"))
                return SOLID;
            else if (line.StartsWith("facet"))
                return FACET;
            else if (line.StartsWith("outer"))
                return OUTER;
            else if (line.StartsWith("vertex"))
                return VERTEX;
            else if (line.StartsWith("endloop"))
                return ENDLOOP;
            else if (line.StartsWith("endfacet"))
                return ENDFACET;
            else if (line.StartsWith("endsolid"))
                return ENDSOLID;
            else
                return EMPTY;
        }

        private static Vector3 StringToVec3(string str)
        {
            string[] split = str.Trim().Split(null);
            Vector3 v = new Vector3();

            float.TryParse(split[0], out v.x);
            float.TryParse(split[1], out v.y);
            float.TryParse(split[2], out v.z);

            return v;
        }


        private static Mesh[] CreateMeshWithFacets(IList<Facet> facets)
        {
            int fl = facets.Count, f = 0, mvc = MAX_FACETS_PER_MESH * 3;
            Mesh[] meshes = new Mesh[fl / MAX_FACETS_PER_MESH + 1];

            for (int i = 0; i < meshes.Length; i++)
            {
                int len = System.Math.Min(mvc, (fl - f) * 3);
                Vector3[] v = new Vector3[len];
                Vector3[] n = new Vector3[len];
                int[] t = new int[len];

                for (int it = 0; it < len; it += 3)
                {
                    v[it] = facets[f].a;
                    v[it + 1] = facets[f].b;
                    v[it + 2] = facets[f].c;

                    n[it] = facets[f].normal;
                    n[it + 1] = facets[f].normal;
                    n[it + 2] = facets[f].normal;

                    t[it] = it;
                    t[it + 1] = it + 1;
                    t[it + 2] = it + 2;

                    f++;
                }

                meshes[i] = new Mesh();
                meshes[i].vertices = v;
                meshes[i].normals = n;
                meshes[i].triangles = t;

            }

            return meshes;
        }

    }
}

另一个解决方案可能是动态组合共享相同空间的顶点。当您在运行时引入模型时,将距离一定阈值内的顶点组合在一起,以将总顶点数减少到65k以下的限制。
或者,使用Mesh Simplify等工具来降低细节级别,使您能够优化性能并将多边形数量降至65k以下,以导入网格而不超过65k的限制。有不同且更经济实惠的选择,但这似乎是其中更好的选择之一。

0

当前的最佳答案已经非常详细了,但整个问题可以用一行代码解决:

myMeshFilter.mesh = new Mesh() { indexFormat = UnityEngine.Rendering.IndexFormat.UInt32 }; // To support meshes > 65k verts

正确设置网格的索引格式将允许更大的顶点列表。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接