Unity批量生成Prefab

在项目中有时会遇到批量生成Prefab的需求。于是写了一个编辑器,用来实现此功能。

在Hierarchy面板中选中多个GameObject,点击生成Prefab即可。

如果所选物体中包含自定义Mesh,需要先在指定目录生成Obj,再将Obj包含的网格赋值给新生成的Prefab。

编辑器脚本如下:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;
/// <summary>
/// CreatePrefabs类为批量创建Prefab的窗口类,选择Hierarchy窗口的物体,点击创建Prefab即可在指定目录生成Prefab
/// 如果所选物体含有动态创建的Mesh,必须先在指定目录先生成OBJ文件
/// </summary>
public class CreatePrefabs : EditorWindow
{
    [MenuItem("AssetsManager/批量生成Prefab")]

    static void AddWindow()
    {
        //创建窗口
        CreatePrefabs window = (CreatePrefabs)EditorWindow.GetWindow(typeof(CreatePrefabs), false, "批量生成Prefab");
        window.Show();

    }

    //输入文字的内容
    private string PrefabPath = "Assets/Resources/";
    private string ObjPath = @"Assets/Obj/";
    GameObject[] selectedGameObjects;



    [InitializeOnLoadMethod]
    public void Awake()
    {
        OnSelectionChange();
    }
    void OnGUI()
    {
        GUIStyle text_style = new GUIStyle();
        text_style.fontSize = 15;
        text_style.alignment = TextAnchor.MiddleCenter;

        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Prefab导出路径:");
        PrefabPath = EditorGUILayout.TextField(PrefabPath);
        if (GUILayout.Button("浏览"))
        { EditorApplication.delayCall += OpenPrefabFolder; }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.BeginHorizontal();

        GUILayout.Label("    Obj导出路径:");
        ObjPath = EditorGUILayout.TextField(ObjPath);
        if (GUILayout.Button("浏览"))
        { EditorApplication.delayCall += OpenObjFolder; }
        EditorGUILayout.EndHorizontal();

        GUILayout.Label("当前选中了" + selectedGameObjects.Length + "个物体", text_style);
        if (GUILayout.Button("如果包含动态创建的Mesh,请先点击生成Obj", GUILayout.MinHeight(20)))
        {
            foreach (GameObject m in selectedGameObjects)
            {
                CreateObj(m);
            }
            AssetDatabase.Refresh();
        }
            if (GUILayout.Button("生成当前选中物体的Prefab", GUILayout.MinHeight(20)))
        {
            if (selectedGameObjects.Length <= 0)
            {
                //打开一个通知栏  
                this.ShowNotification(new GUIContent("未选择所要导出的物体"));
                return;
            }
            if (!Directory.Exists(PrefabPath))
            {
                Directory.CreateDirectory(PrefabPath);
            }
            foreach (GameObject m in selectedGameObjects)
            {
                CreatePrefab(m, m.name);
            }
            AssetDatabase.Refresh();
        }
    }

    void OpenPrefabFolder()
    {
        string path = EditorUtility.OpenFolderPanel("选择要导出的路径", "", "");
        if (!path.Contains(Application.dataPath))
        {
            Debug.LogError("导出路径应在当前工程目录下");
            return;
        }
        if (path.Length != 0)
        {
            int firstindex = path.IndexOf("Assets");
            PrefabPath = path.Substring(firstindex) + "/";
            EditorUtility.FocusProjectWindow();
        }
    }

    void OpenObjFolder()
    {
        string path = EditorUtility.OpenFolderPanel("选择要导出的路径", "", "");
        if (!path.Contains(Application.dataPath))
        {
            Debug.LogError("导出路径应在当前工程目录下");
            return;
        }
        if (path.Length != 0)
        {
            int firstindex = path.IndexOf("Assets");
            ObjPath = path.Substring(firstindex) + "/";
            EditorUtility.FocusProjectWindow();
        }
    }

