Newer
Older
HoloAnatomy / Assets / HoloToolkit / SpatialMapping / Scripts / RemoteMapping / Editor / RoomMeshExporter.cs
SURFACEBOOK2\jackwynne on 25 May 2018 9 KB v1
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Text;
  4. using UnityEditor;
  5. using UnityEngine;
  6. using HoloToolkit.Unity;
  7.  
  8. namespace HoloToolkit.Unity.SpatialMapping
  9. {
  10. public static class RoomMeshExporter
  11. {
  12. private const string ExportDirectoryKey = "_ExportDirectory";
  13. private const string ExportDirectoryDefault = "MeshExport";
  14. private const string ExportDialogErrorTitle = "Export Error";
  15. private const string WavefrontFileExtension = ".obj";
  16.  
  17. public static string ExportDirectory
  18. {
  19. get
  20. {
  21. return EditorPrefsUtility.GetEditorPref(ExportDirectoryKey, ExportDirectoryDefault);
  22. }
  23. set
  24. {
  25. if (string.IsNullOrEmpty(value))
  26. {
  27. value = ExportDirectoryDefault;
  28. }
  29.  
  30. EditorPrefsUtility.SetEditorPref(ExportDirectoryKey, value);
  31. }
  32. }
  33.  
  34. private static bool MakeExportDirectory()
  35. {
  36. try
  37. {
  38. Directory.CreateDirectory(ExportDirectory);
  39. }
  40. catch
  41. {
  42. return false;
  43. }
  44.  
  45. return true;
  46. }
  47.  
  48. [MenuItem("Mixed Reality Toolkit/Export/Export Room (.room) To Wavefront (.obj)...")]
  49. public static void ExportRoomToWavefront()
  50. {
  51. string selectedFile = EditorUtility.OpenFilePanelWithFilters("Select Room File", MeshSaver.MeshFolderName, new string[] { "Room", "room" });
  52. if (string.IsNullOrEmpty(selectedFile))
  53. {
  54. return;
  55. }
  56.  
  57. string fileName = Path.GetFileNameWithoutExtension(selectedFile);
  58. IEnumerable<Mesh> meshes = null;
  59. try
  60. {
  61. meshes = MeshSaver.Load(fileName);
  62. }
  63. catch
  64. {
  65. // Handling exceptions, and null returned by MeshSaver.Load, by checking if meshes
  66. // is still null below.
  67. }
  68.  
  69. if (meshes == null)
  70. {
  71. EditorUtility.DisplayDialog(ExportDialogErrorTitle, "Unable to parse selected file.", "Ok");
  72. return;
  73. }
  74.  
  75. SaveMeshesToWavefront(fileName, meshes);
  76.  
  77. // Open the location on where the mesh was saved.
  78. System.Diagnostics.Process.Start(ExportDirectory);
  79. }
  80.  
  81. [MenuItem("Mixed Reality Toolkit/Export/Export Selection To Wavefront (.obj)")]
  82. public static void ExportSelectionToWavefront()
  83. {
  84. Transform[] selectedTransforms = Selection.transforms;
  85. if (selectedTransforms.Length <= 0)
  86. {
  87. EditorUtility.DisplayDialog(ExportDialogErrorTitle, "Please select GameObject(s) within the scene that you want saved.", "OK");
  88. return;
  89. }
  90.  
  91. List<MeshFilter> meshFilters = new List<MeshFilter>(selectedTransforms.Length);
  92. for (int i = 0, iLength = selectedTransforms.Length; i < iLength; ++i)
  93. {
  94. meshFilters.AddRange(selectedTransforms[i].GetComponentsInChildren<MeshFilter>());
  95. }
  96.  
  97. if (meshFilters.Count == 0)
  98. {
  99. EditorUtility.DisplayDialog(ExportDialogErrorTitle, "Nothing selected contains a MeshFilter.", "Ok");
  100. return;
  101. }
  102.  
  103. SaveMeshFiltersToWavefront("Selection", meshFilters);
  104.  
  105. // Open the location on where the mesh was saved.
  106. System.Diagnostics.Process.Start(ExportDirectory);
  107. }
  108.  
  109. /// <summary>
  110. /// Saves meshes without any modifications during serialization.
  111. /// </summary>
  112. /// <param name="fileName">Name of the file, without path and extension.</param>
  113. public static void SaveMeshesToWavefront(string fileName, IEnumerable<Mesh> meshes)
  114. {
  115. if (!MakeExportDirectory())
  116. {
  117. EditorUtility.DisplayDialog(ExportDialogErrorTitle, "Failed to create export directory.", "Ok");
  118. return;
  119. }
  120.  
  121. string filePath = Path.Combine(ExportDirectory, fileName + WavefrontFileExtension);
  122. using (StreamWriter stream = new StreamWriter(filePath))
  123. {
  124. stream.Write(SerializeMeshes(meshes));
  125. }
  126. }
  127.  
  128. /// <summary>
  129. /// Transform all vertices and normals of the meshes into world space during serialization.
  130. /// </summary>
  131. /// <param name="fileName">Name of the file, without path and extension.</param>
  132. public static void SaveMeshFiltersToWavefront(string fileName, IEnumerable<MeshFilter> meshes)
  133. {
  134. if (!MakeExportDirectory())
  135. {
  136. EditorUtility.DisplayDialog(ExportDialogErrorTitle, "Failed to create export directory.", "Ok");
  137. return;
  138. }
  139.  
  140. string filePath = Path.Combine(ExportDirectory, fileName + WavefrontFileExtension);
  141. using (StreamWriter stream = new StreamWriter(filePath))
  142. {
  143. stream.Write(SerializeMeshFilters(meshes));
  144. }
  145. }
  146.  
  147. private static string SerializeMeshes(IEnumerable<Mesh> meshes)
  148. {
  149. StringWriter stream = new StringWriter();
  150. int offset = 0;
  151. foreach (var mesh in meshes)
  152. {
  153. SerializeMesh(mesh, stream, ref offset);
  154. }
  155. return stream.ToString();
  156. }
  157.  
  158. private static string SerializeMeshFilters(IEnumerable<MeshFilter> meshes)
  159. {
  160. StringWriter stream = new StringWriter();
  161. int offset = 0;
  162. foreach (var mesh in meshes)
  163. {
  164. SerializeMeshFilter(mesh, stream, ref offset);
  165. }
  166. return stream.ToString();
  167. }
  168.  
  169. /// <summary>
  170. /// Write single mesh to the stream passed in.
  171. /// </summary>
  172. /// <param name="meshFilter">Mesh to be serialized.</param>
  173. /// <param name="stream">Stream to write the mesh into.</param>
  174. /// <param name="offset">Index offset for handling multiple meshes in a single stream.</param>
  175. private static void SerializeMesh(Mesh mesh, TextWriter stream, ref int offset)
  176. {
  177. // Write vertices to .obj file. Need to make sure the points are transformed so everything is at a single origin.
  178. foreach (Vector3 vertex in mesh.vertices)
  179. {
  180. stream.WriteLine(string.Format("v {0} {1} {2}", -vertex.x, vertex.y, vertex.z));
  181. }
  182.  
  183. // Write normals. Need to transform the direction.
  184. foreach (Vector3 normal in mesh.normals)
  185. {
  186. stream.WriteLine(string.Format("vn {0} {1} {2}", normal.x, normal.y, normal.z));
  187. }
  188.  
  189. // Write indices.
  190. for (int s = 0, sLength = mesh.subMeshCount; s < sLength; ++s)
  191. {
  192. int[] indices = mesh.GetTriangles(s);
  193. for (int i = 0, iLength = indices.Length - indices.Length % 3; i < iLength; i += 3)
  194. {
  195. // Format is "vertex index / material index / normal index"
  196. stream.WriteLine(string.Format("f {0}//{0} {1}//{1} {2}//{2}",
  197. indices[i + 2] + 1 + offset,
  198. indices[i + 1] + 1 + offset,
  199. indices[i + 0] + 1 + offset));
  200. }
  201. }
  202.  
  203. offset += mesh.vertices.Length;
  204. }
  205.  
  206. /// <summary>
  207. /// Write single, transformed, mesh to the stream passed in.
  208. /// </summary>
  209. /// <param name="meshFilter">Contains the mesh to be transformed and serialized.</param>
  210. /// <param name="stream">Stream to write the transformed mesh into.</param>
  211. /// <param name="offset">Index offset for handling multiple meshes in a single stream.</param>
  212. private static void SerializeMeshFilter(MeshFilter meshFilter, TextWriter stream, ref int offset)
  213. {
  214. Mesh mesh = meshFilter.sharedMesh;
  215.  
  216. // Write vertices to .obj file. Need to make sure the points are transformed so everything is at a single origin.
  217. foreach (Vector3 vertex in mesh.vertices)
  218. {
  219. Vector3 pos = meshFilter.transform.TransformPoint(vertex);
  220. stream.WriteLine(string.Format("v {0} {1} {2}", -pos.x, pos.y, pos.z));
  221. }
  222.  
  223. // Write normals. Need to transform the direction.
  224. foreach (Vector3 meshNormal in mesh.normals)
  225. {
  226. Vector3 normal = meshFilter.transform.TransformDirection(meshNormal);
  227. stream.WriteLine(string.Format("vn {0} {1} {2}", normal.x, normal.y, normal.z));
  228. }
  229.  
  230. // Write indices.
  231. for (int s = 0, sLength = mesh.subMeshCount; s < sLength; ++s)
  232. {
  233. int[] indices = mesh.GetTriangles(s);
  234. for (int i = 0, iLength = indices.Length - indices.Length % 3; i < iLength; i += 3)
  235. {
  236. // Format is "vertex index / material index / normal index"
  237. stream.WriteLine(string.Format("f {0}//{0} {1}//{1} {2}//{2}",
  238. indices[i + 0] + 1 + offset,
  239. indices[i + 1] + 1 + offset,
  240. indices[i + 2] + 1 + offset));
  241. }
  242. }
  243.  
  244. offset += mesh.vertices.Length;
  245. }
  246. }
  247. }