1 using System.Collections.Generic; 2 using System.IO; 3 using UnityEditor; 4 using UnityEngine; 5 6 class CreateAssetbundles 7 { 8 // This method creates an assetbundle of each SkinnedMeshRenderer 9 // found in any selected character fbx, and adds any materials that 10 // are intended to be used by the specific SkinnedMeshRenderer. 11 [MenuItem("Character Generator/Create Assetbundles")] 12 static void Execute() 13 { 14 bool createdBundle = false; 15 foreach (Object o in Selection.GetFiltered(typeof (Object), SelectionMode.DeepAssets))//返回通过类型和选择模式过滤的当前选择的物体。 16 17 18 { 19 if (!(o is GameObject)) continue;//如果不是GameObject就跳过本次循环 20 if (o.name.Contains("@")) continue;//如果是动画片段就跳过本次循环 21 if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) continue;//如果含有指定的目录名就跳过本次循环 22 23 GameObject characterFBX = (GameObject)o;//将o强制转换为GameObject 24 string name = characterFBX.name.ToLower();//获取名字 25 26 Debug.Log("******* Creating assetbundles for: " + name + " *******"); 27 28 // Create a directory to store the generated assetbundles. 29 if (!Directory.Exists(AssetbundlePath))//检查AssetbundlePath是否存在 30 Directory.CreateDirectory(AssetbundlePath);//如果不存在就创建目录 31 32 33 // Delete existing assetbundles for current character. 34 string[] existingAssetbundles = Directory.GetFiles(AssetbundlePath);//获取AssetbundlePath目录下的文件 35 foreach (string bundle in existingAssetbundles) 36 { 37 if (bundle.EndsWith(".assetbundle") && bundle.Contains("/assetbundles/" + name))//删除重复的文件 38 File.Delete(bundle); 39 } 40 41 // Save bones and animations to a seperate assetbundle. Any 42 // possible combination of CharacterElements will use these 43 // assets as a base. As we can not edit assets we instantiate 44 // the fbx and remove what we dont need. As only assets can be 45 // added to assetbundles we save the result as a prefab and delete 46 // it as soon as the assetbundle is created. 47 GameObject characterClone = (GameObject)Object.Instantiate(characterFBX);//克隆一个GO 48 foreach (SkinnedMeshRenderer smr in characterClone.GetComponentsInChildren<SkinnedMeshRenderer>())//得到子物体的SkinnedMeshRenderer组件不包括Inactive 49 Object.DestroyImmediate(smr.gameObject);//销毁资源 50 characterClone.AddComponent<SkinnedMeshRenderer>();//添加SkinnedMeshRenderer组件到Clone体 51 Object characterBasePrefab = GetPrefab(characterClone, "characterbase");//得到一个预制件,并销毁clone体 52 string path = AssetbundlePath + name + "_characterbase.assetbundle";//路径及文件名 53 BuildPipeline.BuildAssetBundle(characterBasePrefab, null, path, BuildAssetBundleOptions.CollectDependencies);//建一个压缩的unity3d文件,包含资源的集合 54 AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(characterBasePrefab));//销毁预制件 55 56 // Collect materials. 57 List<Material> materials = EditorHelpers.CollectAll<Material>(GenerateMaterials.MaterialsPath(characterFBX));//获取fbx目录下的所有Material 58 59 // Create assetbundles for each SkinnedMeshRenderer. 60 foreach (SkinnedMeshRenderer smr in characterFBX.GetComponentsInChildren<SkinnedMeshRenderer>(true))//获取fbx及子物体的SkinnedMeshRenderer组件包括Inactive 61 { 62 List<Object> toinclude = new List<Object>(); 63 64 // Save the current SkinnedMeshRenderer as a prefab so it can be included 65 // in the assetbundle. As instantiating part of an fbx results in the 66 // entire fbx being instantiated, we have to dispose of the entire instance 67 // after we detach the SkinnedMeshRenderer in question. 68 GameObject rendererClone = (GameObject)EditorUtility.InstantiatePrefab(smr.gameObject);//clone给定的预制件 69 GameObject rendererParent = rendererClone.transform.parent.gameObject;//获取父对象 70 rendererClone.transform.parent = null;//清空clone体的父对象引用 71 Object.DestroyImmediate(rendererParent);//摧毁父对象 72 Object rendererPrefab = GetPrefab(rendererClone, "rendererobject");//得到一个预制件,并销毁clone体 73 toinclude.Add(rendererPrefab);//放置到容器中 74 75 // Collect applicable materials. 76 foreach (Material m in materials) 77 if (m.name.Contains(smr.name.ToLower())) toinclude.Add(m); 78 79 // When assembling a character, we load SkinnedMeshRenderers from assetbundles, 80 // and as such they have lost the references to their bones. To be able to 81 // remap the SkinnedMeshRenderers to use the bones from the characterbase assetbundles, 82 // we save the names of the bones used. 83 List<string> boneNames = new List<string>(); 84 foreach (Transform t in smr.bones)//获取骨骼 85 boneNames.Add(t.name); 86 string stringholderpath = "Assets/bonenames.asset"; 87 AssetDatabase.CreateAsset(new StringHolder(boneNames.ToArray()), stringholderpath);//在指定的路径创建资源 88 toinclude.Add(AssetDatabase.LoadAssetAtPath(stringholderpath, typeof (StringHolder)));//返回在指定位置stringholderpath下第一个类型是StringHolder的资源对象。并添加到容器中 89 90 // Save the assetbundle. 91 string bundleName = name + "_" + smr.name.ToLower(); 92 path = AssetbundlePath + bundleName + ".assetbundle"; 93 BuildPipeline.BuildAssetBundle(null, toinclude.ToArray(), path, BuildAssetBundleOptions.CollectDependencies); 94 Debug.Log("Saved " + bundleName + " with " + (toinclude.Count - 2) + " materials"); 95 96 // Delete temp assets. 97 AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(rendererPrefab)); 98 AssetDatabase.DeleteAsset(stringholderpath); 99 createdBundle = true; 100 } 101 } 102 103 if (createdBundle) 104 UpdateCharacterElementDatabase.Execute(); 105 else 106 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"); 107 } 108 109 static Object GetPrefab(GameObject go, string name) 110 { 111 Object tempPrefab = EditorUtility.CreateEmptyPrefab("Assets/" + name + ".prefab");//创建一个empty预制件 112 tempPrefab = EditorUtility.ReplacePrefab(go, tempPrefab);//将GO替换为tmpPrefab 113 Object.DestroyImmediate(go);//销毁资源 114 return tempPrefab;//返回tmpPrefab 115 } 116 117 public static string AssetbundlePath 118 { 119 get { return "assetbundles" + Path.DirectorySeparatorChar; } 120 } 121 }