/// ///////////////////////////////////////////////////////// /// Methods /// ///////////////////////////////////////////////////////// // Add solo shards to closest cluster void SetSoloShardToCluster(List <RFShard> soloShards, List <RFCluster> childClusters) { // No solo shards if (soloShards.Count == 0) { return; } // Find neib cluster for solo shards for (int i = soloShards.Count - 1; i >= 0; i--) { int ind = soloShards[i].GetNeibIndArea(); if (ind >= 0) { RFShard neibShard = soloShards[i].neibShards[ind]; for (int c = 0; c < childClusters.Count; c++) { if (childClusters[c].shards.Contains(neibShard) == true) { childClusters[c].shards.Add(soloShards[i]); soloShards.RemoveAt(i); continue; } } } } }
// Prepare shards. Set bounds, set neibs static void SetShardsByRigids(RFCluster cluster, List <RayfireRigid> rigidList, ConnectivityType connectivity) { for (int i = 0; i < rigidList.Count; i++) { // Get mesh filter MeshFilter mf = rigidList[i].GetComponent <MeshFilter>(); // Child has no mesh if (mf == null) { continue; } // Create new shard RFShard shard = new RFShard(rigidList[i].transform, i); shard.cluster = cluster; shard.rigid = rigidList[i]; shard.uny = rigidList[i].activation.unyielding; shard.col = rigidList[i].physics.meshCollider; // Set faces data for connectivity if (connectivity == ConnectivityType.ByMesh) { RFTriangle.SetTriangles(shard, mf); } // Collect shard cluster.shards.Add(shard); } }
// Set up main cluster and set shards RFCluster SetupMainCluster(ConnectivityType connect) { // Create Base cluster RFCluster cluster = new RFCluster(); cluster.tm = transform; cluster.depth = 0; cluster.pos = transform.position; // Set cluster id cluster.id = 0; // Set shards for main cluster RFShard.SetShards(cluster, connectivity); clusterId = 0; // Collect all shards allShards.Clear(); allShards.AddRange(cluster.shards); // TODO set bound return(cluster); }
// Clear public static void Clear(RFShard shard) { if (shard.tris != null) { shard.tris.Clear(); } shard.tris = null; }
// Set cluster void SetCluster() { cluster = new RFCluster(); // Set shards for main cluster cluster.shards = RFShard.GetShards(rigidList, connectivityType); // Set shard neibs RFShard.SetShardNeibs(cluster.shards, connectivityType); }
/// ///////////////////////////////////////////////////////// /// Collider /// ///////////////////////////////////////////////////////// // Create base cluster with children as shards public static RFCluster SetCluster(Transform transform, ConnectivityType connectivity) { // Create Base cluster RFCluster cluster = new RFCluster(); cluster.tm = transform; cluster.rootParent = null; cluster.depth = 0; cluster.pos = transform.position; // Set cluster id cluster.id = 0; // Set shards for main cluster cluster.shards = RFShard.GetShards(cluster.tm, connectivity); return(cluster); }
// Reset local shard rigid, destroy components static void ResetShardRigid(RFShard shard) { shard.rigid = shard.tm.GetComponent <RayfireRigid>(); if (shard.rigid != null) { // Destroy rigid body if (shard.rigid.physics.rigidBody != null) { shard.rigid.physics.rigidBody.velocity = Vector3.zero; Object.Destroy(shard.rigid.physics.rigidBody); } // TODO TEMP SOLUTION, DESTROY ALL DEBRIS AS WELL if (shard.rigid.HasDebris || shard.rigid.HasDust) { for (int c = shard.tm.childCount - 1; c >= 0; c--) { Object.Destroy(shard.tm.GetChild(c).gameObject); } } Object.Destroy(shard.rigid); // shard.rigid.gameObject.SetActive (false); // Stop cors // shard.rigid.StopAllCoroutines(); // shard.rigid.debrisList = null; // shard.rigid.dustList = null; // // // Reset Rigid // shard.rigid.ResetRigid(); // // // Destroy rigid component // if (shard.rigid.reset.shards == RFReset.ShardsResetType.DestroyRigid) // // else // shard.rigid.initialization = RayfireRigid.InitType.ByMethod; // shard.rigid.gameObject.SetActive (true); } }
// Set cluster void SetCluster(List <Transform> tmList) { // In case of runtime add if (cluster == null) { cluster = new RFCluster(); } // Main cluster cached, reinit non serialized vars if (cluster.shards.Count > 0) { InitShards(rigidList, cluster); } // Create main cluster if (cluster.shards.Count == 0) { cluster = new RFCluster(); cluster.id = RFCluster.GetUniqClusterId(cluster); cluster.tm = transform; cluster.depth = 0; cluster.pos = transform.position; cluster.initialized = true; cluster.demolishable = demolishable; // Set shards for main cluster if (Application.isPlaying == true) { SetShardsByRigids(cluster, rigidList, type); } else { RFShard.SetShardsByTransforms(cluster, tmList, type); } // Set shard neibs RFShard.SetShardNeibs(cluster.shards, type, minimumArea, minimumSize, percentage, seed); // Set range for area and size RFCollapse.SetRangeData(cluster, percentage, seed); // Debug.Log ("SetCluster" + rigidList.Count); } }
// Create one cluster which includes only children meshes, not children of children meshes. static bool ClusterizeConnected(RayfireRigid scr) { // Setup cluster and shard if first time. Do not if copied from parent if (scr.clusterDemolition.cluster == null || scr.clusterDemolition.cluster.id == 0) { // Set cluster scr.clusterDemolition.cluster = RFCluster.SetCluster(scr.transForm, scr.clusterDemolition.connectivity); scr.clusterDemolition.cluster.id = 1; // Set shard neibs RFShard.SetShardNeibs(scr.clusterDemolition.cluster.shards, scr.clusterDemolition.connectivity); } // Get all children meshes List <MeshFilter> childMeshes = new List <MeshFilter>(); for (int i = 0; i < scr.transForm.childCount; i++) { MeshFilter mf = scr.transForm.GetChild(i).GetComponent <MeshFilter>(); if (mf != null) { childMeshes.Add(mf); } } // No meshes in children if (childMeshes.Count == 0) { return(false); } // float t1 = Time.realtimeSinceStartup; // Create mesh colliders for every input mesh and collect RFPhysic.SetClusterColliders(scr, childMeshes.ToArray()); // TODO connectivity check to find solo shards and make sure they are not connected return(true); }
// Set mesh triangles public static void SetTriangles(RFShard shard, MeshFilter mf) { // Check if triangles already calculated if (shard.tris != null) { //Debug.Log (" no calc tris"); return; } //Debug.Log ("calc tris"); // Cached Vars int[] triangles = mf.sharedMesh.triangles; Vector3[] vertices = mf.sharedMesh.vertices; // Collect tris int i1, i2, i3; Vector3 v1, v2, v3, cross, pos; shard.tris = new List <RFTriangle>(); for (int i = 0; i < triangles.Length; i += 3) { // Vertex indexes i1 = triangles[i]; i2 = triangles[i + 1]; i3 = triangles[i + 2]; // Get vertices position and area v1 = shard.tm.TransformPoint(vertices[i1]); v2 = shard.tm.TransformPoint(vertices[i2]); v3 = shard.tm.TransformPoint(vertices[i3]); cross = Vector3.Cross(v1 - v2, v1 - v3); // Set position pos = (v1 + v2 + v3) / 3f; // Create triangle and collect it shard.tris.Add(new RFTriangle(i / 3, (cross.magnitude * 0.5f), mf.sharedMesh.normals[i1], pos)); } }
/// ///////////////////////////////////////////////////////// /// Connectivity /// ///////////////////////////////////////////////////////// // Connectivity check public static void ConnectivityUnyCheck(RFCluster cluster) { // Set up child cluster if (cluster.childClusters != null) { cluster.childClusters.Clear(); } // Not enough shards to check for connectivity if (cluster.shards.Count <= 1) { return; } // Check all shards and collect new clusters int shardsAmount = cluster.shards.Count; // Check all shards for connectivity but keep uny clusters in main cluster List <int> checkedShardsIds = new List <int>(); List <RFShard> checkShards = new List <RFShard>(); List <RFShard> newClusterShards = new List <RFShard>(); for (int s = cluster.shards.Count - 1; s >= 0; s--) { // Skip checked shards if (checkedShardsIds.Contains(cluster.shards[s].id) == true) { continue; } // Collect checkedShardsIds.Add(cluster.shards[s].id); // New possible cluster. Create new bacouse applied to cluster newClusterShards.Clear(); newClusterShards.Add(cluster.shards[s]); // Shards in possible connection checkShards.Clear(); checkShards.Add(cluster.shards[s]); // Collect by neibs while (checkShards.Count > 0) { // Add neibs to check If neib among current cluster shards And not already collected for (int n = 0; n < checkShards[0].neibShards.Count; n++) { if (newClusterShards.Contains(checkShards[0].neibShards[n]) == false) { checkShards.Add(checkShards[0].neibShards[n]); newClusterShards.Add(checkShards[0].neibShards[n]); checkedShardsIds.Add(checkShards[0].neibShards[n].id); } } // Remove checked checkShards.RemoveAt(0); } // Child cluster connected if (shardsAmount == newClusterShards.Count) { break; } // Start over if connected shards has uny if (RFShard.UnyieldingByShard(newClusterShards) == true) { continue; } // Child cluster not connected. Create new cluster and add to parent RFCluster newCluster = new RFCluster(); for (int i = 0; i < newClusterShards.Count; i++) { newCluster.shards.Add(newClusterShards[i]); } newCluster.demolishable = cluster.demolishable; // Set main cluster if (cluster.mainCluster == null) { newCluster.mainCluster = cluster; } else { newCluster.mainCluster = cluster.mainCluster; } // Set uniq id after main cluster defined newCluster.id = GetUniqClusterId(newCluster); // Set shards cluster to new cluster for (int i = 0; i < newCluster.shards.Count; i++) { newCluster.shards[i].cluster = newCluster; } // Set up child cluster if (cluster.childClusters == null) { cluster.childClusters = new List <RFCluster>(); } cluster.childClusters.Add(newCluster); } // Remove new child clusters shards from original cluster shards list before repeat while cycle if (cluster.childClusters != null && cluster.childClusters.Count > 0) { for (int i = cluster.shards.Count - 1; i >= 0; i--) { if (cluster.shards[i].cluster != cluster) { cluster.shards.RemoveAt(i); } } } checkedShardsIds.Clear(); // No uny shards in cluster if (cluster.shards.Count == 0) { // Cluster is not connected. If not main cluster then set biggest child cluster shards to original cluster. ReduceChildClusters(cluster); } }
// Check for connectivity public void CheckConnectivity() { // Do once checkNeed = false; // Clear all activated/demolished shards CleanUpActivatedShards(cluster); // No shards to check if (cluster.shards.Count == 0) { return; } // Reinit neibs after cleaning RFShard.ReinitNeibs(cluster.shards); // List of shards to be activated List <RFShard> soloShards = new List <RFShard>(); // TODO do not collect solo uny shards // Check for solo shards and collect RFCluster.GetSoloShards(cluster, soloShards); // Reinit neibs before connectivity check RFShard.ReinitNeibs(cluster.shards); // Connectivity check RFCluster.ConnectivityCheck(cluster); // Get not connected and not unyielding child cluster CheckUnyielding(cluster); // TODO ONE NEIB DETACH FOR CHILD CLUSTERS // Activate not connected shards. if (soloShards.Count > 0) { for (int i = 0; i < soloShards.Count; i++) { soloShards[i].rigid.Activate(); } } // Clusterize childClusters or activate their shards if (cluster.HasChildClusters == true) { if (clusterize == true) { Clusterize(); } else { for (int c = 0; c < cluster.childClusters.Count; c++) { for (int s = 0; s < cluster.childClusters[c].shards.Count; s++) { cluster.childClusters[c].shards[s].rigid.Activate(); } } } } // Stop checking. Everything activated if (cluster.shards.Count == 0) { checkConnectivity = false; } }
// Base clustering pass for shards List <RFCluster> ClusterizeRangeShards(RFCluster mainCluster) { // Empty list of all new cluster roots List <RFShard> soloShards = new List <RFShard>(); // List with all clusters List <RFCluster> childClusters = new List <RFCluster>(); // Sort from smallest to biggest mainCluster.shards.Sort(); // Clusterize starting from biggest while (mainCluster.shards.Count > 0) { // Local amount of shards in cluster int shardsAmount = Random.Range(minimumAmount, maximumAmount); // Start from biggest shard RFShard startShard = mainCluster.shards[0]; // Remove from lists mainCluster.shards.RemoveAt(0); // Starting shard list List <RFShard> shardGroup = new List <RFShard>(); shardGroup.Add(startShard); // Find neibs for (int s = 0; s < shardsAmount - 1; s++) { // Get neib shard among cluster.shards with biggest shared area RFShard biggestShard = RFShard.GetNeibShardArea(shardGroup, mainCluster.shards); // No neib with shared area if (biggestShard == null) { break; } // TODO check if area is much smaller than with another neibs. Set as solo // Add in group shardGroup.Add(biggestShard); // Remove from cluster.shards mainCluster.shards.RemoveAll(t => t.id == biggestShard.id); } // Solo shard if (shardGroup.Count == 1) { soloShards.Add(startShard); } // Group of shards for cluster else if (shardGroup.Count > 1) { // Clusterize with picked shard RFCluster childCluster = new RFCluster(); childCluster.shards.AddRange(shardGroup); childCluster.depth = 1; // Set id clusterId++; childCluster.id = clusterId; // Collect luster childClusters.Add(childCluster); mainCluster.childClusters.Add(childCluster); } } // First pass Find neib cluster for solo shards SetSoloShardToCluster(soloShards, childClusters); // Second pass Find neib cluster for solo shards SetSoloShardToCluster(soloShards, childClusters); // Roughness pass. Remove shards from cluster and add to another. if (smoothPass > 0) { for (int i = 0; i < smoothPass; i++) { RoughnessPassShards(childClusters); } } // TODO consider solo amount // Set id int startId = 1; for (int i = 0; i < childClusters.Count; i++) { childClusters[i].id = startId + i; } // Set main cluster solo shards back to main cluster mainCluster.shards.Clear(); mainCluster.shards.AddRange(soloShards); return(childClusters); }
/// ///////////////////////////////////////////////////////// /// By range /// ///////////////////////////////////////////////////////// // Second clustering type void ClusterizeRange() { if (type == ClusterType.BySharedArea) { Random.InitState(seed); // Create Base cluster and collect RFCluster mainCluster = SetupMainCluster(ConnectivityType.ByMesh); allClusters.Add(mainCluster); // Set shard neibs RFShard.SetShardNeibs(mainCluster.shards, ConnectivityType.ByMesh); // Clusterize base shards to clusters List <RFCluster> childClusters = ClusterizeRangeShards(mainCluster); // Create root and set shards and children foreach (RFCluster childCluster in childClusters) { CreateRoot(childCluster, transform); } // Add to all clusters allClusters.AddRange(childClusters); // Clusterize clusters in depth if (depth > 1) { for (int i = 1; i < depth; i++) { // Set clusters neib info RFCluster.SetClusterNeib(mainCluster.childClusters, true); // Get new depth clusters List <RFCluster> newClusters = ClusterizeRangeClusters(mainCluster); if (newClusters.Count > 1) { // Create root for all new clusters and set as parent for them foreach (RFCluster cls in newClusters) { CreateRoot(cls, mainCluster.tm); foreach (RFCluster childCLuster in cls.childClusters) { childCLuster.tm.parent = cls.tm; } } // Set as child cluster for main cluster to be clusterized at next pass mainCluster.childClusters = newClusters; // Add to all clusters allClusters.AddRange(newClusters); // Get all nested clusters and increment depth foreach (RFCluster cls in allClusters) { if (cls.id != 0) { cls.depth += 1; } } } } } // Set name to roots SetClusterNames(); } }
/// ///////////////////////////////////////////////////////// /// Voronoi /// ///////////////////////////////////////////////////////// // Clusterize by Voronoi pc void ClusterizeVoronoi() { if (type == ClusterType.ByPointCloud) { // Create Base cluster RFCluster mainCluster = SetupMainCluster(connectivity); // Base amount of clusters is more than shards amount if (baseAmount >= mainCluster.shards.Count) { return; } // Set shard neibs RFShard.SetShardNeibs(mainCluster.shards, connectivity); // List with all clusters List <RFCluster> clusters = new List <RFCluster> { mainCluster }; // Collect base cluster allClusters.Add(mainCluster); // Clusterize while (clusters.Count > 0) { // Get local cluster RFCluster cls = clusters[0]; // Remove current cluster from clustering list clusters.RemoveAt(0); // Low amount of shards if (cls.shards.Count < 4) { continue; } // Get amount int amount = baseAmount; if (cls.depth > 0) { amount = depthAmount; } // Get local depth roots cls.childClusters = ClusterizeClusterByAmount(cls, amount); // Collect new clusters allClusters.AddRange(cls.childClusters); // Check if local cluster should be clusterized further and add to list if (cls.childClusters.Count > 0 && depth > cls.depth + 1) { clusters.AddRange(cls.childClusters); } } // Set name to roots SetClusterNames(); } }