public static GameObject Convert( GameObject toConvert, string fbxDirectoryFullPath = null, string fbxFullPath = null, string prefabDirectoryFullPath = null, string prefabFullPath = null, ConvertToPrefabSettingsSerialize exportOptions = null) { if (toConvert == null) { throw new System.ArgumentNullException("toConvert"); } // If we selected the something that's already backed by an // FBX, don't export. var mainAsset = GetOrCreateFbxAsset(toConvert, fbxDirectoryFullPath, fbxFullPath, exportOptions); // If we selected a prefab *instance* then break the // connection. We only want to update an existing prefab if // we're converting an existing prefab (not an instance). if (PrefabUtility.GetPrefabType(toConvert) == PrefabType.PrefabInstance) { PrefabUtility.DisconnectPrefabInstance(toConvert); } // Get 'toConvert' into an editable state. We can't edit // assets, and toConvert might be an asset. var toConvertInstance = GetOrCreateInstance(toConvert); // Set it up to track the FbxPrefab. SetupFbxPrefab(toConvertInstance, mainAsset); // Now get 'toConvertInstance' into a prefab. If toConvert is // already a prefab, this is equivalent to an 'apply' ; if it's // not, we're creating a new prefab. var prefab = ApplyOrCreatePrefab(toConvertInstance, prefabDirectoryFullPath, prefabFullPath); if (toConvertInstance == toConvert) { // If we were converting an instance, the caller expects // the instance to have the name it got saved with. var path = AssetDatabase.GetAssetPath(prefab); var filename = Path.GetFileNameWithoutExtension(path); toConvert.name = filename; } else { // If 'toConvert' was an asset, we created a temp // instance to add the component; destroy it. Object.DestroyImmediate(toConvertInstance); } return(prefab); }
/// <summary> /// Return an FBX asset that corresponds to 'toConvert'. /// /// If 'toConvert' is the root of an FBX asset, return it. /// /// If it's an instance in a scene the points to the root of an FBX /// asset, return that asset. /// /// Otherwise, export according to the paths and options, and /// return the new asset. /// </summary> /// <param name="toConvert">GameObject for which we want an fbx asset</param> /// <param name="fbxDirectoryFullPath">Export will choose an /// appropriate filename in this directory. Ignored if fbxFullPath is /// set. Ignored if toConvert is an fbx asset or an instance of an /// fbx.</param> /// <param name="fbxDirectoryFullPath">Export will create this /// file. Overrides fbxDirectoryFullPath. Ignored if toConvert is an /// fbx asset or an instance of an fbx.</param> /// <returns>The root of a model prefab asset.</returns> internal static GameObject GetOrCreateFbxAsset(GameObject toConvert, string fbxDirectoryFullPath = null, string fbxFullPath = null, ConvertToPrefabSettingsSerialize exportOptions = null) { if (toConvert == null) { throw new System.ArgumentNullException("toConvert"); } var mainAsset = GetFbxAssetOrNull(toConvert); if (mainAsset) { return(mainAsset); } if (string.IsNullOrEmpty(fbxFullPath)) { // Generate a unique filename. if (string.IsNullOrEmpty(fbxDirectoryFullPath)) { fbxDirectoryFullPath = UnityEditor.Formats.Fbx.Exporter.ExportSettings.FbxAbsoluteSavePath; } else { fbxDirectoryFullPath = Path.GetFullPath(fbxDirectoryFullPath); } var fbxBasename = ModelExporter.ConvertToValidFilename(toConvert.name + ".fbx"); fbxFullPath = Path.Combine(fbxDirectoryFullPath, fbxBasename); if (File.Exists(fbxFullPath)) { fbxFullPath = IncrementFileName(fbxDirectoryFullPath, fbxFullPath); } } var projectRelativePath = ExportSettings.GetProjectRelativePath(fbxFullPath); // Make sure that the object names in the hierarchy are unique. // The import back in to Unity would do this automatically but // we prefer to control it so that the Maya artist can see the // same names as exist in Unity. EnforceUniqueNames(new GameObject[] { toConvert }); // Export to FBX. It refreshes the database. { var fbxActualPath = ModelExporter.ExportObject( fbxFullPath, toConvert, exportOptions != null ? exportOptions : new ConvertToPrefabSettingsSerialize() ); if (fbxActualPath != fbxFullPath) { throw new ConvertToNestedPrefabException("Failed to convert " + toConvert.name); } } // Replace w Model asset. LoadMainAssetAtPath wants a path // relative to the project, not relative to the assets folder. var unityMainAsset = AssetDatabase.LoadMainAssetAtPath(projectRelativePath) as GameObject; if (!unityMainAsset) { throw new ConvertToNestedPrefabException("Failed to convert " + toConvert.name); } return(unityMainAsset); }
public static GameObject Convert( GameObject toConvert, string fbxDirectoryFullPath = null, string fbxFullPath = null, string prefabDirectoryFullPath = null, string prefabFullPath = null, ConvertToPrefabSettingsSerialize exportOptions = null) { if (toConvert == null) { throw new System.ArgumentNullException("toConvert"); } if (PrefabUtility.IsPartOfNonAssetPrefabInstance(toConvert) && !PrefabUtility.IsOutermostPrefabInstanceRoot(toConvert)) { return(null); // cannot convert in this scenario } // can't currently handle converting root of prefab in prefab preview scene if (SceneManagement.EditorSceneManager.IsPreviewSceneObject(toConvert) && toConvert.transform.parent == null) { return(null); } // If we selected the something that's already backed by an // FBX, don't export. var mainAsset = GetOrCreateFbxAsset(toConvert, fbxDirectoryFullPath, fbxFullPath, exportOptions); // if toConvert is part of a prefab asset and not an instance, make it an instance in a preview scene // so that we can unpack it and avoid issues with nested prefab references. bool isPrefabAsset = false; UnityEngine.SceneManagement.Scene?previewScene = null; if (PrefabUtility.IsPartOfPrefabAsset(toConvert) && PrefabUtility.GetPrefabInstanceStatus(toConvert) == PrefabInstanceStatus.NotAPrefab) { previewScene = SceneManagement.EditorSceneManager.NewPreviewScene(); toConvert = PrefabUtility.InstantiatePrefab(toConvert, previewScene.Value) as GameObject; isPrefabAsset = true; } // don't need to undo if we are converting a prefab asset if (!isPrefabAsset) { Undo.IncrementCurrentGroup(); Undo.SetCurrentGroupName(string.Format(UndoConversionGroup, toConvert.name)); } // if root is a prefab instance, unpack it. Unpack everything below as well if (PrefabUtility.GetPrefabInstanceStatus(toConvert) == PrefabInstanceStatus.Connected) { Undo.RegisterFullObjectHierarchyUndo(toConvert, "unpack prefab instance"); PrefabUtility.UnpackPrefabInstance(toConvert, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); } // create prefab variant from the fbx var fbxInstance = PrefabUtility.InstantiatePrefab(mainAsset) as GameObject; // replace hierarchy in the scene if (!isPrefabAsset && toConvert != null) { // don't worry about keeping the world position in the prefab, as we will fix the transform on the instance root fbxInstance.transform.SetParent(toConvert.transform.parent, worldPositionStays: false); fbxInstance.transform.SetSiblingIndex(toConvert.transform.GetSiblingIndex()); } // copy components over UpdateFromSourceRecursive(fbxInstance, toConvert); // make sure we have a path for the prefab if (string.IsNullOrEmpty(prefabFullPath)) { // Generate a unique filename. if (string.IsNullOrEmpty(prefabDirectoryFullPath)) { prefabDirectoryFullPath = UnityEditor.Formats.Fbx.Exporter.ExportSettings.PrefabAbsoluteSavePath; } else { prefabDirectoryFullPath = Path.GetFullPath(prefabDirectoryFullPath); } var prefabBasename = ModelExporter.ConvertToValidFilename(toConvert.name + ".prefab"); prefabFullPath = Path.Combine(prefabDirectoryFullPath, prefabBasename); if (File.Exists(prefabFullPath)) { prefabFullPath = IncrementFileName(prefabDirectoryFullPath, prefabFullPath); } } // make sure the directory structure exists var dirName = Path.GetDirectoryName(prefabFullPath); if (!Directory.Exists(dirName)) { Directory.CreateDirectory(dirName); } var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(fbxInstance, ExportSettings.GetProjectRelativePath(prefabFullPath), InteractionMode.AutomatedAction); // replace hierarchy in the scene if (!isPrefabAsset && toConvert != null) { Undo.DestroyObjectImmediate(toConvert); Undo.RegisterCreatedObjectUndo(fbxInstance, UndoConversionCreateObject); SceneManagement.EditorSceneManager.MarkSceneDirty(fbxInstance.scene); Undo.IncrementCurrentGroup(); return(fbxInstance); } else { Undo.ClearUndo(toConvert); Undo.ClearUndo(fbxInstance); Object.DestroyImmediate(fbxInstance); Object.DestroyImmediate(toConvert); } if (previewScene.HasValue) { SceneManagement.EditorSceneManager.ClosePreviewScene(previewScene.Value); } return(prefab); }