A method for changing the rate at which a function (such as an animation curve) is traversed over time, some of its applications, and a Maya expression that implements it.
Let's say we have a function
This works fine when
Now we have a new question: how should we define
When the value of
When
In order to do this, it can be helpful to change how we think about the effect that
However, we can also think of
This way of thinking about
If
Now we can revisit our examples from before with our new definition for
And when we apply this function to our oscillating object, we get the desired result:
As an additional way to check our work, we can look at how our new function reacts if
Let's make
Then
So we end up with:
Which is the same function that we started with when
While I used
Here's an example using a noise function:
Another interesting property of this function is that negative
Finally, here's an example of how I used this function in my short film Whittled Down. I used a noise function to make the creature's teeth undulate, then applied this function to make them move faster right before the creature strikes.
The Maya scene oscillate-demo.ma
contains an example of how one could implement variable rate function traversal using a Maya expression. The oscillation_controller
curve has attributes frequency
, amplitude
, oscillationCenter
, phase
, and timeOffset
to control the sinusoidal oscillation of the translateY
attribute of cube
. Keying the frequency
attribute of the controller will create the desired speeding-up-and-slowing-down behavior in the cube's oscillation.
Let's map the components of our Maya scene to the elements of oscillation_controller.frequency
attribute's animation curve, our cube.translateY
.
The expression in this scene works by querying the value of the frequency
attribute on every frame and using that information to take a Riemann sum of the frequency
attribute's animation curve to approximate the integral
Unfortunately, this method creates a major performance drawback: it requires an increasing amount of queries to the value of frequency
as the frame count gets higher. For every single frame of animation, all of the frequency
values of the preceding frames must be summed together to approximate the current value of
In simpler terms, the expression gets really slow for big frame numbers.
The simplest workaround for this performance issue is to bake the animation when it's finished to mitigate the performance effects this expression would have on the rest of the scene. However, that doesn't do anything to speed up the expression while it's running.
This expression also requires Maya's cached playback to be disabled, which significantly hurts the performance of all cacheable animations in the scene.
A more performant solution to this problem would be to implement a system that allows the summed frequency
values to be cached, only recalculating them when the animation curve controlling the frequency
is changed. However, as far as I'm aware this sort of functionality is beyond the scope of what can be accomplished with an expression and introduces a significant amount of complexity to this tool. For my use case (individual shots of a film split into separate Maya scenes that are usually less than fifteen seconds long), the simplicity of this expression outweighs the performance issues that one would run into in longer and heavier scenes.
The function
This solution can then be generalized to any function that animates over time. For a function
The file oscillate-demo.ma
contains a simple example of how one could implement this function using a Maya expression. However, the calculation of
Animations created using the manim library