在项目中有时会遇到批量生成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. Word中如何让两个图片垂直居中对齐

    如图,两个图片都剧终了,大小也一致,但是发现没有对齐,那是因为需要设置(矩阵框住的)缩进,让两个在一起,上下对齐.

  2. hdu4099 Revenge of Fibonacci

    题意:给定fibonacci数列,输入前缀,求出下标.题目中fibonacci数量达到100000,而题目输入的前缀顶多为40位数字,这说明我们只需要精确计算fibinacci数前40位即可.查询时使 ...

  3. yarn 查看任务信息

    一.在命令行使用命令查看 (1)查看日志:yarn logs -applicationId application_1469094096026_26612 (2)查看状态:yarn applicait ...

  4. How to initialize th rasp berry PI

    WHAT YOU WILL NEED REQUIRED SD Card We recommend an 8GB class 4 SD card – ideally preinstalled with ...

  5. asp.net使用母版页以及Jquery和prototype要注意的问题

    在母版页中引用了js,css或者其他外部文件之后,子页面就不必再重新引用,否则可能出错 prototype.js和jquery.js冲突的解决方案: <script type="tex ...

  6. UVa 10192 - Vacation &amp; UVa 10066 The Twin Towers ( LCS 最长公共子串)

    链接:UVa 10192 题意:给定两个字符串.求最长公共子串的长度 思路:这个是最长公共子串的直接应用 #include<stdio.h> #include<string.h> ...

  7. 在vs2010中编译log4cxx-0.10.0具体方法(从下载、编译、解决错误具体介绍)

    一. 简单介绍 log4cxx是Java社区著名的log4j的c++移植版.用于为C++程序提供日志功能,以便开发人员对目标程序进行调试和审计,log4cxx是apache软件基金会的开源项目,基于A ...

  8. XP如何在桌面新建宽带连接的快捷方式

    1 打开控制面板,点击网络和Internet连接 2 如果存在宽带连接选项. 则点击左侧的网上邻居,然后点击查看网络连接 右击宽带连接,点击创建快捷方式,放到桌面,改一下快捷方式的名字即可.   3 ...

  9. MySQL架构组成之物理文件组成

    一.日志文件 1.错误日志:Error Log   内容:MyQL Server 执行过程中全部较为严重的警告和错误信息,以及MySQL Server 每次启动和关闭的具体信息. 路径:默认存放位置在 ...

  10. Linux网络编程中tcp_server和tcp_client函数的封装

    本文的主要目的是将server套接字和client套接字的获取,做一个简易的封装,使用C语言完成.   tcp_server   服务器端fd的获取主要分为以下几步: 1.创建socket,这一步仅仅 ...