characterCustomezition的資源打包代碼分析
using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; class CreateAssetbundles { // This method creates an assetbundle of each SkinnedMeshRenderer // found in any selected character fbx, and adds any materials that // are intended to be used by the specific SkinnedMeshRenderer. [MenuItem("Character Generator/Create Assetbundles")] static void Execute() { bool createdBundle = false; foreach (Object o in Selection.GetFiltered(typeof (Object), SelectionMode.DeepAssets))//返回通過類型和選擇模式過濾的當前選擇的物體。 { if (!(o is GameObject)) continue;//如果不是GameObject就跳過本次循環 if (o.name.Contains("@")) continue;//如果是動畫片段就跳過本次循環 if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) continue;//如果含有指定的目錄名就跳過本次循環 GameObject characterFBX = (GameObject)o;//將o強制轉換為GameObject string name = characterFBX.name.ToLower();//獲取名字 Debug.Log("******* Creating assetbundles for: " + name + " *******"); // Create a directory to store the generated assetbundles. if (!Directory.Exists(AssetbundlePath))//檢查AssetbundlePath是否存在 Directory.CreateDirectory(AssetbundlePath);//如果不存在就創建目錄 // Delete existing assetbundles for current character. string[] existingAssetbundles = Directory.GetFiles(AssetbundlePath);//獲取AssetbundlePath目錄下的文件 foreach (string bundle in existingAssetbundles) { if (bundle.EndsWith(".assetbundle") && bundle.Contains("/assetbundles/" + name))//刪除重復的文件 File.Delete(bundle); } // Save bones and animations to a seperate assetbundle. Any // possible combination of CharacterElements will use these // assets as a base. As we can not edit assets we instantiate // the fbx and remove what we dont need. As only assets can be // added to assetbundles we save the result as a prefab and delete // it as soon as the assetbundle is created. GameObject characterClone = (GameObject)Object.Instantiate(characterFBX);//克隆一個GO foreach (SkinnedMeshRenderer smr in characterClone.GetComponentsInChildren<SkinnedMeshRenderer>())//得到子物體的SkinnedMeshRenderer組件不包括Inactive Object.DestroyImmediate(smr.gameObject);//銷毀資源 characterClone.AddComponent<SkinnedMeshRenderer>();//添加SkinnedMeshRenderer組件到Clone體 Object characterBasePrefab = GetPrefab(characterClone, "characterbase");//得到一個預制件,並銷毀clone體 string path = AssetbundlePath + name + "_characterbase.assetbundle";//路徑及文件名 BuildPipeline.BuildAssetBundle(characterBasePrefab, null, path, BuildAssetBundleOptions.CollectDependencies);//建一個壓縮的unity3d文件,包含資源的集合 AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(characterBasePrefab));//銷毀預制件 // Collect materials. List<Material> materials = EditorHelpers.CollectAll<Material>(GenerateMaterials.MaterialsPath(characterFBX));//獲取fbx目錄下的所有Material // Create assetbundles for each SkinnedMeshRenderer. foreach (SkinnedMeshRenderer smr in characterFBX.GetComponentsInChildren<SkinnedMeshRenderer>(true))//獲取fbx及子物體的SkinnedMeshRenderer組件包括Inactive { List<Object> toinclude = new List<Object>(); // Save the current SkinnedMeshRenderer as a prefab so it can be included // in the assetbundle. As instantiating part of an fbx results in the // entire fbx being instantiated, we have to dispose of the entire instance // after we detach the SkinnedMeshRenderer in question. GameObject rendererClone = (GameObject)EditorUtility.InstantiatePrefab(smr.gameObject);//clone給定的預制件 GameObject rendererParent = rendererClone.transform.parent.gameObject;//獲取父對象 rendererClone.transform.parent = null;//清空clone體的父對象引用 Object.DestroyImmediate(rendererParent);//摧毀父對象 Object rendererPrefab = GetPrefab(rendererClone, "rendererobject");//得到一個預制件,並銷毀clone體 toinclude.Add(rendererPrefab);//放置到容器中 // Collect applicable materials. foreach (Material m in materials) if (m.name.Contains(smr.name.ToLower())) toinclude.Add(m); // When assembling a character, we load SkinnedMeshRenderers from assetbundles, // and as such they have lost the references to their bones. To be able to // remap the SkinnedMeshRenderers to use the bones from the characterbase assetbundles, // we save the names of the bones used. List<string> boneNames = new List<string>(); foreach (Transform t in smr.bones)//獲取骨骼 boneNames.Add(t.name); string stringholderpath = "Assets/bonenames.asset"; AssetDatabase.CreateAsset(new StringHolder(boneNames.ToArray()), stringholderpath);//在指定的路徑創建資源 toinclude.Add(AssetDatabase.LoadAssetAtPath(stringholderpath, typeof (StringHolder)));//返回在指定位置stringholderpath下第一個類型是StringHolder的資源對象。並添加到容器中 // Save the assetbundle. string bundleName = name + "_" + smr.name.ToLower(); path = AssetbundlePath + bundleName + ".assetbundle"; BuildPipeline.BuildAssetBundle(null, toinclude.ToArray(), path, BuildAssetBundleOptions.CollectDependencies); Debug.Log("Saved " + bundleName + " with " + (toinclude.Count - 2) + " materials"); // Delete temp assets. AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(rendererPrefab)); AssetDatabase.DeleteAsset(stringholderpath); createdBundle = true; } } if (createdBundle) UpdateCharacterElementDatabase.Execute(); else EditorUtility.DisplayDialog("Character Generator", "No Asset Bundles created. Select the characters folder in the Project pane to process all characters. Select subfolders to process specific characters.", "Ok"); } static Object GetPrefab(GameObject go, string name) { Object tempPrefab = EditorUtility.CreateEmptyPrefab("Assets/" + name + ".prefab");//創建一個empty預制件 tempPrefab = EditorUtility.ReplacePrefab(go, tempPrefab);//將GO替換為tmpPrefab Object.DestroyImmediate(go);//銷毀資源 return tempPrefab;//返回tmpPrefab } public static string AssetbundlePath { get { return "assetbundles" + Path.DirectorySeparatorChar; } } }
