Getting object as prefab (In my case, Animation)

So, as I still have a problem with Unity’s imported FBX’s rotation, I would love to at least know, how to rotate their animations through script.

So, the first thing to do was duplicating animation files from prefab. You just expand it, find animation in prefab and click ‘Ctrl+D’. That’s how I extract animations from imported prefabs.

Then I’m trying to use special script to make everything look a bit better:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class FixAnimationPostprocessor
{
    public Animator animator;

    [MenuItem("Assets/Transform Animations")]
    public static bool TransformAnimations()
    {
        var selected = Selection.objects;

        foreach (Object selection in selected)
        {
            var animation = Resources.Load<Animation>(AssetDatabase.GetAssetPath(selection));
            animation.transform.rotation = Quaternion.Euler(90f, 0f, 0f);
        }

        return Selection.activeObject.GetType() == typeof(Animation);
    }
}

And, this is a bad solution at least because I get this error:

NullReferenceException: Object reference not set to an instance of an object
FixAnimationPostprocessor.TransformAnimations () (at Assets/Editor/FixAnimationPostprocessor.cs:18)

I don’t even know what to use in that case, so that I can access my asset as Animation.class

You probably need to use Animator, AnimatorController, or AnimationClip, not the Animation class. The Animation class is an obsolete legacy component.

Even though I should use it, I still wouldn’t be able to access asset Object.class as Animator.class.

P.S. I put ‘.class’ to mark it as a C# script class.
P.S.S. I’ve also thought that I should use Animator, because it’s a little more precise in my case.

I’m not sure I follow your problem. As far as I can tell, you don’t ever have an “Object” type variable anywhere in your code. In line 17, Resources.Load will return an object of type Animation, and because it’s using the “var” keyword, the assignment will determine the type - therefore “animation” is of type Animation. The problem isn’t that “animation” is an Object, the problem is that it’s null. It’s null because Resources.Load didn’t find anything of type Animation at the specified path, because Unity no longer imports things as type Animation.

@StarManta mhm, I don’t really understand why Resources.Load works only at import, but I’ve tried to use AssetDatabase.LoadAssetAtPath… And it doesn’t work, still.
The code now is:

[MenuItem("Assets/Transform Animations")]
    public static bool TransformAnimations()
    {
        var selected = Selection.objects;

        foreach (Object selection in selected)
        {
            var animation = AssetDatabase.LoadAssetAtPath<Animator>(AssetDatabase.GetAssetPath(selection));
            animation.bodyRotation = Quaternion.Euler(90f, 0f, 0f);
        }

        return Selection.activeObject.GetType() == typeof(Animator);
    }

Ah, it’s so hard to understand :smile:

Could you show a screenshot (including the project window and the inspector) of the object on which you’re attempting to run this script?

@StarManta sorry for being late. Here’s the screenshots step-by-step:


4706813--444644--upload_2019-7-2_20-53-26.png



And I should say - it’s just horrible, that Unity, unlike UE4, does not support FBX’s On-import settings. In UE4, I can easily set local rotation to 90*, in Unity I can change local rotation when importing things with code. However, it does not support animations.

Actually, the rotation for static models works with this code by someone else on r/Unity3D, but I’ve forget the author:

using System.IO;
using UnityEngine;
using UnityEditor;

public class FixFbxModelPostprocessor : AssetPostprocessor
{
    public void OnPostprocessModel(GameObject obj)
    {
        ModelImporter importer = assetImporter as ModelImporter;
        if (Path.GetExtension(importer.assetPath) == ".fbx")
        {
            FixObject(obj.transform);
            Debug.Log("[Fix FBX] Finished for " + Path.GetFileName(importer.assetPath));
        }
    }

    private void FixObject(Transform obj)
    {
        MeshFilter meshFilter = obj.GetComponent<MeshFilter>();

        /*
         * First we need to undo the stupid -90 dregree rotation on the X axis that Unity does
         * on every game object with a mesh
         */
        if (meshFilter)
        {
            obj.localRotation *= Quaternion.Euler(90, 0, 0);
        }

        /*
         * Translate rotation into Unity's coordinate system
         */
        Quaternion lc = obj.transform.localRotation;
        obj.transform.localRotation = Quaternion.Euler(-lc.x, lc.y, -lc.z); //lc.w);

        /*
         * Translate position into Unity's coordinate system
         */
        Vector3 currentPos = obj.transform.localPosition;
        obj.transform.localPosition = new Vector3(-currentPos.x, currentPos.y, -currentPos.z);

        /*
         * Translate mesh into Unity's coordinate system
         */
        if (meshFilter)
        {
            FixMesh(meshFilter.sharedMesh);
        }

        /*
         * Repeat for all sub objects
         */
        foreach (Transform child in obj)
        {
            FixObject(child);
        }
    }

    private void FixMesh(Mesh mesh)
    {
        /*
         * We fix the vertices by flipping Z axis with Y axis
         * Odly enough X has to be inverted. When we store a positive X in Blender somehow it gets inverted in the *.fbx format O.o
         */
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < vertices.Length; i++)
        {
            vertices[i] = new Vector3(-vertices[i].x, vertices[i].z, vertices[i].y);
        }
        mesh.vertices = vertices;

        /*
         * Same goes for normals
         */
        Vector3[] normals = mesh.normals;
        for (int i = 0; i < normals.Length; i++)
        {
            normals[i] = new Vector3(-normals[i].x, normals[i].z, normals[i].y);
        }
        mesh.normals = normals;

        /*
         * Vertex positions have changed, so recalc bounds
         */
        mesh.RecalculateBounds();
    }
}

It works at runtime, so when any model is imported, it’s being converted to Unity’s orientation system.

Hope this will help you to understand the problem.

Alright, those files will be of type AnimationClip.

I may have to burst a bubble here though - the functionality you’re going for may not be doable through normal Unity classes. AnimationClips (at least last time I tried to do something similar) have terrible script accessibility in terms of editing them.

The general advice here (and actually the official answer) would be to make your animated object a child of another object. The parent object will be moved as the primary object, while the child (the model) is rotated at whatever angles are needed to make it upright.

1 Like

@StarManta well, that’s a shame ._.

Actually, it’s not that bad solution, but I just keep answering myself why Unity doesn’t make any better solution within Unity Editor.

Okay, thanks for responding and help! At least I found the more or less suitable solution.

Thanks again.