制作unity导出spine和模型预制体的工具

题外话,策划觉得多材质的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的属性,这句话就是坑,按照这个流程和需求去做,我发现是不能成功的,为什么呢,下面就是相关三个属性的机制

ModelImporter
枚举类型枚举值
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();
        }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用不同的服装模型预制实现换装,可以通过以下步骤实现: 1. 将不同的服装模型预制添加到场景中,并为每个模型设置不同的Animator Controller。 2. 在角色模型上添加一个Skinned Mesh Renderer组件,并将其设置为角色模型的Mesh。 3. 在代码中,获取角色模型的Animator组件,然后调用Play函数来播放不同的动画。在播放动画之前,需要先替换角色模型的Mesh,以显示所选的服装模型。代码如下: ``` public class ChangeClothes : MonoBehaviour { public GameObject[] clothesPrefabs; private SkinnedMeshRenderer skinnedMeshRenderer; private Animator animator; private int currentClothesIndex = 0; void Start() { skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>(); animator = GetComponent<Animator>(); ChangeClothesModel(currentClothesIndex); } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { currentClothesIndex++; if (currentClothesIndex >= clothesPrefabs.Length) { currentClothesIndex = 0; } ChangeClothesModel(currentClothesIndex); } } void ChangeClothesModel(int index) { GameObject clothesPrefab = clothesPrefabs[index]; SkinnedMeshRenderer clothesRenderer = clothesPrefab.GetComponent<SkinnedMeshRenderer>(); skinnedMeshRenderer.sharedMesh = clothesRenderer.sharedMesh; skinnedMeshRenderer.materials = clothesRenderer.sharedMaterials; animator.Play("Idle"); // 播放Idle动画 } } ``` 在上述代码中,clothesPrefabs数组包含不同的服装模型预制,currentClothesIndex表示当前所选的服装模型的索引。在Start函数中,获取角色模型的Skinned Mesh Renderer组件和Animator组件,并调用ChangeClothesModel函数来初始化角色模型的Mesh。 在Update函数中,检测用户是否按下Space键,如果是,则切换到下一个服装模型。在ChangeClothesModel函数中,获取所选的服装模型的Skinned Mesh Renderer组件,并将其Mesh和Material赋给角色模型的Skinned Mesh Renderer组件。最后,播放Idle动画以显示角色模型和所选的服装模型。 通过以上方式,就可以使用不同的服装模型预制实现换装了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值