Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question PlayableGraph.Evaluate in AssetImporterWorker0 Unity instance

Discussion in 'Animation' started by Rukhanka, Sep 27, 2023.

  1. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    195
    Nonlive ECS Subscene baking is performed in background Unity process started with -batchmode parameter. I need to do PlayebleGraph manual evaluation during baking phase, but seems something prevent to PlayebleGraph to be evaluated correctly. With attached AnimationScriptPlayable job I can see that ProcessRootMotion is called (and updated correctly), but ProcessAnimation is not, and no bone transforms get updated. Same code in ordinary Unity Editor process working fine. Is there a bug, or something need to be configured to correctly play animation using PlayableGraph in batchmoded editor instance?
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,173
    I don't know about playables, but this is what I do for capturing bone transforms from animations in baking, which I learned from Joachim Ante's GPU animation package:
    1) Clone the GameObject with the Animator component
    2) Strip all transforms that aren't needed
    3) Optionally enable root motion to get root animation onto the Animator root
    4) Put remaining transforms in a TransformAccessArray
    5) Set animationClip's wrap mode to Clamp
    6) Repeatedly call animationClip.SampleAnimation passing in the clone for each sample you want to capture.
    7) After each captured sample, run a IJobParallelForTransform job to copy the transforms into array data (speeds up incremental baking)
    8) After sampling the clip, restore the original wrap mode
    9) After capturing all clips, destroy the clone

    And with that, you'll have all your sampled transforms to do whatever with. I send them off to ACL for compression, but you probably want to bake the animations into textures?
     
    Rukhanka likes this.
  3. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    195
    You are life saver. Thank you! SampleAnimation working perfectly. I remeber that I have tried it at first, but for some reason was moved to PlayableGraph later. I am doing exactly same algorithm, but instead of SampleAnimation there is PlayableGraph.Evaluate().

    And no, I am not using animation textures in Rukhanka at all. I am using this curves during animation calculation, because monthes of reversing humanoid hips position algorithms still do not give me exact results as Mecanim.
     
  4. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    195
    After some testing I have found that SampleAnimation working somewhat incorrectly with humanoid rigs.
    Some more testing shows that Animator.isInitialized is false in batchmode process, and Animator.Rebind() did not help. Moving further with native debugging I have found that Rebind function has AssetDatabase::IsAssetImportProcess() check with early return on true (and even assembly patching to skip this check did not give expected results). So I think this is intended behavior to prevent avatar functionality in asset importer process. I believe, this is unfortunate end of story.
     
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,173
    Weird. It works fine for me with humanoids. Do you clone the GameObject and operate on the clone?
     
  6. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    195
    Yes, I am operating on the clone. It works with humanoids. Difference is in hips position. With mecanim they always in place, but with SampleAnimation they move according to animation track.
     
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,173
    Yeah. That's root motion and your animator.enableRootMotion setting. If you don't want them to move, just record identity for those transforms.

    Root bone management is kinda a pain (especially with optimized hierarchies where it often isn't exposed). I found it easier to treat the root GameObject with the Animator as the root in a skeleton hierarchy, and bake with root motion enabled to make the root bone motion be applied to the Animator GameObject when sampling.
     
    Rukhanka likes this.
  8. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    195
    Is not that simple. Humanoid hips motion is calculated by internal formulas based on other bone positions (and some other data, like imaginary bone "mass" used as weight. Described here). I have spend a lot of time, trying to reproduce internal formulas using all available documentation, but only with partial success. Always was a cases when my approximations differ significantly from Mecanim. Identity values for rig root bone is not correct solution with or without root motion.

    As example I've made short videos:


    Bottom model is result of baking animation using SampleAnimation method. Top one is original Mecanim. Notice that upper model have slight hips back-forward movement. It will be clearly visible if I set identity to the hips transform in bottom model:


    I beleive that SampleAnimation just plays hips curve on it, without proper humanoid center of mass and hips pose calculation. PlayableGraph produces exact Mecanim results.
     
  9. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,173
    Apologies for the delay. I had some life stuff.

    SampleAnimation definitely accounts for center of mass and hips pose calculation. I know this, because we had a regression where enableRootMotion was off and that caused different and incorrect results. With enableRootMotion on, the root bone will retain local pivoting information (hips rotating in a walk cycle) while the animator root will retain the root motion translation (what is computed from center of mass and all) relative to identity and the start of the clip. To then remove the root motion, you record identity transforms to the animator root, not the root bone. Though in Kinemation, we just account for this at runtime during skinning and writing to entity transform components.

    I wouldn't rule it out that you encountered a test case where my solution is also broken and I haven't realized it yet. Feel free to test it out, or share the authoring prefab and I can test it for you.
     
  10. Rukhanka

    Rukhanka

    Joined:
    Dec 14, 2022
    Posts:
    195
    Sorry to late response, I was carefully testing everything related to root motion sampling in Rukhanka (don't blame others until 100500% sure that it is not yours bug). And I have found a bug in my sampling code. I can confirm, that everithing is working correctly with SampleAnimation method.

    @DreamingImLatios, thank you for your insights. They are were really helpful to track my issues.