Search Unity

Execute code after the animator update but before constraints are applied

Discussion in 'Animation Rigging' started by customphase, Jul 17, 2020.

  1. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    246
    For foot IK you're supposed to raycast to the current foot position and adjust the IK target/weight accordingly. Tried using LateUpdate, but constraints are applied before the LateUpdate. What to do?
     
    cmann likes this.
  2. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    229
  3. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    246
  4. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    229
    Each rig referenced in your rig builder is added as an AnimationPlayableOutput to your Animator. To change the order you can use the following extension method: https://docs.unity3d.com/2019.3/Doc...368.251054526.1595196045-186934525.1591663570

    The order is not guaranteed otherwise like explained in the following thread:
    https://forum.unity.com/threads/my-feedback-on-new-animation-rigging-package.728597/

    "Yes, the PlayableGraph created for Animation Rigging has several outputs, this is no bug. The first output handles the SyncSceneToStream playable chain which synchronizes scene values to make them available to the Animation Rigging jobs. Afterwards, the other outputs handle the multiple Rigs set on your RigBuilder. The Animation Rigging outputs are set to use the previous input evaluation values so that they behave as a post process step to what was evaluated before (see https://docs.unity3d.com/ScriptRefe...utputExtensions.SetAnimationStreamSource.html)

    We created a separate PlayableGraph in order for Animation Rigging to play nice with other animation systems. This way, we can use Animation Rigging with the Animator state machine or Timeline or your custom PlayableGraph.

    However, in 2019.2, we are missing a proper sorting order to better control when a PlayableGraph is evaluated in the Animator. While the Animator state machine always has priority on all other animation systems, we're not guaranteed that the Timeline PlayableGraph will be built before the AnimationRigging graph and thus in the right evaluation order.

    We're fixing that in 2019.3 by adding a sorting order to AnimationPlayableOutput (see https://docs.unity3d.com/2019.3/Doc...PlayableOutputExtensions.SetSortingOrder.html).

    In the meantime, to ensure your PlayableGraph are evaluated in the right order, make sure to also create them in the same order. By controlling when RigBuilder becomes enabled, you will also control when its PlayableGraph will be built, and thus change the evaluation order."
     
    _slash_ likes this.
  5. tuinal

    tuinal

    Joined:
    Dec 14, 2012
    Posts:
    17
    I had the same issue today, came up with a crude solution, by attaching the below script (tweaked from an example - 99% of the code is superfluous) as a child of an 'information' rig. It's constrained object needs to be a child of the root (I used an empty gameobject); the position of this constrained gameobject in Update is the animated position of the source object before IK in the previous frame - which is near enough for a decent raycast unless you're animating Road Runner. That's provided the rig is at the top of the stack in the rig builder, and whilst I've found it works I've not extensively tested it.

    This is an extremely convoluted way of getting at a simple Vector3, but in lieu of a sorely needed convenience method, or any real knowledge of the API, it's the only option I could find in the short time I had.

    It would help if the examples/docs had 1 good example of procedural target placement (foot IK being the best candidate). The vast majority of the documentation is on setting up and manipulating joints in the editor, rather than a worked-through use case. I get that it's meant to be a generic system and it's down to the developer/artist how the targets place themselves, but just one worked example that doesn't involve dragging an editor marker around would be extremely useful.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Animations.Rigging;
    5. using UnityEngine.Experimental.Animations;
    6. using Unity.Burst;
    7. using Unity.Mathematics;
    8. using UnityEngine.Animations;
    9.  
    10. [BurstCompile]
    11. public struct AnimationInfoBinderJob : IWeightedAnimationJob
    12. {
    13.     public ReadWriteTransformHandle constrained;
    14.     public ReadOnlyTransformHandle source;
    15.  
    16.  
    17.     public FloatProperty jobWeight { get; set; }
    18.  
    19.     public void ProcessRootMotion(AnimationStream stream) { }
    20.  
    21.     public void ProcessAnimation(AnimationStream stream)
    22.     {
    23.         float w = jobWeight.Get(stream);
    24.         if (w > 0f)
    25.         {
    26.             constrained.SetPosition(
    27.                 stream,
    28.                 source.GetPosition(stream))
    29.                 ;
    30.         }
    31.     }
    32.  
    33.  
    34. }
    35.  
    36. [System.Serializable]
    37. public struct AnimationInfoBinderData : IAnimationJobData
    38. {
    39.     public Transform constrainedObject;
    40.     [SyncSceneToStream] public Transform sourceObject;
    41.  
    42.     public bool IsValid()
    43.     {
    44.         return !(constrainedObject == null || sourceObject == null);
    45.     }
    46.  
    47.     public void SetDefaultValues()
    48.     {
    49.         constrainedObject = null;
    50.         sourceObject = null;
    51.     }
    52. }
    53.  
    54. public class AnimationInfoBinderBinder : AnimationJobBinder<AnimationInfoBinderJob, AnimationInfoBinderData>
    55. {
    56.     public override AnimationInfoBinderJob Create(Animator animator, ref AnimationInfoBinderData data, Component component)
    57.     {
    58.         return new AnimationInfoBinderJob()
    59.         {
    60.             constrained = ReadWriteTransformHandle.Bind(animator, data.constrainedObject),
    61.             source = ReadOnlyTransformHandle.Bind(animator, data.sourceObject)
    62.         };
    63.     }
    64.  
    65.     public override void Destroy(AnimationInfoBinderJob job) { }
    66. }
    67.  
    68.  
    69. public class AnimationInfoBinder : RigConstraint<
    70.     AnimationInfoBinderJob,
    71.     AnimationInfoBinderData,
    72.     AnimationInfoBinderBinder
    73.     >
    74. {
    75. }
     
  6. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    246
    Yeah, figured that as well after the fact. Ive tried making my own playable behaviour but i couldnt manage to make it execute after the animator updated, even with that order thing. I assume its somehow related to that syncSceneToStream thing. Also according to the profiler, animator processing and animation rigging processing happens in parallel, so there is no actual inbetween step as is, as far as i can tell.

    Tried that as well, didnt work well for me. Anyway, for my solution i ditched the animation rigging altogether, ported the IK part of it (since thats the only thing i need from it really) as a regular main-thread code, and just used that in late update. The whole job/multithreading thing imo is extremely limiting and not necessary in 90% of cases anyway, most games are GPU bound nowadays.
     
  7. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    229
    Yeah the animation rigging constraint are added to the animator so they are definitely processed at the same time when the animation graph is evaluated. The order thing would be the solution for that if it worked...

    If I look at the events execution list there:
    https://docs.unity3d.com/Manual/Exe...640.251054526.1595196045-186934525.1591663570

    Maybe you could have use the FixedUpdate? Also I have tried changing the Update Mode of the Animator?

    Glad you figured out a solution though!
     
  8. adamgryu

    adamgryu

    Joined:
    Mar 1, 2014
    Posts:
    188
    Hey, sorry to revive this thread, but are there any better solutions to this problem yet?

    I'd like to get the position of a bone in an animation before Animation Rigging modifies it.

    Alternatively, I'd just like to stop the player's feet from going through the floor. I'd like to take the current foot position, and if it's underneath the raycast position, set a two-bone constraint weight to 1 to stop it from going through.

    However, once the leg is underground, and the weight is 1, I can no longer poll for the original foot position.
     
  9. adamgryu

    adamgryu

    Joined:
    Mar 1, 2014
    Posts:
    188
  10. Phong

    Phong

    Joined:
    Apr 12, 2010
    Posts:
    2,085
    I have been working with the Animation Rigging package for a week now and am coming to the same conclusion as Customphase. I love the idea of Animation Rigging but think I need to ditch it as there are some serious shortcomings. The main problems:
    • The rig constraints execute off the main thread and it is impossible to do Raycasts or interact with other Unity systems (ReadWrite to Transforms) from inside the executing rig constraint code.
    • I cannot find a way to manually step/pose the animator and have the RigConstraints execute immediately. I can get the animator to pose immediately but the playable graph doesn't evaluate in this case. It is too awkward to try to do all the raycasting in the Update/FixedUpdate loop then store the results and use them in a custom rig constraint.
    • The playableGraph executers outside Update/FixedUpdate loop which is awkward to work with.
    • It is difficult to have code that executers before or after a particular rig constraint execution. This seems to require create custom constraints which is a lot of work and configuring for what is essentially a callback.
    Will try Customphase approach and implement something similar that works on the main thread.
     
    customphase likes this.
  11. SteppySteve

    SteppySteve

    Joined:
    Mar 1, 2016
    Posts:
    2
    Just wanted to add that the option to force the rigging/constraints to evaluate would be great. I need manual control of when physics scenes update and have rigged animation that needs to update between each physics step. Currently, there seems to be no good way of doing this.