Генерация предварительных сеток разрушения DinoFracture Engine без работы с графическим интерфейсом сцены

DinoFracture Engine, актив для добавления в Unity эффекта разлома, облегчающего создание любых сеток, является очень хорошим продуктом.

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

Он может генерировать изломы во время выполнения и в редакторе. Но если вы пытаетесь сделать излом в редакторе (не в режиме игры), вам нужно сделать определенную сцену и прикрепить компонент PreFracturedGeometory, и нажать кнопку «Create Fractures».

В моем случае есть много сеток, на которых нужно сделать изломы, поэтому я сделал скрипт для Dino Fracture, чтобы генерировать изломы без кликов в сцене.

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();
    }

}


Вход в полноэкранный режим Выход из полноэкранного режима

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *