1. 程式人生 > 實用技巧 >【Unity遊戲開發】升級Unity2019後,資源管線後處理採坑記錄

【Unity遊戲開發】升級Unity2019後,資源管線後處理採坑記錄

一、引子

  最近我們的專案由Unity2018升級到了Unity2019.4,但是突然間發現FBX資源匯入時的後處理不生效了。經過一系列的實驗,發現了升級到Unity2019以後,資源管線後處理中的一些坑,今天馬三來和大家分享一下這個過程。

二、情況復現與原因排查

  在我們的專案還使用Unity2018開發的時候,便有一個資源後處理的Editor程式碼,負責處理fbx型別檔案匯入時的一些自動化配置,比如:壓縮動畫曲線、優化模型的網格,關閉模型的Read/Write Enable選項等操作。同時這個自動化處理操作是隻在資源第一次被匯入的時候才會執行的,也就是說只有一個新的FBX剛進來的時候才會自動配置,在這之後我們還可以手動去調整一些引數。因此有了一步判斷資源有沒有被自動化後處理過的過程,用的是判斷fbx對應的.meta檔案存在與否,來指示這個fbx是否是被首次處理,程式碼如下所示:

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using UnityEditor;
  5 using System.IO;
  6 
  7 public class FBXPostProcesser : AssetPostprocessor
  8 {
  9     #region 模型處理
 10     /// <summary>
 11     /// 模型匯入之前呼叫  
 12     /// </summary>
 13     public
void OnPreprocessModel() 14 { 15 16 //判斷資源是否是首次匯入 17 #if UNITY_2019_3_OR_NEWER 18 if (!assetImporter.importSettingsMissing) 19 { 20 assetImporter.userData = "v_0.0.1"; 21 return; 22 } 23 #else 24 var metaPath = this.assetPath + "
.meta"; 25 if (File.Exists(metaPath)) 26 { 27 return; 28 } 29 #endif 30 31 Debug.Log("==模型匯入之前呼叫==" + this.assetPath); 32 ModelImporter modelImporter = (ModelImporter)assetImporter; 33 34 //模型優化 35 modelImporter.optimizeMesh = true; 36 modelImporter.optimizeGameObjects = true; 37 modelImporter.animationCompression = ModelImporterAnimationCompression.Optimal; 38 modelImporter.animationRotationError = 1.0f; 39 modelImporter.animationPositionError = 1.0f; 40 modelImporter.animationScaleError = 1.0f; 41 } 42 43 44 /// <summary> 45 /// 模型匯入之後呼叫 46 /// </summary> 47 /// <param name="go"></param> 48 public void OnPostprocessModel(GameObject go) 49 { 50 //判斷資源是否是首次匯入 51 #if UNITY_2019_3_OR_NEWER 52 if (!assetImporter.importSettingsMissing) 53 { 54 return; 55 } 56 #else 57 var metaPath = this.assetPath + ".meta"; 58 if (File.Exists(metaPath)) 59 { 60 return; 61 } 62 #endif 63 64 // for skeleton animations. 65 Debug.Log("==模型匯入之後呼叫=="); 66 List<AnimationClip> animationClipList = new List<AnimationClip>(AnimationUtility.GetAnimationClips(go)); 67 if (animationClipList.Count == 0) 68 { 69 AnimationClip[] objectList = Object.FindObjectsOfType(typeof(AnimationClip)) as AnimationClip[]; 70 animationClipList.AddRange(objectList); 71 } 72 73 foreach (AnimationClip theAnimation in animationClipList) 74 { 75 try 76 { 77 // 去除scale曲線 78 //foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(theAnimation)) 79 //{ 80 // string name = theCurveBinding.propertyName.ToLower(); 81 // if (name.Contains("scale")) 82 // { 83 // AnimationUtility.SetEditorCurve(theAnimation, theCurveBinding, null); 84 // } 85 //} 86 87 // 浮點數精度壓縮到f3 88 AnimationClipCurveData[] curves = null; 89 curves = AnimationUtility.GetAllCurves(theAnimation); 90 Keyframe key; 91 Keyframe[] keyFrames; 92 for (int ii = 0; ii < curves.Length; ++ii) 93 { 94 AnimationClipCurveData curveDate = curves[ii]; 95 if (curveDate.curve == null || curveDate.curve.keys == null) 96 { 97 //Debuger.LogWarning(string.Format("AnimationClipCurveData {0} don't have curve; Animation name {1} ", curveDate, animationPath)); 98 continue; 99 } 100 keyFrames = curveDate.curve.keys; 101 for (int i = 0; i < keyFrames.Length; i++) 102 { 103 key = keyFrames[i]; 104 key.value = float.Parse(key.value.ToString("f3")); 105 key.inTangent = float.Parse(key.inTangent.ToString("f3")); 106 key.outTangent = float.Parse(key.outTangent.ToString("f3")); 107 keyFrames[i] = key; 108 } 109 curveDate.curve.keys = keyFrames; 110 theAnimation.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve); 111 } 112 } 113 catch (System.Exception e) 114 { 115 Debug.LogError(string.Format("CompressAnimationClip Failed !!! animationPath : {0} error: {1}", assetPath, e)); 116 } 117 } 118 } 119 #endregion 120 121 }

  在Unity2018時,以上的判斷方法可以完好地執行,但是升級到Unity2019以後,就不能再通過.meta檔案存在與否來判斷一個fbx是否是第一次被匯入了。因為Unity2019.3以後資源後處理管線也由AssetPipline v1升級到了Asset Pipline v2,同時Unity生成.meta和呼叫資源後處理介面(比如 OnPreprocessModel()、 OnPostprocessModel(GameObject go)這些回撥介面)的時序也發生了變化。在Unity2018中,一個資源被匯入的時候,會先去呼叫資源後處理介面,然後再生成.meta檔案,因此可以通過.meta檔案存在與否來判斷一個fbx是否是第一次被匯入。但是在Unity2019中,這個時序變成了先生成一個.meta檔案,然後再去呼叫資源後處理介面。如果此時還通過.meta檔案來判斷一個資源是否是被第一次匯入的話,就會造成程式認為這個新匯入的fbx之前是被處理過的,就不會走到資源自動處理的那部分程式碼了,因此也就會表現為資源後處理機制失效了。同時Unity2019中先於資源後處理回撥介面生成的這個.meta檔案,也並不是完整的,只是先生成一個檔案用來佔坑,裡面只有兩行基本資訊,如下圖所示;

  只有在走完資源後處理介面以後,其內容才會被正式地補充完整並寫入,如下圖所示:

  網上有一種比較流行的判斷資源是否是第一次匯入的方式,是通過首次匯入的時候在assetImporter.userData 中寫入一個標記,然後後續通過判斷是否可以讀到這個標記來區分資源是否是首次匯入,因為如果以前匯入過一次了,那麼一定會讀取到userdata的,其程式碼類似於這樣:assetImporter.userData = "v_0.0.1"; ,這個userdata資料會存在資源對應的.meta檔案中。

  但是我們的專案之前沒有加寫入userdata這一步,userdata是讀取不到的。一種比較簡單粗暴的解決辦法就是寫一個工具,遍歷每個fbx資源,然後把userdata寫入到他們的.meta檔案中,這樣就批量地完成了資源meta的升級,新舊資源就可以通過userdata來進行區分了。

  但是這樣做比較拙劣的問題是,專案中資源很多,批量處理起來可能會有一定的風險,那麼有沒有比較優雅且安全係數較高的解決方案呢?其實Unity為我們提供了一個 assetImporter.importSettingsMissing 的介面,他完全可以實現我們的需求。這個介面可以判斷一個資源對應的配置是否存在,對於一個新匯入的資源,其配置肯定是不存在的,因此要執行資源後處理程式碼;而對於一個已經匯入過了的資源,其配置肯定是存在的,所以直接跳過不處理。經過馬三的測驗,它可以良好地在Unity2018和2019上工作,通過使用這個介面來判斷資源是否是被第一次匯入,就可以巧妙的解決上述問題了。同時不用批量的去處理每一個資源對應的meta,不但優雅也降低了風險係數,是一個比較好的相容方式。

三、總結

  在本篇部落格中,馬三跟大家分享了從Unity2018升級到Unity2019以後,資源匯入管線遇到的小問題。一個是Unity2018和Unity2019生成.meta和呼叫資源後處理回撥的時序發生了變化,因此不能再通過判斷.meta檔案是否存在來標記一個資源是否是被第一次匯入;另一個是通過 assetImporter.importSettingsMissing 這個介面去巧妙地相容判斷資原始檔是否是被第一次匯入,解決了上述問題,希望可以幫到大家。

如果覺得本篇部落格對您有幫助,可以掃碼小小地鼓勵下馬三,馬三會寫出更多的好文章,支援微信和支付寶喲!

 

作者:馬三小夥兒
出處:https://www.cnblogs.com/msxh/p/13805008.html
請尊重別人的勞動成果,讓分享成為一種美德,歡迎轉載。另外,文章在表述和程式碼方面如有不妥之處,歡迎批評指正。留下你的腳印,歡迎評論!