How can I get the real Texture/Sprites reference in OnPostprocessSprites in Unity?

Viewed 398

My goal was to create an import script (AssetPostprocessor), that handles a few things for me whenever I drag a spritesheet (a picture that contains multiple frames for an animation) into a specific Unity folder.

I want the script to split the picture up into multiple frames (similar to when its done manually, with Sprite Mode = Multiple), and then create an animation out of it. I parse the instructions (name, sprite frame size, frame holds) from the file name that gets handled.

Example: "Player_Walk_200x100_h3-3-3-3-3.png"

So far, I managed to accomplish all of those points, but whenever I create an animation and link the given Sprites to it, the resulting animation is "empty". As far as I could figure out, that's because the Texture2D and Sprite[] given to OnPostprocessSprites() seems to be temporary. The object exists during creation, but seemingly gets discarded later on. How can I solve this? How can I grab a reference to Sprite[] that doesn't get dropped?

Here is a stripped down version of my current core:

void OnPostprocessTexture( Texture2D texture ) {
    // the texture is split into frames here, code not included since this part works fine and would complicate things.
}

void OnPostprocessSprites( Texture2D texture, Sprite[] sprites ) { 
    if( !this.assetPath.Contains( 'spritetest' ) ) return;

    Debug.Log( "Number of Sprites: "  + sprites.Length ); // shows the correct number of sprites

    if( sprites.Length == 0 ) { 
        AssetDatabase.ImportAsset( this.assetImporter.assetPath );

        return;
    }

    int frameRate = 24;

    AnimationClip clip = new AnimationClip();
    clip.frameRate = frameRate;

    EditorCurveBinding spriteBinding = new EditorCurveBinding();
    spriteBinding.type = typeof( SpriteRenderer );
    spriteBinding.path = "";
    spriteBinding.propertyName = "m_Sprite";

    ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[ sprites.Length ];

    for( int i = 0; i < sprites.Length; i++ ) { 
        spriteKeyFrames[ i ]       = new ObjectReferenceKeyframe();
        spriteKeyFrames[ i ].time  = i;
        spriteKeyFrames[ i ].value = sprites[ i ]; // these sprites are empty in the editor
    }

    AnimationUtility.SetObjectReferenceCurve( clip, spriteBinding, spriteKeyFrames );

    AssetDatabase.CreateAsset( clip, "Assets/Assets/spritetest/Test.anim" );
    AssetDatabase.SaveAssets();
    AssetDatabase.Refresh();

}

I've looked up forum posts, documentations, and even questions here (like Unity Editor Pipeline Scripting: how to Pass Sprite to SpriteRenderer in OnPostprocessSprites() Event? ) but none really managed to resolve this problem: whenever I try to grab the "real" sprite or texture via AssetDatabase, the resulting object is always just null.

For example, if I try doing this:

// attempt 1
Sprite sprites = AssetDatabase.LoadAssetAtPath<Sprite>( this.assetPath );
Debug.Log( "Real Sprite: " + sprite ); // sprite is null

// attempt 2
Object[] objects = AssetDatabase.LoadAllAssetRepresentationsAtPath( this.assetPath );
Debug.Log( "Real Objects: " + objects.Length ); // is always 0

Calling AssetDatabase.SaveAssets() or AssetDatabase.Refresh() beforehand doesn't change the result. I find plenty of people with similar issues, but no code or examples that seem to really resolve this issue.

Here is another person with a similar issue: ( source: https://answers.unity.com/questions/1080430/create-animation-clip-from-sprites-programmaticall.html )

enter image description here

The given link didn't resolve my problem either.

Essentially: How can I create an animation from an imported asset, by using my generated sprites, in AssetPostprocessor?

0 Answers
Related