static void Execute() { bool createdBundle = false; foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets)) { if (!(o is GameObject)) { continue; } if (o.name.Contains("@")) { continue; } if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) { continue; } GameObject characterFBX = (GameObject)o; string name = characterFBX.name.ToLower(); Debug.Log("******* Creating assetbundles for: " + name + " *******"); // Create a directory to store the generated assetbundles. if (!Directory.Exists(AssetbundlePath)) { Directory.CreateDirectory(AssetbundlePath); } // Delete existing assetbundles for current character. string[] existingAssetbundles = Directory.GetFiles(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); foreach (SkinnedMeshRenderer smr in characterClone.GetComponentsInChildren <SkinnedMeshRenderer>()) { Object.DestroyImmediate(smr.gameObject); } characterClone.AddComponent <SkinnedMeshRenderer>(); Object characterBasePrefab = GetPrefab(characterClone, "characterbase"); string path = AssetbundlePath + name + "_characterbase.assetbundle"; BuildPipeline.BuildAssetBundle(characterBasePrefab, null, path, BuildAssetBundleOptions.CollectDependencies); AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(characterBasePrefab)); // Collect materials. List <Material> materials = EditorHelpers.CollectAll <Material>(GenerateMaterials.MaterialsPath(characterFBX)); // Create assetbundles for each SkinnedMeshRenderer. foreach (SkinnedMeshRenderer smr in characterFBX.GetComponentsInChildren <SkinnedMeshRenderer>(true)) { 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); GameObject rendererParent = rendererClone.transform.parent.gameObject; rendererClone.transform.parent = null; Object.DestroyImmediate(rendererParent); Object rendererPrefab = GetPrefab(rendererClone, "rendererobject"); 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))); // 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 void CreateCharacter() { bool createdBundle = false; // 创建一个文件夹保存生成的assetbundles. string exportPath = Application.streamingAssetsPath + "/character/"; if (!Directory.Exists(exportPath)) { Directory.CreateDirectory(exportPath); } BundleXml xml = new BundleXml(); xml.Open(); foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets)) { if (!(o is GameObject)) { continue; } if (o.name.Contains("@")) { continue; } if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) { continue; } GameObject characterFBX = (GameObject)o; string name = characterFBX.name.ToLower(); Debug.Log("******* Creating assetbundles for: " + name + " *******"); GameObject characterClone = (GameObject)Object.Instantiate(characterFBX); foreach (Animation anim in characterClone.GetComponentsInChildren <Animation>()) { anim.cullingType = AnimationCullingType.BasedOnClipBounds; } // 把网格对象删除只留下骨架. foreach (SkinnedMeshRenderer smr in characterClone.GetComponentsInChildren <SkinnedMeshRenderer>()) { Object.DestroyImmediate(smr.gameObject); } // 把骨架保存到assetbundle. string assetName = name;// +"_characterbase"; string bundleName = assetName + ASSETBUNDLE_EXT; string path = exportPath + bundleName; characterClone.AddComponent <SkinnedMeshRenderer>(); Object characterBasePrefab = GetPrefab(characterClone, assetName); BuildPipeline.BuildAssetBundle(null, new Object[] { characterBasePrefab }, path, BuildAssetBundleOptions.CollectDependencies, EditorUserBuildSettings.activeBuildTarget); AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(characterBasePrefab)); xml.UpdateAssetBundle("character/" + bundleName); xml.UpdateAsset(assetName, null); // 收集角色文件夹下的所有材质. List <Material> materials = EditorHelpers.CollectAll <Material>(GenerateMaterials.MaterialsPath(characterFBX)); // 把每个SkinnedMeshRenderer单独保存到assetbundle. foreach (SkinnedMeshRenderer smr in characterFBX.GetComponentsInChildren <SkinnedMeshRenderer>(true)) { 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)PrefabUtility.InstantiatePrefab(smr.gameObject); GameObject rendererParent = rendererClone.transform.parent.gameObject; rendererClone.transform.parent = null; Object.DestroyImmediate(rendererParent); Object rendererPrefab = GetPrefab(rendererClone, "rendererobject"); toinclude.Add(rendererPrefab); // 收集对应的材质 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"; StringHolder holder = ScriptableObject.CreateInstance <StringHolder>(); holder.content = boneNames.ToArray(); AssetDatabase.CreateAsset(holder, stringholderpath); toinclude.Add(AssetDatabase.LoadAssetAtPath(stringholderpath, typeof(StringHolder))); // Save the assetbundle. bundleName = name + "_" + smr.name.ToLower(); path = exportPath + bundleName + ASSETBUNDLE_EXT; BuildPipeline.BuildAssetBundle(null, toinclude.ToArray(), path, BuildAssetBundleOptions.CollectDependencies, EditorUserBuildSettings.activeBuildTarget); Debug.Log("Saved " + bundleName + " with " + (toinclude.Count - 2) + " materials"); xml.UpdateAssetBundle("character/" + bundleName + ASSETBUNDLE_EXT); foreach (Object m in toinclude) { if (m is Material) { xml.UpdateAsset((m as Material).name, null); } } // Delete temp assets. AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(rendererPrefab)); AssetDatabase.DeleteAsset(stringholderpath); createdBundle = true; } } xml.Close(); if (!createdBundle) { 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"); } }