DEV Community

Takaaki Ichijo for head-high

Posted on

Generate DinoFracture Engine pre-fracture meshes without scene GUI operation

DinoFracture Engine, an asset for adding to Unity fracture effect easier to any meshes is very nice product.

https://assetstore.unity.com/packages/tools/physics/dinofracture-a-dynamic-fracture-library-26599

It can generate fractures runtime and editor. But if you try to make fracture in editor (not play mode), you have to make specific scene and attach PreFracturedGeometory component, and press "Create Fractures" button.

In my case there are lots of meshes have to make fractures, so I made a script for Dino Fracture, to generate fractures without the clicking works in the scene.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEditor;
using DinoFracture;
using DinoFracture.Editor;

public class PreFractureInAssetFolder: PreFracturedGeometryEditor
{
    private const string PrefabFolderPath = "Assets/{your prefab folder path}";
    private const string MeshFolderPath = "Assets/{your mesh folder path}";
    private const string ExportFolderName = "PreFractured";

    private const string InsideMaterialPath = "Assets/{your inside material path}.mat";
    private const string StandardFractureTemplatePath = "Assets/DinoFracture/Plugin/Prefabs/StandardFracturePiece.prefab";

    [MenuItem("Tools/DinoFracture/PreFractureInAssetFolder")]
    public static void PreFracture()
    {
        //filter paths you want generate fractures
        string[] allPath = AssetDatabase.GetAllAssetPaths();
        var prefabPathList = allPath.Where(p => p.Contains(PrefabFolderPath))
            .Where(p2 => !p2.Contains(ExportFolderName)).ToList();

        var objectCount = prefabPathList.Count;

        for (var index = 0; index < objectCount; index++)
        {
            var prefabPath = prefabPathList[index];

            var contentsRoot = PrefabUtility.LoadPrefabContents(prefabPath);

            if (contentsRoot.GetComponent<MeshFilter>() == false)
            {
                Debug.Log("contentsRoot " + contentsRoot.name +"doesnt has meshfilter");
                objectCount--;
                continue;
            }

            MakeFractureMeshes(contentsRoot, prefabPath, objectCount);
        }
    }

    private static void MakeFractureMeshes(GameObject contentsRoot, string prefabPath, int objectCount)
    {
        List<Tuple<Mesh, string>> meshAssetList = new List<Tuple<Mesh, string>>();
        List<Tuple<GameObject, string, string>> prefabAssetList = new List<Tuple<GameObject, string, string>>();

        var standardFractureTemplate = AssetDatabase.LoadAssetAtPath<GameObject>(StandardFractureTemplatePath);
        var insideMaterial = AssetDatabase.LoadAssetAtPath<Material>(InsideMaterialPath);


        var geom = contentsRoot.AddComponent<PreFracturedGeometry>();
        geom.FractureTemplate = standardFractureTemplate;
        geom.InsideMaterial = insideMaterial;

        //set parametors as you want
        geom.NumFracturePieces = 4;
        geom.NumIterations = 2;
        geom.NumGenerations = 2;
        geom.UVScale = FractureUVScale.EntireMesh;

        geom.GenerateFractureMeshes(
            (g) =>
            {
                g.GeneratedPieces.SetActive(true);

                //generate meshes
                string meshSaveFolderPath = Path.Combine(MeshFolderPath, ExportFolderName, geom.gameObject.name);

                for (int i = 0; i < geom.GeneratedPieces.transform.childCount; i++)
                {
                    var pieceTransform = geom.GeneratedPieces.transform.GetChild(i);

                    //in my case mesh collider is much CPU usage so replase to BoxCollider
                    var meshCollider = pieceTransform.GetComponent<MeshCollider>();
                    GameObject.DestroyImmediate(meshCollider);
                    var boxCollider = pieceTransform.gameObject.AddComponent<BoxCollider>();
                    boxCollider.enabled = false;

                    var rigidbody = pieceTransform.GetComponent<Rigidbody>();
                    rigidbody.isKinematic = true;

                    MeshFilter mf = geom.GeneratedPieces.transform.GetChild(i).GetComponent<MeshFilter>();
                    if (mf != null && mf.sharedMesh != null)
                    {
                        meshAssetList.Add(new Tuple<Mesh, string>(mf.sharedMesh, meshSaveFolderPath));
                    }
                }

                //save prefabs
                var prefabSaveFolderPath = Path.Combine(Path.GetDirectoryName(prefabPath), ExportFolderName);

                prefabAssetList.Add(new Tuple<GameObject, string, string>(g.GeneratedPieces, prefabSaveFolderPath,
                    contentsRoot.name + ".prefab"));

                if (prefabAssetList.Count >= objectCount)
                {
                    SaveProcess(meshAssetList, prefabAssetList);
                }
            });
    }

    private static void SaveProcess(List<Tuple<Mesh, string>> meshAssetList, List<Tuple<GameObject, string, string>> prefabAssetList)
    {
        Debug.Log("save process");

        //stop Asset import Postprocess
        AssetDatabase.StartAssetEditing();

        //save mesh
        foreach (var meshAsset in meshAssetList)
        {
            DirectoryInfo dir = new DirectoryInfo(meshAsset.Item2);
            if (!dir.Exists)
            {
                dir.Create();
            }
            else
            {
                // delete old meshes
                foreach (FileInfo file in dir.GetFiles())
                {
                    file.Delete(); 
                }
            }

            string assetPath = Path.Combine(meshAsset.Item2, String.Format("{0}.asset", Guid.NewGuid().ToString("B")));
            AssetDatabase.CreateAsset(meshAsset.Item1, assetPath);
        }

        //save prefab
        foreach (var prefabAsset in prefabAssetList)
        {
            DirectoryInfo dir = new DirectoryInfo(prefabAsset.Item2);
            if (!dir.Exists)
            {
                dir.Create();
            }

            PrefabUtility.SaveAsPrefabAsset(prefabAsset.Item1, Path.Combine(prefabAsset.Item2, prefabAsset.Item3 ));

            GameObject.DestroyImmediate(prefabAsset.Item1);
        }

        meshAssetList.Clear();
        prefabAssetList.Clear();

        AssetDatabase.StopAssetEditing();

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

}


Enter fullscreen mode Exit fullscreen mode

Top comments (0)