You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
12 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. /*
  2. Simple Mesh Combine
  3. Copyright Unluck Software
  4. www.chemicalbliss.com
  5. */
  6. using UnityEngine;
  7. using System;
  8. using System.IO;
  9. using System.Text;
  10. using UnityEditor;
  11. [CustomEditor(typeof(SimpleMeshCombine))]
  12. [System.Serializable]
  13. public class SimpleMeshCombineEditor : Editor {
  14. public Texture titleTexture;
  15. public void ExportMesh(MeshFilter meshFilter, string folder, string filename) {
  16. string path = SaveFile(folder, filename, "obj");
  17. if (path != null) {
  18. StreamWriter sw = new StreamWriter(path);
  19. sw.Write(MeshToString(meshFilter));
  20. sw.Flush();
  21. sw.Close();
  22. AssetDatabase.Refresh();
  23. Debug.Log("Exported OBJ file to folder: " + path);
  24. }
  25. }
  26. public string MeshToString(MeshFilter meshFilter) {
  27. Mesh sMesh = meshFilter.sharedMesh;
  28. StringBuilder stringBuilder = new StringBuilder();
  29. stringBuilder.Append("g ").Append(meshFilter.name).Append("\n");
  30. foreach (Vector3 vert in sMesh.vertices) {
  31. Vector3 tPoint = meshFilter.transform.TransformPoint(vert);
  32. stringBuilder.Append(String.Format("v {0} {1} {2}\n", -tPoint.x, tPoint.y, tPoint.z));
  33. }
  34. stringBuilder.Append("\n");
  35. foreach (Vector3 norm in sMesh.normals) {
  36. Vector3 tDir = meshFilter.transform.TransformDirection(norm);
  37. stringBuilder.Append(String.Format("vn {0} {1} {2}\n", -tDir.x, tDir.y, tDir.z));
  38. }
  39. stringBuilder.Append("\n");
  40. foreach (Vector3 uv in sMesh.uv) {
  41. stringBuilder.Append(String.Format("vt {0} {1}\n", uv.x, uv.y));
  42. }
  43. for (int material = 0; material < sMesh.subMeshCount; material++) {
  44. stringBuilder.Append("\n");
  45. int[] tris = sMesh.GetTriangles(material);
  46. for (int i = 0; i < tris.Length; i += 3) {
  47. stringBuilder.Append(String.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n", tris[i] + 1, tris[i + 1] + 1, tris[i + 2] + 1));
  48. }
  49. }
  50. return stringBuilder.ToString();
  51. }
  52. public string SaveFile(string folder, string name, string type) {
  53. string newPath = "";
  54. string path = EditorUtility.SaveFilePanel("Select Folder ", folder, name, type);
  55. if (path.Length > 0) {
  56. if (path.Contains("" + Application.dataPath)) {
  57. string s = "" + path + "";
  58. string d = "" + Application.dataPath + "/";
  59. string p = "Assets/" + s.Remove(0, d.Length);
  60. bool cancel = false;
  61. if (cancel) Debug.Log("Canceled");
  62. newPath = p;
  63. } else {
  64. Debug.LogError("Prefab Save Failed: Can't save outside project: " + path);
  65. }
  66. }
  67. return newPath;
  68. }
  69. public override void OnInspectorGUI() {
  70. var target_cs = (SimpleMeshCombine)target;
  71. GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
  72. GUIStyle buttonStyle2 = new GUIStyle(GUI.skin.button);
  73. buttonStyle.fontStyle = FontStyle.Bold;
  74. buttonStyle.fixedWidth = 150.0f;
  75. buttonStyle.fixedHeight = 35.0f;
  76. buttonStyle.fontSize = 15;
  77. buttonStyle2.fixedWidth = 200.0f;
  78. buttonStyle2.fixedHeight = 20.0f;
  79. buttonStyle2.margin = new RectOffset((int)((Screen.width - 200) * .5f), (int)((Screen.width - 200) * .5f), 0, 0);
  80. buttonStyle.margin = new RectOffset((int)((Screen.width - 150) * .5f), (int)((Screen.width - 150) * .5f), 0, 0);
  81. GUIStyle infoStyle = new GUIStyle(GUI.skin.label);
  82. infoStyle.fontSize = 10;
  83. infoStyle.margin.top = 0;
  84. infoStyle.margin.bottom = 0;
  85. if (!Application.isPlaying) {
  86. GUI.enabled = true;
  87. } else {
  88. GUILayout.Label("Editor can't combine in play-mode", infoStyle);
  89. GUILayout.Label("Use SimpleMeshCombine.CombineMeshes();", infoStyle);
  90. GUI.enabled = false;
  91. }
  92. GUILayout.Space(15.0f);
  93. if (target_cs.combinedGameOjects == null || target_cs.combinedGameOjects.Length == 0) {
  94. if (GUILayout.Button("Combine", buttonStyle)) {
  95. if (target_cs.transform.childCount >= 1) target_cs.CombineMeshes();
  96. }
  97. } else {
  98. if (GUILayout.Button("Release", buttonStyle)) {
  99. target_cs.EnableRenderers(true);
  100. if (target_cs.combined != null) DestroyImmediate(target_cs.combined);
  101. target_cs.combinedGameOjects = null;
  102. target_cs.vCount = 0;
  103. }
  104. }
  105. GUILayout.Space(5.0f);
  106. if (target_cs.combined != null) {
  107. if (!target_cs._canGenerateLightmapUV) {
  108. GUILayout.Label("Warning: Mesh has too high vertex count", EditorStyles.boldLabel);
  109. GUI.enabled = false;
  110. }
  111. if (target_cs.combined.GetComponent<MeshFilter>().sharedMesh.name != "") {
  112. GUI.enabled = false;
  113. } else if (!Application.isPlaying) {
  114. GUI.enabled = true;
  115. }
  116. if (GUILayout.Button("Save Mesh", buttonStyle2)) {
  117. if (target_cs.autoOverwrite != null) {
  118. string apath = AssetDatabase.GetAssetPath(target_cs.autoOverwrite);
  119. if (EditorUtility.DisplayDialog("Replace Asset?",
  120. "Are you sure you want to replace mesh asset:\n" + apath
  121. , "Yes", "No")) {
  122. UnityEngine.Object asset = AssetDatabase.LoadAssetAtPath(apath, (Type)typeof(object));
  123. ((Mesh)asset).Clear();
  124. EditorUtility.CopySerialized(target_cs.combined.GetComponent<MeshFilter>().sharedMesh, asset);
  125. AssetDatabase.SaveAssets();
  126. Debug.Log("Saved mesh asset: " + apath);
  127. }
  128. return;
  129. }
  130. string path = SaveFile("Assets/", target_cs.transform.name + " [SMC Asset]", "asset");
  131. if (path != null) {
  132. UnityEngine.Object asset = AssetDatabase.LoadAssetAtPath(path, (Type)typeof(object));
  133. if (asset == null) {
  134. AssetDatabase.CreateAsset(target_cs.combined.GetComponent<MeshFilter>().sharedMesh, path);
  135. } else {
  136. ((Mesh)asset).Clear();
  137. EditorUtility.CopySerialized(target_cs.combined.GetComponent<MeshFilter>().sharedMesh, asset);
  138. AssetDatabase.SaveAssets();
  139. }
  140. target_cs.combined.GetComponent<MeshFilter>().sharedMesh = (Mesh)AssetDatabase.LoadAssetAtPath(path, (Type)typeof(object));
  141. target_cs.autoOverwrite = (Mesh)AssetDatabase.LoadAssetAtPath(path, (Type)typeof(object));
  142. Debug.Log("Saved mesh asset: " + path);
  143. }
  144. }
  145. GUILayout.BeginHorizontal();
  146. target_cs.autoOverwrite = (Mesh)EditorGUILayout.ObjectField(target_cs.autoOverwrite, (Type)typeof(Mesh), false);
  147. if (GUILayout.Button("Clear")) {
  148. target_cs.autoOverwrite = null;
  149. }
  150. GUILayout.EndHorizontal();
  151. GUILayout.Space(5.0f);
  152. }
  153. if (!Application.isPlaying) {
  154. GUI.enabled = true;
  155. }
  156. if (target_cs.combined != null) {
  157. if (GUILayout.Button("Export OBJ", buttonStyle2)) {
  158. if (target_cs.combined != null) {
  159. ExportMesh(target_cs.combined.GetComponent<MeshFilter>(), "Assets/", target_cs.transform.name + " [SMC Mesh]" + ".obj");
  160. }
  161. }
  162. GUILayout.Space(15.0f);
  163. string bText = "Create Copy";
  164. if (target_cs.combined.GetComponent<MeshFilter>().sharedMesh.name == "") {
  165. bText = bText + " (Saved mesh)";
  166. GUI.enabled = false;
  167. } else if (!Application.isPlaying) {
  168. GUI.enabled = true;
  169. }
  170. if (GUILayout.Button(bText, buttonStyle2)) {
  171. GameObject newCopy = new GameObject();
  172. GameObject newCopy2 = new GameObject();
  173. newCopy2.transform.parent = newCopy.transform;
  174. newCopy2.transform.localPosition = target_cs.combined.transform.localPosition;
  175. newCopy2.transform.localRotation = target_cs.combined.transform.localRotation;
  176. newCopy.name = target_cs.name + " [SMC Copy]";
  177. newCopy2.name = "Mesh [SMC]";
  178. newCopy.transform.position = target_cs.transform.position;
  179. newCopy.transform.rotation = target_cs.transform.rotation;
  180. MeshFilter mf = newCopy2.AddComponent<MeshFilter>();
  181. newCopy2.AddComponent<MeshRenderer>();
  182. mf.sharedMesh = target_cs.combined.GetComponent<MeshFilter>().sharedMesh;
  183. target_cs.copyTarget = newCopy;
  184. CopyMaterials(newCopy2.transform);
  185. CopyColliders();
  186. Selection.activeTransform = newCopy.transform;
  187. }
  188. GUILayout.Space(5.0f);
  189. if (target_cs.copyTarget == null) {
  190. GUI.enabled = false;
  191. } else if (!Application.isPlaying) {
  192. GUI.enabled = true;
  193. }
  194. if (GUILayout.Button("Copy Colliders", buttonStyle2)) {
  195. CopyColliders();
  196. }
  197. GUILayout.Space(5.0f);
  198. if (GUILayout.Button("Copy Materials", buttonStyle2)) {
  199. CopyMaterials(target_cs.copyTarget.transform.Find("Mesh [SMC]"));
  200. }
  201. GUILayout.Space(15.0f);
  202. if (!Application.isPlaying) {
  203. GUI.enabled = true;
  204. }
  205. target_cs.destroyOldColliders = EditorGUILayout.Toggle("Destroy old colliders", target_cs.destroyOldColliders);
  206. target_cs.keepStructure = EditorGUILayout.Toggle("Keep collider structure", target_cs.keepStructure);
  207. target_cs.copyTarget = (GameObject)EditorGUILayout.ObjectField("Copy to: ", target_cs.copyTarget, typeof(GameObject), true);
  208. }
  209. if (target_cs.combined == null) {
  210. target_cs.generateLightmapUV = EditorGUILayout.Toggle("Create Lightmap UV", target_cs.generateLightmapUV);
  211. target_cs.lightmapScale = EditorGUILayout.FloatField("Lightmap Scale", target_cs.lightmapScale);
  212. target_cs.setStatic = EditorGUILayout.Toggle("Static", target_cs.setStatic);
  213. }
  214. GUILayout.Space(5.0f);
  215. EditorGUILayout.BeginVertical("Box");
  216. if (target_cs.combined != null) {
  217. GUILayout.Label("Combined vertex count: " + target_cs.vCount + " / 65536" + " (" + UncombinedVertex() + ")", infoStyle);
  218. GUILayout.Label("Material count: " + target_cs.combined.GetComponent<Renderer>().sharedMaterials.Length, infoStyle);
  219. } else {
  220. GUILayout.Label("Combined vertex count: " + target_cs.vCount + " / 65536" + " (" + UncombinedVertex() + ")", infoStyle);
  221. GUILayout.Label("Material count: -", infoStyle);
  222. }
  223. GUI.color = Color.white;
  224. EditorGUILayout.EndVertical();
  225. GUIStyle buttonStyle3 = new GUIStyle(GUI.skin.button);
  226. buttonStyle3.fixedWidth = 11.0f;
  227. buttonStyle3.fixedHeight = 14.0f;
  228. buttonStyle3.fontSize = 9;
  229. buttonStyle3.padding = new RectOffset(-2, 0, 0, 0);
  230. EditorGUILayout.BeginHorizontal();
  231. GUILayout.FlexibleSpace();
  232. EditorGUILayout.EndHorizontal();
  233. if (GUI.changed) {
  234. EditorUtility.SetDirty(target_cs);
  235. }
  236. }
  237. public int UncombinedVertex(){
  238. int totalMeshes = 0;
  239. int verts = 0;
  240. var target_cs = (SimpleMeshCombine)target;
  241. for (int i = 0; i < target_cs.transform.childCount; i++) {
  242. if (target_cs.combined && target_cs.transform.GetChild(i) != target_cs.combined.transform || !target_cs.combined) {
  243. MeshFilter[] mfs = target_cs.transform.GetChild(i).GetComponentsInChildren<MeshFilter>();
  244. totalMeshes += mfs.Length;
  245. for (int j = 0; j < mfs.Length; j++) {
  246. if (mfs[j].sharedMesh != null) {
  247. verts += mfs[j].sharedMesh.vertexCount;
  248. }
  249. }
  250. }
  251. }
  252. return verts;
  253. }
  254. public void DestroyComponentsExeptColliders(Transform t){
  255. var target_cs = (SimpleMeshCombine)target;
  256. Component[] transforms = t.GetComponentsInChildren(typeof(Transform));
  257. foreach(Transform trans in transforms){
  258. if(!target_cs.keepStructure && trans.transform.parent != t && trans.transform != t && (trans.GetComponent(typeof(Collider)) != null)){
  259. trans.transform.name = ""+ GetParentStructure(t, trans.transform);
  260. trans.transform.parent = t;
  261. }
  262. }
  263. Component[] components = t.GetComponentsInChildren(typeof(Component));
  264. foreach(Component comp in components){
  265. if( !( comp is Collider) && !( comp is Transform) ){
  266. DestroyImmediate(comp);
  267. }
  268. }
  269. }
  270. public string GetParentStructure(Transform root,Transform t){
  271. Transform ct = t;
  272. string s = "";
  273. while(ct !=root ){
  274. s = s.Insert(0, ct.name + " - ");
  275. ct = ct.parent;
  276. }
  277. s = s.Remove(s.Length-3, 3);
  278. return s;
  279. }
  280. public void DestroyEmptyGameObjects(Transform t){
  281. Component[] components = t.GetComponentsInChildren(typeof(Transform));
  282. foreach(Transform comp in components){
  283. if((comp != null) && (comp.childCount == 0 || !CheckChildrenForColliders(comp))){
  284. Collider col = (Collider)comp.GetComponent(typeof(Collider));
  285. if(col == null){
  286. DestroyImmediate(comp.gameObject);
  287. }
  288. }
  289. }
  290. }
  291. public bool CheckChildrenForColliders(Transform t){
  292. Component[] components = t.GetComponentsInChildren(typeof(Collider));
  293. if(components.Length > 0){
  294. return true;
  295. }
  296. return false;
  297. }
  298. public void CopyMaterials(Transform t){
  299. var target_cs = (SimpleMeshCombine)target;
  300. Renderer r = t.GetComponent<Renderer>();
  301. r.sharedMaterials = target_cs.combined.transform.GetComponent<Renderer>().sharedMaterials;
  302. }
  303. public void CopyColliders(){
  304. var target_cs = (SimpleMeshCombine)target;
  305. GameObject clone = (GameObject)Instantiate(target_cs.gameObject, target_cs.copyTarget.transform.position, target_cs.copyTarget.transform.rotation);
  306. if(target_cs.destroyOldColliders){
  307. Transform o = target_cs.copyTarget.transform.Find("Colliders [SMC]");
  308. if(o != null){
  309. DestroyImmediate(o.gameObject);
  310. }
  311. }
  312. clone.transform.name = "Colliders [SMC]";
  313. clone.transform.parent = target_cs.copyTarget.transform;
  314. DestroyComponentsExeptColliders(clone.transform);
  315. DestroyEmptyGameObjects(clone.transform);
  316. }
  317. }