/Assets/Plugins/AstarPathfindingProject/Generators/Utilities/ObjImporter.cs

https://bitbucket.org/Werring/unity-indusim · C# · 256 lines · 225 code · 18 blank · 13 comment · 35 complexity · 92d79e2ca0b49bc38828382382e7f171 MD5 · raw file

  1. /** This is a simple utility class for importing obj files into a Unity mesh at runtime.
  2. * This version of ObjImporter first reads through the entire file, getting a count of how large
  3. * the final arrays will be, and then uses standard arrays for everything (as opposed to ArrayLists
  4. * or any other fancy things).
  5. * \author el anónimo at the UnifyCommunity wiki (at least he seems to have created the page)
  6. */
  7. using UnityEngine;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Text;
  12. public class ObjImporter {
  13. private struct meshStruct
  14. {
  15. public Vector3[] vertices;
  16. public Vector3[] normals;
  17. public Vector2[] uv;
  18. public Vector2[] uv1;
  19. public Vector2[] uv2;
  20. public int[] triangles;
  21. public int[] faceVerts;
  22. public int[] faceUVs;
  23. public Vector3[] faceData;
  24. public string name;
  25. public string fileName;
  26. }
  27. // Use this for initialization
  28. public static Mesh ImportFile (string filePath) {
  29. if (!File.Exists (filePath)) {
  30. Debug.LogError ("No file was found at '"+filePath+"'");
  31. return null;
  32. }
  33. meshStruct newMesh = createMeshStruct(filePath);
  34. populateMeshStruct(ref newMesh);
  35. Vector3[] newVerts = new Vector3[newMesh.faceData.Length];
  36. Vector2[] newUVs = new Vector2[newMesh.faceData.Length];
  37. Vector3[] newNormals = new Vector3[newMesh.faceData.Length];
  38. int i = 0;
  39. /* The following foreach loops through the facedata and assigns the appropriate vertex, uv, or normal
  40. * for the appropriate Unity mesh array.
  41. */
  42. foreach (Vector3 v in newMesh.faceData)
  43. {
  44. newVerts[i] = newMesh.vertices[(int)v.x - 1];
  45. if (v.y >= 1)
  46. newUVs[i] = newMesh.uv[(int)v.y - 1];
  47. if (v.z >= 1)
  48. newNormals[i] = newMesh.normals[(int)v.z - 1];
  49. i++;
  50. }
  51. Mesh mesh = new Mesh();
  52. mesh.vertices = newVerts;
  53. mesh.uv = newUVs;
  54. mesh.normals = newNormals;
  55. mesh.triangles = newMesh.triangles;
  56. mesh.RecalculateBounds();
  57. //mesh.Optimize();
  58. return mesh;
  59. }
  60. private static meshStruct createMeshStruct(string filename)
  61. {
  62. int triangles = 0;
  63. int vertices = 0;
  64. int vt = 0;
  65. int vn = 0;
  66. int face = 0;
  67. meshStruct mesh = new meshStruct();
  68. mesh.fileName = filename;
  69. StreamReader stream = File.OpenText(filename);
  70. string entireText = stream.ReadToEnd();
  71. stream.Close();
  72. using (StringReader reader = new StringReader(entireText))
  73. {
  74. string currentText = reader.ReadLine();
  75. char[] splitIdentifier = { ' ' };
  76. string[] brokenString;
  77. while (currentText != null)
  78. {
  79. if (!currentText.StartsWith("f ") && !currentText.StartsWith("v ") && !currentText.StartsWith("vt ")
  80. && !currentText.StartsWith("vn "))
  81. {
  82. currentText = reader.ReadLine();
  83. if (currentText != null)
  84. {
  85. currentText = currentText.Replace(" ", " ");
  86. }
  87. }
  88. else
  89. {
  90. currentText = currentText.Trim(); //Trim the current line
  91. brokenString = currentText.Split(splitIdentifier, 50); //Split the line into an array, separating the original line by blank spaces
  92. switch (brokenString[0])
  93. {
  94. case "v":
  95. vertices++;
  96. break;
  97. case "vt":
  98. vt++;
  99. break;
  100. case "vn":
  101. vn++;
  102. break;
  103. case "f":
  104. face = face + brokenString.Length - 1;
  105. triangles = triangles + 3 * (brokenString.Length - 2); /*brokenString.Length is 3 or greater since a face must have at least
  106. 3 vertices. For each additional vertice, there is an additional
  107. triangle in the mesh (hence this formula).*/
  108. break;
  109. }
  110. currentText = reader.ReadLine();
  111. if (currentText != null)
  112. {
  113. currentText = currentText.Replace(" ", " ");
  114. }
  115. }
  116. }
  117. }
  118. mesh.triangles = new int[triangles];
  119. mesh.vertices = new Vector3[vertices];
  120. mesh.uv = new Vector2[vt];
  121. mesh.normals = new Vector3[vn];
  122. mesh.faceData = new Vector3[face];
  123. return mesh;
  124. }
  125. private static void populateMeshStruct(ref meshStruct mesh)
  126. {
  127. StreamReader stream = File.OpenText(mesh.fileName);
  128. string entireText = stream.ReadToEnd();
  129. stream.Close();
  130. using (StringReader reader = new StringReader(entireText))
  131. {
  132. string currentText = reader.ReadLine();
  133. char[] splitIdentifier = { ' ' };
  134. char[] splitIdentifier2 = { '/' };
  135. string[] brokenString;
  136. string[] brokenBrokenString;
  137. int f = 0;
  138. int f2 = 0;
  139. int v = 0;
  140. int vn = 0;
  141. int vt = 0;
  142. int vt1 = 0;
  143. int vt2 = 0;
  144. while (currentText != null)
  145. {
  146. if (!currentText.StartsWith("f ") && !currentText.StartsWith("v ") && !currentText.StartsWith("vt ") &&
  147. !currentText.StartsWith("vn ") && !currentText.StartsWith("g ") && !currentText.StartsWith("usemtl ") &&
  148. !currentText.StartsWith("mtllib ") && !currentText.StartsWith("vt1 ") && !currentText.StartsWith("vt2 ") &&
  149. !currentText.StartsWith("vc ") && !currentText.StartsWith("usemap "))
  150. {
  151. currentText = reader.ReadLine();
  152. if (currentText != null)
  153. {
  154. currentText = currentText.Replace(" ", " ");
  155. }
  156. }
  157. else
  158. {
  159. currentText = currentText.Trim();
  160. brokenString = currentText.Split(splitIdentifier, 50);
  161. switch (brokenString[0])
  162. {
  163. case "g":
  164. break;
  165. case "usemtl":
  166. break;
  167. case "usemap":
  168. break;
  169. case "mtllib":
  170. break;
  171. case "v":
  172. mesh.vertices[v] = new Vector3(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]),
  173. System.Convert.ToSingle(brokenString[3]));
  174. v++;
  175. break;
  176. case "vt":
  177. mesh.uv[vt] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]));
  178. vt++;
  179. break;
  180. case "vt1":
  181. mesh.uv[vt1] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]));
  182. vt1++;
  183. break;
  184. case "vt2":
  185. mesh.uv[vt2] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]));
  186. vt2++;
  187. break;
  188. case "vn":
  189. mesh.normals[vn] = new Vector3(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]),
  190. System.Convert.ToSingle(brokenString[3]));
  191. vn++;
  192. break;
  193. case "vc":
  194. break;
  195. case "f":
  196. int j = 1;
  197. List<int> intArray = new List<int>();
  198. while (j < brokenString.Length && ("" + brokenString[j]).Length > 0)
  199. {
  200. Vector3 temp = new Vector3();
  201. brokenBrokenString = brokenString[j].Split(splitIdentifier2, 3); //Separate the face into individual components (vert, uv, normal)
  202. temp.x = System.Convert.ToInt32(brokenBrokenString[0]);
  203. if (brokenBrokenString.Length > 1) //Some .obj files skip UV and normal
  204. {
  205. if (brokenBrokenString[1] != "") //Some .obj files skip the uv and not the normal
  206. {
  207. temp.y = System.Convert.ToInt32(brokenBrokenString[1]);
  208. }
  209. temp.z = System.Convert.ToInt32(brokenBrokenString[2]);
  210. }
  211. j++;
  212. mesh.faceData[f2] = temp;
  213. intArray.Add(f2);
  214. f2++;
  215. }
  216. j = 1;
  217. while (j + 2 < brokenString.Length) //Create triangles out of the face data. There will generally be more than 1 triangle per face.
  218. {
  219. mesh.triangles[f] = intArray[0];
  220. f++;
  221. mesh.triangles[f] = intArray[j];
  222. f++;
  223. mesh.triangles[f] = intArray[j+1];
  224. f++;
  225. j++;
  226. }
  227. break;
  228. }
  229. currentText = reader.ReadLine();
  230. if (currentText != null)
  231. {
  232. currentText = currentText.Replace(" ", " "); //Some .obj files insert double spaces, this removes them.
  233. }
  234. }
  235. }
  236. }
  237. }
  238. }