Unity模型資源使用流程,unity模型使用流程

來源:互聯網
上載者:User

Unity模型資源使用流程,unity模型使用流程

        昨天研究了下Unity中AnimatorController自動產生。今天稍微完善了操作流程,並且補充說明了在MMO中如何使用模型資源(AssetBundle),這個使用方法是MMO這樣模型資源非常大的情況下才需要的。如果是比較小的情況下,直接塞到Resources目錄下,載入Prefab就OK了,根本不用操心這些問題。

       先附上最終修改後的指令碼。它建立了一個菜單選項,選擇一個檔案夾(或者檔案),右鍵選擇CreateAnimation就可以自動遍曆所有的模型資源,然後建立AnimatorController並建立Prefab檔案。在Prefab都產生完畢後(或者在產生的同時),可以使用建立AssetBundle的功能在磁碟任意目錄建立AssetBundle。

using UnityEngine;using UnityEditor;using UnityEditorInternal;using System.IO;using System.Collections;using System.Collections.Generic; public class CreateAnimation : Editor {    //產生出的Prefab的路徑private static readonly string PREFAB_PATH = "Assets/Prefab/";    private static readonly string PATH_TAG = "Assets/";    private static bool _ingnoreExist = true;    // 這些動畫是迴圈播放的(除此之外的迴圈動畫需要手動建立)    private static readonly string[] LOOP_TAG = new string[] { "idle", "walk", "run" }; [MenuItem("Assets/CreateAnimation")]    static void DoCreateAnimation()    {        UnityEngine.Object obj = Selection.activeObject;        string path = AssetDatabase.GetAssetPath(Selection.activeObject);        if (Directory.Exists(path)) {            // 如果是路徑的話            Walk(path, (string fbxPath)=>{                fbxPath = fbxPath.Replace("\\", "/").Replace(".FBX", ".fbx");                string relativePath = fbxPath.Substring(fbxPath.IndexOf(PATH_TAG));                if (!relativePath.EndsWith(".fbx")) {                    return;                }                DoCreateController(relativePath);                DoCreatePrefab(relativePath);            });        } else if (File.Exists(path)) {            // 如果是檔案的話            string fbxPath = path.Replace("\\", "/").Replace(".FBX", ".fbx");            string relativePath = fbxPath.Substring(fbxPath.IndexOf(PATH_TAG));            if (!relativePath.EndsWith(".fbx")) {                return;            }            DoCreateController(relativePath);            DoCreatePrefab(relativePath);        } else {            // 路徑不存在            Debug.LogError(string.Format("路徑不存在: {0}", path));        }        AssetDatabase.Refresh();        Debug.Log(string.Format("轉換完畢: {0}", path));    }    // 遍曆檔案夾    delegate void PathCallBack(string path);    static void Walk(string dir, PathCallBack callback)    {        DirectoryInfo d = new DirectoryInfo(dir);        if (d.GetDirectories() != null) {            FileInfo[] allf = d.GetFiles();            for (int i = 0; i < allf.Length; i++) {                if (callback != null) {                    callback(allf[i].FullName);                }            }            DirectoryInfo[] alldr = d.GetDirectories();            if (alldr != null) {                for (int i = 0; i < alldr.Length; i++) {                    Walk(alldr[i].FullName, callback);                }            }        }    }    static void DoCreateController(string assetPath)    {        // 擷取animationclip        List<AnimationClip> clips = new List<AnimationClip>();        UnityEngine.Object[] objects = AssetDatabase.LoadAllAssetsAtPath(assetPath);        foreach (var obj in objects) {            AnimationClip clip = obj as AnimationClip;            if (clip != null && clip.name.IndexOf("__preview__") == -1) {                clips.Add(clip);            }        }        if (clips.Count <= 0) {            return;        }        // controller檔案可以和fbx放在一起        string acPath = assetPath.Replace(".fbx", ".controller");        // 建立動畫控制器        AnimatorController animatorController = null;        // 更新controller無法及時更新,所以建立controller,但是不能單獨prefab,否則會丟失關聯        animatorController = AnimatorController.CreateAnimatorControllerAtPath(acPath);        AnimatorControllerLayer layer = animatorController.GetLayer(0);        UnityEditorInternal.StateMachine sm = layer.stateMachine;        Vector3 anyStatePosition = sm.anyStatePosition;        float OFFSET_X = 220;        float OFFSET_Y = 60;        float ITEM_PER_LINE = 4;        float originX = anyStatePosition.x - OFFSET_X * (ITEM_PER_LINE / 2.5f);        float originY = anyStatePosition.y + OFFSET_Y;        float x = originX;        float y = originY;        State defaultState = null;        foreach (AnimationClip newClip in clips) {            string clipName = newClip.name.ToLower();            State state = sm.AddState(clipName);            // 設定defaultState,優先選取idle動畫            if (defaultState == null) {                if (clipName.IndexOf("idle") != -1) {                    sm.defaultState = state;                    defaultState = state;                }            } else {                if (clipName == "idle") {                    sm.defaultState = state;                    defaultState = state;                }            }            foreach (var tag in LOOP_TAG) {                //有些動畫我希望天生它就動畫迴圈                if (clipName.IndexOf(tag) != -1) {                    SerializedObject serializedClip = new SerializedObject(newClip);                    AnimationClipSettings clipSettings = new AnimationClipSettings(serializedClip.FindProperty("m_AnimationClipSettings"));                    clipSettings.loopTime = true;                    clipSettings.loopBlend = true;                    serializedClip.ApplyModifiedProperties();                    break;                }            }                        state.SetAnimationClip(newClip, layer);            state.position = new Vector3(x, y, 0);            x += OFFSET_X;            if (x >= originX + OFFSET_X * ITEM_PER_LINE) {                x = originX;                y += OFFSET_Y;            }        }        AssetDatabase.SaveAssets();    }    static void DoCreatePrefab(string assetPath)    {        // 建立對應檔案夾        string destPath = assetPath;        if (!destPath.StartsWith(PREFAB_PATH)) {            destPath = assetPath.Replace("Assets/", PREFAB_PATH);        }        string dirPath = System.IO.Path.GetDirectoryName(destPath);        if (!System.IO.Directory.Exists(dirPath)) {            System.IO.Directory.CreateDirectory(dirPath);        }        string acPath = assetPath.Replace(".fbx", ".controller");        string prefabPath = destPath.Replace(".fbx", ".prefab");        string name = assetPath.Substring(assetPath.LastIndexOf("/") + 1).Replace(".fbx", "");        // 建立prefab        GameObject fbx = AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)) as GameObject;        GameObject go = Instantiate(fbx) as GameObject;        go.name = name;        // 如果controller檔案存在,則建立對應的animator        if (System.IO.File.Exists(acPath)) {            AnimatorController animatorController = AssetDatabase.LoadAssetAtPath(acPath, typeof(AnimatorController)) as AnimatorController;            Animator animator = go.GetComponent<Animator>();            if (animator == null) {                animator = go.AddComponent<Animator>();            }            animator.applyRootMotion = false;            animator.runtimeAnimatorController = animatorController;        }        // 建立prefab        if (System.IO.File.Exists(prefabPath)) {            // 替換原來的prefab (每個prefab都有對應的udid不能直接使用新的,否則所有相關引用都將失效)            GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)) as GameObject;            PrefabUtility.ReplacePrefab(go, prefab);        } else {            // 建立新的prefab            PrefabUtility.CreatePrefab(prefabPath, go, ReplacePrefabOptions.ConnectToPrefab);        }        GameObject.DestroyImmediate(go, true);        AssetDatabase.SaveAssets();    }  class AnimationClipSettings{SerializedProperty m_Property;private SerializedProperty Get (string property) { return m_Property.FindPropertyRelative(property); }public AnimationClipSettings(SerializedProperty prop) { m_Property = prop; }public float startTime   { get { return Get("m_StartTime").floatValue; } set { Get("m_StartTime").floatValue = value; } }public float stopTime{ get { return Get("m_StopTime").floatValue; }  set { Get("m_StopTime").floatValue = value; } }public float orientationOffsetY { get { return Get("m_OrientationOffsetY").floatValue; } set { Get("m_OrientationOffsetY").floatValue = value; } }public float level { get { return Get("m_Level").floatValue; } set { Get("m_Level").floatValue = value; } }public float cycleOffset { get { return Get("m_CycleOffset").floatValue; } set { Get("m_CycleOffset").floatValue = value; } }        public bool loopTime { get { return Get("m_LoopTime").boolValue; } set { Get("m_LoopTime").boolValue = value; } }        public bool loopBlend { get { return Get("m_LoopBlend").boolValue; } set { Get("m_LoopBlend").boolValue = value; } }public bool loopBlendOrientation { get { return Get("m_LoopBlendOrientation").boolValue; } set { Get("m_LoopBlendOrientation").boolValue = value; } }public bool loopBlendPositionY { get { return Get("m_LoopBlendPositionY").boolValue; } set { Get("m_LoopBlendPositionY").boolValue = value; } }public bool loopBlendPositionXZ { get { return Get("m_LoopBlendPositionXZ").boolValue; } set { Get("m_LoopBlendPositionXZ").boolValue = value; } }public bool keepOriginalOrientation { get { return Get("m_KeepOriginalOrientation").boolValue; } set { Get("m_KeepOriginalOrientation").boolValue = value; } }public bool keepOriginalPositionY { get { return Get("m_KeepOriginalPositionY").boolValue; } set { Get("m_KeepOriginalPositionY").boolValue = value; } }public bool keepOriginalPositionXZ { get { return Get("m_KeepOriginalPositionXZ").boolValue; } set { Get("m_KeepOriginalPositionXZ").boolValue = value; } }public bool heightFromFeet { get { return Get("m_HeightFromFeet").boolValue; } set { Get("m_HeightFromFeet").boolValue = value; } }public bool mirror { get { return Get("m_Mirror").boolValue; } set { Get("m_Mirror").boolValue = value; } }}}

這裡有幾個需要說明的地方:

1、產生AnimatorController和Prefab的時間不快,所以一次轉換的模型不要太多。

2、原本可以更新AnimatorController內容會更好些,但是沒有嘗試成功,所以建立完controller就要更新Prefab,這樣關聯資訊不會丟失(miss animator)

3、建立Prefab的時候,如果已存在,則更新Prefab。這樣可以保證其他使用Prefab的地方不會丟失其資訊。因為建立一個新的Prefab,則會產生一個新的uuid,這樣原來的引用就不存在了。

4、在產生controller的時候,有判斷animationclip,如果它是休閑或者跑步動作,則自動化佈建其為loop模式。這個不在指令碼中處理,就需要自己一個模型一個模型去修改。如果不屬於LOOP_TAG中的動畫,然後又需要設定loop可以自己在Unity中操作修改。這裡原本我希望可以通過ModelImporter來修改,但是沒有找到正確的方法。所以參考雨松的方式,直接修改AnimationClip的屬性。


這種資源(AssetBundle)使用流程有這麼幾個好處:

1、開發項目工程不會很大。以程式的思路載入資源。否則一個大的MMO,資源量可能幾G。運行Unity都需要等幾分鐘。

2、AssetBundle可以完全由美術搞定,程式只關心資源載入使用。

3、建立AssetBundle的項目可以分類。比如情境美術一個項目,角色美術一個項目等等。這樣可以進一步減小項目,並且減少衝突的機會。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.