// Set Shatter Runtime Mode properties static void SetShatterRuntimeMode(RFShatter shatter) { shatter.EditorMode(false); shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_shatter, true); shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_cap, true); shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_weld, true); }
// Copy from public void CopyFrom(RFDemolitionMesh demolition) { amount = demolition.amount; variation = demolition.variation; depthFade = demolition.depthFade; seed = demolition.seed; contactBias = demolition.contactBias; useShatter = false; // TODO input mesh for fragments ?? turn off for now meshInput = demolition.meshInput; meshInput = MeshInputType.AtDemolition; properties.CopyFrom(demolition.properties); runtimeCaching = new RFRuntimeCaching(); Reset(); shatterMode = 1; innerSubId = 0; compressPrefab = true; cacheRotationStart = Quaternion.identity; mesh = null; rfShatter = null; }
// Set slicing objects static void SetSlices(RFShatter shatter, Transform tm, RFSlice slices) { // Filter List <Transform> list = new List <Transform>(); for (int i = 0; i < slices.sliceList.Count; i++) { if (slices.sliceList[i] != null) { list.Add(slices.sliceList[i]); } } // No objects if (list.Count == 0) { return; } // Get slice data Vector3[] points = list.Select(t => t.position).ToArray(); Vector3[] norms = list.Select(t => slices.Axis(t)).ToArray(); // Set params shatter.SetBricksParams(points, norms, tm); }
/// ///////////////////////////////////////////////////////// /// Fragmentation types /// ///////////////////////////////////////////////////////// // Set Uniform static void SetVoronoi(RFShatter shatter, int numFragments, Transform tm, Vector3 centerPos, float centerBias) { // Get amount int amount = numFragments; if (amount < 1) { amount = 1; } if (amount > 20000) { amount = 2; } // Set properties shatter.SetFragmentParameter(RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.irregular); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_irr_num, amount); // Set bias to center if (centerBias > 0) { shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_irr_bias, centerBias); shatter.SetCenterParameter(centerPos, tm, Vector3.forward); } }
// Set Shatter Runtime Mode properties static void SetShatterRuntimeMode(RFShatter shatter) { shatter.EditorMode(false); //shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_shatter, true); //shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_cap, true); //shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_weld, true); // TODO tests vals shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_shatter, true); shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_cap, true); shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_weld, true); shatter.SetGeneralParameter(RFShatter.GeneralParams.minFacesFilter, 3); }
// Set Shatter Editor Mode properties static void SetShatterEditorMode(RFShatter shatter, float sizeFilter, bool preCap, bool remCap, bool remDbl, bool exInside) { shatter.EditorMode(true); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_pre_cap, preCap); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_remove_cap_faces, remCap); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_separate_only, false); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_elliminateCollinears_maxIterFuse, 150); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_min_bbox_diag_size_filter, sizeFilter); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_exclude_inside, exInside); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_remove_double_faces, remDbl); shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_remove_inversed_double_faces, remDbl); }
// Set Slabs static void SetSlabs(RFShatter shatter, RFSplinters slabs, Transform tm, Vector3 centerPos, float centerBias) { // Set properties shatter.SetFragmentParameter(RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.irregular); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_irr_num, slabs.Amount); // Set center shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_irr_bias, centerBias); shatter.SetCenterParameter(centerPos, tm, Vector3.forward); // Set Stretching for slabs SetStretching(shatter, slabs.axis, slabs.strength, FragType.Slabs); }
// Set custom point cloud static void SetCustom(RFShatter shatter, RFCustom custom, Transform tm, MeshFilter mf, Bounds bound, RFSplinters splint, RFSplinters slabs, int seed) { // Set properties shatter.SetFragmentParameter(RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.custom); // Get Point Cloud List <Vector3> pointCloud = GetCustomPointCLoud(custom, tm, seed, bound); // Set points shatter.SetVoroCustomPoints(pointCloud.ToArray(), tm); // Set Stretching TODO point cloud rescale by transform // if (custom.modifier == RFCustom.RFModifierType.Splinters) // SetStretching (shatter, splint.axis, splint.strength, FragType.Splinters); // else if (custom.modifier == RFCustom.RFModifierType.Slabs) // SetStretching (shatter, slabs.axis, slabs.strength, FragType.Slabs); }
/// ///////////////////////////////////////////////////////// /// Properties setup /// ///////////////////////////////////////////////////////// // Set common fragmentation properties static RFShatter SetShatter(int shatterMode, Mesh mesh, Transform transform, RFSurface interior, bool decompose, bool deleteCol, int seed = 1, FragmentMode mode = FragmentMode.Runtime, bool preCap = true, bool remCap = false, bool remDbl = true, bool exInside = false, int percSize = 3) { // Creating shatter RFShatter shatter = new RFShatter((RFShatter.RFShatterMode)shatterMode, true); // Safe/unsafe properties if (mode == FragmentMode.Editor) { float sizeFilter = mesh.bounds.size.magnitude * percSize / 100f; // TODO check render bound size SetShatterEditorMode(shatter, sizeFilter, preCap, remCap, remDbl, exInside); } else { SetShatterRuntimeMode(shatter); } // Detach by elements shatter.DecomposeResultMesh(decompose); // Set properties shatter.SetFragmentParameter(RFShatter.FragmentParams.seed, seed); shatter.SetGeneralParameter(RFShatter.GeneralParams.pre_weld_threshold, 0.001f); shatter.SetGeneralParameter(RFShatter.GeneralParams.delete_collinear, deleteCol); // Other shatter.SetGeneralParameter(RFShatter.GeneralParams.maping_scale, interior.mappingScale); shatter.SetGeneralParameter(RFShatter.GeneralParams.restore_normals, true); // Setting shatter params bool inputState = shatter.SetInputMesh(transform, mesh); // Failed input if (inputState == false) { Debug.Log("Bad input mesh: " + transform.name, transform.gameObject); return(null); } return(shatter); }
/// ///////////////////////////////////////////////////////// /// Stretching /// ///////////////////////////////////////////////////////// // Set stretching static void SetStretching(RFShatter shatter, AxisType axis, float strength, FragType fragType) { // Get slab vector Vector3 stretchDir = DirectionAxis(axis); // Adjust for slabs if (fragType == FragType.Slabs) { Vector3 vector = new Vector3(); if (stretchDir.x <= 0) { vector.x = 1f; } if (stretchDir.x >= 1f) { vector.x = 0; } if (stretchDir.y <= 0) { vector.y = 1f; } if (stretchDir.y >= 1f) { vector.y = 0; } if (stretchDir.z <= 0) { vector.z = 1f; } if (stretchDir.z >= 1f) { vector.z = 0; } stretchDir = vector; } // Set stretch vector shatter.SetPoint3Parameter((int)RFShatter.FragmentParams.stretching, stretchDir * Mathf.Lerp(40f, 99f, strength)); }
// Set Radial static void SetRadial(RFShatter shatter, RFRadial radial, Transform tm, Vector3 centerPos, Quaternion centerDirection) { // Set radial properties shatter.SetFragmentParameter(RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.voronoi); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_type, (int)RFShatter.VoronoiType.radial); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_radius, radial.radius); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_divergence, radial.divergence); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_restrict, radial.restrictToPlane); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rings_count, radial.rings); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rings_focus, radial.focus); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rings_strenght, radial.focusStr); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rings_random, radial.randomRings); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rays_count, radial.rays); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rays_random, radial.randomRays); shatter.SetFragmentParameter(RFShatter.FragmentParams.voronoi_rad_rays_twist, radial.twist); // Get direction axis Vector3 directionAxis = DirectionAxis(radial.centerAxis); Vector3 centerRot = tm.rotation * centerDirection * directionAxis; shatter.SetCenterParameter(centerPos, tm, centerRot); }
/// ///////////////////////////////////////////////////////// /// Clusters /// ///////////////////////////////////////////////////////// // Set clusters static void SetClusters(RFShatter shatter, RFShatterCluster gluing) { shatter.InitClustering(true); shatter.SetClusterParameter(RFShatter.ClusterParams.enabled, true); shatter.SetClusterParameter(RFShatter.ClusterParams.by_pcloud_count, gluing.count); shatter.SetClusterParameter(RFShatter.ClusterParams.options_seed, gluing.seed); shatter.SetClusterParameter(RFShatter.ClusterParams.preview_scale, 100f); // Debris shatter.SetClusterParameter(RFShatter.ClusterParams.debris_layers_count, gluing.layers); shatter.SetClusterParameter(RFShatter.ClusterParams.debris_count, gluing.amount); shatter.SetClusterParameter(RFShatter.ClusterParams.debris_scale, gluing.scale); shatter.SetClusterParameter(RFShatter.ClusterParams.debris_min, gluing.min); shatter.SetClusterParameter(RFShatter.ClusterParams.debris_max, gluing.max); shatter.SetClusterParameter(RFShatter.ClusterParams.debris_tessellate, false); shatter.SetClusterParameter(RFShatter.ClusterParams.debris_remove, false); // Glue shatter.SetGeneralParameter(RFShatter.GeneralParams.glue, true); shatter.SetGeneralParameter(RFShatter.GeneralParams.glue_weld_threshold, 0.001f); shatter.SetGeneralParameter(RFShatter.GeneralParams.relax, gluing.relax); }
/// ///////////////////////////////////////////////////////// /// Constructor /// ///////////////////////////////////////////////////////// // Constructor public RFDemolitionMesh() { amount = 15; variation = 0; depthFade = 0.5f; contactBias = 0f; seed = 1; useShatter = false; meshInput = MeshInputType.AtDemolition; properties = new RFFragmentProperties(); runtimeCaching = new RFRuntimeCaching(); Reset(); shatterMode = 1; innerSubId = 0; compressPrefab = true; cacheRotationStart = Quaternion.identity; mesh = null; rfShatter = null; }
// Decompose to elements static void SetDecompose(RFShatter shatter) { shatter.SetGeneralParameter(RFShatter.GeneralParams.editor_mode_separate_only, true); }
// Set Custom Voronoi properties static void SetTet(RFShatter shatter, Bounds bounds, RFTets tets) { // Main shatter.SetFragmentParameter(RFShatter.FragmentParams.type, (int)RFShatter.FragmentType.tetra); shatter.SetFragmentParameter(RFShatter.FragmentParams.tetra_type, (int)tets.lattice); // Get max float max = bounds.size.x; if (bounds.size.y > max) { max = bounds.size.y; } if (bounds.size.z > max) { max = bounds.size.z; } if (max == 0) { max = 0.01f; } // Get density Vector3Int density = new Vector3Int( (int)Mathf.Ceil(bounds.size.x / max * tets.density), (int)Mathf.Ceil(bounds.size.y / max * tets.density), (int)Mathf.Ceil(bounds.size.z / max * tets.density)); // Limit if (density.x > 30) { density.x = 30; } else if (density.x < 1) { density.x = 1; } if (density.y > 30) { density.y = 30; } else if (density.y < 1) { density.y = 1; } if (density.z > 30) { density.z = 30; } else if (density.z < 1) { density.z = 1; } // Set density shatter.SetPoint3Parameter((int)RFShatter.FragmentParams.tetra2_density, density); shatter.SetPoint3Parameter((int)RFShatter.FragmentParams.tetra1_density, density); // Noise shatter.SetFragmentParameter(RFShatter.FragmentParams.tetra_noise, tets.noise); }
/// ///////////////////////////////////////////////////////// /// Slice /// ///////////////////////////////////////////////////////// // Cache for slice public static void SliceMeshes(ref Mesh[] meshes, ref Vector3[] pivots, ref List <RFDictionary> origSubMeshIdsRf, RayfireRigid scr, List <Vector3> sliceData) { // Get mesh scr.meshDemolition.mesh = GetDemolitionMesh(scr); // Set up shatter RFShatter shatter = SetShatter( 2, scr.meshDemolition.mesh, scr.transform, scr.materials, true, scr.meshDemolition.properties.removeCollinear, scr.meshDemolition.seed, FragmentMode.Runtime, false, false, false, false, 3); // Failed input if (shatter == null) { scr.meshDemolition.badMesh++; return; } // Get innerSubId int innerSubId = RFSurface.SetInnerSubId(scr); // Get slice data List <Vector3> points = new List <Vector3>(); List <Vector3> norms = new List <Vector3>(); for (int i = 0; i < sliceData.Count; i++) { points.Add(sliceData[i]); norms.Add(sliceData[i + 1]); i++; } // Set params shatter.SetBricksParams(points.ToArray(), norms.ToArray(), scr.transform); // Calculate fragments List <Dictionary <int, int> > origSubMeshIds = new List <Dictionary <int, int> >(); bool successState = Compute( 2, shatter, scr.transform, ref meshes, ref pivots, scr.meshDemolition.mesh, innerSubId, ref origSubMeshIds, scr.gameObject); // Create RF dictionary origSubMeshIdsRf = new List <RFDictionary>(); for (int i = 0; i < origSubMeshIds.Count; i++) { origSubMeshIdsRf.Add(new RFDictionary(origSubMeshIds[i])); } // Failed fragmentation. Increase bad mesh if (successState == false) { scr.meshDemolition.badMesh++; Debug.Log("Bad mesh: " + scr.name, scr.gameObject); } else { for (int i = 0; i < meshes.Length; i++) { meshes[i].name = scr.name + "_" + i; } } }
/// ///////////////////////////////////////////////////////// /// Shatter /// ///////////////////////////////////////////////////////// // Cache for shatter public static void CacheMeshes(ref Mesh[] meshes, ref Vector3[] pivots, ref List <RFDictionary> origSubMeshIdsRf, RayfireShatter scrShatter) { // TODO check vars by type: slice list, etc // Turn off fast mode for tets and slices int shatterMode = GetShatterMode(scrShatter); // Get mesh Mesh mesh = GetDemolitionMesh(scrShatter);; // Decompose in Editor only, slice runtime only FragmentMode mode = scrShatter.mode; if (scrShatter.type == FragType.Decompose) // TODO FIX { mode = FragmentMode.Editor; } if (scrShatter.type == FragType.Slices) { mode = FragmentMode.Runtime; } // Set up shatter RFShatter shatter = SetShatter( shatterMode, mesh, scrShatter.transform, scrShatter.material, scrShatter.advanced.decompose, scrShatter.advanced.removeCollinear, scrShatter.advanced.seed, mode, scrShatter.advanced.inputPrecap, scrShatter.advanced.outputPrecap, scrShatter.advanced.removeDoubleFaces, scrShatter.advanced.excludeInnerFragments, scrShatter.advanced.elementSizeThreshold); // Failed input if (shatter == null) { meshes = null; pivots = null; return; } // Get innerSubId int innerSubId = RFSurface.SetInnerSubId(scrShatter); // Set fragmentation properties SetFragmentProperties(shatter, scrShatter, null); // Custom points check if (scrShatter.type == FragType.Custom && scrShatter.custom.noPoints == true) { meshes = null; pivots = null; Debug.Log("No custom ponts"); return; } // Calculate fragments List <Dictionary <int, int> > origSubMeshIds = new List <Dictionary <int, int> >(); bool successState = Compute( shatterMode, shatter, scrShatter.transform, ref meshes, ref pivots, mesh, innerSubId, ref origSubMeshIds, scrShatter); // Create RF dictionary origSubMeshIdsRf = new List <RFDictionary>(); for (int i = 0; i < origSubMeshIds.Count; i++) { origSubMeshIdsRf.Add(new RFDictionary(origSubMeshIds[i])); } // Failed fragmentation. Increase bad mesh if (successState == false) { Debug.Log("Bad shatter output mesh: " + scrShatter.name); } else { for (int i = 0; i < meshes.Length; i++) { meshes[i].name = scrShatter.name + "_" + i; } } }
// Set fragmentation properties static void SetFragmentProperties(RFShatter shatter, RayfireShatter scrSh, RayfireRigid scrRigid) { // Rigid demolition without shatter. Set and exit. if (scrRigid != null && scrSh == null) { // Get final amount int percVar = Random.Range(0, scrRigid.meshDemolition.amount * scrRigid.meshDemolition.variation / 100); scrRigid.meshDemolition.totalAmount = scrRigid.meshDemolition.amount + percVar; // Set Voronoi Uniform properties SetVoronoi(shatter, scrRigid.meshDemolition.totalAmount, scrRigid.transform, scrRigid.limitations.contactPoint, scrRigid.meshDemolition.contactBias); return; } // Rigid demolition with shatter. if (scrRigid != null && scrSh != null) { // Set Contact point to shatter component scrSh.centerPosition = scrRigid.transForm.InverseTransformPoint(scrRigid.limitations.contactPoint); // Set total amount by rigid component if (scrSh.type == FragType.Voronoi) { scrRigid.meshDemolition.totalAmount = scrSh.voronoi.Amount; } else if (scrSh.type == FragType.Splinters) { scrRigid.meshDemolition.totalAmount = scrSh.splinters.Amount; } else if (scrSh.type == FragType.Slabs) { scrRigid.meshDemolition.totalAmount = scrSh.slabs.Amount; } else if (scrSh.type == FragType.Radial) { scrRigid.meshDemolition.totalAmount = scrSh.radial.rings * scrSh.radial.rays; } } // Shatter fragmentation if (scrSh != null) { // Center position and direction Vector3 centerPos = scrSh.transform.TransformPoint(scrSh.centerPosition); // Set properties if (scrSh.type == FragType.Voronoi) { SetVoronoi(shatter, scrSh.voronoi.Amount, scrSh.transform, centerPos, scrSh.voronoi.centerBias); } else if (scrSh.type == FragType.Splinters) { SetSplinters(shatter, scrSh.splinters, scrSh.transform, centerPos, scrSh.splinters.centerBias); } else if (scrSh.type == FragType.Slabs) { SetSlabs(shatter, scrSh.slabs, scrSh.transform, centerPos, scrSh.splinters.centerBias); } else if (scrSh.type == FragType.Radial) { SetRadial(shatter, scrSh.radial, scrSh.transform, centerPos, scrSh.centerDirection); } else if (scrSh.type == FragType.Custom) { SetCustom(shatter, scrSh.custom, scrSh.transform, scrSh.meshFilter, scrSh.bound, scrSh.splinters, scrSh.slabs, scrSh.advanced.seed); } else if (scrSh.type == FragType.Slices) { SetSlices(shatter, scrSh.transform, scrSh.slice); } else if (scrSh.type == FragType.Tets) { SetTet(shatter, scrSh.bound, scrSh.tets); } else if (scrSh.type == FragType.Decompose) { SetDecompose(shatter); } // Clustering if (scrSh.clusters.enable == true) { SetClusters(shatter, scrSh.clusters); } } }
/// ///////////////////////////////////////////////////////// /// Compute /// ///////////////////////////////////////////////////////// // Compute static bool Compute(int shatterMode, RFShatter shatter, Transform tm, ref Mesh[] meshes, ref Vector3[] pivots, Mesh mesh, int innerSubId, ref List <Dictionary <int, int> > subIds, Object obj, List <int> markedElements = null) { // Compute fragments bool state = shatterMode == 0 ? shatter.Compute(tm, ref meshes, ref pivots, mesh, innerSubId, ref subIds) : shatter.SimpleCompute(tm, ref meshes, ref pivots, mesh, innerSubId, ref subIds, markedElements); // Failed fragmentation if (state == false) { meshes = null; pivots = null; subIds = new List <Dictionary <int, int> >(); return(false); } // Null check if (meshes == null) { Debug.Log("Null mesh", obj); meshes = null; pivots = null; subIds = new List <Dictionary <int, int> >(); return(false); } // Empty mesh fix if (EmptyMeshState(meshes) == true) { List <Mesh> meshList = new List <Mesh>(); List <Vector3> pivotList = new List <Vector3>(); List <Dictionary <int, int> > subIdsList = new List <Dictionary <int, int> >(); for (int i = 0; i < meshes.Length; i++) { if (meshes[i].vertexCount > 2) { meshList.Add(meshes[i]); pivotList.Add(pivots[i]); subIdsList.Add(subIds[i]); } } pivots = pivotList.ToArray(); meshes = meshList.ToArray(); subIds = subIdsList; Debug.Log("Empty Mesh", obj); } // Single mesh after mesh fix check if (meshes.Length <= 1) { Debug.Log("Mesh amount " + meshes.Length, obj); meshes = null; pivots = null; subIds = new List <Dictionary <int, int> >(); return(false); } // TODO set in library for (int i = 0; i < meshes.Length; i++) { meshes[i].RecalculateTangents(); } return(true); }