• RuntimesUnity
  • Performance Issues with Hidden Spine Animations

Hello Everyone,

We've been happily using Spine for UI animations in our mobile game project for a while. However, we recently discovered some performance issues related to our Spine usage. Due to these issues, our FPS on Android has started dropping below 60 on some test devices, and we're concerned that adding more Spine animations as we develop the game further will worsen the FPS drops.

When we remove Spine animations from UI prefabs and build the project, our FPS nearly doubles. This strongly suggests that the issue is related to how we're using Spine.

The main problem we're facing is that Spine animations seem to impact performance even when they are not being rendered at the time and their GameObjects are set to inactive. Even when no Spine animations are visibly active on the screen, they still affect performance.

  • We are using Spine 4.1

  • We've set "Update When Invisible" to "Nothing".

  • By default, no animation is selected.

  • We are using Linear Color Space and have configured the project to match Straight Alpha export settings.

  • Despite some of our Spine animations having no additive materials and using a single texture, we receive warnings that we need to enable the Multiple Canvas setting. We've enabled this where necessary.

  • Raycasts are disabled for all animations.

Due to certain constraints, I can't share project files or example visuals, but I can provide any specific settings you may need. Has anyone encountered similar issues and found a solution? Any recommendations would be greatly appreciated!

  • Harald відповіли на це.
    Related Discussions
    ...

    It seems like you're experiencing performance issues with Spine animations in your mobile game, even when the animations are not actively being rendered. Here are a few suggestions to help address these issues:

    1. Ensure Proper Use of Update Settings: You've mentioned setting "Update When Invisible" to "Nothing," which is good. Make sure this setting is correctly applied to all relevant Spine components to prevent unnecessary updates.

    2. Optimize Skeleton Complexity: Check the complexity of your skeletons, including the number of bones, vertices, and constraints. Reducing these can help improve performance. Avoid using clipping polygons if possible, as they can be performance-intensive.

    3. Pooling and Instantiation: Consider using object pooling for your Spine animations. Instead of instantiating and destroying animations, reuse them by enabling and disabling as needed. This can reduce the overhead associated with frequent instantiation.

    4. Check Draw Calls and Batching: Ensure that your animations are optimized for batching. Using a single atlas for multiple animations can help reduce draw calls. If you receive warnings about enabling the Multiple Canvas setting, ensure that your setup allows for proper batching.

    5. Profiling and Testing: Use Unity's profiler to identify specific areas where performance is being impacted. This can help pinpoint whether the issue is related to CPU, GPU, or memory usage.

    6. Consider Binary Export: If you're using JSON for your skeletons, consider switching to binary export (.skel.bytes) for potentially faster loading and reduced memory usage.

    By following these steps, you should be able to mitigate some of the performance issues you're experiencing with Spine animations in your project.

    I assume that you're using SkeletonGraphic when you're describing "Spine for UI animations", is this correct?

    KargEn The main problem we're facing is that Spine animations seem to impact performance even when they are not being rendered at the time and their GameObjects are set to inactive.

    Are you sure that you mean that you've disabled the whole skeleton GameObject? If the whole GameObject is disabled, no animation is processed, the mesh isn't updated and nothing is rendered. Animations are updated in Update while the mesh is updated to the changed animation state in LateUpdate.

    KargEn Even when no Spine animations are visibly active on the screen, they still affect performance.

    For SkeletonGraphic (and CanvasRenderers in general), unfortunately only being outside a RectMask2D parent component will trigger the "became invisible" state (based on the RectTransform bounds). This is due to MaskableGraphic.onCullStateChanged limitations by Unity (see this issue ticket here). Unfortuntately Unity does not call OnBecameInvisible as with MeshRenderers when e.g. the Canvas no longer contains the rect.

    So if you can't use a RectMask2D parent, you might want to write your own scripts which detect and disable the RectTransform being outside the sceen rect.

    KargEn Despite some of our Spine animations having no additive materials and using a single texture, we receive warnings that we need to enable the Multiple Canvas setting. We've enabled this where necessary.

    By "Additive materials", do you mean Slots with slot blend mode Additive? If so, please note that additive blend mode can be drawn in a single draw call with PMA shaders. Multiply and Screen slot blend modes however require additional separate Materials.

    • KargEn відповіли на це.
      13 днів пізніше
      • Змінено

      Harald Harald, thank you so much for your response, and I apologize for my late reply. I was only recently able to gather the necessary information. The images I’ll share will have a lot of unnecessary censorship, but unfortunately, that’s the only way I’m allowed to share them.

      It’s highly likely that we’re making a fundamental mistake in our project, which is causing us to experience performance drops to around 40-50 FPS due to our Spine usage. When we first started using Spine last year, the developer that set up the necessary infrastructure for the artists left few months ago, leaving some unanswered questions within the team. Since this was how the setup originally started, unfortunately, we’ve continued adding to it in the same way up until now.

      Some key details:

      We’re using Unity 2022.3.21f1.
      Our Spine version is 4.1.
      We’re working with Linear Color Space.

      Harald I assume that you're using SkeletonGraphic when you're describing "Spine for UI animations", is this correct?

      • Yes, we are using SkeletonGraphic.

      Harald Are you sure that you mean that you've disabled the whole skeleton GameObject?

      Unfortunately, instead of disabling the entire GameObject for inactive popups, we’ve been setting the Canvas's SetActive to false. Would you recommend disabling the entire GameObject instead of just the Canvas, or would our current approach yield the same result?

      Additionally, we’ve been using a custom script written by our former developer to play Spine animations. This script determines which animation to play and whether it should loop. Do you have any thoughts or suggestions regarding this short piece of code?

      spineanimationtriggerer.txt
      2kB

      Using this script, we bind the animation this way. We trigger the animation on On Open Started and complete it on On Close Completed.


      Since we suspect that we're misusing something fundamental, I’m sharing a few images of our implementation. In the Spine example I provided, we used an additive material, which required us to enable Multiple Canvas. Here are our settings inside SkeletonGraphic:


      When imported into the project, our sprite and the generated materials appear as follows:




      I hope the information I’ve shared—within my limits—helps clarify the issue we’re facing. Apologies again for the delayed response, and thank you for your insights!

      • Harald відповіли на це.

        KargEn Unfortunately, instead of disabling the entire GameObject for inactive popups, we’ve been setting the Canvas's SetActive to false.

        I'm a bit confused by the above sentence. SetActive can only be used on a complete GameObject, there is no canvas.SetActive(false). Or do you mean you've disabled the Canvas component via canvas.enabled = false and keep all child GameObjects enabled? If you mean the latter, this explains why you see all child SkeletonGraphic objects still active and animating. I would recommend disabling the Canvas GameObject entirely, or at least disable the more costly GameObjects if you intended to save some enable/disable overhead (which likely does not matter here anyway though).

        KargEn Additionally, we’ve been using a custom script written by our former developer to play Spine animations. This script determines which animation to play and whether it should loop. Do you have any thoughts or suggestions regarding this short piece of code?

        It does not look optimal in that [SerializeField] private string _animName; seems to be using strings to determine the animation to be played, but is missing the [SpineAnimation] attribute which makes selection more comfortable, choosing from a list of animations.

        Other than that, the Spine.Animation could be cached instead of always calling AnimationState.SetAnimation(_trackIndex, _animName, _isLooping); by string _animName. So you would once query the Spine.Animation by name via SkeletonData.FindAnimation and then store it, and use the call SetAnimation(_trackIndex, _cachedAnimation, _isLooping);. But that's just a minor improvement which will not make a measurable difference.