Unity Fbx转Prefab工具

article/2025/9/13 9:43:22

1.功能描述

        a.可将fbx直接导出prefab。

        b.同时为prefab预先按需挂载脚本文件。

        c.同时为挂载的脚本设置参数,绑定资源等。

        d.批量化处理,递归遍历算法,高效可扩展。

 2.实现方式

 a.Editor类

using Lean.Touch;
using Main;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public  enum SystemBody
{[Description("Bones")]guge=1,[Description("Muscle")]jirou,[Description("Vein")]jingmai,[Description("Aetery")]dongmai,[Description("Bones")]neifenmi=5,[Description("Bones")]shenjing,[Description("Skin")]pifu,[Description("Lymph")]lingba,[Description("GenitourinrySelectable")]miniaoshengzhi,[Description("Respiratory")]xiaohua=10,[Description("Joint")]guanjie,[Description("Respiratory")]huxi,
}
public static class EnumExpand
{public static T ToEnum<T>(this string str){return (T)Enum.Parse(typeof(T), str);}
}public class Fbx2Prefab : Editor
{[MenuItem("Assets/Fbx2Prefab/Create GuGe Prefab")]public static void CreateGuGePre(){GameObject obj = Selection.gameObjects[0];GameObject pre = MonoBehaviour.Instantiate(obj);List<GameObject> prelist = new List<GameObject>();for (int i = 0; i < pre.transform.childCount; i++){prelist.Add(pre.transform.GetChild(i).gameObject);}GameObjectTree tree = MonoBehaviour.FindObjectOfType<GameObjectTree>();tree.scriptObjs.Clear();tree.rootTransform = pre.transform;tree.scriptObjs.Add(MonoScript.FromScriptableObject(CreateInstance(typeof(BonesSelectable))));tree.scriptObjs.Add(MonoScript.FromScriptableObject(CreateInstance(typeof(LeanSelectableByFinger))));tree.AddMonoScript();var mts = Resources.FindObjectsOfTypeAll<Material>();//绑定材质球tree.SetCommponentValue<BonesSelectable>(mts.ToList().Find(p=>p.name== SystemBody.guge.ToString()));  foreach (var item in prelist){PrefabUtility.SaveAsPrefabAsset(item, $"Assets/Prefab/{item.name}.prefab");}DestroyImmediate(pre);}[MenuItem("Assets/Fbx2Prefab/Create Jirou Prefab")]public static void CreateJirouPre(){SystemBody body = SystemBody.jirou;CreateNormalPre(body);}[MenuItem("Assets/Fbx2Prefab/Create Normal Prefab")]public static void CreateNormalPre(){SystemBody body = SystemBody.jirou;string n = Selection.gameObjects[0]?.name;if (string.IsNullOrEmpty(n)){Debug.LogError("未选中");}else{body = n.ToLower().ToEnum<SystemBody>();}CreateNormalPre(body);}public static void CreateNormalPre(SystemBody body){GameObject obj = Selection.gameObjects[0];GameObject pre = MonoBehaviour.Instantiate(obj);List<GameObject> prelist = new List<GameObject>();for (int i = 0; i < pre.transform.childCount; i++){prelist.Add(pre.transform.GetChild(i).gameObject);}GameObjectTree tree = MonoBehaviour.FindObjectOfType<GameObjectTree>();tree.scriptObjs.Clear();tree.rootTransform = pre.transform;Type t = Assembly.Load("Unity.ModelView").GetType($"Main.{body.GetDescName()}Selectable");tree.scriptObjs.Add(MonoScript.FromScriptableObject(CreateInstance(t)));tree.scriptObjs.Add(MonoScript.FromScriptableObject(CreateInstance(typeof(LeanSelectableByFinger))));tree.AddMonoScript();var mts = Resources.FindObjectsOfTypeAll<Material>();//绑定材质球tree.SetTypeValue(t, mts.ToList().Find(p => p.name == body.ToString()));foreach (var item in prelist){PrefabUtility.SaveAsPrefabAsset(item, $"Assets/Prefab/{item.name}.prefab");}DestroyImmediate(pre);}
}

b.迭代器(注意:没有必要搞懂迭代如何实现,能用起来就可以)放心直接考到工程就可以用

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;public class GameObjectTree : MonoBehaviour
{#region 零时脚本#endregionpublic Transform rootTransform;public Hashtable gameTs;public Font font;
#if UNITY_EDITORpublic List<MonoScript> scriptObjs;
#endif/// <summary>/// 透明 /// </summary>public Material disableMat, leafMat, NodeMat;[ContextMenu("遍历对象并打印")]public void Traverse(){RecursiveTraverse(rootTransform, (tran) => Debug.Log(tran.name));}[ContextMenu("AddMeshCollider")]public void AddMeshColliderScript(){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out MeshRenderer renderer)){if (!tran.TryGetComponent(out MeshCollider b)){tran.AddComponent<MeshCollider>();}}});}[ContextMenu("ChangeJRTag")]public void ChangeJRTag(){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out MeshRenderer renderer)){if (!tran.TryGetComponent(out MeshCollider b)){tran.AddComponent<MeshCollider>();}tran.tag = "JR";}});}[ContextMenu("ChangeGGTag")]public void ChangeGGTag(){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out MeshRenderer renderer)){if (!tran.TryGetComponent(out MeshCollider b)){tran.AddComponent<MeshCollider>();}tran.tag = "GG";}});}[ContextMenu("RemoveMeshCollider")]public void RemoveMeshColliderScript(){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out MeshRenderer renderer)){if (tran.TryGetComponent(out MeshCollider b)){DestroyImmediate(b);}}});}
#if UNITY_EDITOR[ContextMenu("AddMonoScriptUnderMeshRenderer")]public void AddMonoScript(){List<Type> types = new List<Type>();foreach (var item in scriptObjs){types.Add(item.GetClass());}RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out MeshRenderer renderer)){foreach (var item in types){if (tran.TryGetComponent(item, out Component sss)){DestroyImmediate(sss);}tran.gameObject.AddComponent(item);}Debug.Log(tran.name);if (!tran.TryGetComponent(out MeshCollider mesh)){tran.AddComponent<MeshCollider>();}}});}public void SetCommponentValue<T>(Material m){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out T t)){var v = t.GetType();FieldInfo info = v.GetField("setMt");info.SetValue(t, m);}});}public void SetTypeValue(Type  t,Material m){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(t, out Component c)){var v = c.GetType();FieldInfo info = v.GetField("setMt");info.SetValue(c, m);}});}[ContextMenu("RemoveMonoScript")]public void RemoveMonoScript(){List<Type> types = new List<Type>();foreach (var item in scriptObjs){types.Add(item.GetClass());}RecursiveTraverse(rootTransform, (tran) =>{foreach (var item in types){if (tran.TryGetComponent(item, out Component sss)){DestroyImmediate(sss);}}});}
#endif[ContextMenu("RemoveNameSpace")]public void RemoveNameSpace(){RecursiveTraverse(rootTransform, (tran) =>{string _name = tran.gameObject.name;if (_name.Contains(" ")){Debug.Log(_name);tran.gameObject.name = _name.Replace(" ", "");}});}[ContextMenu("RemoveBoxCollider")]public void RemoveBoxCollider(){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out BoxCollider renderer)){DestroyImmediate(renderer);}});}[ContextMenu("AddMissingFont")]public void AddMissingFont(){RecursiveTraverse(rootTransform, (tran) =>{if (tran.TryGetComponent(out Text renderer) && renderer.font == null){renderer.font = font;}});}[ContextMenu("遍历隐藏")]public void Disable(){RecursiveTraverse(rootTransform, (tran) => { tran.TryGetComponent(out Renderer renderer); renderer.material = disableMat; });}[ContextMenu("遍历显示")]public void EanbleRecurise(){RecursiveTraverse(rootTransform, (tran) => { tran.TryGetComponent(out Renderer renderer); renderer.material = NodeMat; });}[ContextMenu("生成模型快照-1")]public void CreateTreeState(){StringBuilder sb = new StringBuilder();var Root = TreeNode<Transform>.CopyTransformHierarchy(rootTransform, tran =>{return tran;});Root.TraverseDown((s) =>{if (IsActive(s.Name) && IsMeshFilter(s.Name)){sb.Append($"{ s.Name.name},");}});GUIUtility.systemCopyBuffer = sb.ToString();//Clipboard.Copy();// WriteFile("mapData.json", sb.ToString());}bool IsActive(Transform t){return t.gameObject.activeSelf;}bool IsMeshFilter(Transform t){return t.TryGetComponent(out MeshFilter n);}[ContextMenu("构造树")]public void ConstructTree(){treeRootNode = TreeNode<string>.CopyTransformHierarchy(rootTransform, tran => tran.name);var json = PreserveRefToJson(treeRootNode);UnityEngine.Debug.Log(json);WriteFile("treeNode.json", json);//  var reload = ReadFile("treeNode.json");//比较//var reloadNode = PreserveRefFromJson<TreeNode<string>>(reload);//if (PreserveRefToJson(reloadNode).Equals(json))//{//    Debug.Log("相等");//}// string info = treeRootNode.Print(node => GetIndent(node.GetLevel()) + node.Name);// Debug.Log(info);}[ContextMenu("读取保存到文件中的树")]public void ReadTree(){string json = ReadFile("treeNode.json");var reload = PreserveRefFromJson<TreeNode<string>>(json);}public void RecursiveTraverse(Transform tran, Action<Transform> op = null){op?.Invoke(tran);for (int i = 0; i < tran.childCount; i++){var child = tran.GetChild(i);RecursiveTraverse(child, op);}}public TreeNode<string> treeRootNode = new TreeNode<string>();// public TreeNode<string> CopyTransformHierarchy(Transform tran, TreeNode<string> NodeParent = null) {//     TreeNode<string> curNode = new TreeNode<string>();//     curNode.Payload = tran.name;//     NodeParent?.AddChild(curNode);//     for (int i = 0; i < tran.childCount; i++) {//         var child = tran.GetChild(i);//         CopyTransformHierarchy(child, curNode);//     }////     return curNode;// }#region utilspublic string GetIndent(int n){StringBuilder sb = new StringBuilder();for (int i = 0; i < n; i++){sb.Append("=");}sb.Append("|");return sb.ToString();}public string PreserveRefToJson<T>(T obj){var json = JsonConvert.SerializeObject(obj, Formatting.None, /*Formatting.Indented,*/new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });return json;}public T PreserveRefFromJson<T>(string json){T reload = JsonConvert.DeserializeObject<T>(json,new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });return reload;}public void WriteFile(string fileName, string content){File.WriteAllText(Application.streamingAssetsPath + Path.DirectorySeparatorChar + fileName, content);}public string ReadFile(string fileName){return File.ReadAllText(Application.streamingAssetsPath + Path.DirectorySeparatorChar + fileName);}#endregion/** 目前两套方案,一套是复制一份prefab,然后将prefab的模型层级修改成目标层级,解析这个层级来获得配置信息* 另一套方案就是完全用目录结构来重建目标层级,* 在现有的机制下,先构造一套统一的抽象,然后分别用解析文件系统,和解析gameobject 的 transform层级来实现。*/
}public class TreeNode<T>
{public T Name { get; set; }public TreeNode<T> Parent { get; set; }public List<TreeNode<T>> Children;public bool IsRoot() => Parent == null;public bool IsLeaf() => Children == null;public void AddChild(TreeNode<T> node){// Children ??= new List<TreeNode<T>>();if (Children == null) Children = new List<TreeNode<T>>();Children.Add(node);node.Parent = this;}public List<TreeNode<T>> Siblings(){return Parent?.Children ?? null;}public int SiblingCount(){return Parent?.Children?.Count ?? 0;}/// <summary>/// 向下递归遍历所有children,实际会遍历以当前node为root的子树/// </summary>public void TraverseDown(Action<TreeNode<T>> nodeAction){nodeAction?.Invoke(this);Children?.ForEach(child => child.TraverseDown(nodeAction));}/// <summary>/// 向上遍历所有parent,相当与遍历当前node为head,终止node为root的链表/// </summary>public void TraverseUp(Action<TreeNode<T>> nodeAction){nodeAction?.Invoke(this);Parent?.TraverseUp(nodeAction);}/// <summary>/// 递归函数的结构就定义了递归的条件,你无法额外插入新的终止条件,除非你重写这个递归./// 所以这个Find方法,原本只想找到第一个命中就退出,但发现利用TraverseDown是无法立即停下的,/// 即使找到一个命中元素,仍然要完成所有遍历,所以干脆就改了一下实现,Find是找到所有/// </summary>/// <param name="predicate"></param>/// <returns></returns>public List<TreeNode<T>> Find(Predicate<TreeNode<T>> predicate){List<TreeNode<T>> resultList = new List<TreeNode<T>>();TraverseDown((node) =>{if (predicate(node)){resultList.Add(node);}});return resultList;}public TreeNode<T> FindRoot(){TreeNode<T> current = this;while (current.Parent != null){current = current.Parent;}return current;}/// <summary>/// 获得当前Node在树中的深度,root深度值为0,每向下前进一级,level++/// </summary>/// <returns></returns>public int GetLevel(){int level = 0;TreeNode<T> current = this;while (current.Parent != null){current = current.Parent;level++;}return level;}public string Print(Func<TreeNode<T>, string> ToString){StringBuilder sb = new StringBuilder();TraverseDown(node =>{string info = ToString(node);sb.AppendLine(info);});return sb.ToString();}/// <summary>/// 以一个transform为root,将其hierarchy结构映射成一个TreeNode<T>表达的树,返回root Node/// 想要构建一个树状信息图,必须找一个本身就是树状结构的对象,比如transform,比如文件目录,所以这里不需要再用泛型来表达这一层,直接假设目标是Transform/// </summary>/// <param name="tran">以这个transform为起点开始遍历</param>/// <param name="selector">从Transform转换为payload T 的 方法</param>/// <param name="NodeParent">当前节点的父节点(这个需要递归传给每一级子节点来确立父子关系)</param>/// <returns></returns>public static TreeNode<T> CopyTransformHierarchy(Transform tran, Func<Transform, T> selector,TreeNode<T> NodeParent = null){TreeNode<T> curNode = new TreeNode<T>();curNode.Name = selector(tran);NodeParent?.AddChild(curNode);for (int i = 0; i < tran.childCount; i++){var child = tran.GetChild(i);CopyTransformHierarchy(child, selector, curNode);}return curNode;}/// <summary>/// 遍历整个子树,构造所有payload->TreeNode的字典并返回,/// 提供一个通过payload查找的字典/// </summary>/// <returns></returns>public Dictionary<T, TreeNode<T>> GetTreeNodeMap(){Dictionary<T, TreeNode<T>> TreeNodeDict = new Dictionary<T, TreeNode<T>>();TraverseDown(node => { TreeNodeDict.Add(node.Name, node); });return TreeNodeDict;}public Dictionary<K, TreeNode<T>> GetTreeNodeMap<K>(Func<T, K> selector){Dictionary<K, TreeNode<T>> TreeNodeDict = new Dictionary<K, TreeNode<T>>();TraverseDown(node =>{K k = selector(node.Name);TreeNodeDict.Add(k, node);});return TreeNodeDict;}
}

c.关键需要注意的方法

Fbx2Prefab. CreateNormalPre()

Fbx2Prefab. CreateNormalPre(SystemBody body)

GameObjectTree.SetTypeValue(Type  t,Material m)

GameObjectTree.AddMonoScript()

 

 


http://chatgpt.dhexx.cn/article/IY5Gnvbp.shtml

相关文章

将FBX文件导入Unity3d中

在Project中找到选择Assets: 点击鼠标右键出现下拉列表&#xff0c;在下拉列表中选择“Import New Asset..."选项&#xff1a; 点击后选择你要导入的FBX文件&#xff0c;导入&#xff1a; 然而这样导入的模型并不会显示贴图&#xff0c;要让模型可以正常显示贴图&#xff…

【pymxs】max文件导出fbx文件

1. 前言 .max格式是Autodesk公司下的3dsmax软件的通用格式&#xff0c;许多软件出于商业考虑都有自己的格式&#xff0c;例如网易云下载的音乐。 这也就意味着.max文件只能用Autodesk的产品打开&#xff0c;即3dsmax或maya。 Autodesk的产品均是非开源、封闭式的&#xff0c…

Fbx文件解析(一)——FBX SDK for Windows环境配置

Fbx文件解析&#xff08;一&#xff09;——FBX SDK for Windows环境配置 一、下载并安装FBX SDK 下载网址&#xff1a;http://www.autodesk.com/fbx 找到与自己Windows对应、与自己的VS版本对应的SDK版本&#xff0c;下载并按照安装步骤安装。安装时选择的安装文件夹就是下…

pmx转fbx的具体步骤

本文主要讲述了在Windows10环境下&#xff0c;通过blender将pmx格式文件转化为fbx文件的具体步骤 本文主要包括以下三个部分&#xff1a; 一、blender下载与安装二、cats插件安装三、pmx格式转换为fbx格式 一、blender下载与安装 1.下载blender到电脑上 blender下载 建议下载…

关于unity导出FBX文件

最近有项目需求需要根据特殊文件来绘制自定义图形&#xff0c;考虑到其他编辑器对此文件的共用&#xff0c;所以将图形导出为FBX格式。 在网上找到了一个git仓库在这也记录分享一下&#xff1a; Git仓库:UnityFBXExporterhttps://github.com/Ymiku/UnityFBXExporter 插件功能…

加载FBX模型文件

深入理解加载FBX模型文件 每个模型文件都有自己的格式&#xff0c;有自研引擎的模型格式&#xff0c;有AutoDesk提供的模型文件格式&#xff0c;比如FBX模型文件&#xff0c;因为Unity与UE4引擎的使用而备受关注&#xff0c;FBX文件是AutoDesk提供的SDK&#xff0c;已经封装好了…

FBX格式转换为GLTF/GLB格式

有小伙伴说通过blende将fbx转glb/gltb格式的模型无法在web端加载&#xff0c;或glb模型无法打开&#xff0c;比如腾讯地图加载gltf。 这里个大家分享一个插件 可以将fbx格式转换为glb格式 window版本 链接&#xff1a;https://pan.baidu.com/s/17wwI-hmezg9-sOnHZNn_uw?pwd1…

FBX文件导入Unity导致贴图丢失问题解决,以3ds max,Blender导入导出为例

一 . 首先把资产文件导入三维软件中 1 . 3ds Max 1.1 导入FBX——【免费或者质量差的资源可能会出现平滑组错误的情况&#xff0c;可以直接镜像一个模型更改法线或者删除面重新封口能解决问题】 1.2 导出FBX至Unity引擎 1.2.1 导出文件预设 注意【导出之后会产生一个FBX文件和流…

基于FBX SDK的FBX模型解析与加载 -(一)

1. 简介 FBX是Autodesk的一个用于跨平台的免费三维数据交换的格式&#xff08;最早不是由Autodesk开发&#xff0c;但后来被其收购&#xff09;&#xff0c;目前被 众多的标准建模软件所支持&#xff0c;在游戏开发领域也常用来作为各种建模工具的标准导出格式。Autodesk提供…

Unity场景素材导出为 FBX文件的方法

系列文章目录 一、Unity场景素材导出为 FBX文件的方法&#xff1a;http://t.csdn.cn/Xyjxe 二、Unity场景素材导出为 OBJ文件的方法&#xff1a;http://t.csdn.cn/08RY3 三、Unity地形导出为 OBJ文件的方法 &#xff08;大家可以打开我的博客主页进行查看此系列其它文章&…

Unity导入FBX动画文件

给刚入门的同学稍微记一下fbx格式动画导入unity的步骤&#xff1a; 首先直接把fbx文件拖入unity内&#xff0c;如图操作 将avatar骨骼创建之后&#xff0c;我们接下来就根据自己对动画的一些需求设置一下动画的参数&#xff0c;比如截取一下动画的开始帧和结束帧来达到剪切的目…

深入理解加载FBX模型文件

每个模型文件都有自己的格式&#xff0c;有自研引擎的模型格式&#xff0c;有AutoDesk提供的模型文件格式&#xff0c;比如FBX模型文件&#xff0c;因为Unity与UE4引擎的使用而备受关注&#xff0c;FBX文件是AutoDesk提供的SDK&#xff0c;已经封装好了&#xff0c;我们并不能查…

FBX模型

概览 fbx文件&#xff0c;一般是导出给unity使用的模型文件。 如下图所示&#xff0c;建立一个models目录&#xff0c;然后右击&#xff0c;选择 imoprt new asserts 即可导入这些文件。 展示如下&#xff0c;Mesh定义了形状。 铅笔也是同理&#xff0c;只不过铅笔有自己的贴图…

FBX文件简述

1&#xff0e; 关于FBX Autodesk FBX是Autodesk公司出品的一款用于跨平台的免费三维创作与交换格式的软件&#xff0c;通过FBX用户能访问大多数三维供应商的三维文件。FBX 文件格式支持所有主要的三维数据元素以及二维、音频和视频媒体元素。 FBX由Kaydara开发并于2006年被AUT…

fbx格式研究

Part1fbx简介 Autodesk FBX是Autodesk公司出品的一款用于跨平台的免费三维创作与交换格式的软件&#xff0c;通过FBX用户能访问大多数三维供应商的三维文件。FBX 文件格式支持所有主要的三维数据元素以及二维、音频和视频媒体元素。FBX对于三维软件的兼容性非常非常强大&#x…

matlab 画图的颜色

plot函数代表不同颜色的标示符一共有八种&#xff1a; y&#xff1a;黄色&#xff1b;k&#xff1a;黑色&#xff1b;w&#xff1a;白色&#xff1b;b&#xff1a;蓝色&#xff1b;g&#xff1a;绿色&#xff1b;r&#xff1a;红色&#xff1b;c&#xff1a;亮青色&#xff1b…

Matlab画图线型、符号及颜色汇总

【1】线型、标记符、颜色的说明 【2】对于坐标轴的注释内容xlabel,ylabel的属性说明 figure,plot(Seg1,SS1_QJ1,k);hold onplot(Seg1,SS1_QJ1,ks)plot(Seg1,Q1*ones(length(Seg1)),r)xlabel(\bf{安装角}(),FontSize,10.508) %\bf是加粗的意思%xlabel(\fontsize{10.508}\fontn…

matlab绘图颜色RGB

一.1.MATLAB中颜色数值 二.常用颜色

matlab中的颜色,Matlab里面除了常用的还有哪些颜色?已知的颜色不够怎么办?

我这里有个自己写的函数&#xff0c;支持64个色 %% H:取色函数 % INTRODUCTORY TEXT %标题综述************************ %调用默认色图可实现64色的选取 %输入**************************** %①所选颜色个数 %输出**************************** %①待用颜色的RGB矩阵 %调用流程…

Matlab中绘制颜色渐变曲线

大家在文章中是否看见过各类颜色渐变的曲线呢&#xff1f;今天小编就教大家在matlab中如何绘制这类颜色渐变的曲线。 一、scatter3函数 这个函数是大家最常想到的函数&#xff0c;具体用法就看其帮助文档&#xff0c;小编就给出一段示例代码&#xff1a; % Matlab% data z …