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