// Clusterize not connected groups void Clusterize() { for (int i = 0; i < cluster.childClusters.Count; i++) { // set demolishable state for child cluster cluster.demolishable = demolishable; // Set bound cluster.childClusters[i].bound = RFCluster.GetShardsBound(cluster.childClusters[i].shards); // Create cluster cluster.childClusters[i].shards[0].rigid.simulationType = SimType.Dynamic; // TODO IN BETTER WAY cluster.childClusters[i].shards[0].rigid.objectType = ObjectType.ConnectedCluster; RFDemolitionCluster.CreateClusterRuntime(cluster.childClusters[i].shards[0].rigid, cluster.childClusters[i]); cluster.childClusters[i].shards[0].rigid.objectType = ObjectType.Mesh; // Copy preview cluster.childClusters[i].rigid.clusterDemolition.cn = showConnections; cluster.childClusters[i].rigid.clusterDemolition.nd = showNodes; // Destroy components for (int s = 0; s < cluster.childClusters[i].shards.Count; s++) { Destroy(cluster.childClusters[i].shards[s].rigid.physics.rigidBody); Destroy(cluster.childClusters[i].shards[s].rigid); } } }
static void DrawGizmosSelected(RayfireConnectivity targ, GizmoType gizmoType) { // Connections if (targ.showConnections == true) { if (Application.isPlaying == true) { Gizmos.color = Color.green; if (targ.cluster != null && targ.cluster.shards.Count > 0) { foreach (var shard in targ.cluster.shards) { // Set color Gizmos.color = shard.rigid.activation.unyielding == true ? Color.red : Color.green; // draw sphere if (targ.sphereSize > 0) { Gizmos.DrawWireSphere(shard.tm.position, shard.bound.size.magnitude / 13f * targ.sphereSize); } // Draw connection foreach (var neibShard in shard.neibShards) { if (neibShard.rigid.activation.connect != null) { Gizmos.DrawLine(shard.tm.position, neibShard.tm.position); } } } } } } // Gizmo preview if (targ.showGizmo == true) { // Gizmo properties Gizmos.color = wireColor; // Gizmo if (targ.source == RayfireConnectivity.ConnTargetType.Gizmo) { Gizmos.matrix = targ.transform.localToWorldMatrix; Gizmos.DrawWireCube(Vector3.zero, targ.size); } // Children if (targ.source == RayfireConnectivity.ConnTargetType.Children) { if (targ.transform.childCount > 0) { Bounds bound = RFCluster.GetChildrenBound(targ.transform); Gizmos.DrawWireCube(bound.center, bound.size); } } } }
// 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); } }
// Reinit shard's non serialized fields in case of prefab use public static void InitShards(List <RayfireRigid> rigids, RFCluster cluster) { if (cluster.initialized == false) { // Rigid list doesn't match shards. TODO compare per shard if (cluster.shards.Count != rigids.Count) { cluster.shards.Clear(); return; } // Reinit for (int s = 0; s < cluster.shards.Count; s++) { if (rigids[s] != null) { cluster.shards[s].rigid = rigids[s]; cluster.shards[s].uny = rigids[s].activation.unyielding; } cluster.shards[s].cluster = cluster; cluster.shards[s].neibShards = new List <RFShard>(); for (int n = 0; n < cluster.shards[s].nIds.Count; n++) { cluster.shards[s].neibShards.Add(cluster.shards[cluster.shards[s].nIds[n]]); } } cluster.initialized = true; } }
// Create root for cluster at shards center and set shards as children void CreateRoot(RFCluster childCluster, Transform parentTm) { // Get cluster bound Bounds childBound = GetShardsBound(childCluster.shards, childCluster.childClusters); // Set cluster bound childCluster.bound = childBound; // Create root for cluster GameObject childRoot = new GameObject(); // Set cluster root position childCluster.tm = childRoot.transform; childCluster.pos = childBound.center; childCluster.tm.position = childBound.center; // Set cluster parent childCluster.tm.parent = parentTm; // Set cluster root as shards parent foreach (RFShard shard in childCluster.shards) { shard.tm.parent = childCluster.tm; } }
// Add solo shards to closest cluster void SetSoloClusterToCluster(List <RFCluster> soloClusters, List <RFCluster> childClusters) { // No solo clusters if (soloClusters.Count == 0) { return; } // Find neib cluster for solo cluster for (int i = soloClusters.Count - 1; i >= 0; i--) { int ind = soloClusters[i].GetNeibIndArea(); if (ind >= 0) { RFCluster neibCluster = soloClusters[i].neibClusters[ind]; for (int c = 0; c < childClusters.Count; c++) { if (childClusters[c].childClusters.Contains(neibCluster) == true) { childClusters[c].childClusters.Add(soloClusters[i]); soloClusters.RemoveAt(i); continue; } } } } }
// 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); }
/// ///////////////////////////////////////////////////////// /// Roots /// ///////////////////////////////////////////////////////// // Create deleted roots and restore their tm back static void ResetRootsRecursive(RFCluster cluster) { if (cluster.HasChildClusters == true) { for (int i = 0; i < cluster.childClusters.Count; i++) { cluster.childClusters[i].tm.parent = null; // Destroy rigid cluster.childClusters[i].rigid = cluster.childClusters[i].tm.GetComponent <RayfireRigid>(); if (cluster.childClusters[i].rigid != null) { // Destroy rigid body if (cluster.childClusters[i].rigid.physics.rigidBody != null) { Object.Destroy(cluster.childClusters[i].rigid.physics.rigidBody); } Object.Destroy(cluster.childClusters[i].rigid); } // Activate cluster.childClusters[i].tm.gameObject.SetActive(true); // Repeat for children ResetRootsRecursive(cluster.childClusters[i]); } } }
// Init collapse after connection loss static void CollapseCluster(RayfireRigid scr) { // Collect solo shards, remove from cluster, no need to reinit List <RFShard> detachShards = new List <RFShard>(); RFCluster.GetSoloShards(scr.clusterDemolition.cluster, detachShards); // Clear fragments in case of previous demolition if (scr.HasFragments == true) { scr.fragments.Clear(); } // Dynamic cluster connectivity check, all clusters are equal, pick biggest to keep as original if (scr.simulationType == SimType.Dynamic || scr.simulationType == SimType.Sleeping) { // Check left cluster shards for connectivity and collect not connected child clusters. Should be before ClusterizeDetachShards RFCluster.ConnectivityCheck(scr.clusterDemolition.cluster); // Cluster is not connected. Set biggest child cluster shards to original cluster. Cant be 1 child cluster here RFCluster.ReduceChildClusters(scr.clusterDemolition.cluster); } // Kinematik/ Inactive cluster, Connectivity check if cluster has uny shards. Main cluster keeps all not activated else if (scr.simulationType == SimType.Kinematic || scr.simulationType == SimType.Inactive) { RFCluster.ConnectivityUnyCheck(scr.clusterDemolition.cluster); } // Init final cluster ops RFDemolitionCluster.PostDemolitionCluster(scr, detachShards); }
// Get not connected groups void Check() { // Get not connected clusters RFCluster.ConnectivityCheckUny(cluster); // TODO turn of if no objs to activate // clusters }
/// ///////////////////////////////////////////////////////// /// Constructor /// ///////////////////////////////////////////////////////// // Constructor public RFDemolitionCluster() { meshDemolition = false; connectivity = ConnectivityType.ByBoundingBox; contactRadius = 15; cluster = null; Reset(); }
// 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); }
// Create runtime clusters static void CreateClusterRuntime(RayfireRigid source, RFCluster cls) { // Cluster with solo shard. Add rigid component, reparent if (cls.shards.Count == 1) { AddRigidComponent(source, new List <Transform> (1) { cls.shards[0].tm }); cls.shards[0].tm.parent = RayfireMan.inst.transForm; return; } // Create root for left children GameObject leftRoot = new GameObject(); // Turn off leftRoot.SetActive(false); leftRoot.name = source.gameObject.name + "_cls"; leftRoot.transform.position = source.transForm.position; leftRoot.transform.rotation = source.transForm.rotation; leftRoot.transform.parent = RayfireMan.inst.transForm; // Parent to main root for (int s = 0; s < cls.shards.Count; s++) { cls.shards[s].tm.parent = leftRoot.transform; } // Add rigid to object RayfireRigid target = leftRoot.gameObject.AddComponent <RayfireRigid>(); target.initialization = RayfireRigid.InitType.AtStart; // Collect fragment source.fragments.Add(target); // Copy properties from parent to fragment node source.CopyPropertiesTo(target); // Copy particles RFParticles.CopyParticles(source, target); // Set to mesh target.objectType = ObjectType.ConnectedCluster; target.physics.colliderType = RFColliderType.Mesh; // Set cluster target.clusterDemolition.cluster = cls; target.clusterDemolition.cluster.id = 2; // Turn on leftRoot.SetActive(true); }
// Create deleted roots and restore their tm back static void ResetRootsParentsRecursive(RFCluster cluster) { if (cluster.HasChildClusters == true) { for (int i = 0; i < cluster.childClusters.Count; i++) { cluster.childClusters[i].tm.parent = cluster.tm; ResetRootsParentsRecursive(cluster.childClusters[i]); } } }
/// ///////////////////////////////////////////////////////// /// Shards /// ///////////////////////////////////////////////////////// // Prepare shards. Set bounds, set neibs public static void SetShards(RFCluster cluster, ConnectivityType connectivity, bool setRigid = false) { // Get all children tms List <Transform> tmList = new List <Transform>(); for (int i = 0; i < cluster.tm.childCount; i++) { tmList.Add(cluster.tm.GetChild(i)); } // Get child shards SetShardsByTransforms(cluster, tmList, connectivity, setRigid); }
// Clear all activated/demolished shards static void CleanUpActivatedShards(RFCluster cluster) { for (int i = cluster.shards.Count - 1; i >= 0; i--) { if (cluster.shards[i].rigid == null || cluster.shards[i].rigid.activation.connect == null || cluster.shards[i].rigid.limitations.demolished == true) { cluster.shards[i].cluster = null; cluster.shards.RemoveAt(i); } } }
static void GizmoDraw(RayfireConnectivity targ) { if (targ.showGizmo == true) { // Gizmo properties Gizmos.color = wireColor; if (targ.transform.childCount > 0) { Bounds bound = RFCluster.GetChildrenBound(targ.transform); Gizmos.DrawWireCube(bound.center, bound.size); } } }
// Check children for mesh or cluster root until all children will not be checked static void SetDeepShardColliders(RayfireRigid scr, RFCluster cluster) { // Set shard colliders SetShardColliders(scr, cluster); // Set child cluster colliders if (cluster.HasChildClusters == true) { for (int i = 0; i < cluster.childClusters.Count; i++) { SetDeepShardColliders(scr, cluster.childClusters[i]); } } }
// Set range for area and size public static void SetRangeData(RFCluster cluster, int perc = 0, int seed = 0) { if (cluster.shards.Count == 0) { return; } // Start values cluster.maximumSize = cluster.shards[0].sz; cluster.minimumSize = cluster.shards[0].sz; cluster.maximumArea = 0f; cluster.minimumArea = 10000f; cluster.randomCollapse = perc; cluster.randomSeed = seed; // Loop shards for (int i = 0; i < cluster.shards.Count; i++) { if (cluster.shards[i].sz > cluster.maximumSize) { cluster.maximumSize = cluster.shards[i].sz; } if (cluster.shards[i].sz < cluster.minimumSize) { cluster.minimumSize = cluster.shards[i].sz; } for (int j = 0; j < cluster.shards[i].nArea.Count; j++) { if (cluster.shards[i].nArea[j] > cluster.maximumArea) { cluster.maximumArea = cluster.shards[i].nArea[j]; } if (cluster.shards[i].nArea[j] < cluster.minimumArea) { cluster.minimumArea = cluster.shards[i].nArea[j]; } } } // Fix if (cluster.minimumArea < 0.001f) { cluster.minimumArea = 0f; } cluster.areaCollapse = cluster.minimumArea; cluster.sizeCollapse = cluster.minimumSize; }
static void DrawGizmosSelected(RayfireConnectivity targ, GizmoType gizmoType) { // Connections //if (targ.enabled == true) { if (RFCluster.IntegrityCheck(targ.cluster) == false) { Debug.Log("RayFire Connectivity: " + targ.name + " has missing shards. Reset or Setup cluster.", targ.gameObject); } ClusterDraw(targ); GizmoDraw(targ); } }
// CLuster connection and nodes viewport preview static void ClusterDraw(RayfireRigid targ) { if (targ.objectType == ObjectType.ConnectedCluster) { if (targ.clusterDemolition.cluster != null && targ.clusterDemolition.cluster.shards.Count > 0) { // Reinit connections if (targ.clusterDemolition.cluster.initialized == false) { RFCluster.InitCluster(targ, targ.clusterDemolition.cluster); } // Draw for (int i = 0; i < targ.clusterDemolition.cluster.shards.Count; i++) { if (targ.clusterDemolition.cluster.shards[i].uny == false) { if (targ.clusterDemolition.cluster.shards[i].nIds.Count > 0) { Gizmos.color = Color.blue; } else { Gizmos.color = Color.gray; } } else { Gizmos.color = Color.red; } if (targ.clusterDemolition.nd == true) { Gizmos.DrawWireSphere(targ.clusterDemolition.cluster.shards[i].tm.position, targ.clusterDemolition.cluster.shards[i].sz / 12f); } if (targ.clusterDemolition.cn == true) { if (targ.clusterDemolition.cluster.shards[i].neibShards != null) { for (int j = 0; j < targ.clusterDemolition.cluster.shards[i].neibShards.Count; j++) { Gizmos.DrawLine(targ.clusterDemolition.cluster.shards[i].tm.position, targ.clusterDemolition.cluster.shards[i].neibShards[j].tm.position); } } } } } } }
/// ///////////////////////////////////////////////////////// /// Cluster Colliders /// ///////////////////////////////////////////////////////// // Set cluster colliders by shards public static void CollectClusterColliders(RayfireRigid scr, RFCluster cluster) { // Reset original cluster colliders list if (scr.physics.clusterColliders == null) { scr.physics.clusterColliders = new List <Collider>(); } else { scr.physics.clusterColliders.Clear(); } // Collect all shards colliders CollectDeepColliders(scr, cluster); }
// Set up main cluster and set shards RFCluster SetupMainCluster(ConnectivityType connect) { // Create Base cluster RFCluster cluster = RFCluster.SetCluster(transform, connect); clusterId = 0; // Collect all shards allShards.Clear(); allShards.AddRange(cluster.shards); // TODO set bound return(cluster); }
// Save cluster/shards tm static void RestoreClusterTmRecursive(RFCluster cluster) { // Save cluster tm cluster.tm.rotation = cluster.rot; cluster.tm.position = cluster.pos; // Repeat for child clusters if (cluster.HasChildClusters == true) { for (int i = 0; i < cluster.childClusters.Count; i++) { RestoreClusterTmRecursive(cluster.childClusters[i]); } } }
// Set bound and size public static void SetBound(RayfireRigid scr) { if (scr.objectType == ObjectType.Mesh) { scr.limitations.bound = scr.meshRenderer.bounds; } else if (scr.objectType == ObjectType.SkinnedMesh) { scr.limitations.bound = scr.skinnedMeshRend.bounds; } else if (scr.objectType == ObjectType.NestedCluster || scr.objectType == ObjectType.ConnectedCluster) { scr.limitations.bound = RFCluster.GetChildrenBound(scr.transForm); } scr.limitations.bboxSize = scr.limitations.bound.size.magnitude; }
// 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); } }
// Prepare shards. Set bounds, set neibs public static void SetShardsByTransforms(RFCluster cluster, List <Transform> tmList, ConnectivityType connectivity, bool setRigid = false) { cluster.shards = new List <RFShard>(); for (int i = 0; i < tmList.Count; i++) { // Get mesh filter MeshFilter mf = tmList[i].GetComponent <MeshFilter>(); // Child has no mesh if (mf == null) { continue; } // Has no mesh if (mf.sharedMesh == null) { continue; } // Create new shard RFShard shard = new RFShard(tmList[i], i); shard.cluster = cluster; // Set faces data for connectivity if (connectivity == ConnectivityType.ByMesh || connectivity == ConnectivityType.ByBoundingBoxAndMesh) { RFTriangle.SetTriangles(shard, mf); } // Collect shard cluster.shards.Add(shard); } // Set rigid component if (setRigid == true) { for (int i = 0; i < cluster.shards.Count; i++) { cluster.shards[i].rigid = cluster.shards[i].tm.GetComponent <RayfireRigid>(); } } }
// Check children for mesh or cluster root until all children will not be checked static void CollectDeepColliders(RayfireRigid scr, RFCluster cluster) { // Collect shards colliders for (int i = 0; i < cluster.shards.Count; i++) { scr.physics.clusterColliders.Add(cluster.shards[i].col); } // Set child cluster colliders if (scr.objectType == ObjectType.NestedCluster) { if (cluster.HasChildClusters == true) { for (int i = 0; i < cluster.childClusters.Count; i++) { CollectDeepColliders(scr, cluster.childClusters[i]); } } } }
/// ///////////////////////////////////////////////////////// /// Reset shard rigid /// ///////////////////////////////////////////////////////// // Reset local shard rigid, destroy components static void ResetDeepShardRigid(RayfireRigid scr, RFCluster cluster) { // Collect shards colliders for (int i = 0; i < cluster.shards.Count; i++) { ResetShardRigid(cluster.shards[i]); } // Set child cluster colliders if (scr.objectType == ObjectType.NestedCluster) { if (cluster.HasChildClusters == true) { for (int i = 0; i < cluster.childClusters.Count; i++) { ResetDeepShardRigid(scr, cluster.childClusters[i]); } } } }
// Remove neibs by area static int RemNeibRandom(RFCluster cluster, int percent, int seed) { int removed = 0; cluster.randomSeed = seed; for (int s = 0; s < cluster.shards.Count; s++) { // Skip unyielding if (cluster.shards[s].uny == true) { continue; } for (int n = cluster.shards[s].neibShards.Count - 1; n >= 0; n--) { // Set random state for same pair Random.InitState(cluster.shards[s].id + cluster.shards[s].neibShards[n].id + seed); if (Random.Range(0, 100) < percent) { // Remove self in neib's neib list for (int i = cluster.shards[s].neibShards[n].neibShards.Count - 1; i >= 0; i--) { if (cluster.shards[s].neibShards[n].neibShards[i] == cluster.shards[s]) { cluster.shards[s].neibShards[n].nIds.RemoveAt(i); cluster.shards[s].neibShards[n].nArea.RemoveAt(i); cluster.shards[s].neibShards[n].neibShards.RemoveAt(i); break; } } // Remove in self cluster.shards[s].nIds.RemoveAt(n); cluster.shards[s].nArea.RemoveAt(n); cluster.shards[s].neibShards.RemoveAt(n); removed++; } } } return(removed); }