78 KiB
78 KiB
#unity/白日梦/代码缓存
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text;
using System.Linq;
using System.Text.RegularExpressions;
using ResourcesModule.LMNA;
namespace SkinToolModule.M.Editor
{
public struct LODDynamicColliderData
{
public Transform colTrans;
public string name;
public float radius;
public string rootName;
public LODDynamicColliderData(string n, float r = 0.3f, string rn = "", Transform c = null)
{
name = n;
radius = r;
rootName = rn;
colTrans = c;
}
}
public struct LODDynamicBoneParams
{
public Transform root;
public float Damping;
public float Elasticty;
public float Stiffness;
public float Inert;
public float Friction;
public float Radius;
public List<LODDynamicColliderData> colliderDataList;
public LODDynamicBoneParams(Transform t, float d = 0.02f, float e = 0.08f, float s = 0.06f, float i = 0.8f, float f = 0.6f, float r = 0.0f, List<LODDynamicColliderData> colliders = null)
{
root = t;
Damping = d;
Elasticty = e;
Stiffness = s;
Inert = i;
Friction = f;
Radius = r;
colliderDataList = colliders;
}
}
public class SkinToolEditor : EditorWindow
{
private enum MatType
{
Character,
Transparent,
Fakeskin,
Fur,
Error,
}
private static SkinToolEditor m_Window;
public const string m_SuiteLevelPath = "Assets/Editor/ArtResources/Tool/Config/SuiteLevel.txt";
private const string m_DefaultMatPath = "Assets/Editor/ArtResources/Tool/Config/DefaultMaterial.mat";
private const string m_FbxDirIng = "/ResourcesRaw/CommonRegion/InGame/Skins/Characters/";
private const string m_FbxDirLob = "/ResourcesRaw/CommonRegion/OutsideGame/Skins/Characters/";
private const string m_PrefabDirIng = "Assets/BundleResources/CommonRegion/InGame/Skins/Characters/";
private const string m_PrefabDirLob = "Assets/BundleResources/CommonRegion/OutsideGame/Skins/Characters/";
private const string m_DynamicBoneParamDir = "Assets/Editor/ArtResources/Tool/LODDynamicBoneParams";
private string m_OldFBXPath = "Assets/ResourcesRaw/CommonRegion/Skins/Characters/Models/";
private bool m_IsLobby;
private bool m_IsOld; // 是否是重导的减面资源
private GameObject m_OldPrefab;
private FileInfo m_FbxFile;
private FileInfo[] m_TgaFiles;
private string m_FolderPath = "";
private string m_FbxPath = "";
private string m_PrefabPath = "";
private string LOD_m_PrefabPath = "";
private string m_DynamicBonePrefabPath;
private Dictionary<string,eAssetLodLevel> levelDic = new Dictionary<string, eAssetLodLevel>
{
["lv0"] = eAssetLodLevel.Lv0,
["lv1"] = eAssetLodLevel.Lv1,
["lv2"] = eAssetLodLevel.Lv2,
["lv3"] = eAssetLodLevel.Lv3,
["lv4"] = eAssetLodLevel.Lv4
};
private Dictionary<string, eAssetSceneType> sceneDic = new Dictionary<string, eAssetSceneType>
{
["lob"] = eAssetSceneType.Lobby,
["ing"] = eAssetSceneType.InGame,
};
private eAssetSceneType currentAssetSceneType = eAssetSceneType.Unknown;
private eAssetLodLevel currentAssetLodLevel = eAssetLodLevel.None;
private Dictionary<int,FileInfo> mFbxFileList = new Dictionary<int,FileInfo>();
private Dictionary<int, string> mFolderPathList = new Dictionary<int, string>();
private Dictionary<int,string> mFbxPathList = new Dictionary<int,string>();
private Dictionary<int,string> mPrefabPathList = new Dictionary<int,string>();
// 品质相关
public enum SuiteLevel {
white = 0,
blue = 1,
purple = 2,
orangee = 3,
pink = 4,
};
private SuiteLevel m_SuiteLevel = SuiteLevel.white;
private GameObject m_FbxSenceObject;
// Dynamic bone相关
private GameObject m_DynamicBoneSenceObject;
Dictionary<Transform, string> m_TaggedTransformDict = new Dictionary<Transform, string>(); // 被标记的骨骼节点 - 对应父节点名字
Dictionary<string, LODDynamicBoneParams> m_TagToDynamicBoneParamDict = new Dictionary<string, LODDynamicBoneParams>(); // 被标记的骨骼节点名字 - 对应DynamicBone参数组
List<Transform> m_SkinPartTransformList = new List<Transform>(); // 部位
// 眨眼相关
string BlinkFaceTag = "head_fx_01";
Dictionary<string, string[]> m_BlinkFaceDict = new Dictionary<string, string[]> {
{ "Thief_08", new string[]{"Thief_08_head_OpenEyes_01_height", "Thief_08_head_CloseEyes_01_height"} },
{ "Police_05", new string[]{ "Police_05_head_OpenEyes_01_height", "Police_05_head_CloseEyes_01_height" } },
};
// 界面相关
Color m_BlueColor = new Color(129 / 255f, 209 / 255f, 248 / 255f, 1);
Color m_PinkColor = new Color(253 / 255f, 184 / 255f, 225 / 255f, 1);
Color m_RedColor = new Color(233 / 255f, 74 / 255f, 110 / 255f, 1);
Color m_PurpColor = new Color(125 / 255f, 128 / 255f, 227 / 255f, 1);
float m_RowHeight = 20f;
int m_RowFontSize = 12;
GUIStyle m_MainHeaderStyle;
GUIStyle m_SubHeaderStyle;
GUIStyle m_ButtonStyle;
GUIStyle m_TipsStyle;
GUIStyle m_ErrorTipsStyle;
GUIStyle m_LabelStyle;
GUIStyle m_TagLabelStyle;
GUIStyle m_ParamsLabelStyle;
private string[] ModelName = new[]
{
"clothes",
"hand",
"head",
"shoes",
"trousers",
};
private string[] DynamicBoneTag = new[]
{
"CLOTHES_",
"HEAD_",
"HAND_",
"SHOES_",
"TROUSERS_"
};
[UnityEditor.MenuItem("美术工具/导入时装资源", false, 1)]
static void ShowWindow()
{
if (m_Window == null)
{
m_Window = (SkinToolEditor)EditorWindow.GetWindow(typeof(SkinToolEditor), true, "SkinToolEditor");
m_Window.Show();
}
else
{
m_Window.Close();
m_Window = null;
}
}
#region GUI
void OnGUI()
{
InitStyles();
EditorGUILayout.BeginVertical();
// Title
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Bunny Editor", m_MainHeaderStyle, GUILayout.Height(30));
if (GUILayout.Button("清除", m_ButtonStyle, GUILayout.Width(150), GUILayout.Height(m_RowHeight)))
{
if (EditorUtility.DisplayDialog("警告", "确定要清除本次生成的所有资源么?", "删就完事儿了"))
{
OnClickClearButton();
}
}
// if (GUILayout.Button(m_IsOld?"当前:老资源合入": "当前:新资源合入", m_ButtonStyle, GUILayout.Width(250), GUILayout.Height(m_RowHeight)))
// {
// m_IsOld = !m_IsOld;
// }
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
DrawSplitLine(25);
// Load fbx
if (GUILayout.Button("选fbx所在文件夹", m_ButtonStyle, GUILayout.Width(150), GUILayout.Height(m_RowHeight)))
{
OnClickCreateButton(OnClickLoadButton());
}
EditorGUILayout.Space();
// Show FolderPath
// if (!string.IsNullOrEmpty(m_FolderPath))
// {
// if (!Directory.Exists(m_FolderPath)&&!m_IsOld)
// {
// EditorGUILayout.TextArea("地址已存在:\n" + m_FolderPath, m_TipsStyle);
// }
// else if(!Directory.Exists(m_FolderPath)&&m_IsOld)
// {
// EditorGUILayout.TextArea("导入完毕,资源地址为:\n" + m_OldFBXPath, m_TipsStyle);
// }
// else
// {
// EditorGUILayout.TextArea("导入完毕,资源地址为:\n" + m_FolderPath, m_TipsStyle);
// }
// }
// else
// {
// EditorGUILayout.TextArea("无资源导入...", m_TipsStyle);
// }
EditorGUILayout.Space();
// Select Suite Level
// m_SuiteLevel = (SuiteLevel)EditorGUILayout.EnumPopup("选择时装品质", m_SuiteLevel, GUILayout.Width(300));
// EditorGUILayout.Space();
// Create Prefab without Dynamic bone
// if (GUILayout.Button("生成模型", m_ButtonStyle, GUILayout.Width(150), GUILayout.Height(m_RowHeight)))
// {
// OnClickCreateButton();
// }
EditorGUILayout.Space();
// show prefab path
if (!string.IsNullOrEmpty(LOD_m_PrefabPath))
{
EditorGUILayout.TextArea("创建Prefab完毕,资源地址为:\n" + LOD_m_PrefabPath, m_TipsStyle);
}
else
{
EditorGUILayout.TextArea("无Prefab创建...", m_TipsStyle);
}
EditorGUILayout.Space();
// Put prefab in
// EditorGUILayout.TextArea("部件模型路径", m_LabelStyle);
// Rect modelRect = EditorGUILayout.GetControlRect(GUILayout.Width(500));
// m_DynamicBonePrefabPath = EditorGUI.TextField(modelRect, m_DynamicBonePrefabPath);
// EditorGUILayout.Space();
// if ((Event.current.type == EventType.DragUpdated)
// && modelRect.Contains(Event.current.mousePosition))
// {
// DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
// }
//
// if ((Event.current.type == EventType.DragPerform) && modelRect.Contains(Event.current.mousePosition))
// {
// if (DragAndDrop.paths != null && DragAndDrop.paths.Length > 0)
// {
// m_DynamicBonePrefabPath = DragAndDrop.paths[0];
// }
// }
// // Analysis Dynamic bone params
// if (GUILayout.Button("生成DynamicBone参数", m_ButtonStyle, GUILayout.Width(150),
// GUILayout.Height(m_RowHeight)))
// {
// }
// OnClickCreateLODDynamicBoneParams();
// EditorGUILayout.Space();
// if (m_TagToDynamicBoneParamDict.Count > 0)
// {
// //在 foreach 中修改Dictionary中的值是不允许的,可以将key 先放在List中,foreach 这个list ,找到需要修改的项后,再修改原Dic中的内容
// OnDrawListView();
// EditorGUILayout.Space();
// EditorGUILayout.BeginHorizontal();
// // Create Prefab with Dynamic bone
// if (GUILayout.Button("挂DynamicBone脚本", m_ButtonStyle, GUILayout.Width(200),
// GUILayout.Height(m_RowHeight)))
// {
// OnClickDynamicBoneButton();
// }
//
// if (GUILayout.Button("导入DynamicBone文件", m_ButtonStyle, GUILayout.Width(200),
// GUILayout.Height(m_RowHeight)))
// {
// OnClickImportDynamicBoneFile();
// }
//
// if (GUILayout.Button("导出DynamicBone文件", m_ButtonStyle, GUILayout.Width(200),
// GUILayout.Height(m_RowHeight)))
// {
// OnClickExportDynamicBoneFile();
// }
//
// EditorGUILayout.EndHorizontal();
//
// }
}
/// <summary>
/// 初始化,清空数据
/// </summary>
void ClearData()
{
mFbxFileList.Clear();
mFolderPathList.Clear();
mFbxFileList.Clear();
mPrefabPathList.Clear();
}
void OnDestroy()
{
ClearScenePrefabs();
}
void InitStyles()
{
if (m_MainHeaderStyle == null)
{
m_MainHeaderStyle = new GUIStyle(GUI.skin.label);
m_MainHeaderStyle.fontSize = 20;
m_MainHeaderStyle.fontStyle = FontStyle.Bold;
m_MainHeaderStyle.normal.textColor = m_BlueColor;
}
if (m_SubHeaderStyle == null)
{
m_SubHeaderStyle = new GUIStyle(GUI.skin.label);
m_SubHeaderStyle.fontSize = 14;
m_SubHeaderStyle.fontStyle = FontStyle.Bold;
m_SubHeaderStyle.normal.textColor = m_BlueColor;
}
if (m_ButtonStyle == null)
{
m_ButtonStyle = new GUIStyle(GUI.skin.button);
m_ButtonStyle.fontSize = 14;
}
if (m_TipsStyle == null)
{
m_TipsStyle = new GUIStyle(GUI.skin.label);
m_TipsStyle.normal.textColor = m_PinkColor;
m_TipsStyle.fontSize = m_RowFontSize;
}
if (m_ErrorTipsStyle == null)
{
m_ErrorTipsStyle = new GUIStyle(GUI.skin.label);
m_ErrorTipsStyle.normal.textColor = m_RedColor;
m_ErrorTipsStyle.fontSize = m_RowFontSize;
}
if (m_LabelStyle == null)
{
m_LabelStyle = new GUIStyle(GUI.skin.label);
m_LabelStyle.normal.textColor = m_BlueColor;
m_LabelStyle.fontSize = 18;
}
if (m_TagLabelStyle == null)
{
m_TagLabelStyle = new GUIStyle(GUI.skin.label);
m_TagLabelStyle.normal.textColor = m_PinkColor;
m_TagLabelStyle.fontSize = 16;
}
if (m_ParamsLabelStyle == null)
{
m_ParamsLabelStyle = new GUIStyle(GUI.skin.label);
m_ParamsLabelStyle.normal.textColor = m_PurpColor;
m_ParamsLabelStyle.fontSize = 13;
}
}
void DrawSplitLine(float height)
{
GUI.Box(new Rect(0, height, position.width, 1), string.Empty);
}
// 这里是scrollview
Vector2 _scrollPos;
void OnDrawListView()
{
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, false, false, GUILayout.Width(500), GUILayout.Height(400));
List<string> keyList = new List<string>();
foreach (KeyValuePair<string, LODDynamicBoneParams> pair in m_TagToDynamicBoneParamDict)
{
keyList.Add(pair.Key);
}
foreach (string key in keyList)
{
EditorGUILayout.TextArea(key, m_TagLabelStyle, GUILayout.Height(20));
LODDynamicBoneParams inputValue;
float Damping = EditorGUILayout.FloatField("Damping", m_TagToDynamicBoneParamDict[key].Damping, m_ParamsLabelStyle);
float Elasticty = EditorGUILayout.FloatField("Elasticty",
m_TagToDynamicBoneParamDict[key].Elasticty, m_ParamsLabelStyle);
float Stiffness = EditorGUILayout.FloatField("Stiffness",
m_TagToDynamicBoneParamDict[key].Stiffness, m_ParamsLabelStyle);
float Inert =
EditorGUILayout.FloatField("Inert", m_TagToDynamicBoneParamDict[key].Inert, m_ParamsLabelStyle);
float Friction =
EditorGUILayout.FloatField("Friction", m_TagToDynamicBoneParamDict[key].Friction, m_ParamsLabelStyle);
float Radius =
EditorGUILayout.FloatField("Radius", m_TagToDynamicBoneParamDict[key].Friction, m_ParamsLabelStyle);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("+", m_ButtonStyle, GUILayout.Width(50), GUILayout.Height(m_RowHeight)))
{
OnClickAddCollider(key);
}
if (GUILayout.Button("-", m_ButtonStyle, GUILayout.Width(50), GUILayout.Height(m_RowHeight)))
{
OnClickRemoveCollider(key);
}
EditorGUILayout.EndHorizontal();
if (m_TagToDynamicBoneParamDict[key].colliderDataList != null)
{
for (int i = 0; i < m_TagToDynamicBoneParamDict[key].colliderDataList.Count; i++)
{
EditorGUILayout.BeginHorizontal();
LODDynamicColliderData inputColliderValue;
// 列出这个标记位下绑到的所有collider信息
List<LODDynamicColliderData> colliderList = m_TagToDynamicBoneParamDict[key].colliderDataList;
LODDynamicColliderData collider = colliderList[i];
EditorGUILayout.LabelField(collider.name, GUILayout.MaxWidth(80));
float collRadius = EditorGUILayout.FloatField("碰撞体半径:", collider.radius, m_ParamsLabelStyle);
EditorGUILayout.LabelField("关联骨骼名字:", GUILayout.MaxWidth(80));
GUI.SetNextControlName("RootNameText");
string collAttachName = EditorGUILayout.TextField(collider.rootName, m_ParamsLabelStyle,
GUILayout.MaxWidth(200), GUILayout.Height(m_RowHeight));
EditorGUILayout.EndHorizontal();
// 改碰撞体list
if (collRadius != collider.radius || collAttachName != collider.rootName)
{
inputColliderValue = new LODDynamicColliderData(collider.name, collRadius, collAttachName, collider.colTrans);
colliderList[i] = inputColliderValue;
inputValue = new LODDynamicBoneParams(null, Damping, Elasticty, Stiffness, // TODO: 这些地方要把null替换掉!
Inert,
Friction, Radius, colliderList);
m_TagToDynamicBoneParamDict[key] = inputValue;
}
}
}
// 只改Dynamicbone的数字参数,不涉及碰撞体list
if (Damping != m_TagToDynamicBoneParamDict[key].Damping ||
Elasticty != m_TagToDynamicBoneParamDict[key].Elasticty ||
Stiffness != m_TagToDynamicBoneParamDict[key].Stiffness ||
Inert != m_TagToDynamicBoneParamDict[key].Inert ||
Friction != m_TagToDynamicBoneParamDict[key].Friction ||
Radius != m_TagToDynamicBoneParamDict[key].Radius)
{
List<LODDynamicColliderData> colliderList = m_TagToDynamicBoneParamDict[key].colliderDataList;
inputValue = new LODDynamicBoneParams(null, Damping, Elasticty, Stiffness, Inert,// TODO: 这些地方要把null替换掉!
Friction, Radius, colliderList);
m_TagToDynamicBoneParamDict[key] = inputValue;
}
EditorGUILayout.Space();
}
EditorGUILayout.EndScrollView(); // 组结束
}
#endregion
#region LoadFile
bool OnClickLoadButton()
{
ClearData();
bool success = true;
m_OldPrefab = null;
string defaultFolder = PlayerPrefs.GetString("BunnyflopFilesDefalutFolder", "");
string folder = EditorUtility.OpenFolderPanel("Select Versions Folder", defaultFolder, "");
if (string.IsNullOrEmpty(folder))
{
return false;
}
m_SuiteLevel = SuiteLevel.white;
PlayerPrefs.SetString("BunnyflopFilesDefalutFolder", folder);
DirectoryInfo direction = new DirectoryInfo(folder);
FileInfo[] fbxFiles = direction.GetFiles("*.fbx", SearchOption.AllDirectories);
if (fbxFiles.Length == 0)
{
NamingChecker.PopupErrorMessage("未检测到有fbx导入!");
return false;
}
for (int i = 0; i < fbxFiles.Length; i++)
{
m_FbxFile = fbxFiles[i];// 只允许载入一个
mFbxFileList.Add(i,m_FbxFile);
// if(m_IsOld)
// {
// // 重新导入性能优化使用的低模不检查命名规范,但要找到老的fbx,不然就报错退出
// m_OldPrefab = FindOldPrefabByFbxFile(m_FbxFile.Name);
// if(m_OldPrefab==null)
// {
// EditorUtility.DisplayDialog("警告", "项目内找不到名为"+m_FbxFile.Name+"的模型文件,请确认减面优化资源命名是否与老资源完全一致!", "我知道了");
// return;
// }
// }
// else
// {
// bool isPassCheck = NamingChecker.PreCheck(m_FbxFile);
// if (!isPassCheck)
// {
// return;
// }
// }
m_IsLobby = !m_FbxFile.Name.Contains("Low") && !m_FbxFile.Name.Contains("low")&&!m_FbxFile.Name.Contains("&ing");
success = LoadFbxFile(i);
if (success == false)
{
break;
}
}
return success;
}
GameObject FindOldPrefabByFbxFile(string fileName)
{
string fbxName = fileName.Split('.')[0];
string[] allPath = AssetDatabase.FindAssets("t:Model", new string[] { "Assets/ResourcesRaw/CommonRegion/Skins/Characters/Models" });
foreach(string singlePath in allPath)
{
string assetPath = AssetDatabase.GUIDToAssetPath(singlePath);
if(assetPath.Contains(fbxName+".FBX"))
m_OldFBXPath = assetPath.Replace(fbxName+".FBX","");
if(assetPath.Contains(fbxName+".fbx"))
m_OldFBXPath = assetPath.Replace(fbxName+".fbx","");
if(!GetFbxName(assetPath).Equals(fbxName))
{
continue;
}
// 找到同名的fbx之后再找依赖fbx的prefab
GameObject fbx = AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)) as GameObject;
GameObject dependPrefab = GetPrefabDependByThisFbx(singlePath,fbxName);
return dependPrefab;
}
return null;
}
GameObject GetPrefabDependByThisFbx(string fbxGuid,string fbxName)
{
List<string> prefabExtension = new List<string>() { ".prefab" };
string[] files = new string[10000];
if(fbxName.Contains("low")||fbxName.Contains("&ing"))
files = Directory.GetFiles(Application.dataPath + "/BundleResources/CommonRegion/InGame/Skins/Characters/", "*.*", SearchOption.AllDirectories)
.Where(s => prefabExtension.Contains(Path.GetExtension(s).ToLower())).ToArray();
if(fbxName.Contains("&lob")||fbxName.Contains("height"))
files = Directory.GetFiles(Application.dataPath + "/BundleResources/CommonRegion/OutsideGame/Skins/Characters/", "*.*", SearchOption.AllDirectories)
.Where(s => prefabExtension.Contains(Path.GetExtension(s).ToLower())).ToArray();
string prefabFileName = "";
foreach (string file in files)
{
if (Regex.IsMatch(File.ReadAllText(file), fbxGuid))
{
prefabFileName = file;
}
}
if (string.IsNullOrEmpty(prefabFileName))
{
return null;
}
else
{
// 得到的filename是类似【G:/DMM_Art_B/Assets/BundleResources/Prefabs/Characters/SkinParts\Police_03_01_height_skin.prefab】这样的
string[] words_1 = prefabFileName.Split('/');
string[] words_2 = words_1[words_1.Length - 1].Split('\\'); ; // SkinParts\Police_03_01_height_skin.prefab
string prefabName = words_2[words_2.Length-1];
string prefabPath = "";
string pathname = CombinePath(prefabName)+"/Prefabs/";
if(fbxName.Contains("low")||fbxName.Contains("&ing"))
prefabPath = Application.dataPath + "/BundleResources/CommonRegion/InGame/Skins/Characters/" +pathname+ prefabName;
if(fbxName.Contains("&lob")||fbxName.Contains("height"))
prefabPath = Application.dataPath + "/BundleResources/CommonRegion/OutsideGame/Skins/Characters/" +pathname+ prefabName;
return AssetDatabase.LoadAssetAtPath(NamingChecker.GetRelativePath(prefabPath), typeof(GameObject)) as GameObject;
}
}
string RenameFBX(string fbxName)
{
string newName = "";
return newName;
}
bool LoadFbxFile(int index)
{
string fbxName = m_FbxFile.Name;
// if (fbxName.Contains("height_") && !fbxName.Contains("lob"))
// {
// EditorUtility.DisplayDialog("错误", fbxName+"的模型文件命名不正确,缺少前缀lob或者多了height后缀!", "我知道了");
// return false;
// // fbxName = fbxName.Replace("height_", "").Replace("&", "&lob");
// }
// else if (fbxName.Contains("low_") && !fbxName.Contains("ing"))
// {
// EditorUtility.DisplayDialog("错误", fbxName+"的模型文件命名不正确,缺少前缀ing或者多了low后缀!", "我知道了");
// return false;
// // fbxName = fbxName.Replace("low_", "").Replace("&", "&ing");
// }
// if (!fbxName.Contains("mdl&"))
// {
// EditorUtility.DisplayDialog("警告", fbxName+"的模型文件命名不正确缺少前缀!", "我知道了");
// return;
// }
if(!m_IsOld)
{
m_FolderPath = CreateFolder(fbxName);
m_FbxPath = m_FolderPath + fbxName;
mFolderPathList.Add(index, m_FolderPath);
mFbxPathList.Add(index,m_FbxPath);
if (File.Exists(m_FbxPath))
{
File.Delete(m_FbxPath);
}
m_FbxFile.CopyTo(m_FbxPath);
}
else
{
m_FolderPath = m_OldFBXPath;
m_FbxPath = m_FolderPath+fbxName;
if (File.Exists(m_FbxPath))
{
File.Delete(m_FbxPath);
}
m_FbxFile.CopyTo(m_FbxPath);
}
/*if (!Directory.Exists(m_FolderPath))
{
// NamingChecker.PopupErrorMessage("创建文件夹失败:" + m_FolderPath);
}*/
AssetDatabase.Refresh();
// 如果是AnimPrefab则需要reimport一次,否则无法自动挂上Animation脚本(刚导入只能是Animator)
if (fbxName.Contains(NamingChecker.AnimPattern))
{
ModelImporter mi = AssetImporter.GetAtPath(NamingChecker.GetRelativePath(m_FbxPath)) as ModelImporter;
mi.SaveAndReimport();
}
// 这里就可以开始分析skinpart命名是否规范
// if(m_IsOld)
// {
//
// }
// else
// {
// if (!NamingChecker.SkinpartCheck(GetFbxGameobject()))
// {
// Clear();
// return;
// }
// }
return true;
}
string LODCombinePath(string prefabName)
{
string realpath = String.Empty;
string path = "SkinParts";
string feature = "";
string config = "";
string[] splitname = prefabName.Split('_');
if (prefabName.Contains("&ing") || prefabName.Contains("&lob"))
{
if (splitname.Length >= 4)
{
string[] nameList = splitname[0].Split('&');
feature = $"{nameList[1].Replace("lob","").Replace("ing","")}_{splitname[1]}";
config = splitname[2];
realpath = $"{feature}/{path}/{config}";
return realpath;
}
}
else
{
//兼容原版fbx导入
if (splitname.Length > 4)
{
feature = $"{splitname[0].Replace("mdl&","")}_{splitname[1]}";
config = splitname[2];
}
realpath = $"{feature}/{path}/{config}";
}
return realpath;
}
string CombinePath(string prefabName)
{
string realpath = String.Empty;
string path = "SkinParts";
string feature = "";
string config = "";
string[] splitname = prefabName.Split('_');
if (prefabName.Contains("&ing") || prefabName.Contains("&lob"))
{
if (splitname.Length >= 4)
{
// feature = $"{splitname[1]}_{splitname[2]}";
// config = splitname[3];
string[] nameList = splitname[0].Split('&');
string frontDelete = nameList[0] + "&";
feature =
$"{splitname[0].Replace("mdl&", "").Replace("pfb&", "").Replace(frontDelete, "").Replace("lob", "").Replace("ing", "")}_{splitname[1]}";
config = splitname[2];
}
realpath = $"{feature}/{path}/{config}";
}
else
{
//兼容原版prefab导入
if (splitname.Length >= 4)
{
feature = $"{splitname[0].Replace("mdl&","").Replace("pfb&","")}_{splitname[1]}";
config = splitname[2];
}
realpath = $"{feature}/{path}/{config}";
}
return realpath;
}
void CreatePrefabFodler(string path)
{
string dirPath = Application.dataPath + path.Replace("Assets/", "/");
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
if (!Directory.Exists(m_FolderPath))
{
NamingChecker.PopupErrorMessage("创建文件夹失败:" + m_FolderPath);
}
}
string CreateFolder(string fbxName)
{
string path = "";
if (fbxName.Contains("&ing")||fbxName.Contains("low"))
{
path = m_FbxDirIng + LODCombinePath(fbxName)+"/Models/";
}else if (fbxName.Contains("&lob")||fbxName.Contains("height"))
{
path = m_FbxDirLob + LODCombinePath(fbxName)+"/Models/";
}else
Debug.LogError(fbxName+"FBX命名不规范,未包含前缀lob or ing!");
string dirPath = Application.dataPath + path;
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
return dirPath;
}
string GetFbxDirectry(string fbxName)
{
string rst = "";
string[] wordList = fbxName.Split('_');
rst = wordList[0] + wordList[1] + "/SkinParts/" + wordList[2] + "/";
return rst;
}
string GetFbxName(string assetPath)
{
string[] wordList = assetPath.Split('/');
return wordList[wordList.Length - 1].Split('.')[0];//TODO
}
#endregion
#region CreatePrefab
void OnClickCreateButton(bool isSuccess = true)
{
if (isSuccess == false)
{
return;
}
m_PrefabPath = "";
if (m_FolderPath == "")
{
return;
}
for (int i = 0; i < mFolderPathList.Count; i++)
{
GameObject fbxObject = GetFbxGameobject(mFolderPathList[i],mFbxFileList[i]);
// WriteSuiteLevel();
// 性能检查分析
// if (!DataAnalysisUtility.IsInIgnoreList(fbxObject.name) && !DataAnalysisUtility.ResourcesDataCheck(fbxObject))
// {
// //此处先忽略
// Clear();
// return;
// }
CreatePrefab(ref fbxObject,i);
}
}
void WriteSuiteLevel()
{
string fbxName = m_FbxFile.Name.Replace(".FBX","");
string writeLine = fbxName + "*" + (int)m_SuiteLevel;
StreamReader sr = null;
if (!File.Exists(m_SuiteLevelPath))
{
File.Create(m_SuiteLevelPath).Dispose();
}
sr = new StreamReader(m_SuiteLevelPath, Encoding.Default);
string readStr = "";
List<string> content = new List<string>();
// 先缓存下所有除了本次处理fbx信息以外
while (sr != null && (readStr = sr.ReadLine()) != null)
{
if (!readStr.Contains(fbxName))
{
content.Add(readStr);
}
}
sr.Close();
// 重写文件内容
StreamWriter sw = new StreamWriter(m_SuiteLevelPath, false);
foreach(string str in content)
{
sw.WriteLine(str);
}
sw.Close();
// 末尾补上新改的一段
FileInfo fi = new FileInfo(m_SuiteLevelPath);
sw = fi.AppendText();
sw.WriteLine(writeLine);
sw.Close();
sw.Dispose();
}
GameObject GetFbxGameobject(string m_FolderPath,FileInfo m_FbxFile)
{
DirectoryInfo direction = new DirectoryInfo(m_FolderPath);
FileInfo[] fbxFiles = direction.GetFiles("*.fbx", SearchOption.AllDirectories);
string fbxFileChoosed = "";
foreach (FileInfo fbxfile in fbxFiles)
{
if (fbxfile.Name.Equals(m_FbxFile.Name))
{
fbxFileChoosed = fbxfile.FullName;
break;
}
}
string relativePath = NamingChecker.GetRelativePath(fbxFileChoosed);
Transform fbxTrans = AssetDatabase.LoadAssetAtPath(relativePath, typeof(Transform)) as Transform;
if (m_FbxSenceObject != null) // 不要重复生成,关闭的时候清不掉
{
DestroyImmediate(m_FbxSenceObject.gameObject);
}
m_FbxSenceObject = Instantiate(fbxTrans).gameObject;
return m_FbxSenceObject;
}
void CreatePrefab(ref GameObject fbxGameObject,int index)
{
string prefabName = "";
string realPrefabName = "";
if (m_IsOld)
{
prefabName = m_OldPrefab.name;
}
else
{
prefabName = fbxGameObject.name.Split('(')[0];
realPrefabName = GetPrefabName(prefabName);
prefabName = DropPostfix(prefabName);
}
string pathname = "";
string instPrefabPath = "";
pathname = CombinePath(prefabName)+"/Prefabs/";
if (prefabName.Contains("&ing")||prefabName.Contains("low"))
{
instPrefabPath = m_PrefabDirIng + pathname;
CreatePrefabFodler(instPrefabPath);
m_PrefabPath = instPrefabPath + realPrefabName + ".prefab";
LOD_m_PrefabPath = LOD_m_PrefabPath + instPrefabPath + realPrefabName + ".prefab\n";
mPrefabPathList.Add(index, m_PrefabPath);
}
else if(prefabName.Contains("&lob")||prefabName.Contains("height"))
{
instPrefabPath = m_PrefabDirLob + pathname;
CreatePrefabFodler(instPrefabPath);
m_PrefabPath = instPrefabPath+ realPrefabName + ".prefab";
LOD_m_PrefabPath = LOD_m_PrefabPath + instPrefabPath + realPrefabName + ".prefab\n";
mPrefabPathList.Add(index,m_PrefabPath);
}
else
{
Debug.LogError(prefabName+"资源命名缺少前缀ing or lob!");
}
// 【注意】不能使用绝对路径!https://blog.csdn.net/MAOMAOXIAOHUO/article/details/51204230
Material defaultMat = AssetDatabase.LoadAssetAtPath(m_DefaultMatPath, typeof(Material)) as Material;
// Dictionary<string, string> dict = new Dictionary<string, string>();
// if (m_IsOld)
// {
// // 拿到当前项目里已经存在的prefab中的材质与mesh映射关系
// dict = GetMaterialRelationFromOldPrefab();
// }
// fbxGameObject.name = fbxGameObject.name.Replace("mdl&", "").Replace("(Clone)", "");
// if (m_IsOld)
// {
// // 赋予新生成的go材质
// foreach (Transform temp in fbxGameObject.transform)
// {
// if (temp.GetComponent<SkinnedMeshRenderer>() != null)
// {
// string matPath = "";
// if (dict.TryGetValue(temp.name, out matPath))
// {
// temp.GetComponent<SkinnedMeshRenderer>().sharedMaterial = AssetDatabase.LoadAssetAtPath(matPath, typeof(Material)) as Material;
// }
// }
// }
// }
// else
// {
DMMCharacterRevisionWindow.LODLoadPresetToGameObject(ref fbxGameObject,currentAssetLodLevel,currentAssetSceneType,realPrefabName);
// }
// 这一段是试图挂blink eye脚本
foreach (Transform temp in fbxGameObject.transform)
{
foreach (string m_name in ModelName)
{
if (temp.gameObject.name.Contains(m_name) && temp.GetComponent<SkinnedMeshRenderer>() != null)
{
if (m_IsLobby && temp.gameObject.name.Contains(BlinkFaceTag) && temp.gameObject.GetComponent<BlinkController>() == null)
{
string characterTag = prefabName.Split('_')[0] + "_" + prefabName.Split('_')[1];
string[] faceNames;
bool hasBlinkface = m_BlinkFaceDict.TryGetValue(characterTag, out faceNames);
if (hasBlinkface)
{
// 挂脚本
temp.GetComponent<SkinnedMeshRenderer>().sharedMaterial = defaultMat;
BlinkController ctrl = temp.gameObject.AddComponent<BlinkController>();
ctrl.m_OpenEyesMatName = faceNames[0];
ctrl.mCloseEyesMatName = faceNames[1];
}
}
break;
}
}
}
string DynaMicPath = AddDynamicBoneData(Path.GetFileNameWithoutExtension(mPrefabPathList[index]));
PrefabUtility.SaveAsPrefabAssetAndConnect(fbxGameObject, mPrefabPathList[index], InteractionMode.AutomatedAction);
// GameObject m_prefabRoot = PrefabUtility.GetCorrespondingObjectFromOriginalSource(fbxGameObject) as GameObject;
AssetDatabase.SaveAssets();
DestroyImmediate(fbxGameObject.gameObject);
// 自动生成动态骨骼
// 读取prefab
Transform model = AssetDatabase.LoadAssetAtPath(mPrefabPathList[index], typeof(Transform)) as Transform;
if (m_DynamicBoneSenceObject != null) // 不要重复生成,关闭的时候清不掉
{
DestroyImmediate(m_DynamicBoneSenceObject.gameObject);
}
m_DynamicBoneSenceObject = Instantiate(model).gameObject;
// 找出标记父节点并初始化一系列成员变量
ProcessPrefabToInit(ref m_DynamicBoneSenceObject);
//如果存在配置文件,就按照标准保存
if (DynaMicPath.Length > 0)
{
OnClickImportDynamicBoneFileByName(DynaMicPath);
}
// 根据m_TagToDynamicBoneParamDict动态生成可调节Dynamic Bone参数
RePaintDynamicBoneParamsPanel();
// 在对应部位挂HeadBoneAttach
AddHeadBoneAttach();
// 保存prefab
SaveDynamicBonePrefab();
}
/// <summary>
/// 缓存导入,已有的dynamic配置参数
/// </summary>
/// <param name="DynamicBoneName"></param>
string AddDynamicBoneData(string DynamicBoneName)
{
string objectName = DynamicBoneName.Split('(')[0];
string pathName;
string DynamicPath = "";
pathName = CombinePath(objectName) + "/Prefabs/";
string assetPath = "";
if (objectName.Contains("&ing") || objectName.Contains("low"))
{
assetPath = m_PrefabDirIng + pathName + objectName + ".prefab";
}
else if (objectName.Contains("&lob") || objectName.Contains("height"))
{
assetPath = m_PrefabDirLob + pathName + objectName + ".prefab";
}
Transform model = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Transform)) as Transform;
if (model != null)
{
GameObject DynamicObj = Instantiate(model).gameObject;
ProcessPrefabToInit(ref DynamicObj);
DynamicPath = OnClickExportDynamicBoneFileByName(DynamicObj.name);
DestroyImmediate(DynamicObj);
}
return DynamicPath;
}
void RePaintDynamicBoneParamsPanel()
{
this.Repaint();
}
Dictionary<string, string> GetMaterialRelationFromOldPrefab()
{
Dictionary<string, string> rst = new Dictionary<string, string>();
foreach (Transform temp in m_OldPrefab.transform)
{
if (temp.GetComponent<SkinnedMeshRenderer>() != null)
{
Material mat = temp.GetComponent<SkinnedMeshRenderer>().sharedMaterial;
rst.Add(temp.name, AssetDatabase.GetAssetPath(mat));
}
}
return rst;
}
// 去掉_SRN后缀
string DropPostfix(string name)
{
return name.Replace("mdl", "pfb");
// string postfix = NamingChecker.GetPostfix(name);
// bool isValid = NamingChecker.IsValidPostfix(postfix);
// if (isValid)
// {
// return name.Replace("_" + postfix, "").Replace("mdl", "pfb");
// }
// else
// {
// return name.Replace("mdl", "pfb");
// }
}
/// <summary>
/// 获取fbx对应的prefab名字
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
string GetPrefabName(string name)
{
string[] nameList = name.Split('&');
eAssetLodLevel level = eAssetLodLevel.None;
string finalName = String.Empty;
foreach (KeyValuePair<string,eAssetLodLevel> keyValuePair in levelDic)
{
if (nameList[0].Contains(keyValuePair.Key))
{
level = keyValuePair.Value;
currentAssetLodLevel = level;
break;
}
}
foreach (KeyValuePair<string,eAssetSceneType> keyValuePair in sceneDic)
{
if (nameList[1].Contains(keyValuePair.Key))
{
currentAssetSceneType = keyValuePair.Value;
}
}
if (nameList.Length == 2 )
{
string[] logicNamelist = nameList[1].Split('_');
if (logicNamelist.Length >= 4)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Clear();
for (int i = 0; i < 3; i++)
{
stringBuilder.Append(logicNamelist[i] + "_");
}
stringBuilder.Append(logicNamelist[3]);
string prefabName = stringBuilder.ToString();
//识别补充后缀
if (!prefabName.Contains("_skin"))
{
prefabName = prefabName + "_skin";
}
stringBuilder.Clear();
finalName = LMNAResMapUtil.AssembleAssetName(prefabName, eAssetFunctionType.GameObject,
level);
}
}
return finalName;
}
// 处理需要蒙皮的特效部位
void ProcessEffectPart(ref GameObject prefab)
{
foreach(Transform temp in prefab.transform)
{
if (!temp.name.Contains(NamingChecker.AttachmentPatterns[2])) continue;
// 新建一个子go
GameObject go = new GameObject();
go.transform.SetParent(temp);
// 把自己挂着的skinmeshrenderer剪切到子go上
SkinnedMeshRenderer smr = temp.GetComponent<SkinnedMeshRenderer>();
UnityEditorInternal.ComponentUtility.CopyComponent(smr);
UnityEditorInternal.ComponentUtility.PasteComponentAsNew(go);
// 挂上PlayerEffectController
PlayerEffectController pec = temp.gameObject.AddComponent<PlayerEffectController>();
pec.m_Effect = go;
}
}
#endregion
#region Clear
void OnClickClearButton()
{
ClearFbxAndTextures(() =>
{
NamingChecker.PopupErrorMessage("成功清除" + m_FolderPath + "下新导入的资源!");
});
ClearPrefabFolder(() =>
{
NamingChecker.PopupErrorMessage("成功清除" + m_PrefabPath + "!");
});
AssetDatabase.Refresh();
this.Repaint();
}
void Clear(System.Action onFbxSucc = null, System.Action onPrefabSucc = null)
{
ClearFbxAndTextures(onFbxSucc);
ClearPrefabFolder(onPrefabSucc);
m_OldPrefab = null; ;
AssetDatabase.Refresh();
this.Repaint();
}
void ClearFbxAndTextures(System.Action onSucc = null)
{
if (!Directory.Exists(m_FolderPath))
return;
// 删除fbx同目录下所有文件
string tempMatDir = m_FolderPath;
DirectoryInfo tempDirection = new DirectoryInfo(tempMatDir);
FileInfo[] files = tempDirection.GetFiles("*.*", SearchOption.TopDirectoryOnly);
File.Delete(m_FbxPath);
m_FbxPath = "";
m_FolderPath = "";
if (onSucc != null) onSucc();
}
void ClearPrefabFolder(System.Action onSucc = null)
{
if (!File.Exists(m_PrefabPath))
return;
File.Delete(m_PrefabPath);
m_PrefabPath = "";
if (onSucc != null) onSucc();
}
#endregion
#region DynamicBone
void OnClickCreateLODDynamicBoneParams()
{
if (string.IsNullOrEmpty(m_DynamicBonePrefabPath))
{
return;
}
// 读取prefab
Transform model = AssetDatabase.LoadAssetAtPath(m_DynamicBonePrefabPath, typeof(Transform)) as Transform;
if (m_DynamicBoneSenceObject != null) // 不要重复生成,关闭的时候清不掉
{
DestroyImmediate(m_DynamicBoneSenceObject.gameObject);
}
m_DynamicBoneSenceObject = Instantiate(model).gameObject;
// 找出标记父节点并初始化一系列成员变量
ProcessPrefabToInit(ref m_DynamicBoneSenceObject);
// 根据m_TagToDynamicBoneParamDict动态生成可调节Dynamic Bone参数
RePaintLODDynamicBoneParamsPanel();
}
void OnClickDynamicBoneButton()
{
// 在对应部位挂HeadBoneAttach
AddHeadBoneAttach();
// 保存prefab
SaveDynamicBonePrefab();
}
void OnClickAddCollider(string key)
{
int idx = 0;
LODDynamicColliderData newItem;
List<LODDynamicColliderData> tempList = new List<LODDynamicColliderData>();
LODDynamicBoneParams tempDictData = m_TagToDynamicBoneParamDict[key]; // 用于给字典赋值
// 添加碰撞体
if (m_TagToDynamicBoneParamDict[key].colliderDataList != null)
{
tempList = m_TagToDynamicBoneParamDict[key].colliderDataList;
idx = tempList.Count; // 目前有多少个collider了
}
// 点击添加键时就需要创建并挂上transform
string name = "Collider_" + idx;
GameObject collider = new GameObject();
collider.name = name;
collider.transform.SetParent(GetTransformByName(key).GetChild(0));
DynamicBoneCollider dc = collider.AddComponent<DynamicBoneCollider>();
newItem = new LODDynamicColliderData(name, 0.3f, null, collider.transform);
dc.m_Radius = newItem.radius;
tempList.Add(newItem);
tempDictData = new LODDynamicBoneParams(tempDictData.root, tempDictData.Damping, tempDictData.Elasticty,
tempDictData.Stiffness, tempDictData.Inert, tempDictData.Friction, tempDictData.Radius,
tempList);
m_TagToDynamicBoneParamDict[key] = tempDictData;
RePaintLODDynamicBoneParamsPanel();
}
void OnClickRemoveCollider(string key)
{
if (m_TagToDynamicBoneParamDict[key].colliderDataList == null) return;
int idx = m_TagToDynamicBoneParamDict[key].colliderDataList.Count;
List<LODDynamicColliderData> tempList = m_TagToDynamicBoneParamDict[key].colliderDataList;
LODDynamicBoneParams tempDictData = m_TagToDynamicBoneParamDict[key]; // 用于给字典赋值
DestroyImmediate(tempList[idx - 1].colTrans.gameObject);
tempList.Remove(tempList[idx - 1]);
tempDictData = new LODDynamicBoneParams(tempDictData.root, tempDictData.Damping, tempDictData.Elasticty,
tempDictData.Stiffness, tempDictData.Inert, tempDictData.Friction, tempDictData.Radius,
tempList);
m_TagToDynamicBoneParamDict[key] = tempDictData;
RePaintLODDynamicBoneParamsPanel();
}
// 导入Dynamicbone配置文件
void OnClickImportDynamicBoneFile()
{
TryReadSBFile();
}
void OnClickImportDynamicBoneFileByName(string path)
{
TryReadSBFileByName(path);
}
// 导出Dynamicbone配置文件
void OnClickExportDynamicBoneFile()
{
WriteSBInfo();
EditorUtility.DisplayDialog("成功", "导出完毕", "确定");
AssetDatabase.Refresh();
}
string OnClickExportDynamicBoneFileByName(string name)
{
string path = WriteSBInfoByName(name);
// EditorUtility.DisplayDialog("成功", "导出完毕", "确定");
AssetDatabase.Refresh();
return path;
}
void SaveDynamicBonePrefab()
{
string senceObjectName = m_DynamicBoneSenceObject.name.Split('(')[0];
string pathname = "";
pathname = CombinePath(senceObjectName)+"/Prefabs/";
// string dirPath = Application.dataPath + m_PrefabDirLob + pathname.Replace("Assets/", "/");
// if (!Directory.Exists(dirPath))
// {
// Directory.CreateDirectory(dirPath);
// }
if (senceObjectName.Contains("&ing")||senceObjectName.Contains("low"))
PrefabUtility.SaveAsPrefabAsset(m_DynamicBoneSenceObject, m_PrefabDirIng +pathname+ senceObjectName + ".prefab");
else if(senceObjectName.Contains("&lob")||senceObjectName.Contains("height"))
PrefabUtility.SaveAsPrefabAsset(m_DynamicBoneSenceObject, m_PrefabDirLob +pathname+ senceObjectName + ".prefab");
AssetDatabase.SaveAssets();
}
void ProcessPrefabToInit(ref GameObject senceObject)
{
m_SkinPartTransformList.Clear();
m_TaggedTransformDict.Clear();
m_TagToDynamicBoneParamDict.Clear();
// 初始化m_SkinPartTransformList
for (int i = 0; i < senceObject.transform.childCount; i++)
{
foreach (string part in ModelName)
{
if (senceObject.transform.GetChild(i).name.Contains(part) &&
!senceObject.transform.GetChild(i).name.Contains(part + "_ex") &&
!senceObject.transform.GetChild(i).name.Contains(part + "_fx"))
{
m_SkinPartTransformList.Add(senceObject.transform.GetChild(i));
break;
}
}
}
// 初始化m_TaggedTransformDict和m_TagToDynamicBoneParamDict
foreach (Transform child in senceObject.GetComponentsInChildren<Transform>())
{
foreach (string tag in DynamicBoneTag)
{
if (child.name.Contains(tag))
{
m_TaggedTransformDict.Add(child, child.parent.name);
LODDynamicBoneParams param = GetLODDynamicBoneParams(child);
m_TagToDynamicBoneParamDict.Add(child.name, param);
break;
}
}
}
}
void RePaintLODDynamicBoneParamsPanel()
{
this.Repaint();
}
void AddHeadBoneAttach()
{
foreach (KeyValuePair<Transform, string> part in m_TaggedTransformDict)
{
Transform targetTrans = null;
if (part.Key.name.Contains("CLOTHES_"))
{
targetTrans = m_SkinPartTransformList.Find(x => x.name.Contains("clothes"));
}
else if (part.Key.name.Contains("HEAD_"))
{
targetTrans = m_SkinPartTransformList.Find(x => x.name.Contains("head"));
}
else if (part.Key.name.Contains("HAND_"))
{
targetTrans = m_SkinPartTransformList.Find(x => x.name.Contains("hand"));
}
else if (part.Key.name.Contains("SHOES_"))
{
targetTrans = m_SkinPartTransformList.Find(x => x.name.Contains("shoes"));
}
else if (part.Key.name.Contains("TROUSERS_"))
{
targetTrans = m_SkinPartTransformList.Find(x => x.name.Contains("trousers"));
}
if (targetTrans == null)
{
Debug.LogError("在绑DynamicBone时未找到" + part.Key.name + "对应的部位Transform!");
}
else
{
bool isShouldAdd = true; // 检查一下是否已经挂了一模一样的attachment脚本
HeadBoneAttach[] comps = targetTrans.gameObject.GetComponents<HeadBoneAttach>();
HeadBoneAttach comp;
Transform attachment = part.Key.GetChild(0);
for (int i = 0; i < comps.Length; i++)
{
if (comps[i].m_Attachment == attachment && comps[i].m_HeadBoneName.Equals(part.Value))
{
isShouldAdd = false;
break;
}
}
if (isShouldAdd)
{
comp = targetTrans.gameObject.AddComponent<HeadBoneAttach>();
comp.m_Attachment = attachment;
comp.m_HeadBoneName = part.Value;
}
part.Key.SetParent(targetTrans);
// 骨骼串的跟节点挂DynamicBone脚本
SetLODDynamicBoneParams(ref attachment, m_TagToDynamicBoneParamDict[part.Key.name]);
// collider的attachment
// TODO:我忘了。。DB需不需要和SB一样都要对collider的transform也挂上HeadBoneAttach脚本?先注释掉
/*
LODDynamicBoneParams dbParams = m_TagToDynamicBoneParamDict[part.Key.name];
List<LODDynamicColliderData> collParams = dbParams.colliderDataList;
HeadBoneAttach collComp;
if (collParams != null)
{
for (int i = 0; i < collParams.Count; i++)
{
bool isShouldAddCollAttach = !string.IsNullOrEmpty(collParams[i].rootName);
for (int j = 0; j < comps.Length; j++)
{
// 检查一下是否已经挂了一模一样的attachment脚本
if (comps[j].m_Attachment == null || string.IsNullOrEmpty(comps[j].m_HeadBoneName))
continue;
if (comps[j].m_Attachment.name.Equals(collParams[i].name) &&
comps[j].m_HeadBoneName.Equals(collParams[i].rootName))
{
isShouldAddCollAttach = false;
break;
}
}
if (isShouldAddCollAttach)
{
collComp = targetTrans.gameObject.AddComponent<HeadBoneAttach>();
collComp.m_Attachment = collParams[i].colTrans;
collComp.m_HeadBoneName = collParams[i].rootName;
}
}
}
*/
}
}
}
Transform GetTransformByName(string name)
{
foreach (Transform VARIABLE in m_DynamicBoneSenceObject.transform.GetComponentsInChildren<Transform>())
{
if (VARIABLE.name.Equals(name))
return VARIABLE;
}
return null;
}
LODDynamicBoneParams GetLODDynamicBoneParams(Transform trans)
{
LODDynamicBoneParams rst = new LODDynamicBoneParams(trans.GetChild(0), 0.02f, 0.08f, 0.06f, 0.8f, 0.6f, 0.02f, null); // TODO: 这个经验数值应该也用不了
if (trans.childCount == 0 || trans.GetChild(0).childCount == 0)
return rst;
DynamicBone root = trans.GetChild(0).gameObject.GetComponent<DynamicBone>();
if (root == null)
{
root = trans.GetChild(0).gameObject.AddComponent<DynamicBone>();
}
rst.root = trans.GetChild(0);
rst.Damping = root.m_Damping;
rst.Elasticty = root.m_Elasticity;
rst.Inert = root.m_Inert;
rst.Friction = root.m_Friction;
rst.Stiffness = root.m_Stiffness;
rst.Radius = root.m_Radius;
rst.colliderDataList = new List<LODDynamicColliderData>();
if(root.m_Colliders!=null)
{
for (int i = 0; i < root.m_Colliders.Count; i++)
{
DynamicBoneCollider dc = root.m_Colliders[i] as DynamicBoneCollider;
string rootName = GetAttachmentRootName(dc.transform);
LODDynamicColliderData collData = new LODDynamicColliderData(dc.name, dc.m_Radius, rootName, dc.transform);
rst.colliderDataList.Add(collData);
}
}
return rst;
}
void SetLODDynamicBoneParams(ref Transform trans, LODDynamicBoneParams param)
{
if (trans == null || param.root == null)
return;
DynamicBone db = trans.GetComponent<DynamicBone>();
if (db == null)
{
db = trans.gameObject.AddComponent<DynamicBone>();
}
db.m_Root = trans;
db.m_Damping = param.Damping;
db.m_Elasticity = param.Elasticty;
db.m_Stiffness = param.Stiffness;
db.m_Inert = param.Inert;
db.m_Friction = param.Friction;
db.m_Radius = param.Radius;
}
string GetAttachmentRootName(Transform collider)
{
string name = "";
HeadBoneAttach[] partAttaches = collider.GetComponentsInParent<HeadBoneAttach>();
if (partAttaches != null)
{
for (int i = 0; i < partAttaches.Length; i++)
{
if (partAttaches[i].m_Attachment == collider)
{
name = partAttaches[i].m_HeadBoneName;
}
}
}
return name;
}
Transform GetCollider(Transform parent, string name)
{
for (int i = 0; i < parent.childCount; i++)
{
if (parent.GetChild(i).name.Equals(name))
return parent.GetChild(i);
}
return null;
}
void ClearScenePrefabs()
{
if (m_FbxSenceObject != null && m_FbxSenceObject.gameObject != null)
{
GameObject.DestroyImmediate(m_FbxSenceObject.gameObject);
}
if (m_DynamicBoneSenceObject != null && m_DynamicBoneSenceObject.gameObject != null)
{
GameObject.DestroyImmediate(m_DynamicBoneSenceObject.gameObject);
}
}
#endregion
#region Export/ImportDynamicBoneInfo
string GetDynamicBoneInfoFilePath()
{
if (m_DynamicBoneSenceObject != null && m_DynamicBoneSenceObject.gameObject != null)
{
string fileName = m_DynamicBoneSenceObject.transform.name.Replace("(Clone)", ""); // 就是prefab同名
return m_DynamicBoneParamDir + fileName + ".txt";
}
else
{
EditorUtility.DisplayDialog("警告", "先生成Dynamicbone参数才能正确取到文件名字!", "好吧");
return "";
}
}
/// <summary>
/// 通过名字,拿到对应的动态骨骼配置文件
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
string GetDynamicBoneInfoFilePathByName(string name)
{
string fileName = name.Replace("(Clone)", ""); // 就是prefab同名
return m_DynamicBoneParamDir + fileName + ".txt";
}
/// <summary>
/// 通过名字写入动态骨骼配置文件
/// </summary>
/// <param name="name"></param>
string WriteSBInfoByName(string name)
{
string path = GetDynamicBoneInfoFilePathByName(name);
StreamWriter sw;
if (!File.Exists(path))
{
File.Create(path).Dispose();
}
else
{
// 清空
File.WriteAllText(path, string.Empty);
}
FileInfo fi = new FileInfo(path);
sw = fi.AppendText();
// 写入m_TagToDynamicBoneParamDict
WriteSBParamInfo(sw);
sw.Close();
sw.Dispose();
AssetDatabase.Refresh();
return path;
}
void WriteSBInfo()
{
string path = GetDynamicBoneInfoFilePath();
StreamWriter sw;
if (!File.Exists(path))
{
File.Create(path).Dispose();
}
else
{
// 清空
File.WriteAllText(path, string.Empty);
}
FileInfo fi = new FileInfo(path);
sw = fi.AppendText();
// 写入m_TagToDynamicBoneParamDict
WriteSBParamInfo(sw);
sw.Close();
sw.Dispose();
}
void TryReadSBFile()
{
string path = GetDynamicBoneInfoFilePath();
if (!File.Exists(path))
{
EditorUtility.DisplayDialog("警告", "找不到对应的DynamicBone参数文件!", "好吧");
}
if (EditorUtility.DisplayDialog("警告", "确定要覆盖DynamicBone参数么?", "确定"))
{
LoadSBFile();
}
}
/// <summary>
/// 加载动态骨骼配置文件(通过名字)
/// </summary>
/// <param name="path"></param>
void TryReadSBFileByName(string path)
{
// string path = GetDynamicBoneInfoFilePathByName(name);
// if (!File.Exists(path))
// {
// EditorUtility.DisplayDialog("警告", "找不到对应的DynamicBone参数文件!", "好吧");
// }
// if (EditorUtility.DisplayDialog("警告", "确定要覆盖DynamicBone参数么?", "确定"))
// {
// LoadSBFileByName(name);
// }
if (File.Exists(path))
{
LoadSBFileByName(path);
}
}
void LoadSBFile()
{
string path = GetDynamicBoneInfoFilePath();
StreamReader sr = new StreamReader(path, Encoding.Default);
string readStr = "";
string fileInfoString = ""; // 整个文件的内容都存入
while (sr != null && (readStr = sr.ReadLine()) != null)
{
fileInfoString += readStr;
}
sr.Close();
SetLODDynamicBoneParams(fileInfoString);
Repaint();
EditorUtility.DisplayDialog("成功", "导入完毕", "确定");
}
void LoadSBFileByName(string path)
{
// string path = GetDynamicBoneInfoFilePathByName(name);
StreamReader sr = new StreamReader(path, Encoding.Default);
string readStr = "";
string fileInfoString = ""; // 整个文件的内容都存入
while (sr != null && (readStr = sr.ReadLine()) != null)
{
fileInfoString += readStr;
}
sr.Close();
SetLODDynamicBoneParams(fileInfoString);
Repaint();
// EditorUtility.DisplayDialog("成功", "导入完毕", "确定");
}
void SetLODDynamicBoneParams(string fileInfoString)
{
string[] tags = fileInfoString.Split('!');
string currTagKey;
LODDynamicBoneParams currDBParam;
foreach (string tagStr in tags)
{
currTagKey = "";
currDBParam = new LODDynamicBoneParams(null, 0.02f, 0.08f, 0.06f, 0.8f, 0.6f, 0.02f, null);
if (string.IsNullOrEmpty(tagStr)) continue;
string[] pairStrs = tagStr.Split('%');
foreach (string pairStr in pairStrs)
{
if (string.IsNullOrEmpty(pairStr)) continue;
string[] pair = pairStr.Split(':');
string key = "";
string value = "";
if (pair.Length != 2)
{
Debug.LogError("数据对" + pairStr + "解析失败!");
}
if (!string.IsNullOrEmpty(pair[0])) key = pair[0];
if (!string.IsNullOrEmpty(pair[1])) value = pair[1];
// 简陋的字符匹配
if (key.Contains("TagName"))
{
currTagKey = value;
if (m_TagToDynamicBoneParamDict.ContainsKey(currTagKey))
{
currDBParam = m_TagToDynamicBoneParamDict[currTagKey]; // 应该是最先被赋值的,保证后面参数修改的都是拿到了有值的currDBParam
}
}
else if (key.Contains("DB_Root"))
{
currDBParam.root = GetRootFromPath(value);
}
else if (key.Contains("DB_Damping"))
{
currDBParam.Damping = float.Parse(value);
}
else if (key.Contains("DB_Elasticty"))
{
currDBParam.Elasticty = float.Parse(value);
}
else if (key.Contains("DB_Stiffness"))
{
currDBParam.Stiffness = float.Parse(value);
}
else if (key.Contains("DB_Inert"))
{
currDBParam.Inert = float.Parse(value);
}
else if (key.Contains("DB_Friction"))
{
currDBParam.Friction = float.Parse(value);
}
else if (key.Contains("DB_Radius"))
{
currDBParam.Radius = float.Parse(value);
}
else if (key.Contains("SBC_List"))
{
SetColliders(currTagKey, ref currDBParam.colliderDataList, value);
}
else
{
Debug.LogError("读取文件发现异常内容:" + pairStr);
}
}
m_TagToDynamicBoneParamDict[currTagKey] = currDBParam;
}
}
void SetColliders(string tagName, ref List<LODDynamicColliderData> colliderDataList, string colliderInfoStr)
{
string[] collInfoStrs = colliderInfoStr.Split('$');
foreach (string infoStrs in collInfoStrs)
{
if (string.IsNullOrEmpty(infoStrs)) continue;
string[] infoStrArray = infoStrs.Split('@');
string name = infoStrArray[1];
float radius = float.Parse(infoStrArray[2]);
string rootName = infoStrArray[3];
string[] posArray = infoStrArray[4].Split('#');
float x, y, z;
if (posArray.Length != 3)
{
Debug.LogError("读取" + name + "collider坐标失败!");
x = y = z = 0f;
}
else
{
x = float.Parse(posArray[0]);
y = float.Parse(posArray[1]);
z = float.Parse(posArray[2]);
}
// 查找colliderDataList是否存在同名Collider,存在则覆盖,不存在则新建
bool isNeedAdd = true;
LODDynamicColliderData scData;
for (int i = 0; i < colliderDataList.Count; i++)
{
scData = colliderDataList[i];
if (scData.name.Equals(name))
{
isNeedAdd = false;
// 存在,覆盖
scData.radius = radius;
scData.rootName = rootName;
scData.colTrans.localPosition = new Vector3(x, y, z);
break;
}
}
// 新建并赋值
if (isNeedAdd)
{
GameObject collider = new GameObject();
collider.name = name;
collider.transform.SetParent(GetTransformByName(tagName).GetChild(0));
collider.transform.localPosition = new Vector3(x, y, z);
DynamicBoneCollider dc = collider.AddComponent<DynamicBoneCollider>();
dc.m_Radius = radius;
scData = new LODDynamicColliderData(name, radius, rootName, collider.transform);
colliderDataList.Add(scData);
}
}
}
void WriteSBParamInfo(StreamWriter sw)
{
Dictionary<string, string> TagInfo = new Dictionary<string, string>();
foreach (KeyValuePair<string, LODDynamicBoneParams> pair in m_TagToDynamicBoneParamDict)
{
LODDynamicBoneParams param = pair.Value;
TagInfo = new Dictionary<string, string>
{
{"TagName:", pair.Key},
{"DB_Root:", CreateDynamicBoneRoot(pair.Key, param.root==null?"":param.root.name)},
{"DB_Damping:", param.Damping.ToString()},
{"DB_Elasticty:", param.Elasticty.ToString()},
{"DB_Stiffness:", param.Stiffness.ToString()},
{"DB_Inert:", param.Inert.ToString()},
{"DB_Friction:", param.Friction.ToString()},
{"DB_Radius:", param.Radius.ToString()},
{"SBC_List:", GetColliderListString(pair.Key, param.colliderDataList)}
};
sw.WriteLine('!');
foreach (KeyValuePair<string, string> tag in TagInfo)
{
sw.WriteLine('%' + tag.Key + tag.Value);
}
}
}
string GetColliderListString(string tagName, List<LODDynamicColliderData> colliderDataList)
{
string rst = "";
string singleCollDataStr = "";
if (colliderDataList == null) return "";
for (int i = 0; i < colliderDataList.Count; i++)
{
singleCollDataStr = "";
// 普通的参数普通地获取
singleCollDataStr += "@" + colliderDataList[i].name;
singleCollDataStr += "@" + colliderDataList[i].radius;
singleCollDataStr += "@" + colliderDataList[i].rootName;
// 厉害的参数遍历获取(?)
foreach (Transform trans in m_DynamicBoneSenceObject.transform.GetComponentsInChildren<Transform>())
{
if (!trans.name.Equals(tagName)) continue;
// 找到标记位下面同名的collider,拿到position
foreach (DynamicBoneCollider collider in trans.GetComponentsInChildren<DynamicBoneCollider>())
{
if (!collider.transform.name.Equals(colliderDataList[i].name)) continue;
Vector3 pos = collider.transform.localPosition;
singleCollDataStr += "@" + pos.x + "#" + pos.y + "#" + pos.z; // @-0.21#0#0
}
}
rst += singleCollDataStr + "$"; // collider单条信息以$结尾
}
return rst;
}
string CreateDynamicBoneRoot(string parentName, string childName)
{
return parentName + "/" + childName;
}
Transform GetRootFromPath(string path)
{
DynamicBone[] transList = m_DynamicBoneSenceObject.transform.GetComponentsInChildren<DynamicBone>();
foreach(DynamicBone trans in transList)
{
if(path.Contains(trans.name) &&path.Contains(trans.transform.parent.name))
{
return trans.transform;
}
}
return null;
}
#endregion
}
}