Changing animation playRate programmatically

Hello,

I am currently working on changing the speed (playRate) of a walking animation programmatically based on the speed of my character and I am facing some problems.

I first started noticing that only changing the playRate itself messes up with the animation frame that is currently being shown. For example, if I am on frame 20 and I duplicate the playRate of my animation, my character will show the posture it had by frame 10, since it’s moving twice as fast. This results in visual glitches on my simulation.

After some trials I came to the conclusion that I needed to change the animationPlayStart variable too to adjust for this. I came up with this formula:

animationPlayStart = currentFrame * (1 - playRate)

using this I can adjust the animationPlayStart and the playRate. For example, if I am on frame 20 and I duplicate the playRate of my animation and then adjust the animationPlayStart to be -20 then my character will show the same posture on frame 20, since it traveled twice the frames twice as fast.

I created a node in Omnigraph that takes my current frame and the speed the character is moving as inputs and calculates the playRate and the animationPlayStart accordingly and these are given to the animation on my sequencer. However I’m still seeing some glitching behavior.

My theory is that the calculation takes some time and the frame that I passed to my node is not the current one anymore, therefore my calculation comes up with a wrong animationPlayStart.

Is there a way to achieve what I am trying here? Is there a better approach?

Hello @jominga! I reached out to the dev team for help here! I will post back when I have more information!

So I updated the code again but I still get a similar glitching behavior.
I adjusted the formula to the following to take into account previous playRates and playStarts :

animationFrame = (currentFrame - currentAnimationPlayStart)/currentAnimationPlayRate
animationPlayStart = currentFrame - animationFrame*playRate

My Omnigraph Node looks like the following:

Here is the code of the Node. For testing purposes I am changing the speed of the animation every 50 frames:

"""
This is the implementation of the OGN node defined in OgnAdjustAnimationSpeedWithThreshold.ogn
"""

# Array or tuple values are accessed as numpy arrays so you probably need this import
from matplotlib import animation
import numpy


class OgnAdjustAnimationSpeedWithThreshold:
    """

    """
    @staticmethod
    def compute(db) -> bool:
        """Compute the outputs from the current input"""

        try:

            current_frame = db.inputs.current_frame
            current_animation_play_rate = db.inputs.current_animation_play_rate
            current_animation_play_start = db.inputs.current_animation_play_start
            
            if(int(current_frame) == 0):
                db.outputs.animation_play_rate = 1.0
                db.outputs.animation_play_start = 0.0 
            
            else:
                if(int(current_frame) >= 1 and int(current_frame < 50)):
                    play_rate = 1.0
                elif (int(current_frame) >= 50 and int(current_frame) < 100):
                    play_rate = 2.0
                elif (int(current_frame) >= 100 and int(current_frame) < 150):
                    play_rate = 0.5
                elif (int(current_frame) >= 150 and int(current_frame) < 200):
                    play_rate = 2.0
                elif (int(current_frame) >= 200 and int(current_frame) < 250):
                    play_rate = 0.5
                else:
                    play_rate = 1.0        
            
                if round(current_animation_play_rate,1) == play_rate :
                    db.outputs.animation_play_rate = round(current_animation_play_rate)
                    db.outputs.animation_play_start = round(current_animation_play_start)        
                else:
                    animation_frame = (current_frame - current_animation_play_start)/current_animation_play_rate
                    animation_play_start = current_frame - animation_frame*play_rate

                    db.outputs.animation_play_rate = play_rate 
                    db.outputs.animation_play_start = animation_play_start
            pass
        except Exception as error:
            db.log_error(str(error))
            return False

        return True

And the .ogn file:

{
    "adjust_animation_speed_with_threshold": {
        "version": 1,
        "description": "",
        "language": "Python",
        "inputs": {
            "current_frame": {
                "type": "double",
                "description": "",
                "default": 0
            },
            "current_animation_play_rate": {
                "type": "float",
                "description": "",
                "default": 1.0
            },
            "current_animation_play_start": {
                "type": "timecode",
                "description": "",
                "default": 0
            }
        },
        "outputs": {
            "animation_play_rate": {
                "type": "float",
                "description": "",
                "default": 1.0
            },
            "animation_play_start": {
                "type": "timecode",
                "description": "",
                "default": 0.0
            }
        }
    }
}

I created a very simple scene to recreate the issue with the default Worker human model of Omniverse and using it’s default animation, which is about 200 frames long. As you can see the first change in the animation speed (2nd second of the video) does work. But the second and third one (4th and 6th second of the video) do glitch:

Any input in the matter will be highly appreciated.