• RuntimesUnity
  • Render and cache frames of a Spine animation as a runtime generated texture

Hi,

I need to dynamically create a rendered frame of my Spine animations so I can use them within another library.

The editor of the game I'm working on is done using a Dear ImGui Binding (UImGui) for Unity and I have to show all the Spine based objects within the Dear ImGui based UI.
So what I aim to do is to implement a simple caching system that renders and caches single frames of arbitrary Skeletons and returns those to my UI code - but, right now, I have a hard time finding good info about how to do this in a simple and easy way.

Any suggestions about the best way to get this done?

Thanks a lot

Related Discussions
...

To render and cache frames of a Spine animation as a runtime-generated texture in Unity, you can use Unity's RenderTexture to capture the current state of the Spine skeleton and save it as a texture. Here are the steps to achieve this:

  1. Set up a RenderTexture:
    Create a RenderTexture that will be used to capture the frame.

  2. Render the Spine skeleton to the RenderTexture:
    Use a camera to render the Spine skeleton to the RenderTexture.

  3. Convert the RenderTexture to a Texture2D:
    Read the pixels from the RenderTexture and store them in a Texture2D.

  4. Cache the Texture2D:
    Store the Texture2D in a cache for later use.

Here is a sample code snippet to illustrate these steps:

using UnityEngine;

public class SpineFrameCacher : MonoBehaviour
{
    public Camera renderCamera;
    public RenderTexture renderTexture;
    private Dictionary<string, Texture2D> frameCache = new Dictionary<string, Texture2D>();

    public Texture2D GetFrame(SkeletonAnimation skeletonAnimation, string frameKey)
    {
        if (frameCache.ContainsKey(frameKey))
        {
            return frameCache[frameKey];
        }

        // Set the camera to render the skeleton
        renderCamera.targetTexture = renderTexture;
        renderCamera.Render();

        // Create a new Texture2D and read the RenderTexture into it
        Texture2D texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGBA32, false);
        RenderTexture.active = renderTexture;
        texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        texture.Apply();

        // Cache the texture
        frameCache[frameKey] = texture;

        // Clean up
        RenderTexture.active = null;
        renderCamera.targetTexture = null;

        return texture;
    }
}

Explanation:

  1. RenderTexture Setup:

    • renderTexture is the RenderTexture where the frame will be rendered.
    • renderCamera is the camera that will render the Spine skeleton to the RenderTexture.
  2. Rendering and Caching:

    • The GetFrame method checks if the frame is already cached.
    • If not, it sets the camera's target texture to the RenderTexture and renders the scene.
    • It then reads the pixels from the RenderTexture into a Texture2D and caches it.

Additional Tips:

  • Ensure the camera is set up correctly to only render the Spine skeleton.
  • Adjust the camera's orthographic size and position to fit the skeleton properly.
  • You can optimize the caching mechanism by implementing a cache eviction policy if memory usage becomes an issue.

By following these steps, you can dynamically create and cache rendered frames of your Spine animations for use within your Dear ImGui-based UI.

@Nelvin You might also want to check out the SkeletonRenderTexture and SkeletonGraphicRenderTexture components which can precisely render skeletons to a render texture and then draw them on an equal-sized quad. See the documentation here:
http://esotericsoftware.com/spine-unity-utility-components#SkeletonRenderTexture
While it might not be exactly what you need, perhaps it might perhaps come in handy as a reference to base your own implementation on, if you need to render to exact boundaries.

  • Nelvin ответили на это сообщение.
  • Nelvin оценил это.

    Harald Thanks for the infos an the link - given this and other threads I've found I now have a basic working version (much more limited/simpler implementation but it does exactly what I need).

    Thanks again Harald - your support is stellar.

    @Nelvin Very glad to hear it helped, thanks for your kind words.