示例#1
0
        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);
        }