zoukankan      html  css  js  c++  java
  • 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("
    ");
    17         for(int i=0;i<m.vertices.Length;i++)
    18             sb.Append(string.Format("v {0} {1} {2}
    ", -m.vertices[i].x, m.vertices[i].y, m.vertices[i].z));
    19         sb.Append("
    ");
    20         for (int i = 0; i < m.normals.Length; i++)
    21             sb.Append(string.Format("vn {0} {1} {2}
    ", -m.normals[i].x, m.normals[i].y, m.normals[i].z));
    22         sb.Append("
    ");
    23         for (int i = 0; i < m.uv.Length; i++)
    24             sb.Append(string.Format("vt {0} {1}
    ",m.uv[i].x, m.uv[i].y));
    25 
    26         for (int material = 0; material < m.subMeshCount; material++)
    27         {
    28             sb.Append("
    ");
    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}
    ",
    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
  • 相关阅读:
    Web Services Software Factory tutorial (3 of 5)
    [转]张孟苏考上的不是大学
    试用期要盯紧你的“四金”
    Asp.net 随记 Part2 (31 49)
    如何查找当前页面元素---DataList
    Web Services Software Factory tutorial (2 of 5)
    SharePoint:扩展DVWP 第19部分:可维护的下拉框 填充关系列表(下)
    SharePoint:扩展DVWP 第14部分:用jQuery编写PreSaveAction()实务
    SharePoint:扩展DVWP 第16部分:为实现可维护的下拉框准备数据
    SharePoint:扩展DVWP 第5部分:在保存操作提交前做些事情——PreSaveAction()
  • 原文地址:https://www.cnblogs.com/luxishi/p/6638358.html
Copyright © 2011-2022 走看看