MB3_MeshBakerGrouper.cs 25 KB

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