Search Unity

Question Optimize Game objects limitation: Cannot retrieve internal skeleton state

Discussion in 'Animation' started by TimHeijden2, Nov 16, 2021.

  1. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    I've been looking at optimizing my enemies in the game I'm working on, and cannot find a good solution because I'm running into limitations that seem like they should be simple enough to expose in some way by unity. So below I'm presenting my use case & possible solutions I've tried.

    My enemies have a ragdoll, which uses colliders, rigidbodies & joints on child transforms of the model. Unfortunately, these components cost performance by just existing in two ways:
    1. The animator / animation system moves these child gameobjects, causing a lot of extra transform calculations (this is what "optimize game objects" would resolve)
    2. The physics system can't fully disable rigidbodies, causing physics overhead even though the ragdolls are "off".

    In order to fix both, the best solution would likely be to create a second prefab/model which is "hot-swapped" the moment the enemy dies. This would allow "alive" enemies to be fully optimized in both ways, and keep the functionalities of the ragdoll as well. However, this is where the limitation comes in:

    It is not possible to retrieve positions & rotations of the skeleton when game objects are optimized, even though this is used by unity interally by both the animator & skinned mesh renderer components.

    This means it is impossible to position the ragdoll-copy in such a way that it has the same pose of the animating enemy that is dying.

    The bad thing about this is that it means the entire solution of making a copy is impossible as well, and I can't think of any other solution to improve performance for both the gameobject & the ragdoll without losing functionalitly or otherwise causing performance spikes at the time of swapping.


    A list of solutions that are not feasable:
    - Using animator GetCurrentAnimatorStateInfo & GetCurrentAnimatorClipInfo to merge clips, weight & time myself.
    Would require so much calculations that it creates a performance spike.

    - Using AnimatorUtility.DeoptimizeTransformHierarchy
    Causes performance spike due to creation of objects, also has no options to only deoptimize "some" transforms, all or nothing.

    - meshRenderer.BakeMesh()
    Doesn't update bones, only copies mesh

    There have also been other threads of people with similar problems, but these had no real responses:
    - Get Bone Transform From Avatar With Generic Rig? - Unity Forum
    - Optimized Game Object & RagDoll - Unity Forum (strangely unity references a get here, but it doesn't exist!)
    - Optimized Transform Hierarchy and Ragdolls - Unity Forum
     
  2. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
  3. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    510
    It is possible to know the positions and rotations of the bones…when you have an optimized character you need to expose the bones you want to match for the ragdoll.

    The bones will be read only (which means you cannot alter them or parent other gameobjects to them) and they will be in a flat hierarchy which will perform much better than the deep hierarchy of a de-optimized skeleton.
     
  4. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    You're totally correct, in my specific case this doesn't help much though. The skeleton itself is already quite optimized and it might cut the amount of objects in half, but in my case I can have over a hundred enemies alive at a time which means even with an optimized setup having only ragdoll transforms it is still a lot of gameobjects/transforms in total.

    The main performance hit I'm experiencing is also the fact that rigidbodies/colliders/joints are on the enemies whilst they aren't "actively" using it, the physics still takes over 1ms of frame time. (yes the colliders are turned off)

    Truth is, I feel we should just be able to access unity's internal skeleton and I'd be able to implement all this very quickly. For now I'm going to sacrifice quality by simply swapping an optimized version with a ragdoll version that is in a t-pose like position so it looks "good enough" most of the time. Getting to this point & implementing that takes much more time, is less efficient and bloats the development process in code & art.

    Example: There are now 2 models needed for what is actually just 1 model, meaning either artists need to not forget to update the ragdoll version, or we need to make yet another tool automating the process. So much to do for something so trivial :(
     
  5. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    510
    I feel your pain. Im actually recreating the zombies in my game and how they go ragdoll right now

    My setup is optimized hierarchy only has colliders on bones exposed.

    I then hot swap a full ragdoll with joints rigidbodies and colliders on death.

    To make sure there are no issues with any of my characters setup….you guessed right… I made a tool to generate both versions.

    I wish it was simpler as well…but such a everything we gotta find work arounds.

    Good luck.
     
    TimHeijden2 likes this.
  6. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    396

    Can't you get the transforms or is it too pricey to get for all characters?
     
  7. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    The problem is that when you optimize away the gameobjects (which is the most efficient solution) there are no gameobjects/transforms. "Unity animation system’s internal skeleton" is used to still modify the meshrenderer (and to properly update any transforms NOT optimized away) which means that all we would need is to get a snapshot of that skeleton to hot-swap a more complex prefab that does contain the transforms.

    Unfortunately this isn't possible, and FiveFingerStudios method seems to be the closest you can get and its nice to get confirmation on that :)

    Time for Unity to fix the problem! I'm sure that any DOTS animation that will be implemented would also be using this "internal skeleton", so hopefully they'll actually expose it / make an API for it... for my current game though, will just have to work around it since I don't expect a solution any time soon, unity hasn't commented multiple threads about this problem (see original post) so I assume they're just not interested?
     
  8. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    396
    Oh ok it says "the animator will write directly transform matrices into the skin mesh matrices".

    How about you create a puppet rig with ragdoll colliders' positions. It transforms itself into the dying ragdoll, gets the rotations, and depending on those rotations you can modify the replacement body. Only one rig would be enough since it'll transform itself to anyone when needed.
     
  9. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    510
    Also I forgot to mention... I've done this technique before which requires no bones exposed..

    It works as long as you are not using IK or any other procedural alterations to the animations. Simply copy the animation state info from the optimized character and set it on the animator of the ragdoll (which of course needs an animator), then disable the animator of the ragdoll.
     
  10. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    I'm not sure I understand what you are saying, though its possible my latest attempt will also invalidate this solution.

    In trying to also optimize the ragdoll (so that only one rig/model is needed) I realized that transforms created from "Optimize Game Objects" are mostly read-only. When applying the ragdoll, the transforms move as expected but the SkinnedMeshRenderer doesn't update the mesh accordingly. (see image)

    I haven't looked at all options yet, but I don't think that can be solved manually because you'd miss data from bones optimized away.

    Unfortunately I'm using multiple layers, blend trees and transitions which means retrieving info from the animator using animation state info etc. is unfeasable. It would be possible, but would require a LOT of code, cause a lot of GC Alloc & take a lot of performance. (this may be different for humanoid rigs btw, I noticed a seperate function for this)
     

    Attached Files:

  11. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    510
    Just curious, have you tested performance with the exposed bones vs no exposed bones?

    I've read somewhere, (can't remember where but it was Unity Docs) that roughly 50 gameObjects are optimal amount of children when they move....so transform movements can be grouped and it will lessen the groups. I wish they would be more transparent with that info though.
     
  12. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    I did this quite some time ago, and thought to be 100% sure at the time there was a major difference. After explicitly testing this again, it looks like the difference is now very minor! Thats good news for my case, because it means I may not need to optimize at all, circumventing the issue.

    I'm already looking into other avenues as well, like recording a ragdoll as an animation & playing them on death based on direction & intensity... this would not only improve performance whilst they're alive, but also when they are "ragdolling" so that would be even better performance wise. (though sacrificing some quality of course)

    Thanks for asking again RE: Testing performance! Yet again proven that you must check multiple times whats going on :)

    It's possible I profiled some combination of improvements which obfuscated the result. (or that there was an issue since last time I profiled the issue which has since been fixed)
     
    FiveFingerStudios likes this.
  13. Vincent454

    Vincent454

    Joined:
    Oct 26, 2014
    Posts:
    167
    Just in case anyone needs more information on the performance difference of a flat hierarchy with many vs no exposed bones:
    I tested this with 900 animated meshes, once with 19 exposed bones, once with 0.
    There was no noticeable difference visible in the profiler at all. As frametimes fluctuate a lot it can be hard to spot such minor differences but there was literally no difference at all I believe.

    So in the end the amount of exposed bones in an already optimized hierarchy won't matter at all, at least in my test
     
    Last edited: Nov 2, 2023
  14. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    It was my results too, I always wondered what was the purpose of that setting. Even on pretty old mobile devices it makes no difference. It is probably something that had sense with mobile soc of the early Unity and nobody ever removed.
     
    Vincent454 likes this.