题外话,策划觉得多材质的spine导出后的名字不行,还要去修改一下spine资源导入时生成的文件名,在AsssetUtility中的IngestSpineAtlas静态方法中修改相关细节
对于资源修改最后一定要调用AssetDataBase.SaveAssets()和AssetDataBase.Refresh(),这样才会弹出提示要保存修改,不然使用的人以为就做完了,他们是不知道还需要做什么操作的,因为他们可能是策划或者美术。
先说说方案
1.下载spine的源码,模仿SpineEditorUtilities.cs,继承AssetPostprocessor,类标记为[InitializeOnLoad],然后再去写工具,监听这个接口OnPostprocessAllAssets(自动导出所有资源)
2.中规中矩自己写一套,不过自己在写工具的过程中,才到几个坑,这本身也是自己对fbx模型导出的机制不了解的原因
先说说自己踩得几个坑点,第一impoerter,第二AssetDataBase.SaveAssets和AssetDataBase.Refresh,第三AssetDataBase.Importer和AssetDataBase.Refresh
在使用ModelImporter的时候,先抛出自己的代码,使用了终极霸器
ModelImporter mi = AssetImporter.GetAtPath(fileName + ".fbx") as ModelImporter;
mi.materialLocation = ModelImporterMaterialLocation.External;
mi.materialName = ModelImporterMaterialName.BasedOnTextureName;
mi.materialSearch = ModelImporterMaterialSearch.Local;
EditorUtility.SetDirty(mi);
AssetDatabase.ImportAsset(fileName + ".fbx");
Thread.Sleep(1000);
第一个坑:AssetImporter.GetAtPath的文件名必须带后缀,否则无法成功获取资源
第二个坑:美术给的模型文件只有fbx文件和对应的一张贴图,其中之一需要我写工具自己去生成材质,然后修改shader以及shader的属性,这句话就是坑,按照这个流程和需求去做,我发现是不能成功的,为什么呢,下面就是相关三个属性的机制
枚举类型 | 枚举值 |
---|---|
ModelImporterMaterialLocation | External:从模型文件内部提取材质和贴图 InPrefab:从预制件内部提取 |
ModelImporterMaterialName | BasedOnTextureName:基于贴图名字 BasedOnMaterialName:基于材质名字 BasedOnModelNameAndMaterialName:基于材质和模型名字 BasedOnTextureName_Or_ModelNameAndMaterialName: |
ModelImporterMaterialSearch | Local: RecursiveUp: Everywhere: |
有事,拖了几天,对于资源类,记得标记dirty以及重导。这个是所有全部重导的功能,不过这个功能对于美术而言,是不完善的,因为生成的预制件美术还会做二次修改,里面的材质等等,所以不能直接全删重新生成,前几天美术就提了这样的一个需求,可以选中选中文件夹导出以及单个选中导出,就是因为上述问题。暂时这个版本不做,美术要求6月12号出包之后在做这个工具。
public static void GerenateModelPrefab(string resFolder, string prefabFolder)
{
string folderPath = Application.dataPath + "/Game/ModelResources/" + resFolder;
string assetPath = "Assets/Game/ModelResources/" + resFolder;
string saveFolder = "Assets/Resources/Model/" + prefabFolder;
Debug.LogError("模型资源目录:" + assetPath);
Debug.LogError("模型预制存放目录:" + saveFolder);
if (!Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder);
}
DirectoryInfo saveDi = new DirectoryInfo(saveFolder);
foreach (FileInfo fi in saveDi.GetFiles())
{
if (!fi.Name.Contains("membernode")
&& !fi.Name.Contains("Role")
&& !fi.Name.Contains("Role1"))
{
File.Delete(fi.FullName);
}
}
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
DirectoryInfo root = new DirectoryInfo(folderPath);
foreach (DirectoryInfo di in root.GetDirectories())
{
string fileName = assetPath + "/" + di.Name + "/" + di.Name;
Texture2D td = AssetDatabase.LoadAssetAtPath(fileName + ".png", typeof(Texture2D)) as Texture2D;
TextureImporter ti = AssetImporter.GetAtPath(fileName + ".png") as TextureImporter;
ti.textureType = TextureImporterType.Default;
ti.wrapMode = TextureWrapMode.Repeat;
EditorUtility.SetDirty(td);
EditorUtility.SetDirty(ti);
string matPath = assetPath + "/" + di.Name + "/Materials/" + di.Name + ".mat";
if (!Directory.Exists(folderPath + "/" + di.Name + "/Materials"))
{
Directory.CreateDirectory(folderPath + "/" + di.Name + "/Materials");
}
ModelImporter mi = AssetImporter.GetAtPath(fileName + ".fbx") as ModelImporter;
mi.materialLocation = ModelImporterMaterialLocation.External;
mi.materialName = ModelImporterMaterialName.BasedOnTextureName;
mi.materialSearch = ModelImporterMaterialSearch.Local;
EditorUtility.SetDirty(mi);
//资源重导
AssetDatabase.ImportAsset(fileName + ".fbx");
Thread.Sleep(1000);
//AssetDatabase.SaveAssets();
if (!File.Exists(matPath))
{
Debug.LogError("材质导出失败:" + matPath);
}
Material mt = AssetDatabase.LoadAssetAtPath<Material>(matPath);
mt.shader = Shader.Find("MiCangGame/Furniture");
mt.SetTexture("_MainTex", td);
mt.SetFloat("_BaseCellSharpness", 0.5f);
EditorUtility.SetDirty(mt);
GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(fileName + ".fbx");
go = GameObject.Instantiate(go);
go.name = di.Name;
Animator am = go.GetComponent<Animator>();
am.runtimeAnimatorController = (RuntimeAnimatorController)AssetDatabase.LoadAssetAtPath("Assets/Game/art/animation/role_new/new_role_ani/AvatarAnim_new.controller", typeof(RuntimeAnimatorController));
NavMeshModifierVolume nmmv = go.AddComponent<NavMeshModifierVolume>();
nmmv.size = new Vector3(1, 2, 1);
nmmv.center = new Vector3(0, 1, 0);
bool success = false;
PrefabUtility.SaveAsPrefabAsset(go, saveFolder + "/" + go.name + ".prefab", out success);
Debug.Log(string.Format(go.name + " 预制体保存{0}", success ? "成功" : "失败"));
GameObject.DestroyImmediate(go);
go = null;
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
spine自动导出生成预制件的工具,写的时候,对于textureimporter设置TextureImporterSettings属性时,只是刷新并没有重导,导致贴图并没有重新生成meta文件,也就是并没有保存。算是不熟悉的缘故,后来人可以看看。
public static void GenerateSpinePrefab(string resFolder, string prefabFolder)
{
string folderPath = Application.dataPath + "/Game/SpineResources/" + resFolder;
string assetPath = "Assets/Game/SpineResources/" + resFolder;
string saveFolder = "Assets/Resources/" + prefabFolder;
Debug.LogError("spine资源目录:" + assetPath);
Debug.LogError("spine预制存放目录:" + saveFolder);
DirectoryInfo saveDi = new DirectoryInfo(saveFolder);
if (Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder);
}
foreach (FileInfo fi in saveDi.GetFiles())
{
File.Delete(fi.FullName);
}
if (Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
DirectoryInfo root = new DirectoryInfo(folderPath);
foreach (DirectoryInfo di in root.GetDirectories())
{
GameObject go = new GameObject(di.Name);
SkeletonGraphic sg = go.AddComponent<SkeletonGraphic>();
string spineAsset = assetPath + "/" + di.Name + "/" + di.Name + "_SkeletonData.asset";
sg.skeletonDataAsset = AssetDatabase.LoadAssetAtPath(spineAsset, typeof(SkeletonDataAsset)) as SkeletonDataAsset;
int matCount = 0;
foreach (FileInfo fi in di.GetFiles())
{
if (fi.Extension == ".mat")
{
matCount += 1;
string matAsset = assetPath + "/" + di.Name + "/" + fi.Name;
Material mt = AssetDatabase.LoadAssetAtPath(matAsset, typeof(Material)) as Material;
mt.shader = Shader.Find("Spine/SkeletonGraphic");
mt.SetInt("_StraightAlphaInput", 0);
mt.SetFloat("_UseUIAlphaClip", 0);
EditorUtility.SetDirty(mt);
if (matCount == 1)
{
sg.material = mt;
}
}
if (fi.Extension == ".png")
{
TextureImporter ti = AssetImporter.GetAtPath(assetPath + "/" + di.Name + "/" + fi.Name) as TextureImporter;
ti.alphaIsTransparency = false;
//TextureImporterSettings ts = new TextureImporterSettings();
//ts.textureType = TextureImporterType.Sprite;
//ts.alphaIsTransparency = false;
//ts.ApplyTextureType(ts.textureType);
//ti.ReadTextureSettings(ts);
//ti.SetTextureSettings(ts);
AssetDatabase.ImportAsset(assetPath + "/" + di.Name + "/" + fi.Name);
//EditorUtility.SetDirty(ti);
//AssetDatabase.Refresh();
}
}
sg.allowMultipleCanvasRenderers = matCount > 1;
sg.startingAnimation = resFolder == "Emoji" ? "animation" : "idle";
sg.startingLoop = true;
if (!Directory.Exists(saveFolder))
{
Debug.Log("目录不存在:" + saveFolder);
Directory.CreateDirectory(saveFolder);
}
bool success = false;
string prefabName = saveFolder + "/" + di.Name + ".prefab";
if (File.Exists(prefabName))
{
//Debug.LogError(prefabName);
File.Delete(prefabName);
}
PrefabUtility.SaveAsPrefabAsset(go, prefabName, out success);
Debug.Log(string.Format(go.name + " 预制体保存{0}", success ? "成功" : "失败"));
GameObject.DestroyImmediate(go);
go = null;
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}