MB_Utility.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. //----------------------------------------------
  2. // MeshBaker
  3. // Copyright © 2011-2012 Ian Deane
  4. //----------------------------------------------
  5. using UnityEngine;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System;
  10. namespace DigitalOpus.MB.Core{
  11. public class MB_Utility{
  12. public static bool DO_INTEGRITY_CHECKS = false;
  13. public struct MeshAnalysisResult{
  14. public Rect uvRect;
  15. public bool hasOutOfBoundsUVs;
  16. public bool hasOverlappingSubmeshVerts;
  17. public bool hasOverlappingSubmeshTris;
  18. public bool hasUVs;
  19. public float submeshArea;
  20. }
  21. public static Texture2D createTextureCopy(Texture2D source){
  22. Texture2D newTex = new Texture2D(source.width,source.height,TextureFormat.ARGB32,true);
  23. newTex.SetPixels(source.GetPixels());
  24. return newTex;
  25. }
  26. public static bool ArrayBIsSubsetOfA(System.Object[] a, System.Object[] b){
  27. for (int i = 0; i < b.Length; i++){
  28. bool foundBinA = false;
  29. for (int j = 0; j < a.Length; j++){
  30. if (a[j] == b[i]){
  31. foundBinA = true;
  32. break;
  33. }
  34. }
  35. if (foundBinA == false) return false;
  36. }
  37. return true;
  38. }
  39. public static Material[] GetGOMaterials(GameObject go){
  40. if (go == null) return new Material[0];
  41. Material[] sharedMaterials = null;
  42. Mesh mesh = null;
  43. MeshRenderer mr = go.GetComponent<MeshRenderer>();
  44. if (mr != null){
  45. sharedMaterials = mr.sharedMaterials;
  46. MeshFilter mf = go.GetComponent<MeshFilter>();
  47. if (mf == null){
  48. throw new Exception("Object " + go + " has a MeshRenderer but no MeshFilter.");
  49. }
  50. mesh = mf.sharedMesh;
  51. }
  52. SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>();
  53. if (smr != null){
  54. sharedMaterials = smr.sharedMaterials;
  55. mesh = smr.sharedMesh;
  56. }
  57. if (sharedMaterials == null){
  58. Debug.LogError("Object " + go.name + " does not have a MeshRenderer or a SkinnedMeshRenderer component");
  59. return new Material[0];
  60. } else if (mesh == null){
  61. Debug.LogError("Object " + go.name + " has a MeshRenderer or SkinnedMeshRenderer but no mesh.");
  62. return new Material[0];
  63. } else {
  64. if (mesh.subMeshCount < sharedMaterials.Length){
  65. Debug.LogWarning("Object " + go + " has only " + mesh.subMeshCount + " submeshes and has " + sharedMaterials.Length + " materials. Extra materials do nothing.");
  66. Material[] newSharedMaterials = new Material[mesh.subMeshCount];
  67. Array.Copy(sharedMaterials,newSharedMaterials,newSharedMaterials.Length);
  68. sharedMaterials = newSharedMaterials;
  69. }
  70. return sharedMaterials;
  71. }
  72. }
  73. public static Mesh GetMesh(GameObject go){
  74. if (go == null) return null;
  75. MeshFilter mf = go.GetComponent<MeshFilter>();
  76. if (mf != null){
  77. return mf.sharedMesh;
  78. }
  79. SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>();
  80. if (smr != null){
  81. return smr.sharedMesh;
  82. }
  83. return null;
  84. }
  85. public static void SetMesh(GameObject go, Mesh m)
  86. {
  87. if (go == null) return;
  88. MeshFilter mf = go.GetComponent<MeshFilter>();
  89. if (mf != null)
  90. {
  91. mf.sharedMesh = m;
  92. }
  93. else
  94. {
  95. SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>();
  96. if (smr != null)
  97. {
  98. smr.sharedMesh = m;
  99. }
  100. }
  101. }
  102. public static Renderer GetRenderer(GameObject go){
  103. if (go == null) return null;
  104. MeshRenderer mr = go.GetComponent<MeshRenderer>();
  105. if (mr != null) return mr;
  106. SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>();
  107. if (smr != null) return smr;
  108. return null;
  109. }
  110. public static void DisableRendererInSource(GameObject go){
  111. if (go == null) return;
  112. MeshRenderer mf = go.GetComponent<MeshRenderer>();
  113. if (mf != null){
  114. mf.enabled = false;
  115. return;
  116. }
  117. SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>();
  118. if (smr != null){
  119. smr.enabled = false;
  120. return;
  121. }
  122. }
  123. public static bool hasOutOfBoundsUVs(Mesh m, ref Rect uvBounds){
  124. MeshAnalysisResult mar = new MeshAnalysisResult();
  125. bool outVal = hasOutOfBoundsUVs(m, ref mar);
  126. uvBounds = mar.uvRect;
  127. return outVal;
  128. }
  129. public static bool hasOutOfBoundsUVs(Mesh m, ref MeshAnalysisResult putResultHere, int submeshIndex = -1, int uvChannel = 0)
  130. {
  131. if (m == null)
  132. {
  133. putResultHere.hasOutOfBoundsUVs = false;
  134. return putResultHere.hasOutOfBoundsUVs;
  135. }
  136. Vector2[] uvs;
  137. if (uvChannel == 0) {
  138. uvs = m.uv;
  139. } else if (uvChannel == 1)
  140. {
  141. uvs = m.uv2;
  142. } else if (uvChannel == 2)
  143. {
  144. uvs = m.uv3;
  145. } else {
  146. uvs = m.uv4;
  147. }
  148. return hasOutOfBoundsUVs(uvs, m, ref putResultHere, submeshIndex);
  149. }
  150. public static bool hasOutOfBoundsUVs(Vector2[] uvs, Mesh m, ref MeshAnalysisResult putResultHere, int submeshIndex = -1)
  151. {
  152. putResultHere.hasUVs = true;
  153. if (uvs.Length == 0)
  154. {
  155. putResultHere.hasUVs = false;
  156. putResultHere.hasOutOfBoundsUVs = false;
  157. putResultHere.uvRect = new Rect();
  158. return putResultHere.hasOutOfBoundsUVs;
  159. }
  160. float minx, miny, maxx, maxy;
  161. if (submeshIndex >= m.subMeshCount)
  162. {
  163. putResultHere.hasOutOfBoundsUVs = false;
  164. putResultHere.uvRect = new Rect();
  165. return putResultHere.hasOutOfBoundsUVs;
  166. }
  167. else if (submeshIndex >= 0)
  168. {
  169. //checking specific submesh
  170. int[] tris = m.GetTriangles(submeshIndex);
  171. if (tris.Length == 0)
  172. {
  173. putResultHere.hasOutOfBoundsUVs = false;
  174. putResultHere.uvRect = new Rect();
  175. return putResultHere.hasOutOfBoundsUVs;
  176. }
  177. minx = maxx = uvs[tris[0]].x;
  178. miny = maxy = uvs[tris[0]].y;
  179. for (int idx = 0; idx < tris.Length; idx++)
  180. {
  181. int i = tris[idx];
  182. if (uvs[i].x < minx) minx = uvs[i].x;
  183. if (uvs[i].x > maxx) maxx = uvs[i].x;
  184. if (uvs[i].y < miny) miny = uvs[i].y;
  185. if (uvs[i].y > maxy) maxy = uvs[i].y;
  186. }
  187. }
  188. else {
  189. //checking all UVs
  190. minx = maxx = uvs[0].x;
  191. miny = maxy = uvs[0].y;
  192. for (int i = 0; i < uvs.Length; i++)
  193. {
  194. if (uvs[i].x < minx) minx = uvs[i].x;
  195. if (uvs[i].x > maxx) maxx = uvs[i].x;
  196. if (uvs[i].y < miny) miny = uvs[i].y;
  197. if (uvs[i].y > maxy) maxy = uvs[i].y;
  198. }
  199. }
  200. Rect uvBounds = new Rect();
  201. uvBounds.x = minx;
  202. uvBounds.y = miny;
  203. uvBounds.width = maxx - minx;
  204. uvBounds.height = maxy - miny;
  205. if (maxx > 1f || minx < 0f || maxy > 1f || miny < 0f)
  206. {
  207. putResultHere.hasOutOfBoundsUVs = true;
  208. }
  209. else
  210. {
  211. putResultHere.hasOutOfBoundsUVs = false;
  212. }
  213. putResultHere.uvRect = uvBounds;
  214. return putResultHere.hasOutOfBoundsUVs;
  215. }
  216. public static void setSolidColor(Texture2D t, Color c){
  217. Color[] cs = t.GetPixels();
  218. for (int i = 0; i < cs.Length; i++){
  219. cs[i] = c;
  220. }
  221. t.SetPixels(cs);
  222. t.Apply();
  223. }
  224. public static Texture2D resampleTexture(Texture2D source, int newWidth, int newHeight){
  225. TextureFormat f = source.format;
  226. if (f == TextureFormat.ARGB32 ||
  227. f == TextureFormat.RGBA32 ||
  228. f == TextureFormat.BGRA32 ||
  229. f == TextureFormat.RGB24 ||
  230. f == TextureFormat.Alpha8 ||
  231. f == TextureFormat.DXT1)
  232. {
  233. Texture2D newTex = new Texture2D(newWidth,newHeight,TextureFormat.ARGB32,true);
  234. float w = newWidth;
  235. float h = newHeight;
  236. for (int i = 0; i < newWidth; i++){
  237. for (int j = 0; j < newHeight; j++){
  238. float u = i/w;
  239. float v = j/h;
  240. newTex.SetPixel(i,j,source.GetPixelBilinear(u,v));
  241. }
  242. }
  243. newTex.Apply();
  244. return newTex;
  245. } else {
  246. Debug.LogError("Can only resize textures in formats ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. texture:" + source + " was in format: " + source.format);
  247. return null;
  248. }
  249. }
  250. class MB_Triangle{
  251. int submeshIdx;
  252. int[] vs = new int[3];
  253. public bool isSame(object obj){
  254. MB_Triangle tobj = (MB_Triangle) obj;
  255. if (vs[0] == tobj.vs[0] &&
  256. vs[1] == tobj.vs[1] &&
  257. vs[2] == tobj.vs[2] &&
  258. submeshIdx != tobj.submeshIdx){
  259. return true;
  260. }
  261. return false;
  262. }
  263. public bool sharesVerts(MB_Triangle obj){
  264. if (vs[0] == obj.vs[0] ||
  265. vs[0] == obj.vs[1] ||
  266. vs[0] == obj.vs[2]){
  267. if (submeshIdx != obj.submeshIdx) return true;
  268. }
  269. if (vs[1] == obj.vs[0] ||
  270. vs[1] == obj.vs[1] ||
  271. vs[1] == obj.vs[2]){
  272. if (submeshIdx != obj.submeshIdx) return true;
  273. }
  274. if (vs[2] == obj.vs[0] ||
  275. vs[2] == obj.vs[1] ||
  276. vs[2] == obj.vs[2]){
  277. if (submeshIdx != obj.submeshIdx) return true;
  278. }
  279. return false;
  280. }
  281. public void Initialize(int[] ts, int idx, int sIdx){
  282. vs[0] = ts[idx];
  283. vs[1] = ts[idx + 1];
  284. vs[2] = ts[idx + 2];
  285. submeshIdx = sIdx;
  286. Array.Sort(vs);
  287. }
  288. }
  289. public static bool AreAllSharedMaterialsDistinct(Material[] sharedMaterials){
  290. for (int i = 0; i < sharedMaterials.Length; i++){
  291. for (int j = i + 1; j < sharedMaterials.Length; j++){
  292. if (sharedMaterials[i] == sharedMaterials[j]){
  293. return false;
  294. }
  295. }
  296. }
  297. return true;
  298. }
  299. public static int doSubmeshesShareVertsOrTris(Mesh m, ref MeshAnalysisResult mar){
  300. MB_Triangle consider = new MB_Triangle();
  301. MB_Triangle other = new MB_Triangle();
  302. //cache all triangles
  303. int[][] tris = new int[m.subMeshCount][];
  304. for (int i = 0; i < m.subMeshCount; i++){
  305. tris[i] = m.GetTriangles(i);
  306. }
  307. bool sharesVerts = false;
  308. bool sharesTris = false;
  309. for (int i = 0; i < m.subMeshCount; i++){
  310. int[] smA = tris[i];
  311. for (int j = i+1; j < m.subMeshCount; j++){
  312. int[] smB = tris[j];
  313. for (int k = 0; k < smA.Length; k+=3){
  314. consider.Initialize(smA,k,i);
  315. for (int l = 0; l < smB.Length; l+=3){
  316. other.Initialize(smB,l,j);
  317. if (consider.isSame(other)){
  318. sharesTris = true;
  319. break;
  320. }
  321. if (consider.sharesVerts(other)){
  322. sharesVerts = true;
  323. break;
  324. }
  325. }
  326. }
  327. }
  328. }
  329. if (sharesTris){
  330. mar.hasOverlappingSubmeshVerts = true;
  331. mar.hasOverlappingSubmeshTris = true;
  332. return 2;
  333. } else if (sharesVerts){
  334. mar.hasOverlappingSubmeshVerts = true;
  335. mar.hasOverlappingSubmeshTris = false;
  336. return 1;
  337. } else {
  338. mar.hasOverlappingSubmeshTris = false;
  339. mar.hasOverlappingSubmeshVerts = false;
  340. return 0;
  341. }
  342. }
  343. public static bool GetBounds(GameObject go, out Bounds b){
  344. if (go == null){
  345. Debug.LogError("go paramater was null");
  346. b = new Bounds(Vector3.zero,Vector3.zero);
  347. return false;
  348. }
  349. Renderer r = GetRenderer(go);
  350. if (r == null){
  351. Debug.LogError("GetBounds must be called on an object with a Renderer");
  352. b = new Bounds(Vector3.zero,Vector3.zero);
  353. return false;
  354. }
  355. if (r is MeshRenderer){
  356. b = r.bounds;
  357. return true;
  358. } else if (r is SkinnedMeshRenderer){
  359. b = r.bounds;
  360. return true;
  361. }
  362. Debug.LogError("GetBounds must be called on an object with a MeshRender or a SkinnedMeshRenderer.");
  363. b = new Bounds(Vector3.zero,Vector3.zero);
  364. return false;
  365. }
  366. public static void Destroy(UnityEngine.Object o){
  367. if (Application.isPlaying){
  368. MonoBehaviour.Destroy(o);
  369. } else {
  370. // string p = AssetDatabase.GetAssetPath(o);
  371. // if (p != null && p.Equals("")) // don't try to destroy assets
  372. MonoBehaviour.DestroyImmediate(o,false);
  373. }
  374. }
  375. public static string ConvertAssetsRelativePathToFullSystemPath(string pth)
  376. {
  377. string aPth = Application.dataPath.Replace("Assets", "");
  378. return aPth + pth;
  379. }
  380. }
  381. }