Unity RunTime 解析obj文件

  unity3D并没有在运行时解析obj文件的方法,网上找的方法刚开始能满足我的需求,后来公司提供的obj文件,导致obj解析时候模型出现破面和索引面连接不对,通过查看模型的各项顶点和面数都超出unity解析面数的6倍左右,然后详细查看其它博客的时候发现,自己所用的代码并没有做三角面的整合,试过多个使用三角面整合的代码后,模型能正常的解析出来uv和法线都是正常的.唯一的问题就是整合的时候代码都是使用多层for循环去进行面的整合对比,在模型点面不多的情况下还是能整的解析出来,但是上到几万面的obj文件是要解析3-5分钟,这种解析速度肯定不能使用的.于是我在github里面找到一个可以使用字典的方式进行整合三角面的方法,通过此方法进行修改,终于将速度提升到和原来基本差不多的解析速度.(注意此方法只针对单模型的解析,拆解类型的obj还是用我在github找到的方法就可以使用了)

  ObjData.cs

public class ObjData
{
    public string MatlName;
    public List<Vector2> UV;
    public List<Vector3> VN;
    public List<Vector3> V;

    public ObjData()
    {
        MatlName = "";
        UV = new List<Vector2>();
        VN = new List<Vector3>();
        V = new List<Vector3>();
    }
}

  obj解析函数

/// <summary>
/// bj文件进行解析
/// </summary>
/// <param name="obj_text">obj文件的字符串</param>
/// <param name="isNegative">切换左右</param>
/// <returns></returns>
public static Mesh Load_Obj_From_Text(string obj_text,bool isNegative = true)
{
        bool hasNormals = false;
        ObjData tempObj = new ObjData();//存放临时获取的obj数据
        ObjData utempObj = new ObjData();//存放初步处理后的obj数据
        ObjData objMesh = new ObjData();

        List<int> faceList = new List<int>();
        //使用字典整合三角面
        Dictionary<string, int> hashtable = new Dictionary<string, int>();
        Dictionary<int, int> remapTable = new Dictionary<int, int>();

        string[] objLines = obj_text.Split('\n');
        foreach (string ln in objLines)
        {
            if (ln.Length > 0 && ln[0] != '#')
            {
                string l = ln.Trim().Replace("  ", " ");
                string[] cmps = l.Split(' ');
                string data = l.Remove(0, l.IndexOf(' ') + 1);

                if (cmps[0] == "usemtl")
                {
                    tempObj.MatlName = data;
                }
                else if (cmps[0] == "v")
                {
                    tempObj.V.Add(Convert_To_Vector3(cmps, isNegative));
                }
                else if (cmps[0] == "vn")
                {
                    tempObj.VN.Add(Convert_To_Vector3(cmps, isNegative));
                }
                else if (cmps[0] == "vt")
                {
                    tempObj.UV.Add(Convert_To_Vector3(cmps));
                }
                else if (cmps[0] == "f")
                {
                    int[] indexes = new int[cmps.Length - 1];
                    for (int i = 1; i < cmps.Length; i++)
                    {
                        string felement = cmps[i];
                        int vertexIndex = -1;
                        int normalIndex = -1;
                        int uvIndex = -1;
                        if (felement.Contains("//"))
                        {
                            string[] elementComps = felement.Split('/');
                            vertexIndex = Convert_To_Int(elementComps[0]) - 1;
                            normalIndex = Convert_To_Int(elementComps[2]) - 1;
                        }
                        else if (felement.Count(x => x == '/') == 2)
                        {
                            string[] elementComps = felement.Split('/');
                            vertexIndex = Convert_To_Int(elementComps[0]) - 1;
                            uvIndex = Convert_To_Int(elementComps[1]) - 1;
                            normalIndex = Convert_To_Int(elementComps[2]) - 1;
                        }
                        else if (!felement.Contains("/"))
                        {
                            vertexIndex = Convert_To_Int(felement) - 1;
                        }
                        else
                        {
                            string[] elementComps = felement.Split('/');
                            vertexIndex = Convert_To_Int(elementComps[0]) - 1;
                            uvIndex = Convert_To_Int(elementComps[1]) - 1;
                        }

                        string hashEntry = vertexIndex + "|" + normalIndex + "|" + uvIndex;
                        if (hashtable.ContainsKey(hashEntry))
                        {
                            indexes[i - 1] = hashtable[hashEntry];
                        }
                        else
                        {
                            indexes[i - 1] = hashtable.Count;
                            hashtable[hashEntry] = hashtable.Count;
                            utempObj.V.Add(tempObj.V[vertexIndex]);
                            if (normalIndex < 0 || (normalIndex > (tempObj.VN.Count - 1)))
                            {
                                utempObj.VN.Add(Vector3.zero);
                            }
                            else
                            {
                                hasNormals = true;
                                utempObj.VN.Add(tempObj.VN[normalIndex]);
                            }

                            if (uvIndex < 0 || (uvIndex > (tempObj.UV.Count - 1)))
                            {
                                utempObj.UV.Add(Vector2.zero);
                            }
                            else
                            {
                                utempObj.UV.Add(tempObj.UV[uvIndex]);
                            }

                        }
                    }
                    //存放三角面索引
                    if (indexes.Length < 5 && indexes.Length >= 3)
                    {
                        if (isNegative)
                        {
                            for (int i = 2; i >= 0 ; i--)
                            {
                                faceList.Add(indexes[i]);
                            }
                            if (indexes.Length > 3)
                            {
                                faceList.Add(indexes[0]);
                                faceList.Add(indexes[3]);
                                faceList.Add(indexes[2]);
                            }
                        }
                        else
                        {
                            for (int i = 0; i < 3; i++)
                            {
                                faceList.Add(indexes[i]);
                            }
                            if (indexes.Length > 3)
                            {
                                faceList.Add(indexes[2]);
                                faceList.Add(indexes[3]);
                                faceList.Add(indexes[0]);
                            }
                        }
                        
                    }
                }
            }
        }

        Mesh mesh = new Mesh();
        mesh.name = "default";
        //重新整合三角面
        for (int i = 0; i < faceList.Count; i++)
        {
            int idx = faceList[i];
            if (remapTable.ContainsKey(idx))
            {
                faceList[i] = remapTable[idx];
            }
            else
            {
                objMesh.V.Add(utempObj.V[idx]);
                objMesh.VN.Add(utempObj.VN[idx]);
                objMesh.UV.Add(utempObj.UV[idx]);
                remapTable[idx] = objMesh.V.Count - 1;
                faceList[i] = remapTable[idx];
            }
        }

        mesh.vertices = objMesh.V.ToArray();
        mesh.normals = objMesh.VN.ToArray();
        mesh.uv = objMesh.UV.ToArray();
        mesh.triangles = faceList.ToArray();

        if (!hasNormals)
        {
            mesh.RecalculateNormals();
        }

        mesh.RecalculateBounds();

        return mesh;
    }

此方法直接输出的是Mesh需要输出其类型就自行需要修改即可,顺便附上大神的源码github

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值