IEnumerator LoadOBJFile(string fn, ActionAfterLoaded done) { string meshName = Path.GetFileNameWithoutExtension(fn); bool hasNormals = false; //OBJ LISTS List <Vector3> vertices = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); //UMESH LISTS List <Vector3> uvertices = new List <Vector3>(); List <Vector3> unormals = new List <Vector3>(); List <Vector2> uuvs = new List <Vector2>(); //MESH CONSTRUCTION List <string> materialNames = new List <string>(); List <string> objectNames = new List <string>(); Dictionary <string, int> hashtable = new Dictionary <string, int>(); List <OBJFace> faceList = new List <OBJFace>(); string cmaterial = ""; string cmesh = "default"; //CACHE Material[] materialCache = null; //save this info for later FileInfo OBJFileInfo = new FileInfo(fn); yield return(null); foreach (string ln in File.ReadAllLines(fn)) { 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] == "mtllib") { //load cache string pth = OBJGetFilePath(data, OBJFileInfo.Directory.FullName + Path.DirectorySeparatorChar, meshName); if (pth != null) { yield return(materialCache = LoadMTLFile(pth)); } //yield return null; } else if ((cmps[0] == "g" || cmps[0] == "o") && splitByMaterial == false) { cmesh = data; if (!objectNames.Contains(cmesh)) { objectNames.Add(cmesh); } } else if (cmps[0] == "usemtl") { cmaterial = data; if (!materialNames.Contains(cmaterial)) { materialNames.Add(cmaterial); } if (splitByMaterial) { if (!objectNames.Contains(cmaterial)) { objectNames.Add(cmaterial); } } } else if (cmps[0] == "v") { //VERTEX vertices.Add(ParseVectorFromCMPS(cmps)); } else if (cmps[0] == "vn") { //VERTEX NORMAL normals.Add(ParseVectorFromCMPS(cmps)); } else if (cmps[0] == "vt") { //VERTEX UV uvs.Add(ParseVectorFromCMPS(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("//")) { //doubleslash, no UVS. string[] elementComps = felement.Split('/'); vertexIndex = int.Parse(elementComps[0]) - 1; normalIndex = int.Parse(elementComps[2]) - 1; } else if (felement.Count(x => x == '/') == 2) { //contains everything string[] elementComps = felement.Split('/'); vertexIndex = int.Parse(elementComps[0]) - 1; uvIndex = int.Parse(elementComps[1]) - 1; normalIndex = int.Parse(elementComps[2]) - 1; } else if (!felement.Contains("/")) { //just vertex inedx vertexIndex = int.Parse(felement) - 1; } else { //vertex and uv string[] elementComps = felement.Split('/'); vertexIndex = int.Parse(elementComps[0]) - 1; uvIndex = int.Parse(elementComps[1]) - 1; } string hashEntry = vertexIndex + "|" + normalIndex + "|" + uvIndex; if (hashtable.ContainsKey(hashEntry)) { indexes[i - 1] = hashtable[hashEntry]; } else { //create a new hash entry indexes[i - 1] = hashtable.Count; hashtable[hashEntry] = hashtable.Count; uvertices.Add(vertices[vertexIndex]); if (normalIndex < 0 || (normalIndex > (normals.Count - 1))) { unormals.Add(Vector3.zero); } else { hasNormals = true; unormals.Add(normals[normalIndex]); } if (uvIndex < 0 || (uvIndex > (uvs.Count - 1))) { uuvs.Add(Vector2.zero); } else { uuvs.Add(uvs[uvIndex]); } } } if (indexes.Length < 5 && indexes.Length >= 3) { OBJFace f1 = new OBJFace(); f1.materialName = cmaterial; f1.indexes = new int[] { indexes[0], indexes[1], indexes[2] }; f1.meshName = (splitByMaterial) ? cmaterial : cmesh; faceList.Add(f1); if (indexes.Length > 3) { OBJFace f2 = new OBJFace(); f2.materialName = cmaterial; f2.meshName = (splitByMaterial) ? cmaterial : cmesh; f2.indexes = new int[] { indexes[2], indexes[3], indexes[0] }; faceList.Add(f2); } } } } } if (objectNames.Count == 0) { objectNames.Add("default"); } //build objects GameObject parentObject = new GameObject(meshName); foreach (string obj in objectNames) { GameObject subObject = new GameObject(obj); subObject.transform.parent = parentObject.transform; subObject.transform.localScale = new Vector3(-1, 1, 1); //Create mesh Mesh m = new Mesh(); m.name = obj; //LISTS FOR REORDERING List <Vector3> processedVertices = new List <Vector3>(); List <Vector3> processedNormals = new List <Vector3>(); List <Vector2> processedUVs = new List <Vector2>(); List <int[]> processedIndexes = new List <int[]>(); Dictionary <int, int> remapTable = new Dictionary <int, int>(); //POPULATE MESH List <string> meshMaterialNames = new List <string>(); Dictionary <string, List <OBJFace> > ofDict = new Dictionary <string, List <OBJFace> >(); foreach (OBJFace f in faceList) { if (f.meshName == obj) { if (!ofDict.ContainsKey(f.materialName)) { ofDict[f.materialName] = new List <OBJFace>(); } ofDict[f.materialName].Add(f); } } yield return(null); //List<OBJFace> oflist = new List<OBJFace>(); //foreach (OBJFace f in faceList) //{ // if (f.meshName == obj) // { // oflist.Add(f); // } //} //OBJFace[] ofaces = faceList.Where(x => x.meshName == obj).ToArray(); foreach (string mn in materialNames) { //OBJFace[] faces = ofaces.Where(x => x.materialName == mn).ToArray(); //List<OBJFace> faces = new List<OBJFace>(); //foreach (OBJFace f in oflist) //{ // if (f.materialName == mn) // faces.Add(f); //} if (ofDict.ContainsKey(mn)) { List <OBJFace> faces = ofDict[mn]; if (faces.Count > 0) { //int[] indexes = new int[0]; //foreach (OBJFace f in faces) //{ // int l = indexes.Length; // System.Array.Resize(ref indexes, l + f.indexes.Length); // System.Array.Copy(f.indexes, 0, indexes, l, f.indexes.Length); //} List <int> indexList = new List <int>(); foreach (OBJFace f in faces) { for (int i = 0; i < f.indexes.Length; i++) { indexList.Add(f.indexes[i]); } } int[] indexes = indexList.ToArray(); meshMaterialNames.Add(mn); if (m.subMeshCount != meshMaterialNames.Count) { m.subMeshCount = meshMaterialNames.Count; } for (int i = 0; i < indexes.Length; i++) { int idx = indexes[i]; //build remap table if (remapTable.ContainsKey(idx)) { //ezpz indexes[i] = remapTable[idx]; } else { processedVertices.Add(uvertices[idx]); processedNormals.Add(unormals[idx]); processedUVs.Add(uuvs[idx]); remapTable[idx] = processedVertices.Count - 1; indexes[i] = remapTable[idx]; } } processedIndexes.Add(indexes); } else { } } } //apply stuff m.vertices = processedVertices.ToArray(); m.normals = processedNormals.ToArray(); m.uv = processedUVs.ToArray(); for (int i = 0; i < processedIndexes.Count; i++) { m.SetTriangles(processedIndexes[i], i); } if (!hasNormals) { m.RecalculateNormals(); } m.RecalculateBounds(); //m.Optimize(); MeshFilter mf = subObject.AddComponent <MeshFilter>(); MeshRenderer mr = subObject.AddComponent <MeshRenderer>(); Material[] processedMaterials = new Material[meshMaterialNames.Count]; for (int i = 0; i < meshMaterialNames.Count; i++) { if (materialCache == null) { //processedMaterials[i] = new Material(Shader.Find("Standard (Specular setup)")); processedMaterials[i] = Instantiate(standardMat); } else { Material mfn = Array.Find(materialCache, x => x.name == meshMaterialNames[i]);; if (mfn == null) { //processedMaterials[i] = new Material(Shader.Find("Standard (Specular setup)")); processedMaterials[i] = Instantiate(standardMat); } else { processedMaterials[i] = mfn; } } processedMaterials[i].name = meshMaterialNames[i]; } mr.materials = processedMaterials; mf.mesh = m; } if (done != null) { done(parentObject); } }
public void LoadOBJ(string fn, ActionAfterLoaded done) { StartCoroutine(LoadOBJFile(fn, done)); }