MegaCacheOBJImport.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. using UnityEngine;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. public class MegaCacheOBJMtl
  6. {
  7. public string name;
  8. public Color Ka;
  9. public Color Kd;
  10. public Color Ks;
  11. public Color Tf;
  12. public float Tr;
  13. public Color Ke;
  14. public float Ns;
  15. public float Ni;
  16. public float d;
  17. public int illum;
  18. public string map_Ka;
  19. public string map_Kd;
  20. public Texture2D Kdtexture;
  21. }
  22. public class MegaCacheObjImporter
  23. {
  24. class MegaCacheOBJFace
  25. {
  26. public int[] v = new int[4];
  27. public int[] uv = new int[4];
  28. public int[] n = new int[4];
  29. public bool quad = false;
  30. public int smthgrp;
  31. public int mtl;
  32. }
  33. class MegaCacheOBJMesh
  34. {
  35. public List<Vector3> vertices = new List<Vector3>();
  36. public List<Vector3> normals = new List<Vector3>();
  37. public List<Vector2> uv = new List<Vector2>();
  38. public List<Vector2> uv1 = new List<Vector2>();
  39. public List<Vector2> uv2 = new List<Vector2>();
  40. public List<MegaCacheOBJFace> faces = new List<MegaCacheOBJFace>();
  41. }
  42. static List<MegaCacheOBJMtl> mtls = new List<MegaCacheOBJMtl>();
  43. static List<MegaCacheFace> faces = new List<MegaCacheFace>();
  44. static int currentmtl;
  45. static int smthgrp;
  46. static int offset = 0;
  47. static int offsetmtl = 0;
  48. static MegaCacheOBJMtl loadmtl;
  49. static public void Init()
  50. {
  51. mtls.Clear();
  52. }
  53. static public int NumMtls()
  54. {
  55. return mtls.Count;
  56. }
  57. static public MegaCacheOBJMtl GetMtl(int i)
  58. {
  59. return mtls[i];
  60. }
  61. static string importpath;
  62. static public Mesh ImportFile(string filePath, float scale, bool adjust, bool tangents, bool loadmtls, bool optimize, bool recalcnormals)
  63. {
  64. #if UNITY_EDITOR
  65. faces.Clear();
  66. importpath = Path.GetDirectoryName(filePath);
  67. StreamReader stream = File.OpenText(filePath);
  68. string entireText = stream.ReadToEnd();
  69. stream.Close();
  70. MegaCacheOBJMesh newMesh = new MegaCacheOBJMesh();
  71. populateMeshStructNew(entireText, ref newMesh, loadmtls);
  72. Mesh mesh = new Mesh();
  73. int v1 = 0;
  74. int v2 = 1;
  75. int v3 = 2;
  76. int v4 = 3;
  77. currentmtl = 0;
  78. smthgrp = 0;
  79. for ( int i = 0; i < newMesh.vertices.Count; i++ )
  80. {
  81. newMesh.vertices[i] *= scale;
  82. if ( adjust )
  83. {
  84. Vector3 p = newMesh.vertices[i];
  85. p.x = -p.x;
  86. newMesh.vertices[i] = p;
  87. }
  88. }
  89. for ( int i = 0; i < newMesh.normals.Count; i++ )
  90. {
  91. Vector3 p = newMesh.normals[i];
  92. p.x = -p.x;
  93. newMesh.normals[i] = p;
  94. }
  95. Vector3 n1 = Vector3.forward;
  96. Vector3 n2 = Vector3.forward;
  97. Vector3 n3 = Vector3.forward;
  98. Vector3 n4 = Vector3.forward;
  99. if ( newMesh.normals.Count == 0 )
  100. recalcnormals = true;
  101. if ( newMesh.uv.Count == 0 )
  102. {
  103. for ( int t = 0; t < newMesh.faces.Count; t++ )
  104. {
  105. MegaCacheOBJFace f = newMesh.faces[t];
  106. if ( newMesh.normals.Count > 0 )
  107. {
  108. n1 = newMesh.normals[f.n[v1]];
  109. n2 = newMesh.normals[f.n[v2]];
  110. n3 = newMesh.normals[f.n[v3]];
  111. if ( f.quad )
  112. n4 = newMesh.normals[f.n[v4]];
  113. }
  114. if ( adjust )
  115. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v3]], newMesh.vertices[f.v[v2]], n1, n3, n2, Vector3.zero, Vector3.zero, Vector3.zero, 1, f.mtl));
  116. else
  117. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v2]], newMesh.vertices[f.v[v3]], n1, n2, n3, Vector3.zero, Vector3.zero, Vector3.zero, 1, f.mtl));
  118. if ( f.quad )
  119. {
  120. if ( adjust )
  121. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v4]], newMesh.vertices[f.v[v3]], n1, n4, n3, Vector3.zero, Vector3.zero, Vector3.zero, 1, f.mtl));
  122. else
  123. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v3]], newMesh.vertices[f.v[v4]], n1, n3, n4, Vector3.zero, Vector3.zero, Vector3.zero, 1, f.mtl));
  124. }
  125. }
  126. MegaCacheMeshConstructorOBJNoUV.Construct(faces, mesh, newMesh.vertices.ToArray(), false, recalcnormals, tangents);
  127. }
  128. else
  129. {
  130. for ( int t = 0; t < newMesh.faces.Count; t++ )
  131. {
  132. MegaCacheOBJFace f = newMesh.faces[t];
  133. if ( newMesh.normals.Count > 0 )
  134. {
  135. n1 = newMesh.normals[f.n[v1]];
  136. n2 = newMesh.normals[f.n[v2]];
  137. n3 = newMesh.normals[f.n[v3]];
  138. if ( f.quad )
  139. n4 = newMesh.normals[f.n[v4]];
  140. }
  141. if ( adjust )
  142. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v3]], newMesh.vertices[f.v[v2]], n1, n3, n2, newMesh.uv[f.uv[v1]], newMesh.uv[f.uv[v3]], newMesh.uv[f.uv[v2]], 1, f.mtl));
  143. else
  144. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v2]], newMesh.vertices[f.v[v3]], n1, n2, n3, newMesh.uv[f.uv[v1]], newMesh.uv[f.uv[v2]], newMesh.uv[f.uv[v3]], 1, f.mtl));
  145. if ( f.quad )
  146. {
  147. if ( adjust )
  148. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v4]], newMesh.vertices[f.v[v3]], n1, n4, n3, newMesh.uv[f.uv[v1]], newMesh.uv[f.uv[v4]], newMesh.uv[f.uv[v3]], 1, f.mtl));
  149. else
  150. faces.Add(new MegaCacheFace(newMesh.vertices[f.v[v1]], newMesh.vertices[f.v[v3]], newMesh.vertices[f.v[v4]], n1, n3, n4, newMesh.uv[f.uv[v1]], newMesh.uv[f.uv[v3]], newMesh.uv[f.uv[v4]], 1, f.mtl));
  151. }
  152. }
  153. MegaCacheMeshConstructorOBJ.Construct(faces, mesh, newMesh.vertices.ToArray(), false, recalcnormals, tangents);
  154. }
  155. return mesh;
  156. #else
  157. return null;
  158. #endif
  159. }
  160. static public string ReadLine(string input)
  161. {
  162. StringBuilder sb = new StringBuilder();
  163. while ( true )
  164. {
  165. if ( offset >= input.Length )
  166. break;
  167. int ch = input[offset++];
  168. if ( ch == '\r' || ch == '\n' )
  169. {
  170. while ( offset < input.Length )
  171. {
  172. int ch1 = input[offset++];
  173. if ( ch1 != '\n' )
  174. {
  175. offset--;
  176. break;
  177. }
  178. }
  179. return sb.ToString();
  180. }
  181. sb.Append((char)ch);
  182. }
  183. if ( sb.Length > 0 )
  184. return sb.ToString();
  185. return null;
  186. }
  187. static public string ReadLineMtl(string input)
  188. {
  189. StringBuilder sb = new StringBuilder();
  190. while ( true )
  191. {
  192. if ( offsetmtl >= input.Length )
  193. break;
  194. int ch = input[offsetmtl++];
  195. if ( ch == '\r' || ch == '\n' )
  196. {
  197. while ( offsetmtl < input.Length )
  198. {
  199. int ch1 = input[offsetmtl++];
  200. if ( ch1 != '\n' )
  201. {
  202. offsetmtl--;
  203. break;
  204. }
  205. }
  206. return sb.ToString();
  207. }
  208. sb.Append((char)ch);
  209. }
  210. if ( sb.Length > 0 )
  211. return sb.ToString();
  212. return null;
  213. }
  214. static void populateMeshStructNew(string entireText, ref MegaCacheOBJMesh mesh, bool loadmtls)
  215. {
  216. offset = 0;
  217. string currentText = ReadLine(entireText);
  218. char[] splitIdentifier = { ' ' };
  219. char[] splitIdentifier2 = { '/' };
  220. string[] brokenString;
  221. string[] brokenBrokenString;
  222. //int smthgrp = -1;
  223. while ( currentText != null )
  224. {
  225. currentText = currentText.Trim();
  226. brokenString = currentText.Split(splitIdentifier, 50);
  227. switch ( brokenString[0] )
  228. {
  229. case "g": break;
  230. case "usemtl":
  231. brokenString[1] = brokenString[1].Replace(':', '_');
  232. if ( loadmtls )
  233. currentmtl = GetMtlID(brokenString[1]);
  234. else
  235. currentmtl = 0;
  236. break;
  237. case "usemap": break;
  238. case "mtllib":
  239. if ( loadmtls )
  240. {
  241. string p = importpath + "/" + brokenString[1];
  242. LoadMtlLib(p);
  243. }
  244. break;
  245. case "v": mesh.vertices.Add(new Vector3(float.Parse(brokenString[1]), float.Parse(brokenString[2]), float.Parse(brokenString[3]))); break;
  246. case "vt": mesh.uv.Add(new Vector2(float.Parse(brokenString[1]), float.Parse(brokenString[2]))); break;
  247. case "vt1": mesh.uv1.Add(new Vector2(float.Parse(brokenString[1]), float.Parse(brokenString[2]))); break;
  248. case "vt2": mesh.uv2.Add(new Vector2(float.Parse(brokenString[1]), float.Parse(brokenString[2]))); break;
  249. case "vn": mesh.normals.Add(new Vector3(float.Parse(brokenString[1]), float.Parse(brokenString[2]), float.Parse(brokenString[3]))); break;
  250. case "vc": break;
  251. case "f":
  252. int j = 1;
  253. MegaCacheOBJFace oface = new MegaCacheOBJFace();
  254. oface.mtl = currentmtl;
  255. oface.smthgrp = smthgrp;
  256. while ( j < brokenString.Length && ("" + brokenString[j]).Length > 0 )
  257. {
  258. if ( j > 4 )
  259. {
  260. Debug.LogError("OBJ file contains faces with more than 4 sides, importer only supports quads and tris!");
  261. return;
  262. }
  263. brokenBrokenString = brokenString[j].Split(splitIdentifier2, 3);
  264. if ( j == 4 )
  265. oface.quad = true;
  266. oface.v[j - 1] = int.Parse(brokenBrokenString[0]) - 1;
  267. if ( oface.v[j - 1] < 0 )
  268. oface.v[j - 1] = mesh.vertices.Count + oface.v[j - 1] + 1;
  269. if ( brokenBrokenString.Length > 1 )
  270. {
  271. if ( brokenBrokenString[1] != "" )
  272. {
  273. oface.uv[j - 1] = int.Parse(brokenBrokenString[1]) - 1;
  274. if ( oface.uv[j - 1] < 0 )
  275. oface.uv[j - 1] = mesh.uv.Count + oface.uv[j - 1] + 1;
  276. }
  277. if ( brokenBrokenString.Length > 2 )
  278. {
  279. oface.n[j - 1] = int.Parse(brokenBrokenString[2]) - 1;
  280. if ( oface.n[j - 1] < 0 )
  281. oface.n[j - 1] = mesh.normals.Count + oface.n[j - 1] + 1;
  282. }
  283. }
  284. j++;
  285. }
  286. mesh.faces.Add(oface);
  287. break;
  288. case "s":
  289. //if ( brokenString[1] == "off" )
  290. //smthgrp = -1;
  291. //else
  292. //smthgrp = int.Parse(brokenString[1]);
  293. break;
  294. }
  295. currentText = ReadLine(entireText);
  296. if ( currentText != null )
  297. currentText = currentText.Replace(" ", " ");
  298. }
  299. }
  300. static public void ImportMtl(string filePath)
  301. {
  302. LoadMtlLib(filePath);
  303. }
  304. static MegaCacheOBJMtl HaveMaterial(string name)
  305. {
  306. for ( int i = 0; i < mtls.Count; i++ )
  307. {
  308. if ( mtls[i].name == name )
  309. {
  310. return mtls[i];
  311. }
  312. }
  313. MegaCacheOBJMtl mtl = new MegaCacheOBJMtl();
  314. mtl.Ka = Color.white;
  315. mtl.Kd = Color.white;
  316. mtl.Ks = Color.white;
  317. mtl.Ke = Color.white;
  318. mtl.name = name;
  319. mtls.Add(mtl);
  320. return mtl;
  321. }
  322. static int GetMtlID(string name)
  323. {
  324. if ( mtls.Count > 0 )
  325. {
  326. for ( int i = 0; i < mtls.Count; i++ )
  327. {
  328. if ( mtls[i].name == name )
  329. {
  330. return i;
  331. }
  332. }
  333. Debug.Log("Missing Material " + name);
  334. }
  335. return 0;
  336. }
  337. #if false
  338. static public Texture2D LoadTexture(string filename)
  339. {
  340. Texture2D tex = null;
  341. if ( File.Exists(filename) )
  342. {
  343. byte[] buf = File.ReadAllBytes(filename);
  344. tex = new Texture2D(2, 2);
  345. tex.LoadImage(buf);
  346. }
  347. return tex;
  348. }
  349. #endif
  350. static void LoadMtlLib(string filename)
  351. {
  352. #if UNITY_EDITOR
  353. offsetmtl = 0;
  354. string path = Path.GetDirectoryName(filename);
  355. StreamReader stream = File.OpenText(filename);
  356. string entireText = stream.ReadToEnd();
  357. stream.Close();
  358. //using ( StringReader reader = new StringReader(entireText) )
  359. {
  360. //string currentText = reader.ReadLine();
  361. string currentText = ReadLineMtl(entireText);
  362. char[] splitIdentifier = { ' ' };
  363. string[] brokenString;
  364. while ( currentText != null )
  365. {
  366. currentText = currentText.Trim();
  367. brokenString = currentText.Split(splitIdentifier, 50);
  368. switch ( brokenString[0] )
  369. {
  370. case "newmtl":
  371. brokenString[1] = brokenString[1].Replace(':', '_');
  372. MegaCacheOBJMtl mtl = HaveMaterial(brokenString[1]);
  373. loadmtl = mtl;
  374. break;
  375. case "Ns":
  376. loadmtl.Ns = float.Parse(brokenString[1]);
  377. break;
  378. case "Ni":
  379. loadmtl.Ni = float.Parse(brokenString[1]);
  380. break;
  381. case "d":
  382. loadmtl.d = float.Parse(brokenString[1]);
  383. break;
  384. case "Tr":
  385. loadmtl.Tr = float.Parse(brokenString[1]);
  386. break;
  387. case "Tf":
  388. loadmtl.Tf.r = float.Parse(brokenString[1]);
  389. loadmtl.Tf.g = float.Parse(brokenString[2]);
  390. loadmtl.Tf.b = float.Parse(brokenString[3]);
  391. break;
  392. case "illum":
  393. loadmtl.illum = int.Parse(brokenString[1]);
  394. break;
  395. case "Ka":
  396. loadmtl.Ka.r = float.Parse(brokenString[1]);
  397. loadmtl.Ka.g = float.Parse(brokenString[2]);
  398. loadmtl.Ka.b = float.Parse(brokenString[3]);
  399. break;
  400. case "Kd":
  401. loadmtl.Kd.r = float.Parse(brokenString[1]);
  402. loadmtl.Kd.g = float.Parse(brokenString[2]);
  403. loadmtl.Kd.b = float.Parse(brokenString[3]);
  404. break;
  405. case "Ks":
  406. loadmtl.Ks.r = float.Parse(brokenString[1]);
  407. loadmtl.Ks.g = float.Parse(brokenString[2]);
  408. loadmtl.Ks.b = float.Parse(brokenString[3]);
  409. break;
  410. case "Ke":
  411. loadmtl.Ke.r = float.Parse(brokenString[1]);
  412. loadmtl.Ke.g = float.Parse(brokenString[2]);
  413. loadmtl.Ke.b = float.Parse(brokenString[3]);
  414. break;
  415. case "map_Ka":
  416. if ( brokenString.Length > 1 )
  417. loadmtl.map_Ka = brokenString[1];
  418. break;
  419. case "map_Kd":
  420. if ( brokenString.Length > 1 )
  421. {
  422. string dir = Path.GetDirectoryName(brokenString[1]);
  423. if ( dir.Length == 0 )
  424. loadmtl.map_Kd = path + "/" + brokenString[1];
  425. else
  426. loadmtl.map_Kd = brokenString[1];
  427. }
  428. break;
  429. }
  430. //currentText = reader.ReadLine();
  431. currentText = ReadLineMtl(entireText);
  432. if ( currentText != null )
  433. currentText = currentText.Replace(" ", " ");
  434. }
  435. }
  436. #endif
  437. }
  438. }