// Copy from public void CopyFrom(RFSurface interior) { innerMaterial = interior.innerMaterial; mappingScale = interior.mappingScale; needNewMat = interior.needNewMat; outerMaterial = interior.outerMaterial; }
/// ///////////////////////////////////////////////////////// /// Rigid /// ///////////////////////////////////////////////////////// // Prepare rigid component to cache fragment meshes public static bool InputMesh(RayfireRigid scr) { // Set up shatter if (SetRigidShatter(scr) == false) { return(false); } // Get innerSubId scr.meshDemolition.innerSubId = RFSurface.SetInnerSubId(scr); // Set fragmentation properties SetFragmentProperties(scr.meshDemolition.rfShatter, scr.meshDemolition.scrShatter, scr); return(true); }
/// ///////////////////////////////////////////////////////// /// 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); }
// Create slices by mesh and pivots array public static List <RayfireRigid> CreateSlices(RayfireRigid scr) { // Fragments list List <RayfireRigid> scrArray = new List <RayfireRigid>(); // Stop if has no any meshes if (scr.meshes == null) { return(scrArray); } // Create RayFire manager if not created RayfireMan.RayFireManInit(); // Create root object and parent RFLimitations.CreateRoot(scr); // Vars int baseLayer = scr.meshDemolition.GetLayer(scr); string baseTag = scr.gameObject.tag; string baseName = scr.gameObject.name + fragmentStr; // Get original mats Material[] mats = scr.skinnedMeshRend != null ? scr.skinnedMeshRend.sharedMaterials : scr.meshRenderer.sharedMaterials; // Create fragment objects for (int i = 0; i < scr.meshes.Length; ++i) { // Get object from pool or create RayfireRigid rfScr = RayfireMan.inst == null ? RFPoolingFragment.CreateRigidInstance() : RayfireMan.inst.fragments.GetPoolObject(RayfireMan.inst.transForm); // Setup rfScr.transform.position = scr.transForm.position + scr.pivots[i]; rfScr.transform.parent = scr.rootChild; rfScr.name = baseName + i; rfScr.gameObject.tag = baseTag; rfScr.gameObject.layer = baseLayer; rfScr.meshFilter.sharedMesh = scr.meshes[i]; rfScr.rootParent = scr.rootChild; // Copy properties from parent to fragment node scr.CopyPropertiesTo(rfScr); // Copy particles RFParticles.CopyParticles(scr, rfScr); // Set collider RFPhysic.SetFragmentMeshCollider(rfScr, scr.meshes[i]); // Shadow casting if (RayfireMan.inst.advancedDemolitionProperties.sizeThreshold > 0 && RayfireMan.inst.advancedDemolitionProperties.sizeThreshold > scr.meshes[i].bounds.size.magnitude) { rfScr.meshRenderer.shadowCastingMode = ShadowCastingMode.Off; } // Turn on rfScr.gameObject.SetActive(true); // Set multymaterial RFSurface.SetMaterial(scr.subIds, mats, scr.materials, rfScr.meshRenderer, i, scr.meshes.Length); // Update depth level and amount rfScr.limitations.currentDepth = scr.limitations.currentDepth + 1; //rfScr.meshDemolition.amount = (int)(rfScr.meshDemolition.amount * rfScr.meshDemolition.depthFade); //if (rfScr.meshDemolition.amount < 2) // rfScr.meshDemolition.amount = 2; // Add in array scrArray.Add(rfScr); } // Empty lists scr.DeleteCache(); return(scrArray); }
// Create fragments by mesh and pivots array public static List <RayfireRigid> CreateFragments(RayfireRigid scr) { // Fragments list List <RayfireRigid> scrArray = new List <RayfireRigid>(); // Stop if has no any meshes if (scr.meshes == null) { return(scrArray); } // Create RayFire manager if not created RayfireMan.RayFireManInit(); // Create root object and parent RFLimitations.CreateRoot(scr); // Vars int baseLayer = scr.meshDemolition.GetLayer(scr); string baseTag = scr.gameObject.tag; string baseName = scr.gameObject.name + fragmentStr; // Save original rotation // Quaternion originalRotation = rootChild.transform.rotation; // Set rotation to precache rotation if (scr.demolitionType == DemolitionType.AwakePrecache) { scr.rootChild.transform.rotation = scr.cacheRotation; } // Get original mats Material[] mats = scr.skinnedMeshRend != null ? scr.skinnedMeshRend.sharedMaterials : scr.meshRenderer.sharedMaterials; // Create fragment objects for (int i = 0; i < scr.meshes.Length; ++i) { // Get object from pool or create RayfireRigid rfScr = RayfireMan.inst == null ? RFPoolingFragment.CreateRigidInstance() : RayfireMan.inst.fragments.GetPoolObject(RayfireMan.inst.transForm); // Setup rfScr.transform.position = scr.transForm.position + scr.pivots[i]; rfScr.transform.parent = scr.rootChild; rfScr.name = baseName + i; rfScr.gameObject.tag = baseTag; rfScr.gameObject.layer = baseLayer; rfScr.meshFilter.sharedMesh = scr.meshes[i]; rfScr.rootParent = scr.rootChild; // Copy properties from parent to fragment node scr.CopyPropertiesTo(rfScr); // Copy particles RFParticles.CopyParticles(scr, rfScr); // Set collider RFPhysic.SetFragmentMeshCollider(rfScr, scr.meshes[i]); // Shadow casting if (RayfireMan.inst.advancedDemolitionProperties.sizeThreshold > 0 && RayfireMan.inst.advancedDemolitionProperties.sizeThreshold > scr.meshes[i].bounds.size.magnitude) { rfScr.meshRenderer.shadowCastingMode = ShadowCastingMode.Off; } // Turn on rfScr.gameObject.SetActive(true); // Set multymaterial RFSurface.SetMaterial(scr.subIds, mats, scr.materials, rfScr.meshRenderer, i, scr.meshes.Length); // Update depth level and amount rfScr.limitations.currentDepth = scr.limitations.currentDepth + 1; rfScr.meshDemolition.amount = (int)(rfScr.meshDemolition.amount * rfScr.meshDemolition.depthFade); if (rfScr.meshDemolition.amount < 3) { rfScr.meshDemolition.amount = 3; } // Add in array scrArray.Add(rfScr); // Debug.Log (rfScr.rootParent); } // Fix transform for precached fragments if (scr.demolitionType == DemolitionType.AwakePrecache) { scr.rootChild.rotation = scr.transForm.rotation; } // Fix runtime caching rotation difference. Get rotation difference and add to root if (scr.demolitionType == DemolitionType.Runtime && scr.meshDemolition.runtimeCaching.type != CachingType.Disable) { Quaternion cacheRotationDif = scr.transForm.rotation * Quaternion.Inverse(scr.meshDemolition.cacheRotationStart); scr.rootChild.rotation = cacheRotationDif * scr.rootChild.rotation; } return(scrArray); }
// Create fragments by mesh and pivots array private List <GameObject> CreateFragments(GameObject lastRoot = null) { // No mesh were cached if (meshes == null) { return(null); } // Clear array for new fragments GameObject[] fragArray = new GameObject[meshes.Length]; // Vars string goName = gameObject.name; string baseName = goName + "_sh_"; // Create root object GameObject root = lastRoot; if (lastRoot == null) { root = new GameObject(goName + "_root"); root.transform.position = transForm.position; root.transform.rotation = transForm.rotation; root.transform.parent = transForm.parent; rootChildList.Add(root.transform); } // KEVINJ: when operating on project assets, causes the new root object to be in the scene rather than a child of the prefab // Use https://docs.unity3d.com/ScriptReference/PrefabUtility.LoadPrefabContents.html in order to be able to set the parent // PrefabMode prefabMode = GetPrefabMode(gameObject); // if ( prefabMode != PrefabMode.Scene) // { // // PREFAB, AVOID CREATING INTO SCENE // root.transform.parent = transForm; // } // else // { // // ORIGINAL BEHAVIOR // root.transform.parent = transForm.parent; // } // Create instance for fragments GameObject fragInstance; if (advanced.copyComponents == true) { fragInstance = Instantiate(gameObject); fragInstance.transform.rotation = Quaternion.identity; fragInstance.transform.localScale = Vector3.one; // Destroy shatter DestroyImmediate(fragInstance.GetComponent <RayfireShatter>()); } else { fragInstance = new GameObject(); fragInstance.AddComponent <MeshFilter>(); fragInstance.AddComponent <MeshRenderer>(); } // Get original mats Material[] mats = skinnedMeshRend != null ? skinnedMeshRend.sharedMaterials : meshRenderer.sharedMaterials; // Create fragment objects for (int i = 0; i < meshes.Length; ++i) { // Rescale mesh if (rescaleFix != 1f) { RFFragment.RescaleMesh(meshes[i], rescaleFix); } // Instantiate. IMPORTANT do not parent when Instantiate GameObject fragGo = Instantiate(fragInstance); fragGo.transform.localScale = Vector3.one; // Set multymaterial MeshRenderer targetRend = fragGo.GetComponent <MeshRenderer>(); RFSurface.SetMaterial(origSubMeshIdsRF, mats, material, targetRend, i, meshes.Length); // Set fragment object name and tm fragGo.name = baseName + (i + 1); fragGo.transform.position = root.transform.position + (pivots[i] / rescaleFix); fragGo.transform.parent = root.transform; // Set fragment mesh MeshFilter mf = fragGo.GetComponent <MeshFilter>(); /*// KevinJ: #if UNITY_EDITOR * // Up to the caller to use AssetDatabase.RemoveObjectFromAsset to remove meshes from any prior calls to CreateFragments() * if (prefabMode == PrefabMode.Asset) * { * AssetDatabase.AddObjectToAsset(meshes[i], gameObject.scene.path); * } * else if (prefabMode == PrefabMode.PrefabEditingMode) * { * //string assetPath = UnityEditor.Experimental.GetPrefabStage(gameObject).prefabAssetPath; * //AssetDatabase.AddObjectToAsset(meshes[i], assetPath); * } #endif*/ mf.sharedMesh = meshes[i]; mf.sharedMesh.name = fragGo.name; // Set mesh collider MeshCollider mc = fragGo.GetComponent <MeshCollider>(); if (mc != null) { mc.sharedMesh = meshes[i]; } // Add in array fragArray[i] = fragGo; } // Destroy instance DestroyImmediate(fragInstance); // Empty lists meshes = null; pivots = null; origSubMeshIdsRF = new List <RFDictionary>(); return(fragArray.ToList()); }
/// ///////////////////////////////////////////////////////// /// Methods /// ///////////////////////////////////////////////////////// // Set material to fragment by it's interior properties and parent material public static void SetMaterial(List <RFDictionary> origSubMeshIdsRF, Material[] sharedMaterials, RFSurface interior, MeshRenderer targetRend, int i, int amount) { if (origSubMeshIdsRF != null && origSubMeshIdsRF.Count == amount) { Material[] newMaterials = new Material[origSubMeshIdsRF[i].values.Count]; // TODO implement in fragmentation to avoid calcs if (interior.outerMaterial != null) { for (int j = 0; j < newMaterials.Length; j++) { newMaterials[j] = interior.outerMaterial; } } else { for (int j = 0; j < origSubMeshIdsRF[i].values.Count; j++) { int matId = origSubMeshIdsRF[i].values[j]; if (matId < sharedMaterials.Length) { newMaterials[j] = sharedMaterials[matId]; } else { newMaterials[j] = interior.innerMaterial; } } } targetRend.sharedMaterials = newMaterials; } }
/// ///////////////////////////////////////////////////////// /// 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; } } }
// Create slices by mesh and pivots array List <RayfireRigid> CreateSlices() { // Create root object RFLimitations.CreateRoot(this); // Clear array for new fragments List <RayfireRigid> scrArray = new List <RayfireRigid>(); // Vars int baseLayer = meshDemolition.GetLayer(this); string baseTag = gameObject.tag; string baseName = gameObject.name + "_sl_"; // Create fragment objects for (int i = 0; i < meshes.Length; ++i) { // Get object from pool or create RayfireRigid rfScr = RayfireMan.inst.GetPoolObject(); // Setup rfScr.transform.position = transForm.position + pivots[i]; rfScr.transform.parent = rootChild; rfScr.name = baseName + i; rfScr.gameObject.tag = baseTag; rfScr.gameObject.layer = baseLayer; rfScr.meshFilter.sharedMesh = meshes[i]; rfScr.meshFilter.sharedMesh.name = baseName + i; rfScr.rootParent = rootChild; // Copy properties from parent to fragment node CopyPropertiesTo(rfScr); // Copy particles RFParticles.CopyParticles(this, rfScr); // Shadow casting if (RayfireMan.inst.advancedDemolitionProperties.sizeThreshold > 0 && RayfireMan.inst.advancedDemolitionProperties.sizeThreshold > meshes[i].bounds.size.magnitude) { rfScr.meshRenderer.shadowCastingMode = ShadowCastingMode.Off; } // Turn on rfScr.gameObject.SetActive(true); // Set multymaterial RFSurface.SetMaterial(subIds, meshRenderer.sharedMaterials, materials, rfScr.meshRenderer, i, meshes.Length); // Inherit same current depth level rfScr.limitations.currentDepth = limitations.currentDepth + 1; // Set collider mesh MeshCollider mc = rfScr.physics.meshCollider as MeshCollider; if (mc != null) { mc.sharedMesh = meshes[i]; mc.name = meshes[i].name; } // Add in array scrArray.Add(rfScr); } // Empty lists DeleteCache(); return(scrArray); }