1掖棉、問題說明
項目中部分粒子系統(tǒng)(Particle System)需要用到Mesh仍翰,因此引入了一些為粒子系統(tǒng)提供Mesh的FBX冯凹。在性能測試時發(fā)現(xiàn)吉嚣,加載粒子總會伴隨著Standard Shader的編譯消耗梢薪。檢查下來發(fā)現(xiàn),F(xiàn)BX在導(dǎo)入Unity時會關(guān)聯(lián)上默認(rèn)材質(zhì)(Default-Material)然后引用內(nèi)建的標(biāo)準(zhǔn)Shader(Standard)尝哆。這個材質(zhì)和Shader是多余的秉撇,因為粒子系統(tǒng)使用的是Particle System - Renderer中設(shè)置的內(nèi)容。
說明:我們沒有把Builtin Shader放入到工程中合并打包,所以會出現(xiàn)每次加載粒子都產(chǎn)生Shader編譯的耗時琐馆。如果對這類Shader做過處理规阀,可能不會看到這個現(xiàn)象,但是問題是存在的瘦麸。
2谁撼、深入測試
上面的問題是老大描述給我的,但是我自己進行測試時滋饲,并沒有發(fā)現(xiàn)這個現(xiàn)象厉碟。然后我們對比了測試代碼,發(fā)現(xiàn)這個問題發(fā)生在異步加載資源的時候屠缭。然而在我這異步加載也沒有復(fù)現(xiàn) Orz……
后面對資源箍鼓、代碼進行了各種嘗試,發(fā)現(xiàn)了下面的一些條件(結(jié)論):
- 如果FBX和引用它的資源打到同一個AB里呵曹,這個AB不會包含F(xiàn)BX中多余的內(nèi)容款咖;如果FBX單獨打包,它會包含模型中的全部內(nèi)容逢并,比如:Material之剧、Shader、骨骼節(jié)點等砍聊。
- 加載粒子系統(tǒng)時使用LoadAssetAsync才會把多余Standard加載出來背稼。(加載AssetBundle使用LoadFromFile還是LoadFromFileAsync都無所謂)
項目中與此有關(guān)的用法有:
1.Particle System使用FBX中的Mesh
2.Animation直接使用FBX中的AnimationClip
第2種用法通常會引入多余的骨骼節(jié)點,因為做動畫FBX的時候會帶著角色骨骼玻蝌。而實際使用時骨骼會單獨打包蟹肘,或和SkinnedMeshRenderer打在一起。這個情況也很好處理俯树,直接把AnimationClip從FBX中分離后再使用就可以帘腹。
【2017-9-12補充】
FBX和引用它的資源打到同一個AB里有兩種情況,一種是只給引用FBX的資源設(shè)置ABName许饿,一種是給FBX和引用它的資源設(shè)置相同的ABName阳欲。對于前者,符合上面的結(jié)論1陋率;對于后者球化,它的情況和打包到兩個AB中是一樣的。
這個情況也好理解瓦糟,當(dāng)給資源設(shè)置了ABName筒愚,就表示你需要這個資源的全部內(nèi)容,Unity無法替你過濾菩浙。
3巢掺、解決問題
解決Standard多次編譯的方法有好幾種句伶,比如合并打包Shader、破壞上述發(fā)生條件等陆淀。我們使用的是刪除FBX默認(rèn)導(dǎo)入的材質(zhì)考余。
4、代碼處理
終于到本文要介紹的內(nèi)容了...
public class ModelMatTool : AssetPostprocessor
{
private static bool _needWaiting = false;
/// <summary>
/// 是否啟用刪除操作
/// OnPostprocessModel回調(diào)在模型導(dǎo)入的時候就會調(diào)到绢要,
/// 通過這個標(biāo)記位保證只在調(diào)用腳本函數(shù)的時候執(zhí)行吏恭。
/// </summary>
private static bool _enableDelete = false;
/// <summary>
/// 批量刪除模型上的材質(zhì)
/// </summary>
public static IEnumerator DelModelMats(Object[] models)
{
foreach (Object obj in models)
{
while (_needWaiting) yield return null;
DelModelMat(obj as GameObject);
}
}
/// <summary>
/// 刪除模型上綁定的材質(zhì)
/// </summary>
/// <param name="model">模型對象</param>
public static void DelModelMat(GameObject model)
{
if (null == model) return;
string assetPath = AssetDatabase.GetAssetPath(model);
ModelImporter importer = AssetImporter.GetAtPath(assetPath) as ModelImporter;
if (null == importer) return;
_enableDelete = true;
_needWaiting = true;
importer.importMaterials = true;
importer.importMaterials = false;
AssetDatabase.ImportAsset(assetPath);
}
private void OnPostprocessModel(GameObject model)
{
if (null == model) return;
if (!_enableDelete) return;
_enableDelete = false;
Renderer[] renders = model.GetComponentsInParent<Renderer>();
if (null == renders) return;
foreach (Renderer render in renders)
{
render.sharedMaterials = new Material[render.sharedMaterials.Length];
}
_needWaiting = false;
}
}
使用代碼:
[MenuItem("Assets/Wal Editor/刪除選中模型的材質(zhì)")]
static void DelSelectedModelMat()
{
Object[] objs = Selection.GetFiltered(typeof (Object), SelectionMode.DeepAssets);
if(null == objs) return;
EditorCoroutine.Start(DelModelMats(objs));
}
有幾個地方需要注意:
1.代碼方式修改FBX實際改變的是Unity緩存(Library/metadata)的內(nèi)容,因此它不能被版控管理重罪。這個腳本要在發(fā)布機上執(zhí)行樱哼。
2.這里的處理,在執(zhí)行【右鍵 - Reimport】操作后會恢復(fù)原樣剿配。
3.批處理函數(shù)要用協(xié)程的方式執(zhí)行搅幅,可以參考上一篇文章