在项目中有时会遇到批量生成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 = ;
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()))
{
foreach (GameObject m in selectedGameObjects)
{
CreateObj(m);
}
AssetDatabase.Refresh();
}
if (GUILayout.Button("生成当前选中物体的Prefab", GUILayout.MinHeight()))
{
if (selectedGameObjects.Length <= )
{
//打开一个通知栏
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 != )
{
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 != )
{
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 > )
{
for (int i = ; 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 > )
{
MeshFilter[] prefabmeshfilters = tempPrefab.GetComponentsInChildren<MeshFilter>();
for (int i = ; 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

 using UnityEngine;
using System.Collections;
using System.IO;
using System.Text; public class ObjExporter
{ public static string MeshToString(MeshFilter mf)
{
Mesh m = mf.sharedMesh;
// Material[] mats = mf.GetComponent<MeshRenderer>().sharedMaterials; StringBuilder sb = new StringBuilder(); sb.Append("g ").Append(mf.name).Append("\n");
for(int i=;i<m.vertices.Length;i++)
sb.Append(string.Format("v {0} {1} {2}\n", -m.vertices[i].x, m.vertices[i].y, m.vertices[i].z));
sb.Append("\n");
for (int i = ; i < m.normals.Length; i++)
sb.Append(string.Format("vn {0} {1} {2}\n", -m.normals[i].x, m.normals[i].y, m.normals[i].z));
sb.Append("\n");
for (int i = ; i < m.uv.Length; i++)
sb.Append(string.Format("vt {0} {1}\n",m.uv[i].x, m.uv[i].y)); for (int material = ; material < m.subMeshCount; material++)
{
sb.Append("\n"); int[] triangles = m.GetTriangles(material);
for (int i = ; i < triangles.Length; i += )
{
//Because we inverted the x-component, we also needed to alter the triangle winding.
sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
triangles[i] + , triangles[i + ] + , triangles[i + ] + ));
}
}
return sb.ToString();
} public static void MeshToFile(MeshFilter mf, string filename)
{
using (StreamWriter sw = new StreamWriter(filename))
{
sw.Write(MeshToString(mf));
}
}
}

ObjExporter

Unity批量生成Prefab的更多相关文章

  1. unity工具IGamesTools之批量生成帧动画

    unity工具IGamesTools批量生成帧动画,可批量的将指定文件夹下的帧动画图片自动生成对应的资源文件(Animation,AnimationController,Prefabs) unity工 ...

  2. 将表里的数据批量生成INSERT语句的存储过程 增强版

    将表里的数据批量生成INSERT语句的存储过程 增强版 有时候,我们需要将某个表里的数据全部或者根据查询条件导出来,迁移到另一个相同结构的库中 目前SQL Server里面是没有相关的工具根据查询条件 ...

  3. 脚本工具(获取某个文件夹下的所有图片属性批量生成css样式)

    问题描述: 由于有一次工作原因,就是将某个文件夹下的所有图片,通过CSS描述他们的属性,用的时候就可以直接引用.但是我觉得那个文件夹下的图片太多,而且CSS文件的格式又有一定的规律,所有想通过脚本来生 ...

  4. 代码批量生成WORD的遇到的问题及解决

    好久没搞工具了,最近因为处理大规模公文处理单文档,自己写了个批量处理WORD的程序:在调试过程中,主要遇到两个问题 第一个是WORD的模板 数据很多,但是WORD模板只需要一个,将数据替换WORD里标 ...

  5. FluentData-新型轻量级ORM 利用T4模板 批量生成多文件 实体和业务逻辑 代码

    FluentData,它是一个轻量级框架,关注性能和易用性. 下载地址:FlunenData.Model 利用T4模板,[MultipleOutputHelper.ttinclude]批量生成多文件 ...

  6. 使用html2canvas实现批量生成条形码

    /*前台代码*/ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Generat ...

  7. 用ticons指令结合ImageMagickDisplay工具批量生成Android适应图片

    用ticons指令结合ImageMagickDisplay工具批量生成Android适应图片 ticons的用法可以百度 这里记录下具体的编译方法 在安装了ticons和ImageMagickDisp ...

  8. PHP 批量生成静态文件目录代码

    <?php /** * @author:jiangzaixing 20160314 * 获取静态文件方法 */ class StaticFile { const MAP_FILE_NAME = ...

  9. 将表里的数据批量生成INSERT语句的存储过程 继续增强版

    文章继续 桦仔兄的文章 将表里的数据批量生成INSERT语句的存储过程 增强版 继续增强... 本来打算将该内容回复于桦仔兄的文章的下面的,但是不知为何博客园就是不让提交!.... 所以在这里贴出来吧 ...

随机推荐

  1. Tiny4412在Ubuntu下给MiniTools添加快捷方式

    解压MiniTools-Linux-20140317.tgz root@ubuntu:~/tiny4412/MiniTools-# ls -l total -rw-r--r-- root root M ...

  2. 命令行解析函数:getopt/getopt_long

    参考: http://blog.csdn.net/zhangyang0402/article/details/5671410 http://www.cnblogs.com/gnuhpc/archive ...

  3. Unitity 常用工具类

    ylbtech-Unitity_C#: Unitity 常用代码 1.A,效果图返回顶部   1.B,源代码返回顶部 1,日期字符串 using System; using System.Xml; / ...

  4. 解决The prefix 'context' for element 'context:component-scan' is not bound

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w ...

  5. zabbix主机自动发现和监控

    在主机较多的时候,配置主机自动发现并加入监控可以代替手动的添加主机,减轻工作量,自动发现由服务端主动发起,Zabbix Server开启发现进程,定时扫描局域网中IP服务器.设备.可以根据需要,在对主 ...

  6. [Functional Programming] Read and Transform Values from a State ADT’s State (get)

    Many times we need to access and transform state, either in part or in full, to be used when calcula ...

  7. [Functional Programming] Compose Simple State ADT Transitions into One Complex Transaction

    State is a lazy datatype and as such we can combine many simple transitions into one very complex on ...

  8. Sending SMS And Dialing Numbers without User Consent(Context is not needed)

    Sending SMS And Dialing Numbers without User Consent Sending SMS does not require context or user in ...

  9. Android 创建Listener监听器形式选择:匿名内部类?外部类?

    说到监听器,第一感觉就是直接写作匿名内部类来用,可是依据单一职责原则,好像又不应该作为匿名内部类来写(由于监听中有时要写较多的逻辑代码),所曾经段时间把有共性的listener单独创建放在glut.l ...

  10. UVA - 434 Matty&#39;s Blocks

    题意:给你正视和側视图,求最多多少个,最少多少个 思路:贪心的思想.求最少的时候:由于能够想象着移动,尽量让两个视图的重叠.所以我们统计每一个视图不同高度的个数.然后计算.至于的话.就是每次拿正视图的 ...