    void CreateObj(GameObject go)
    {
        if (!Directory.Exists(ObjPath))
        {
            Directory.CreateDirectory(ObjPath);
        }
        MeshFilter[] meshfilters = go.GetComponentsInChildren<MeshFilter>();
        if (meshfilters.Length > 0)
        {
            for (int i = 0; i < meshfilters.Length; i++)
            {
                ObjExporter.MeshToFile(meshfilters[i], ObjPath + meshfilters[i].gameObject.name + ".obj");

            }
        }
    }
    /// <summary>
    /// 此函数用来根据某物体创建指定名字的Prefab
    /// </summary>
    /// <param name="go">选定的某物体</param>
    /// <param name="name">物体名</param>
    /// <returns>void</returns>
    void CreatePrefab(GameObject go, string name)
    {  
        //先创建一个空的预制物体
        //预制物体保存在工程中路径,可以修改("Assets/" + name + ".prefab");
        GameObject tempPrefab = PrefabUtility.CreatePrefab(PrefabPath + name + ".prefab", go);

        MeshFilter []meshfilters= go.GetComponentsInChildren<MeshFilter>();
        if (meshfilters.Length > 0)
        {
            MeshFilter[] prefabmeshfilters = tempPrefab.GetComponentsInChildren<MeshFilter>();
            for (int i = 0; i < meshfilters.Length; i++)
            {
               Mesh m_mesh = AssetDatabase.LoadAssetAtPath<Mesh>(ObjPath + meshfilters[i].gameObject.name + ".obj");
                prefabmeshfilters[i].sharedMesh = m_mesh;
            }
        }
        //返回创建后的预制物体
    }

    void OnInspectorUpdate()
    {
        //这里开启窗口的重绘,不然窗口信息不会刷新
        this.Repaint();
    }

    void OnSelectionChange()
    {
        //当窗口出去开启状态,并且在Hierarchy视图中选择某游戏对象时调用
        selectedGameObjects = Selection.gameObjects;

    }
}
CreatePrefabs
 1 using UnityEngine;
 2 using System.Collections;
 3 using System.IO;
 4 using System.Text;
 5 
 6 public class ObjExporter
 7 {
 8 
 9     public static string MeshToString(MeshFilter mf)
10     {
11         Mesh m = mf.sharedMesh;
12         //  Material[] mats = mf.GetComponent<MeshRenderer>().sharedMaterials;
13 
14         StringBuilder sb = new StringBuilder();
15 
16         sb.Append("g ").Append(mf.name).Append("\n");
17         for(int i=0;i<m.vertices.Length;i++)
18             sb.Append(string.Format("v {0} {1} {2}\n", -m.vertices[i].x, m.vertices[i].y, m.vertices[i].z));
19         sb.Append("\n");
20         for (int i = 0; i < m.normals.Length; i++)
21             sb.Append(string.Format("vn {0} {1} {2}\n", -m.normals[i].x, m.normals[i].y, m.normals[i].z));
22         sb.Append("\n");
23         for (int i = 0; i < m.uv.Length; i++)
24             sb.Append(string.Format("vt {0} {1}\n",m.uv[i].x, m.uv[i].y));
25 
26         for (int material = 0; material < m.subMeshCount; material++)
27         {
28             sb.Append("\n");
29 
30             int[] triangles = m.GetTriangles(material);
31             for (int i = 0; i < triangles.Length; i += 3)
32             {
33                 //Because we inverted the x-component, we also needed to alter the triangle winding.
34                 sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
35                     triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1));
36             }
37         }
38         return sb.ToString();
39     }
40 
41     public static void MeshToFile(MeshFilter mf, string filename)
42 {
43     using (StreamWriter sw = new StreamWriter(filename))
44     {
45         sw.Write(MeshToString(mf));
46     }
47 }
48 }
ObjExporter

 

转载于:https://www.cnblogs.com/luxishi/p/6638358.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值