Search Unity

Feedback Bicubic procedural animation

Discussion in 'Works In Progress' started by CodeKiwi, Apr 22, 2019.

  1. CodeKiwi

    CodeKiwi

    Joined:
    Oct 27, 2016
    Posts:
    69
    I saw this thread a few days ago and decided to try the new animation rigging system. I’m planning to make some procedural animations based on this animation boot camp video. I’m also trying ideas from motion matching and Ubisoft's IK Rig. I don’t mind losing a bit of control or quality if it helps me make animations faster.

    This method uses less keyframes and does bicubic interpolation instead of linear interpolation . Because bicubic interpolation isn’t supported by the animator it tried setting up a new animation job to blend between four keyframes e.g. keyframes a,b,c,d with time t to blend between b and c. t might be controlled by time, movement distance, jump height etc. These four keyframes are similar to blocking animation so I’ll just call them block poses from now on. Once t is greater than 1 I push a new block pose to the end and delete the first. Blocking poses don’t animate and have a new LinearConstraint to blend between two keyframes. If t is less than 0 then it creates and anticipation pose, if t is greater than 1 it creates an overshot. The four main block poses should be basic rigs e.g. no twist bones, face bones, just the main limbs (I’m using the full character rig in the video). They can also have other constraints applied e.g. open door pose might move the character to the door and use IK to reach the door handle. The bicubic animated character can then apply more constraints like twist bones, IK etc.


    Video:
    The four characters at the top are the blocking poses. The character on the bottom right is blending these blocking poses with a new Bicubic InterpolateConstraint. The staff the character is holding has an updated JiggleChainConstraint and a PositionConstraint to the hand (rotation is from the bicubic animation). When the animation changes from run to walk it has an overshot to push the next pose a bit more. The character on the bottom left shows the LinearConstraint blending from -100% to 200%. The red ball has a BezierPathConstraint. This could be used for walking paths or climbing. The bent staff on the left has a SpineChainConstraint that makes the bones follow a path (Quadrupeds)

    Animation keyframes
    This process uses fixed keyframes/poses rather than a smooth animation. I tried a few other ideas but decided to use a standard animation clip (helps with posing and timing). I duplicate an existing animation and move it to a higher parent, this allows me to keyframe multiple rigs in the animator e.g. constraints, weapons or character interaction. I then find the key poses I want in the animation and use “Add Keyframe” to key all layers. Then I delete the keyframes in between, only the main keyframes are used. The last keyframe isn’t used in looping animations and is only set to get the duration. Because I can’t get the clip info at runtime I create a scriptable object called KeyframeClip with a reference to the clip and a list of the keyframe times. To display a keyframe I assign the clip and keyframe index to the LinearConstraint. I can also manually pose the character or animate constraints like IK weights.

    TODO
    Currently time moves linear, i might add an animation curve to control timing e.g. a punch might start slow and end quick.
    Character movement.
    Damped symmetry: if I have a couch and jump pose with the arms in the air then I might not want the arms to be at the highest point at the same time. If one arms animation is slightly slower or staggered then it should make more of a wave motion.
    Update block poses e.g. draw gun could update keyframes, bicubic animation might look better than animating the IK on the final rig.
    Motion matching
    Center of mass constraint
    Self collision constraint (just basic spheres)
    Foot placement with BezierPathConstraint and IK.
    Quadruped

    I’m mainly trying ideas at the moment but I’d appreciate any suggestions or links to other procedural methods.
     
    ZhavShaw likes this.
  2. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    942
    This looks great!


    I think it might be worthwhile to check out this post describing a more "modular" approach to poses / keyframing stuff.


    I fleshed my ideas out a bit more and proposed them to Unity (for a chance at a native implementation), but I doubt they're interested since they usually have their own ideas about stuff like this.
    That said, maybe my ideas and basic framework can help give you some direction.


    Also...


    This is me in a nutshell.

    I need a more straightforward way to animate -- and this method is ripe with opportunity for that.
     
    CodeKiwi likes this.
  3. CodeKiwi

    CodeKiwi

    Joined:
    Oct 27, 2016
    Posts:
    69
    Thanks, this is exactly what I was looking for. After reading your posts I think I’ll change it to something more similar to the ClipKey, ClipSequence, ClipLayer, ClipModule classes you mentioned. There are a few issues with my current clip setup. This includes not being able to reuse poses, no mirroring and the clip uses more data than required. It’s also difficult to add to displays e.g. have to set the clip and a keyframe index instead of just a ClipKey. I’m also thinking of dropping the block pose keyframe rigs. If I override the keyframes then the poses should already be close enough for the blended rig to use normal IK. I’d probably add some extra data to the ClipKey to help with positioning e.g. world position of hands and feet. I might try creating a new avatar so I can use the avatar masks.
     
    awesomedata likes this.
  4. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    942
    Awesome! -- I'm glad to hear that.

    You should check out my post again under the "Modules" section -- I added some extra ideas about mirroring modules, which could also be applied to any Clip-Effects, which should result in WAY faster processing for mirrored bits (since a separate job would not have to be scheduled for the mirrored parts.)
     
  5. mutp

    mutp

    Joined:
    Oct 1, 2018
    Posts:
    10
    I'm curious how you do the overshoot part of this. Do you have two extra poses that just act as overshot poses?
     
  6. CodeKiwi

    CodeKiwi

    Joined:
    Oct 27, 2016
    Posts:
    69
    I haven’t looked at this code for a while. I was mainly experimenting with some ideas so my code probably isn’t that usable. I didn’t have extra custom overshot poses, instead I generated them dynamically with something like nextKeyPose = Quaternion.SlerpUnclamped(currentKeyPose, nextKeyPose, 1.5f). The main issue with dynamically creating them is that the limbs can bend in unnatural angles (can clamp with an extra post process). The other issue was that it required a weight mask e.g. don’t want to overshot fingers / face. Creating custom overshot poses would probably look better but takes more time.

    One random idea I had is that you might be able to create an overshot animation by using the slope on an animation curve and a dynamic additive animation clip (single pose). So the additive clip animation curve values could be set to the curves slope multiplied by a single overshot weight (animate in/out). It might also be able to use an avatar mask to exclude the face and fingers. A humanoid avatar could be easier to setup as it has normalized muscles (clamp to a valid pose).
     
  7. mutp

    mutp

    Joined:
    Oct 1, 2018
    Posts:
    10
    Thanks for your response.

    Right now, I'm using the AnimationMixerPlayable to blend between two poses. I just set the weight to between 0 and 1 and I get a blend of the poses. However, Playables prevent me from going beyond this range. Does this mean that Playables is the wrong approach for overshoot?
    I guess I'm also confused as to where nextKeyPose = Quaternion.SlerpUnclamped(currentKeyPose, nextKeyPose, 1.5f). fits in here.
     
  8. CodeKiwi

    CodeKiwi

    Joined:
    Oct 27, 2016
    Posts:
    69
    I tried some tests with machinima and the old playables API before but I also couldn’t get them to work outside of the normalized range or with bicubic interpolation. I ended up testing a custom constraint in the new animation rigging system and also by directly sampling the animation (I wouldn't recommend it) e.g.

    Code (CSharp):
    1. poseAClip.SampleAnimation(gameObj, 0)
    2. StoreBoneTransforms()
    3. poseBClip.SampleAnimation(gameObj, 0)
    4.  
    5. // interpolate past limit
    6. Var t = 1.5f;
    7. Foreach (var bone in bones) {
    8.     bone.rotation =Quaternion.SlerpUnclamped(prevRotations[bone], bone.rotation)
    9. }
    10.  
    I haven’t tried the new animation jobs but it seems like it would work better.
    https://github.com/Unity-Technologies/animation-jobs-samples
     
  9. mutp

    mutp

    Joined:
    Oct 1, 2018
    Posts:
    10
    I'm using an AnimationCurve window below to do the cubic interpolation between the two poses.
    upload_2020-2-12_21-40-11.png

    So, here pose A has most weight when t = 0, and pose B has most weight when t = 0.1 using this code -

    Code (CSharp):
    1.     void Update()
    2.     {
    3.          weight = Mathf.Clamp01(runCurveSimple.Evaluate(timer));
    4.          mixerPlayable.SetInputWeight(currentClip, weight);
    5.          mixerPlayable.SetInputWeight(nextClip, 1.0f - weight);
    6.     }

    Unless I've gotten this completely wrong, I was under the impression that this way I'm able to interpolate between my poses like in Overgrowth.

    Also, I did take a look at those Jobs Samples. However, since it's built on top of the Playables API, I don't see how I'd be able to go beyond the clamped values.
     
  10. CodeKiwi

    CodeKiwi

    Joined:
    Oct 27, 2016
    Posts:
    69
    Test.png

    I included a modified version of the mixer job sample (swapped slerp and lerp with unclamped versions). I'm not sure if there's a better way but it seems to work.
     

    Attached Files:

    mutp likes this.
  11. mutp

    mutp

    Joined:
    Oct 1, 2018
    Posts:
    10
    This certainly works. Thanks for sending this across.
     
  12. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    942
    Yay me -- I've finally cracked this system wide open.
    How to implement it inside Unity is tricky, but doable -- assuming one has a performant ragdoll mode.
    I'll elaborate later. For now, just know my initial assessment of how this was done was somewhat incorrect. I've since found the error of my ways since it kept irking me that I was running into the same problem you guys are running into now. In other words -- my assumptions about the 0-1 range were flawed.


    The problem here is that the animation doesn't explicitly need to go beyond the 0-1 range.

    He calculates his 0-1 normally, just like you would expect for any standard interpolation. The "overshoot" portion of the system is actually applied on an altogether different layer of the system.

    In other words -- you will need to composite your animation curves in an "animation layer" sort of system first, then you would apply the "overshoot" portion. This is how he is able to do "overshoot" across multiple poses and animations simultaneously. See the gun reload prototype with the spring/dampening he showed in his video. None of those are different poses -- those are entirely different (single-frame) animations -- and, as such, they should be viewed that way in terms of your implementation method.
     
    mutp and CodeKiwi like this.
unityunity