MB3_MeshBakerGrouper.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using DigitalOpus.MB.Core;
  6. #if UNITY_EDITOR
  7. using UnityEditor;
  8. #endif
  9. public class MB3_MeshBakerGrouper : MonoBehaviour, MB_IMeshBakerSettingsHolder
  10. {
  11. public enum ClusterType
  12. {
  13. none,
  14. grid,
  15. pie,
  16. agglomerative,
  17. }
  18. public MB3_MeshBakerGrouperCore grouper;
  19. public ClusterType clusterType = ClusterType.none;
  20. public GrouperData data = new GrouperData();
  21. //these are for getting a resonable bounds in which to draw gizmos.
  22. [HideInInspector] public Bounds sourceObjectBounds = new Bounds(Vector3.zero, Vector3.one);
  23. public MB3_MeshCombinerSettings meshBakerSettingsAsset;
  24. public MB3_MeshCombinerSettingsData meshBakerSettings;
  25. public MB_IMeshBakerSettings GetMeshBakerSettings()
  26. {
  27. if (meshBakerSettingsAsset == null)
  28. {
  29. return meshBakerSettings;
  30. }
  31. else
  32. {
  33. return meshBakerSettingsAsset.GetMeshBakerSettings();
  34. }
  35. }
  36. #if UNITY_EDITOR
  37. public SerializedProperty GetMeshBakerSettingsAsSerializedProperty()
  38. {
  39. if (meshBakerSettingsAsset == null)
  40. {
  41. UnityEditor.SerializedObject so = new UnityEditor.SerializedObject(this);
  42. return so.FindProperty("meshBakerSettings");
  43. }
  44. else
  45. {
  46. UnityEditor.SerializedObject so = new UnityEditor.SerializedObject(meshBakerSettingsAsset);
  47. return so.FindProperty("data");
  48. }
  49. }
  50. #endif
  51. void OnDrawGizmosSelected()
  52. {
  53. if (grouper == null)
  54. {
  55. grouper = CreateGrouper(clusterType, data);
  56. }
  57. if (grouper.d == null)
  58. {
  59. grouper.d = data;
  60. }
  61. grouper.DrawGizmos(sourceObjectBounds);
  62. }
  63. public MB3_MeshBakerGrouperCore CreateGrouper(ClusterType t, GrouperData data)
  64. {
  65. if (t == ClusterType.grid) grouper = new MB3_MeshBakerGrouperGrid(data);
  66. if (t == ClusterType.pie) grouper = new MB3_MeshBakerGrouperPie(data);
  67. if (t == ClusterType.agglomerative)
  68. {
  69. MB3_TextureBaker tb = GetComponent<MB3_TextureBaker>();
  70. List<GameObject> gos;
  71. if (tb != null)
  72. {
  73. gos = tb.GetObjectsToCombine();
  74. }
  75. else
  76. {
  77. gos = new List<GameObject>();
  78. }
  79. grouper = new MB3_MeshBakerGrouperCluster(data, gos);
  80. }
  81. if (t == ClusterType.none) grouper = new MB3_MeshBakerGrouperNone(data);
  82. return grouper;
  83. }
  84. public void DeleteAllChildMeshBakers()
  85. {
  86. MB3_MeshBakerCommon[] mBakers = GetComponentsInChildren<MB3_MeshBakerCommon>();
  87. for (int i = 0; i < mBakers.Length; i++)
  88. {
  89. MB3_MeshBakerCommon mb = mBakers[i];
  90. GameObject resultGameObject = mb.meshCombiner.resultSceneObject;
  91. MB_Utility.Destroy(resultGameObject);
  92. MB_Utility.Destroy(mb.gameObject);
  93. }
  94. }
  95. }
  96. namespace DigitalOpus.MB.Core
  97. {
  98. /// all properties go here so that settings are remembered as user switches between cluster types
  99. [Serializable]
  100. public class GrouperData
  101. {
  102. public bool clusterOnLMIndex;
  103. public bool clusterByLODLevel;
  104. public Vector3 origin;
  105. //Normally these properties would be in the subclasses but putting them here makes writing the inspector much easier
  106. //for grid
  107. public Vector3 cellSize;
  108. //for pie
  109. public int pieNumSegments = 4;
  110. public Vector3 pieAxis = Vector3.up;
  111. public float ringSpacing = 100f;
  112. public bool combineSegmentsInInnermostRing = false;
  113. //for clustering
  114. public int height = 1;
  115. public float maxDistBetweenClusters = 1f;
  116. public bool includeCellsWithOnlyOneRenderer = true;
  117. }
  118. [Serializable]
  119. public abstract class MB3_MeshBakerGrouperCore
  120. {
  121. public GrouperData d;
  122. public abstract Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection);
  123. public abstract void DrawGizmos(Bounds sourceObjectBounds);
  124. public void DoClustering(MB3_TextureBaker tb, MB3_MeshBakerGrouper grouper)
  125. {
  126. //todo warn for no objects and no Texture Bake Result
  127. Dictionary<string, List<Renderer>> cell2objs = FilterIntoGroups(tb.GetObjectsToCombine());
  128. if (d.clusterOnLMIndex)
  129. {
  130. Dictionary<string, List<Renderer>> cell2objsNew = new Dictionary<string, List<Renderer>>();
  131. foreach (string key in cell2objs.Keys)
  132. {
  133. List<Renderer> gaws = cell2objs[key];
  134. Dictionary<int, List<Renderer>> idx2objs = GroupByLightmapIndex(gaws);
  135. foreach (int keyIdx in idx2objs.Keys)
  136. {
  137. string keyNew = key + "-LM-" + keyIdx;
  138. cell2objsNew.Add(keyNew, idx2objs[keyIdx]);
  139. }
  140. }
  141. cell2objs = cell2objsNew;
  142. }
  143. if (d.clusterByLODLevel)
  144. {
  145. //visit each cell
  146. //visit each renderer
  147. //check if that renderer is a child of an LOD group
  148. // visit each LOD level check if this renderer is in that list.
  149. // if not add it to LOD0 for that cell
  150. // otherwise add it to LODX for that cell creating LODs as necessary
  151. Dictionary<string, List<Renderer>> cell2objsNew = new Dictionary<string, List<Renderer>>();
  152. foreach (string key in cell2objs.Keys)
  153. {
  154. List<Renderer> gaws = cell2objs[key];
  155. foreach (Renderer r in gaws)
  156. {
  157. if (r == null) continue;
  158. bool foundInLOD = false;
  159. LODGroup lodg = r.GetComponentInParent<LODGroup>();
  160. if (lodg != null)
  161. {
  162. LOD[] lods = lodg.GetLODs();
  163. for (int i = 0; i < lods.Length; i++)
  164. {
  165. LOD lod = lods[i];
  166. if (Array.Find<Renderer>(lod.renderers, x => x == r) != null)
  167. {
  168. foundInLOD = true;
  169. List<Renderer> rs;
  170. string newKey = String.Format("{0}_LOD{1}", key, i);
  171. if (!cell2objsNew.TryGetValue(newKey, out rs))
  172. {
  173. rs = new List<Renderer>();
  174. cell2objsNew.Add(newKey, rs);
  175. }
  176. if (!rs.Contains(r)) rs.Add(r);
  177. }
  178. }
  179. }
  180. if (!foundInLOD)
  181. {
  182. List<Renderer> rs;
  183. string newKey = String.Format("{0}_LOD0", key);
  184. if (!cell2objsNew.TryGetValue(newKey, out rs))
  185. {
  186. rs = new List<Renderer>();
  187. cell2objsNew.Add(newKey, rs);
  188. }
  189. if (!rs.Contains(r)) rs.Add(r);
  190. }
  191. }
  192. }
  193. cell2objs = cell2objsNew;
  194. }
  195. int clustersWithOnlyOneRenderer = 0;
  196. foreach (string key in cell2objs.Keys)
  197. {
  198. List<Renderer> gaws = cell2objs[key];
  199. if (gaws.Count > 1 || grouper.data.includeCellsWithOnlyOneRenderer)
  200. {
  201. AddMeshBaker(grouper, tb, key, gaws);
  202. }
  203. else
  204. {
  205. clustersWithOnlyOneRenderer++;
  206. }
  207. }
  208. Debug.Log(String.Format("Found {0} cells with Renderers. Not creating bakers for {1} because there is only one mesh in the cell. Creating {2} bakers.", cell2objs.Count, clustersWithOnlyOneRenderer, cell2objs.Count - clustersWithOnlyOneRenderer));
  209. }
  210. Dictionary<int, List<Renderer>> GroupByLightmapIndex(List<Renderer> gaws)
  211. {
  212. Dictionary<int, List<Renderer>> idx2objs = new Dictionary<int, List<Renderer>>();
  213. for (int i = 0; i < gaws.Count; i++)
  214. {
  215. List<Renderer> objs = null;
  216. if (idx2objs.ContainsKey(gaws[i].lightmapIndex))
  217. {
  218. objs = idx2objs[gaws[i].lightmapIndex];
  219. }
  220. else
  221. {
  222. objs = new List<Renderer>();
  223. idx2objs.Add(gaws[i].lightmapIndex, objs);
  224. }
  225. objs.Add(gaws[i]);
  226. }
  227. return idx2objs;
  228. }
  229. void AddMeshBaker(MB3_MeshBakerGrouper grouper, MB3_TextureBaker tb, string key, List<Renderer> gaws)
  230. {
  231. int numVerts = 0;
  232. for (int i = 0; i < gaws.Count; i++)
  233. {
  234. Mesh m = MB_Utility.GetMesh(gaws[i].gameObject);
  235. if (m != null)
  236. numVerts += m.vertexCount;
  237. }
  238. GameObject nmb = new GameObject("MeshBaker-" + key);
  239. nmb.transform.position = Vector3.zero;
  240. MB3_MeshBakerCommon newMeshBaker;
  241. if (numVerts >= 65535)
  242. {
  243. newMeshBaker = nmb.AddComponent<MB3_MultiMeshBaker>();
  244. newMeshBaker.useObjsToMeshFromTexBaker = false;
  245. }
  246. else
  247. {
  248. newMeshBaker = nmb.AddComponent<MB3_MeshBaker>();
  249. newMeshBaker.useObjsToMeshFromTexBaker = false;
  250. }
  251. newMeshBaker.textureBakeResults = tb.textureBakeResults;
  252. newMeshBaker.transform.parent = tb.transform;
  253. newMeshBaker.meshCombiner.settingsHolder = grouper;
  254. for (int i = 0; i < gaws.Count; i++)
  255. {
  256. newMeshBaker.GetObjectsToCombine().Add(gaws[i].gameObject);
  257. }
  258. }
  259. }
  260. [Serializable]
  261. public class MB3_MeshBakerGrouperNone : MB3_MeshBakerGrouperCore
  262. {
  263. public MB3_MeshBakerGrouperNone(GrouperData d)
  264. {
  265. this.d = d;
  266. }
  267. public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection)
  268. {
  269. Debug.Log("Filtering into groups none");
  270. Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
  271. List<Renderer> rs = new List<Renderer>();
  272. for (int i = 0; i < selection.Count; i++)
  273. {
  274. if (selection[i] != null)
  275. {
  276. rs.Add(selection[i].GetComponent<Renderer>());
  277. }
  278. }
  279. cell2objs.Add("MeshBaker", rs);
  280. return cell2objs;
  281. }
  282. public override void DrawGizmos(Bounds sourceObjectBounds)
  283. {
  284. }
  285. }
  286. [Serializable]
  287. public class MB3_MeshBakerGrouperGrid : MB3_MeshBakerGrouperCore
  288. {
  289. public MB3_MeshBakerGrouperGrid(GrouperData d)
  290. {
  291. this.d = d;
  292. }
  293. public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection)
  294. {
  295. Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
  296. if (d.cellSize.x <= 0f || d.cellSize.y <= 0f || d.cellSize.z <= 0f)
  297. {
  298. Debug.LogError("cellSize x,y,z must all be greater than zero.");
  299. return cell2objs;
  300. }
  301. Debug.Log("Collecting renderers in each cell");
  302. foreach (GameObject t in selection)
  303. {
  304. if (t == null)
  305. {
  306. continue;
  307. }
  308. GameObject go = t;
  309. Renderer mr = go.GetComponent<Renderer>();
  310. if (mr is MeshRenderer || mr is SkinnedMeshRenderer)
  311. {
  312. //get the cell this gameObject is in
  313. Vector3 gridVector = mr.bounds.center;
  314. gridVector.x = Mathf.Floor((gridVector.x - d.origin.x) / d.cellSize.x) * d.cellSize.x;
  315. gridVector.y = Mathf.Floor((gridVector.y - d.origin.y) / d.cellSize.y) * d.cellSize.y;
  316. gridVector.z = Mathf.Floor((gridVector.z - d.origin.z) / d.cellSize.z) * d.cellSize.z;
  317. List<Renderer> objs = null;
  318. string gridVectorStr = gridVector.ToString();
  319. if (cell2objs.ContainsKey(gridVectorStr))
  320. {
  321. objs = cell2objs[gridVectorStr];
  322. }
  323. else
  324. {
  325. objs = new List<Renderer>();
  326. cell2objs.Add(gridVectorStr, objs);
  327. }
  328. if (!objs.Contains(mr))
  329. {
  330. //Debug.Log("Adding " + mr + " todo " + gridVectorStr);
  331. objs.Add(mr);
  332. }
  333. }
  334. }
  335. return cell2objs;
  336. }
  337. public override void DrawGizmos(Bounds sourceObjectBounds)
  338. {
  339. Vector3 cs = d.cellSize;
  340. if (cs.x <= .00001f || cs.y <= .00001f || cs.z <= .00001f) return;
  341. Vector3 p = sourceObjectBounds.center - sourceObjectBounds.extents;
  342. Vector3 offset = d.origin;
  343. offset.x = offset.x % cs.x;
  344. offset.y = offset.y % cs.y;
  345. offset.z = offset.z % cs.z;
  346. //snap p to closest cell center
  347. Vector3 start;
  348. p.x = Mathf.Round((p.x) / cs.x) * cs.x + offset.x;
  349. p.y = Mathf.Round((p.y) / cs.y) * cs.y + offset.y;
  350. p.z = Mathf.Round((p.z) / cs.z) * cs.z + offset.z;
  351. if (p.x > sourceObjectBounds.center.x - sourceObjectBounds.extents.x) p.x = p.x - cs.x;
  352. if (p.y > sourceObjectBounds.center.y - sourceObjectBounds.extents.y) p.y = p.y - cs.y;
  353. if (p.z > sourceObjectBounds.center.z - sourceObjectBounds.extents.z) p.z = p.z - cs.z;
  354. start = p;
  355. int numcells = Mathf.CeilToInt(sourceObjectBounds.size.x / cs.x + sourceObjectBounds.size.y / cs.y + sourceObjectBounds.size.z / cs.z);
  356. if (numcells > 200)
  357. {
  358. Gizmos.DrawWireCube(d.origin + cs / 2f, cs);
  359. }
  360. else
  361. {
  362. for (; p.x < sourceObjectBounds.center.x + sourceObjectBounds.extents.x; p.x += cs.x)
  363. {
  364. p.y = start.y;
  365. for (; p.y < sourceObjectBounds.center.y + sourceObjectBounds.extents.y; p.y += cs.y)
  366. {
  367. p.z = start.z;
  368. for (; p.z < sourceObjectBounds.center.z + sourceObjectBounds.extents.z; p.z += cs.z)
  369. {
  370. Gizmos.DrawWireCube(p + cs / 2f, cs);
  371. }
  372. }
  373. }
  374. }
  375. }
  376. }
  377. [Serializable]
  378. public class MB3_MeshBakerGrouperPie : MB3_MeshBakerGrouperCore
  379. {
  380. public MB3_MeshBakerGrouperPie(GrouperData data)
  381. {
  382. d = data;
  383. }
  384. public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection)
  385. {
  386. Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
  387. if (d.pieNumSegments == 0)
  388. {
  389. Debug.LogError("pieNumSegments must be greater than zero.");
  390. return cell2objs;
  391. }
  392. if (d.pieAxis.magnitude <= .000001f)
  393. {
  394. Debug.LogError("Pie axis vector is too short.");
  395. return cell2objs;
  396. }
  397. if (d.ringSpacing <= .000001f)
  398. {
  399. Debug.LogError("Ring spacing is too small.");
  400. return cell2objs;
  401. }
  402. d.pieAxis.Normalize();
  403. Quaternion pieAxis2yIsUp = Quaternion.FromToRotation(d.pieAxis, Vector3.up);
  404. Debug.Log("Collecting renderers in each cell");
  405. foreach (GameObject t in selection)
  406. {
  407. if (t == null)
  408. {
  409. continue;
  410. }
  411. GameObject go = t;
  412. Renderer mr = go.GetComponent<Renderer>();
  413. if (mr is MeshRenderer || mr is SkinnedMeshRenderer)
  414. {
  415. //get the cell this gameObject is in
  416. Vector3 origin2obj = mr.bounds.center - d.origin;
  417. origin2obj = pieAxis2yIsUp * origin2obj;
  418. Vector2 origin2Obj2D = new Vector2(origin2obj.x, origin2obj.z);
  419. float radius = origin2Obj2D.magnitude;
  420. origin2obj.Normalize();
  421. float deg_aboutY = 0f;
  422. if (Mathf.Abs(origin2obj.x) < 10e-5f && Mathf.Abs(origin2obj.z) < 10e-5f)
  423. {
  424. deg_aboutY = 0f;
  425. }
  426. else
  427. {
  428. deg_aboutY = Mathf.Atan2(origin2obj.x, origin2obj.z) * Mathf.Rad2Deg;
  429. if (deg_aboutY < 0f) deg_aboutY = 360f + deg_aboutY;
  430. }
  431. // Debug.Log ("Obj " + mr + " angle " + d_aboutY);
  432. int segment = Mathf.FloorToInt(deg_aboutY / 360f * d.pieNumSegments);
  433. int ring = Mathf.FloorToInt(radius / d.ringSpacing);
  434. if (ring == 0 && d.combineSegmentsInInnermostRing)
  435. {
  436. segment = 0;
  437. }
  438. List<Renderer> objs = null;
  439. string segStr = "seg_" + segment + "_ring_" + ring;
  440. if (cell2objs.ContainsKey(segStr))
  441. {
  442. objs = cell2objs[segStr];
  443. }
  444. else
  445. {
  446. objs = new List<Renderer>();
  447. cell2objs.Add(segStr, objs);
  448. }
  449. if (!objs.Contains(mr))
  450. {
  451. objs.Add(mr);
  452. }
  453. }
  454. }
  455. return cell2objs;
  456. }
  457. public override void DrawGizmos(Bounds sourceObjectBounds)
  458. {
  459. if (d.pieAxis.magnitude < .1f) return;
  460. if (d.pieNumSegments < 1) return;
  461. float rad = sourceObjectBounds.extents.magnitude;
  462. int numRings = Mathf.CeilToInt(rad / d.ringSpacing);
  463. numRings = Mathf.Max(1, numRings);
  464. for (int i = 0; i < numRings; i++)
  465. {
  466. DrawCircle(d.pieAxis.normalized, d.origin, d.ringSpacing * (i + 1), 24);
  467. }
  468. Gizmos.color = Color.white;
  469. Quaternion yIsUp2PieAxis = Quaternion.FromToRotation(Vector3.up, d.pieAxis);
  470. Quaternion rStep = Quaternion.AngleAxis(180f / d.pieNumSegments, Vector3.up);
  471. Vector3 r = Vector3.forward;
  472. for (int i = 0; i < d.pieNumSegments; i++)
  473. {
  474. Vector3 rr = yIsUp2PieAxis * r;
  475. Vector3 origin = d.origin;
  476. int nr = numRings;
  477. if (d.combineSegmentsInInnermostRing)
  478. {
  479. origin = d.origin + rr.normalized * d.ringSpacing;
  480. nr = numRings - 1;
  481. }
  482. if (nr == 0) break;
  483. Gizmos.DrawLine(origin, origin + nr * d.ringSpacing * rr.normalized);
  484. r = rStep * r;
  485. r = rStep * r;
  486. }
  487. }
  488. static int MaxIndexInVector3(Vector3 v)
  489. {
  490. int idx = 0;
  491. float val = v.x;
  492. if (v.y > val)
  493. {
  494. idx = 1;
  495. val = v.y;
  496. }
  497. if (v.z > val)
  498. {
  499. idx = 2;
  500. val = v.z;
  501. }
  502. return idx;
  503. }
  504. public static void DrawCircle(Vector3 axis, Vector3 center, float radius, int subdiv)
  505. {
  506. Quaternion q = Quaternion.AngleAxis(360 / subdiv, axis);
  507. int maxIdx = MaxIndexInVector3(axis);
  508. int otherIdx = maxIdx == 0 ? maxIdx + 1 : maxIdx - 1;
  509. Vector3 r = axis; //r construct a vector perpendicular to axis
  510. float temp = r[maxIdx];
  511. r[maxIdx] = r[otherIdx];
  512. r[otherIdx] = -temp;
  513. r = Vector3.ProjectOnPlane(r, axis);
  514. r.Normalize();
  515. r *= radius;
  516. for (int i = 0; i < subdiv + 1; i++)
  517. {
  518. Vector3 r2 = q * r;
  519. Gizmos.color = Color.white;
  520. Gizmos.DrawLine(center + r, center + r2);
  521. r = r2;
  522. }
  523. }
  524. }
  525. [Serializable]
  526. public class MB3_MeshBakerGrouperKMeans : MB3_MeshBakerGrouperCore
  527. {
  528. public int numClusters = 4;
  529. public Vector3[] clusterCenters = new Vector3[0];
  530. public float[] clusterSizes = new float[0];
  531. public MB3_MeshBakerGrouperKMeans(GrouperData data)
  532. {
  533. d = data;
  534. }
  535. public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection)
  536. {
  537. Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
  538. List<GameObject> validObjs = new List<GameObject>();
  539. int numClusters = 20;
  540. foreach (GameObject t in selection)
  541. {
  542. if (t == null)
  543. {
  544. continue;
  545. }
  546. GameObject go = t;
  547. Renderer mr = go.GetComponent<Renderer>();
  548. if (mr is MeshRenderer || mr is SkinnedMeshRenderer)
  549. {
  550. //get the cell this gameObject is in
  551. validObjs.Add(go);
  552. }
  553. }
  554. if (validObjs.Count > 0 && numClusters > 0 && numClusters < validObjs.Count)
  555. {
  556. MB3_KMeansClustering kmc = new MB3_KMeansClustering(validObjs, numClusters);
  557. kmc.Cluster();
  558. clusterCenters = new Vector3[numClusters];
  559. clusterSizes = new float[numClusters];
  560. for (int i = 0; i < numClusters; i++)
  561. {
  562. List<Renderer> lr = kmc.GetCluster(i, out clusterCenters[i], out clusterSizes[i]);
  563. if (lr.Count > 0)
  564. {
  565. cell2objs.Add("Cluster_" + i, lr);
  566. }
  567. }
  568. }
  569. else
  570. {
  571. //todo error messages
  572. }
  573. return cell2objs;
  574. }
  575. public override void DrawGizmos(Bounds sceneObjectBounds)
  576. {
  577. if (clusterCenters != null && clusterSizes != null && clusterCenters.Length == clusterSizes.Length)
  578. {
  579. for (int i = 0; i < clusterSizes.Length; i++)
  580. {
  581. Gizmos.DrawWireSphere(clusterCenters[i], clusterSizes[i]);
  582. }
  583. }
  584. }
  585. }
  586. [Serializable]
  587. public class MB3_MeshBakerGrouperCluster : MB3_MeshBakerGrouperCore
  588. {
  589. public MB3_AgglomerativeClustering cluster;
  590. float _lastMaxDistBetweenClusters;
  591. public float _ObjsExtents = 10f;
  592. public float _minDistBetweenClusters = .001f;
  593. List<MB3_AgglomerativeClustering.ClusterNode> _clustersToDraw = new List<MB3_AgglomerativeClustering.ClusterNode>();
  594. float[] _radii;
  595. public MB3_MeshBakerGrouperCluster(GrouperData data, List<GameObject> gos)
  596. {
  597. d = data;
  598. }
  599. public override Dictionary<string, List<Renderer>> FilterIntoGroups(List<GameObject> selection)
  600. {
  601. Dictionary<string, List<Renderer>> cell2objs = new Dictionary<string, List<Renderer>>();
  602. for (int i = 0; i < _clustersToDraw.Count; i++)
  603. {
  604. MB3_AgglomerativeClustering.ClusterNode node = _clustersToDraw[i];
  605. List<Renderer> rrs = new List<Renderer>();
  606. for (int j = 0; j < node.leafs.Length; j++)
  607. {
  608. Renderer r = cluster.clusters[node.leafs[j]].leaf.go.GetComponent<Renderer>();
  609. if (r is MeshRenderer || r is SkinnedMeshRenderer)
  610. {
  611. rrs.Add(r);
  612. }
  613. }
  614. cell2objs.Add("Cluster_" + i, rrs);
  615. }
  616. return cell2objs;
  617. }
  618. public void BuildClusters(List<GameObject> gos, ProgressUpdateCancelableDelegate progFunc)
  619. {
  620. if (gos.Count == 0)
  621. {
  622. Debug.LogWarning("No objects to cluster. Add some objects to the list of Objects To Combine.");
  623. return;
  624. }
  625. if (cluster == null) cluster = new MB3_AgglomerativeClustering();
  626. List<MB3_AgglomerativeClustering.item_s> its = new List<MB3_AgglomerativeClustering.item_s>();
  627. for (int i = 0; i < gos.Count; i++)
  628. {
  629. if (gos[i] != null && its.Find(x => x.go == gos[i]) == null)
  630. {
  631. Renderer mr = gos[i].GetComponent<Renderer>();
  632. if (mr != null && (mr is MeshRenderer || mr is SkinnedMeshRenderer))
  633. {
  634. MB3_AgglomerativeClustering.item_s ii = new MB3_AgglomerativeClustering.item_s();
  635. ii.go = gos[i];
  636. ii.coord = mr.bounds.center;
  637. its.Add(ii);
  638. }
  639. }
  640. }
  641. cluster.items = its;
  642. //yield return cluster.agglomerate();
  643. cluster.agglomerate(progFunc);
  644. if (!cluster.wasCanceled)
  645. {
  646. float smallest, largest;
  647. _BuildListOfClustersToDraw(progFunc, out smallest, out largest);
  648. d.maxDistBetweenClusters = Mathf.Lerp(smallest, largest, .9f);
  649. }
  650. }
  651. void _BuildListOfClustersToDraw(ProgressUpdateCancelableDelegate progFunc, out float smallest, out float largest)
  652. {
  653. _clustersToDraw.Clear();
  654. if (cluster.clusters == null)
  655. {
  656. smallest = 1f;
  657. largest = 10f;
  658. return;
  659. }
  660. if (progFunc != null) progFunc("Building Clusters To Draw A:", 0);
  661. List<MB3_AgglomerativeClustering.ClusterNode> removeMe = new List<MB3_AgglomerativeClustering.ClusterNode>();
  662. largest = 1f;
  663. smallest = 10e6f;
  664. for (int i = 0; i < cluster.clusters.Length; i++)
  665. {
  666. MB3_AgglomerativeClustering.ClusterNode node = cluster.clusters[i];
  667. //don't draw clusters that were merged too far apart and only want leaf nodes
  668. if (node.distToMergedCentroid <= d.maxDistBetweenClusters /*&& node.leaf == null*/)
  669. {
  670. if (d.includeCellsWithOnlyOneRenderer)
  671. {
  672. _clustersToDraw.Add(node);
  673. }
  674. else if (node.leaf == null)
  675. {
  676. _clustersToDraw.Add(node);
  677. }
  678. }
  679. if (node.distToMergedCentroid > largest)
  680. {
  681. largest = node.distToMergedCentroid;
  682. }
  683. if (node.height > 0 && node.distToMergedCentroid < smallest)
  684. {
  685. smallest = node.distToMergedCentroid;
  686. }
  687. }
  688. if (progFunc != null) progFunc("Building Clusters To Draw B:", 0);
  689. for (int i = 0; i < _clustersToDraw.Count; i++)
  690. {
  691. removeMe.Add(_clustersToDraw[i].cha);
  692. removeMe.Add(_clustersToDraw[i].chb);
  693. }
  694. for (int i = 0; i < removeMe.Count; i++)
  695. {
  696. _clustersToDraw.Remove(removeMe[i]);
  697. }
  698. _radii = new float[_clustersToDraw.Count];
  699. if (progFunc != null) progFunc("Building Clusters To Draw C:", 0);
  700. for (int i = 0; i < _radii.Length; i++)
  701. {
  702. MB3_AgglomerativeClustering.ClusterNode n = _clustersToDraw[i];
  703. Bounds b = new Bounds(n.centroid, Vector3.one);
  704. for (int j = 0; j < n.leafs.Length; j++)
  705. {
  706. Renderer r = cluster.clusters[n.leafs[j]].leaf.go.GetComponent<Renderer>();
  707. if (r != null)
  708. {
  709. b.Encapsulate(r.bounds);
  710. }
  711. }
  712. _radii[i] = b.extents.magnitude;
  713. }
  714. if (progFunc != null) progFunc("Building Clusters To Draw D:", 0);
  715. _ObjsExtents = largest + 1f;
  716. _minDistBetweenClusters = Mathf.Lerp(smallest, 0f, .9f);
  717. if (_ObjsExtents < 2f) _ObjsExtents = 2f;
  718. }
  719. public override void DrawGizmos(Bounds sceneObjectBounds)
  720. {
  721. if (cluster == null || cluster.clusters == null)
  722. {
  723. return;
  724. }
  725. if (_lastMaxDistBetweenClusters != d.maxDistBetweenClusters)
  726. {
  727. float s, l;
  728. _BuildListOfClustersToDraw(null, out s, out l);
  729. _lastMaxDistBetweenClusters = d.maxDistBetweenClusters;
  730. }
  731. for (int i = 0; i < _clustersToDraw.Count; i++)
  732. {
  733. Gizmos.color = Color.white;
  734. MB3_AgglomerativeClustering.ClusterNode node = _clustersToDraw[i];
  735. Gizmos.DrawWireSphere(node.centroid, _radii[i]);
  736. }
  737. }
  738. }
  739. }