Unity3D批處理腳本


Max09在模型到處的模型和U3D場景的尺寸不一致,Max09中的1m導到U3D中,只有0.01m,這時可以在U3D中將模型的FbxImporter中將Scale Factor改為1。

上述事情也可以通過腳本直接處理:

using UnityEditor;
using UnityEngine;
using System.Collections;

public class FBXSeting : AssetPostprocessor
{
void OnPreprocessModel()
{
ModelImporter modelImporter = (ModelImporter)assetImporter;
if(assetImporter.assetPath.Contains(".fbx"))
{
modelImporter.globalScale = 1.0f;
modelImporter.generateMaterials = ModelImporterGenerateMaterials.None;
}
}
}

 

U3D有自動生成材質的功能(FbxImporter/Materials Generation,有3個選項可選),但我推薦使用腳本統一處理所有模型的材質。下面的代碼拋磚引玉,通過菜單修改模型材質的顏色:

using UnityEditor;
using UnityEngine;
using System.Collections;

public class MaterialGeneration
{
[MenuItem("Actor/Generate Material")]
static void Execute()
{
foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
{
if (!(o is GameObject)) continue;
if (o.name.Contains("@")) continue;
//if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) continue;

GameObject charFbx = (GameObject)o;

foreach (SkinnedMeshRenderer smr in charFbx.GetComponentsInChildren<SkinnedMeshRenderer>(true))
{
smr.material.color = Color.red;
}
}
}
}

上面是處理人物材質的蒙皮網格的材質,對於場景模型,則改為修改MeshRenderer的數據。思路大致如此,細節以此類推。
根據本人自己的經驗,將modelImporter.generateMaterials設為PerMaterial(支持多重材質),然后批處理Fbx模型的Mesh,找到其材質,並修改之(包括修改Shader及Shader數據)。不建議刪除現有材質,然后自己創建材質,並賦予給相應的Mesh,因為這種做法有個不好的地方:U3D重啟后,材質關聯丟失。而前面的方法,只是修改Mesh所關聯材質的數據,后者是修改關聯。

思緒:

U3D雖然降低了游戲編程門檻,不過定制功能真心強大,繼續探索中......

 

有些地方需要手動創建Prefab,可以通過以下代碼實現代碼批處理創建:

Object tempPrefab = EditorUtility.CreateEmptyPrefab("Assets/" + name + ".prefab");

tempPrefab = EditorUtility.ReplacePrefab(go, tempPrefab);

 

通過腳本給模型prefab添加AnimationEvent:

using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections;
using System.Collections.Generic;

public class AnimationEventBatch
{
    [MenuItem("Animation/AnimationEvent Batch")]
    static void Execute()
    {
        List<string> lstAnimName = new List<string>();

        foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
        {
            if (!(o is GameObject))
                continue;
            if (o.name.Contains("@"))
                continue;
            if (o.name.Contains("anim") || o.name.Contains("ANIM"))
                continue;
            if (o.name.Contains("meta"))
                continue;
            
            GameObject charFbx = (GameObject)o;
            
            AnimationClip[] clips = AnimationUtility.GetAnimationClips(charFbx.animation);
            
            foreach(AnimationClip clip in clips)
            {
                if(clip.name.Contains("Take 0"))
                    continue;
                    
                List<AnimationEvent> events = new List<AnimationEvent>(AnimationUtility.GetAnimationEvents(clip));
                
                if(HasStartEvent(events) && HasEndEvent(events))
                    continue;
                
                if(!HasStartEvent(events))
                {
                    AnimationEvent startEvent = new AnimationEvent();
                    startEvent.time = 0.0005f;
                    startEvent.functionName = "StartCallBack";
                    events.Add(startEvent);
                }
                
                if(!HasEndEvent(events))
                {
                    AnimationEvent endEvent = new AnimationEvent();
                    endEvent.time = clip.length - 0.0005f;
                    endEvent.functionName = "EndCallBack";
                    events.Add(endEvent);
                }
                
                AnimationUtility.SetAnimationEvents(clip, events.ToArray());
            }
            
            EditorUtility.DisplayDialog("fbxname", clips[0].name, "OK");
        }
    }
    
    static bool HasStartEvent(List<AnimationEvent> events)
    {
        foreach(AnimationEvent eventElem in events)
        {
            if(eventElem.functionName == "StartCallBack")
                return true;
        }
        return false;
    }
    
    static bool HasEndEvent(List<AnimationEvent> events)
    {
        foreach(AnimationEvent eventElem in events)
        {
            if(eventElem.functionName == "EndCallBack")
                return true;
        }
        return false;
    }
}

上述代碼僅供參考,代碼中有幾個注意事項:

(1)一定要在現有AnimationEvent[]數組的基礎上添加,而不是新建一個這樣的數組,然后Set給對應的AnimationClip,這樣會導致現有的關鍵幀事件丟失;

(2)要避免重復添加同意關鍵幀事件(貌似u3d對於同樣時間同樣函數名的關鍵幀只會添加一次);

(3)可以看到,在添加關鍵幀事件時,只需要給出函數的名字,那么,在此動作執行時,U3D會檢查這個GameObject身上的所有組件腳本,如果組件A包含此名字的函數,則會執行此函數。並且所有組件的此名字的函數都會執行一次。

 

批量設置圖片的格式:

public class GuideUITextureProcess 
{
    [MenuItem("Editor/Texture/GuideUITexture")]
    static void Execute()
    {
        foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
        {
            if (!(o is Texture))
                continue;

            Texture tex = o as Texture;
            string path = AssetDatabase.GetAssetPath(tex);
            TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
            textureImporter.textureType = TextureImporterType.GUI;
            AssetDatabase.ImportAsset(path);
        }
        AssetDatabase.Refresh();
    }
}

   Prefab.Apply操作的回調:

using UnityEngine;
using UnityEditor;

[InitializeOnLoad]
public class PrefabExtension : MonoBehaviour
{
    static PrefabExtension()
    {
        UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate;
    }

    static void OnPrefabInstanceUpdate(GameObject instance)
    {
        UnityEngine.Debug.Log("[Callback] Prefab.Apply on instance named :" + instance.name);

        GameObject prefab = UnityEditor.PrefabUtility.GetPrefabParent(instance) as GameObject;
        string prefabPath = AssetDatabase.GetAssetPath(prefab);
        UnityEngine.Debug.Log("@Prefab originPath=" + prefabPath);
    }
}

 


繼續探索中......




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM