using System; using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; /* (C) 2015 AARO4130 Edited by Pillars of SY */ public class SimpleOBJ { //Structures struct OBJFace { public string meshName; public int[] indexes; } //Connections //[Header("Connections")] //Prefabs //[Header("Prefabs")] //Attributes //[Header("Attributes")] private static string[] searchPaths = new string[] { "", "%FileName%_Textures" + Path.DirectorySeparatorChar }; //Stats //[Header("Stats")] //Getter //Delegates //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //setup //*********************************************************************************************************************** //update //*********************************************************************************************************************** //refresh //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //*********************************************************************************************************************** //events //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //*********************************************************************************************************************** //private, protected private static Vector3 ParseVectorFromCMPS(string[] cmps) { float x = float.Parse(cmps[1]); float y = float.Parse(cmps[2]); if (cmps.Length == 4) { float z = float.Parse(cmps[3]); return new Vector3(x, y, z); } return new Vector2(x, y); } //------------------------------------------------------------------------------------------------------------------ private static string OBJGetFilePath(string path, string basePath, string fileName) { foreach (string sp in searchPaths) { string s = sp.Replace("%FileName%", fileName); if (File.Exists(basePath + s + path)) { return basePath + s + path; } else if (File.Exists(path)) { return path; } } return null; } //------------------------------------------------------------------------------------------------------------------ //*********************************************************************************************************************** //public static public static GameObject LoadOBJFile(string path, Material mat, bool addCollider = true) { //Does the File exist? if (File.Exists(path)) { string meshName = Path.GetFileNameWithoutExtension(path); bool hasNormals = false; //OBJ LISTS List vertices = new List(); List normals = new List(); //UMESH LISTS List uvertices = new List(); List unormals = new List(); //MESH CONSTRUCTION List objectNames = new List(); Dictionary hashtable = new Dictionary(); List faceList = new List(); string cmesh = "default"; //Go through FileLines foreach (string ln in File.ReadAllLines(path)) { 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] == "g" || cmps[0] == "o")) { cmesh = data; if (!objectNames.Contains(cmesh)) { objectNames.Add(cmesh); } } 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] == "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; if ( felement.Contains("//") || //no UVs? felement.Count(x => x == '/') == 2) //with UVs? { string[] elementComps = felement.Split('/'); vertexIndex = int.Parse(elementComps[0]) - 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; } string hashEntry = vertexIndex + "|" + normalIndex; 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 (indexes.Length < 5 && indexes.Length >= 3) { OBJFace f1 = new OBJFace(); f1.indexes = new int[] { indexes[0], indexes[1], indexes[2] }; f1.meshName = cmesh; faceList.Add(f1); if (indexes.Length > 3) { OBJFace f2 = new OBJFace(); f2.meshName = 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); //Go through Objects 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 processedVertices = new List(); List processedNormals = new List(); List processedIndexes = new List(); Dictionary remapTable = new Dictionary(); //POPULATE MESH OBJFace[] faces = faceList.Where(x => x.meshName == obj).ToArray(); if (faces.Length > 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); } m.subMeshCount = 1; 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]); remapTable[idx] = processedVertices.Count - 1; indexes[i] = remapTable[idx]; } } processedIndexes.Add(indexes); } //apply stuff m.vertices = processedVertices.ToArray(); m.normals = processedNormals.ToArray(); for (int i = 0; i < processedIndexes.Count; i++) { m.SetTriangles(processedIndexes[i], i); } if (!hasNormals) { m.RecalculateNormals(); } m.RecalculateBounds(); //Add MeshFilter MeshFilter mf = subObject.AddComponent(); mf.mesh = m; //Add MeshRenderer MeshRenderer mr = subObject.AddComponent(); mr.materials = new Material[] { mat }; //Add MeshCollider subObject.AddComponent(); } return parentObject; } else { return null; } } //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //*********************************************************************************************************************** //public //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //*********************************************************************************************************************** //getter, setter //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ }