private HashSet <string> GetAnimatedGameObjects(AnimationClip[] animClips, GameObject animatorObject)
        {
            var animatedObjects = new HashSet <string>();

            foreach (var clip in animClips)
            {
                foreach (EditorCurveBinding uniCurveBinding in AnimationUtility.GetCurveBindings(clip))
                {
                    Object uniObj = AnimationUtility.GetAnimatedObject(animatorObject, uniCurveBinding);
                    if (!uniObj)
                    {
                        continue;
                    }

                    GameObject unityGo = ModelExporter.GetGameObject(uniObj);
                    if (!unityGo)
                    {
                        continue;
                    }

                    // also it's parents up until but excluding the root (the root will have a different name)
                    var parent = unityGo.transform;
                    while (parent != null && parent.parent != null)
                    {
                        animatedObjects.Add(parent.name);
                        parent = parent.parent;
                    }
                }
            }
            return(animatedObjects);
        }
        protected bool SelectionContainsPrefabInstanceWithAddedObjects()
        {
            var            exportSet = GetToExport();
            Stack <Object> stack     = new Stack <Object>(exportSet);

            while (stack.Count > 0)
            {
                var go = ModelExporter.GetGameObject(stack.Pop());
                if (!go)
                {
                    continue;
                }

                if (PrefabUtility.IsAnyPrefabInstanceRoot(go) && PrefabUtility.GetAddedGameObjects(go).Count > 0)
                {
                    return(true);
                }

                foreach (Transform child in go.transform)
                {
                    stack.Push(child.gameObject);
                }
            }
            return(false);
        }
        protected void SetGameObjectsToConvert(IEnumerable <GameObject> toConvert)
        {
            ToExport = toConvert.OrderBy(go => go.name).ToArray();

            TransferAnimationSource = null;
            TransferAnimationDest   = null;

            var    toExport    = ToExport;
            string fbxFileName = null;

            if (toExport.Length == 1)
            {
                var go = ModelExporter.GetGameObject(toExport[0]);
                // check if the GameObject is a model instance, use as default filename and path if it is
                GameObject mainAsset = ConvertToNestedPrefab.GetFbxAssetOrNull(go);
                if (!mainAsset)
                {
                    // Use the game object's name
                    m_prefabFileName = go.name;
                }
                else
                {
                    // Use the asset's name
                    var mainAssetRelPath = AssetDatabase.GetAssetPath(mainAsset);
                    // remove Assets/ from beginning of path
                    mainAssetRelPath = mainAssetRelPath.Substring("Assets".Length);

                    m_prefabFileName = System.IO.Path.GetFileNameWithoutExtension(mainAssetRelPath);
                    ExportSettings.AddFbxSavePath(System.IO.Path.GetDirectoryName(mainAssetRelPath));

                    fbxFileName = m_prefabFileName;
                }

                var fullPrefabPath = System.IO.Path.Combine(ExportSettings.PrefabAbsoluteSavePath, m_prefabFileName + ".prefab");
                if (System.IO.File.Exists(fullPrefabPath))
                {
                    m_prefabFileName = System.IO.Path.GetFileNameWithoutExtension(ConvertToNestedPrefab.IncrementFileName(ExportSettings.PrefabAbsoluteSavePath, m_prefabFileName + ".prefab"));
                }

                // if only one object selected, set transfer source/dest to this object
                if (go)
                {
                    TransferAnimationSource = go.transform;
                    TransferAnimationDest   = go.transform;
                }
            }
            else if (toExport.Length > 1)
            {
                m_prefabFileName = "(automatic)";
            }

            // if there is an existing fbx file then use its name, otherwise use the same name as for the prefab
            this.SetFilename(fbxFileName != null? fbxFileName : m_prefabFileName);
        }
Exemplo n.º 4
0
 protected bool ExportSetContainsAnimation()
 {
     foreach (var obj in GetToExport())
     {
         var go = ModelExporter.GetGameObject(obj);
         if (go.GetComponentInChildren <Animation>() || go.GetComponentInChildren <Animator>())
         {
             return(true);
         }
     }
     return(false);
 }
Exemplo n.º 5
0
        /// <summary>
        /// Return the number of objects in the selection that contain RectTransforms.
        /// </summary>
        protected int GetUIElementsInExportSetCount()
        {
            int count = 0;

            foreach (var obj in GetToExport())
            {
                var go             = ModelExporter.GetGameObject(obj);
                var rectTransforms = go.GetComponentsInChildren <RectTransform>();
                count += rectTransforms.Length;
            }
            return(count);
        }
Exemplo n.º 6
0
        /// <summary>
        /// collect all object dependencies for given animation clip
        /// </summary>
        public void CollectDependencies(
            AnimationClip animClip,
            GameObject rootObject,
            IExportOptions exportOptions
            )
        {
            Debug.Assert(rootObject != null);
            Debug.Assert(exportOptions != null);

            if (this.animationClips.ContainsKey(animClip))
            {
                // we have already exported gameobjects for this clip
                return;
            }

            // NOTE: the object (animationRootObject) containing the animation is not necessarily animated
            // when driven by an animator or animation component.
            this.animationClips.Add(animClip, rootObject);

            foreach (EditorCurveBinding uniCurveBinding in AnimationUtility.GetCurveBindings(animClip))
            {
                Object uniObj = AnimationUtility.GetAnimatedObject(rootObject, uniCurveBinding);
                if (!uniObj)
                {
                    continue;
                }

                GameObject unityGo = ModelExporter.GetGameObject(uniObj);
                if (!unityGo)
                {
                    continue;
                }

                if (!exportOptions.AnimateSkinnedMesh && unityGo.GetComponent <SkinnedMeshRenderer>())
                {
                    continue;
                }

                // If we have a clip driving a camera or light then force the export of FbxNodeAttribute
                // so that they point the right way when imported into Maya.
                if (unityGo.GetComponent <Light>())
                {
                    this.exportComponent[unityGo] = typeof(Light);
                }
                else if (unityGo.GetComponent <Camera>())
                {
                    this.exportComponent[unityGo] = typeof(Camera);
                }

                this.goExportSet.Add(unityGo);
            }
        }
 /// <summary>
 /// Return true if the given set contains only prefab assets on disk,
 /// and nothing from the scene.
 /// </summary>
 /// <returns></returns>
 internal static bool SetContainsOnlyPrefabAssets(Object[] toConvert)
 {
     foreach (var obj in toConvert)
     {
         var go = ModelExporter.GetGameObject(obj);
         if (go != null && !PrefabUtility.IsPartOfPrefabAsset(go))
         {
             // return as soon as we find something that is not part of a prefab asset
             // on disk
             return(false);
         }
     }
     return(true);
 }
        /// <summary>
        /// For all scene objects holding a reference to origObj, replaces the references to newObj.
        ///
        /// If one of the scene objects is toConvertRoot or a child of it, then do not fix its references as it
        /// will be deleted after conversion.
        /// </summary>
        /// <param name="origObj"></param>
        /// <param name="newObj"></param>
        /// <param name="toConvertRoot"></param>
        internal static void FixSceneReferences(Object origObj, Object newObj, GameObject toConvertRoot)
        {
            var sceneObjs = GetSceneReferencesToObject(origObj);

            // try to fix references on each component of each scene object, if applicable
            foreach (var sceneObj in sceneObjs)
            {
                var go = ModelExporter.GetGameObject(sceneObj);
                if (go && go.transform.IsChildOf(toConvertRoot.transform))
                {
                    // if this is a child of what we are converting, don't update its references.
                    continue;
                }

                var components = sceneObj.GetComponents <Component>();
                foreach (var component in components)
                {
                    var serializedComponent = new SerializedObject(component);
                    var property            = serializedComponent.GetIterator();
                    property.Next(true); // skip generic field
                    // For SkinnedMeshRenderer, the bones array doesn't have visible children, but may have references that need to be fixed.
                    // For everything else, filtering by visible children in the while loop and then copying properties that don't have visible children,
                    // ensures that only the leaf properties are copied over. Copying other properties is not usually necessary and may break references that
                    // were not meant to be copied.
                    while (property.Next((component is SkinnedMeshRenderer) ? property.hasChildren : property.hasVisibleChildren))
                    {
                        if (!property.hasVisibleChildren)
                        {
                            // with Undo operations, copying m_Father reference causes issues. Also, it is not required as the reference is fixed when
                            // the transform is parented under the correct hierarchy (which happens before this).
                            if (property.propertyType == SerializedPropertyType.ObjectReference && property.propertyPath != "m_GameObject" &&
                                property.propertyPath != "m_Father" && property.objectReferenceValue &&
                                (property.objectReferenceValue == origObj))
                            {
                                property.objectReferenceValue = newObj;
                                serializedComponent.ApplyModifiedProperties();
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 9
0
        protected void SetGameObjectsToConvert(IEnumerable <GameObject> toConvert)
        {
            SetToExport(toConvert.OrderBy(go => go.name).ToArray());

            TransferAnimationSource = null;
            TransferAnimationDest   = null;
            if (GetToExport().Length == 1)
            {
                var go = ModelExporter.GetGameObject(GetToExport()[0]);
                // check if the GameObject is a model instance, use as default filename and path if it is
                var mainAsset = ConvertToModel.GetFbxAssetOrNull(go);
                if (!mainAsset)
                {
                    // Use the game object's name
                    m_prefabFileName = go.name;
                }
                else
                {
                    // Use the asset's name
                    var mainAssetRelPath = AssetDatabase.GetAssetPath(mainAsset);
                    // remove Assets/ from beginning of path
                    mainAssetRelPath = mainAssetRelPath.Substring("Assets".Length);

                    m_prefabFileName = System.IO.Path.GetFileNameWithoutExtension(mainAssetRelPath);
                    ExportSettings.AddFbxSavePath(System.IO.Path.GetDirectoryName(mainAssetRelPath));
                }

                // if only one object selected, set transfer source/dest to this object
                if (go)
                {
                    TransferAnimationSource = go.transform;
                    TransferAnimationDest   = go.transform;
                }
            }
            else if (GetToExport().Length > 1)
            {
                m_prefabFileName = "(automatic)";
            }

            this.SetFilename(m_prefabFileName);
        }
        protected bool SelectionContainsPrefabInstanceWithAddedObjects()
        {
            var exportSet = GetToExport();

            // FBX-60 (fogbug 1307749):
            // On Linux OnGUI() sometimes gets called a few times before
            // the export set is set and window.show() is called.
            // This leads to this function being called from OnGUI() with a
            // null or empty export set, and an ArgumentNullException when
            // creating the stack.
            // Check that the set exists and has values before creating the stack.
            if (exportSet == null || exportSet.Length <= 0)
            {
                return(false);
            }

            Stack <Object> stack = new Stack <Object>(exportSet);

            while (stack.Count > 0)
            {
                var go = ModelExporter.GetGameObject(stack.Pop());
                if (!go)
                {
                    continue;
                }

                if (PrefabUtility.IsAnyPrefabInstanceRoot(go) && PrefabUtility.GetAddedGameObjects(go).Count > 0)
                {
                    return(true);
                }

                foreach (Transform child in go.transform)
                {
                    stack.Push(child.gameObject);
                }
            }
            return(false);
        }
Exemplo n.º 11
0
        protected override bool Export()
        {
            if (string.IsNullOrEmpty(ExportFileName))
            {
                Debug.LogError("FbxExporter: Please specify an fbx filename");
                return(false);
            }

            if (string.IsNullOrEmpty(m_prefabFileName))
            {
                Debug.LogError("FbxExporter: Please specify a prefab filename");
                return(false);
            }

            var fbxDirPath = ExportSettings.FbxAbsoluteSavePath;
            var fbxPath    = System.IO.Path.Combine(fbxDirPath, ExportFileName + ".fbx");

            var prefabDirPath = ExportSettings.PrefabAbsoluteSavePath;
            var prefabPath    = System.IO.Path.Combine(prefabDirPath, m_prefabFileName + ".prefab");

            if (GetToExport() == null)
            {
                Debug.LogError("FbxExporter: missing object for conversion");
                return(false);
            }

            int rectTransformCount = GetUIElementsInExportSetCount();

            if (rectTransformCount > 0)
            {
                // Warn that UI elements will break if converted
                string warning = string.Format("Warning: UI Components (ie, RectTransform) are not saved when converting to FBX.\n{0} item(s) in the selection will lose their UI components.",
                                               rectTransformCount);
                bool result = UnityEditor.EditorUtility.DisplayDialog(
                    string.Format("{0} Warning", ModelExporter.PACKAGE_UI_NAME), warning, "Convert and Lose UI", "Cancel");

                if (!result)
                {
                    return(false);
                }
            }

            if (SettingsObject.UseMayaCompatibleNames && SettingsObject.AllowSceneModification)
            {
                string warning = "Names of objects in the hierarchy may change with the Compatible Naming option turned on";
                if (ExportSetContainsAnimation())
                {
                    warning = "Compatible Naming option turned on. Names of objects in hierarchy may change and break animations.";
                }

                // give a warning dialog that indicates that names in the scene may change
                int result = UnityEditor.EditorUtility.DisplayDialogComplex(
                    string.Format("{0} Warning", ModelExporter.PACKAGE_UI_NAME), warning, "OK", "Turn off and continue", "Cancel"
                    );
                if (result == 1)
                {
                    // turn compatible naming off
                    SettingsObject.SetUseMayaCompatibleNames(false);
                }
                else if (result == 2)
                {
                    return(false);
                }
            }

            if (GetToExport().Length == 1)
            {
                var go = ModelExporter.GetGameObject(GetToExport()[0]);

                // Check if we'll be clobbering files. If so, warn the user
                // first and let them cancel out.
                if (!OverwriteExistingFile(prefabPath))
                {
                    return(false);
                }

                if (ConvertToNestedPrefab.WillExportFbx(go))
                {
                    if (!OverwriteExistingFile(fbxPath))
                    {
                        return(false);
                    }
                }

                ConvertToNestedPrefab.Convert(
                    go, fbxFullPath: fbxPath, prefabFullPath: prefabPath, exportOptions: ExportSettings.instance.ConvertToPrefabSettings.info
                    );
                return(true);
            }

            bool onlyPrefabAssets = ConvertToNestedPrefab.SetContainsOnlyPrefabAssets(GetToExport());
            int  groupIndex       = -1;

            // no need to undo if we aren't converting anything that's in the scene
            if (!onlyPrefabAssets)
            {
                Undo.IncrementCurrentGroup();
                groupIndex = Undo.GetCurrentGroup();
                Undo.SetCurrentGroupName(ConvertToNestedPrefab.UndoConversionCreateObject);
            }
            foreach (var obj in GetToExport())
            {
                // Convert, automatically choosing a file path that won't clobber any existing files.
                var go = ModelExporter.GetGameObject(obj);
                ConvertToNestedPrefab.Convert(
                    go, fbxDirectoryFullPath: fbxDirPath, prefabDirectoryFullPath: prefabDirPath, exportOptions: ExportSettings.instance.ConvertToPrefabSettings.info
                    );
            }
            if (!onlyPrefabAssets && groupIndex >= 0)
            {
                Undo.CollapseUndoOperations(groupIndex);
                Undo.IncrementCurrentGroup();
            }
            return(true);
        }
Exemplo n.º 12
0
        protected override bool Export()
        {
            if (string.IsNullOrEmpty(ExportFileName))
            {
                Debug.LogError("FbxExporter: Please specify an fbx filename");
                return(false);
            }

            if (string.IsNullOrEmpty(m_prefabFileName))
            {
                Debug.LogError("FbxExporter: Please specify a prefab filename");
                return(false);
            }

            var fbxDirPath = ExportSettings.FbxAbsoluteSavePath;
            var fbxPath    = System.IO.Path.Combine(fbxDirPath, ExportFileName + ".fbx");

            var prefabDirPath = ExportSettings.PrefabAbsoluteSavePath;
            var prefabPath    = System.IO.Path.Combine(prefabDirPath, m_prefabFileName + ".prefab");

            if (GetToExport() == null)
            {
                Debug.LogError("FbxExporter: missing object for conversion");
                return(false);
            }

            if (SettingsObject.UseMayaCompatibleNames && SettingsObject.AllowSceneModification)
            {
                string warning = "Names of objects in the hierarchy may change with the Compatible Naming option turned on";
                if (ExportSetContainsAnimation())
                {
                    warning = "Compatible Naming option turned on. Names of objects in hierarchy may change and break animations.";
                }

                // give a warning dialog that indicates that names in the scene may change
                int result = UnityEditor.EditorUtility.DisplayDialogComplex(
                    string.Format("{0} Warning", ModelExporter.PACKAGE_UI_NAME), warning, "OK", "Turn off and continue", "Cancel"
                    );
                if (result == 1)
                {
                    // turn compatible naming off
                    SettingsObject.SetUseMayaCompatibleNames(false);
                }
                else if (result == 2)
                {
                    return(false);
                }
            }

            if (GetToExport().Length == 1)
            {
                var go = ModelExporter.GetGameObject(GetToExport()[0]);

                // Check if we'll be clobbering files. If so, warn the user
                // first and let them cancel out.
                if (ConvertToModel.WillCreatePrefab(go))
                {
                    if (!OverwriteExistingFile(prefabPath))
                    {
                        return(false);
                    }
                }
                if (ConvertToModel.WillExportFbx(go))
                {
                    if (!OverwriteExistingFile(fbxPath))
                    {
                        return(false);
                    }
                }

                ConvertToModel.Convert(
                    go, fbxFullPath: fbxPath, prefabFullPath: prefabPath, exportOptions: ExportSettings.instance.ConvertToPrefabSettings.info
                    );
                return(true);
            }

            foreach (var obj in GetToExport())
            {
                // Convert, automatically choosing a file path that won't clobber any existing files.
                var go = ModelExporter.GetGameObject(obj);
                ConvertToModel.Convert(
                    go, fbxDirectoryFullPath: fbxDirPath, prefabDirectoryFullPath: prefabDirPath, exportOptions: ExportSettings.instance.ConvertToPrefabSettings.info
                    );
            }
            return(true);
        }