In traditional vector animation, there
is a concept called interpolation curves, which describes the way we move between
one animation keyframe and the next Depending on the shape of this curve,
we can control motion to slowly ease in, to slowly ease out, or even to
anticipate and overshoot the keyframe The choice of animation curves can greatly affect
the feeling of inertia and energy in the motion This grants the animator a good deal of
artistic expression in describing motion while keeping the number of keyframes economical In procedural animation, however, it can be
very powerful to do away with the concept of keyframes entirely, freeing the system
to move however the situation demands This adaptability is one of the main reasons
to incorporate procedural animation in games For example, in the game I’m working on, I have
this little robot character which moves its body and legs using inverse kinematics in response to
realtime requests to move and change orientation I’m controlling it with my mouse here,
and you can find tutorials for how to and you can find tutorials for how to
implement this sort of thing online In game, this same flexibility allows
the character to immediately respond to changing gameplay situations This is pretty nice, but because we
don’t have keyframes for these inputs, we can't really use interpolation curves
to add that sense of inertia What we’d really like is the ability to
achieve something like this, using an intuitive abstraction
similar to interpolation curves, but without losing out on the dynamic
responsiveness of a keyframe-free system Let’s start off by describing the problem
we want to solve a bit more precisely Given some dynamically changing
input x from our game world, we want to produce some dynamic output y
which tracks the input x, but is imbued with some sort of characteristic that conveys
the way that we want the motion to feel In the simplest case, y=x, and our system
rigidly conforms to whatever input we give it This isn’t very useful on its own,
but it is a good starting point Whatever changes we make to this equation, we’ll
want to ensure that in the long term, when x isn’t changing,
y should eventually settle at x To introduce the possibility for interesting dynamics, let’s add some velocity and
acceleration terms, represented here as first and second order derivatives with respect
to time, scaled by some values k1, k2, and k3 The dot notation here is just a shorthand
way of writing time derivatives, which you may have also seen written like this, or this This type of relationship involving
up to a second order time derivative is known as a second order system Mechanical motions in the real world tend to
be second order, which you can think of as being related to the fact that forces act
on acceleration, the second derivative of position, as described by Newton’s second law
These forces usually arise out of stiffness, where they are a function of displacement, or
out of friction, where they are a function of velocity, hence our choice of terms For example, this is the equation of motion of a rigid body being dragged along one axis through a linear damped spring And this is the equation of motion
for the SmoothDamp function in Unity By playing around with these values k1, k2, and
k3, we can generate a whole host of different interesting behaviors, but as an artist,
it might not be very intuitive how these values map to those different behaviors First, let’s simplify the visualization to look at
the response to a single sudden change in the input The resulting output is known as the
step response, which is a standard way of visualizing the dynamics of a system, and
captures the essence of the system’s behavior Next, using k1 k2 and k3, we’ll
define 3 new variables: f, zeta, and r We’ll use f, zeta, and r
(which I’ll explain in a moment) as the design parameters for the system’s motion Under the hood, we can use them
to compute k1, k2, and k3 In this new parameterization of f, zeta, and r,
each term controls something that we can develop some reasonable intuition about f is the natural frequency of the system
measured in Hz, or cycles per second It describes the speed at which the system will
respond to changes in the input, as well as the frequency the system will tend to vibrate at, but
does not affect the shape of the resulting motion zeta is known as the damping coefficient It describes how the system
comes to settle at the target When zeta is 0, vibration never dies
down, and the system is undamped Between values of 0 and 1, the system
is underdamped, and will vibrate more, or less, depending on the magnitude of zeta When zeta is greater than 1, the system will not vibrate, and instead slowly settle toward the target x,
depending on the magnitude of zeta The SmoothDamp function in Unity uses a zeta equal
to exactly 1 which is known as critical damping r is a value which controls the
initial response of the system When r is 0, the system takes time
to begin accelerating from rest When r is positive, the system
reacts immediately to movement in x When r is greater than 1, the
system will overshoot the target When r is negative, the system
will anticipate the motion When modeling a mechanical connection,
a value of 2 for r is typical Now, as artists, we have all we
need to start playing with the characteristics of the motion of
our procedurally animated object If we want to control the settling behavior
of the system, we can play with zeta If we want to control the initial
response of the system, we can play with r If we want to control how fast or slowly
the system behaves, we can play with f Coming back to this robot character, you can
see I used an underdamped movement for the body with zeta of 0.5, and r of -2 to give
it some anticipation before fast movements For a bit of extra flavor, I tilt
the body towards the target position, to further hint at the intent behind the motion
I want the turning to be smooth, so for the body orientation I use a zeta of 1 and r of 0
I do the same for the head orientation, but with a smaller f, to make it lag behind
the body as a sort of secondary motion The cables are animated with a little trick
that I explained over on twitter a while ago Let’s now look at an approach for
solving this equation in real-time, so that we can begin using it in practice There are many ways of numerically
solving differential equations such as our second order one, but a particularly
straightforward one is called Euler’s method Today, I will present a slight variation
known as the semi-implicit Euler method, which, for our system, happens to have the same
accuracy as the more complex Verlet integration First, we need to allocate some state
variables: position and velocity These are our estimates of
y and its first derivative At timestep 0, they need to be
initialized to some initial values Now, when the game is running, we’ll want to
iteratively update these variables each frame Let’s call the amount of time
that passes between frames T First, we update the position estimate by
taking the previous iteration’s position  and adding T times the velocity Next, we update the velocity by
taking the previous iteration’s velocity and adding T times the acceleration To compute this acceleration,
recall our equation of motion We can solve for acceleration here And substitute in our most recent
estimates of position and velocity Note that in semi-implicit Euler, we are using
the updated position to compute velocity, which is slightly different from the regular Euler
method where we use the previous frame’s position In the case that the input velocity, x dot, is
unknown, we can also estimate it using historical measurements, for example, by approximating it
as the average velocity since the previous sample This algorithm naturally translates
almost line by line into code If we were to implement this in-game, we
would see that it does work as designed I hooked up the code to allow for f,
zeta, and r to be changed in real time, and the system responds appropriately There is one big issue that we’ll run
into after a bit of experimentation though Set the resonant frequency f too high relative
to the frame rate, and the system becomes completely unstable, launching itself to infinity While it’s possible to simply keep f low
enough such that this type of glitch is unlikely, in a game engine, we would really like to
have a stronger guarantee that something like this doesn’t happen in corner cases, such as a lag spike causing the time step to be much larger than anticipated This is a problem that can be solved, but
to understand it properly, we’ll have to get a bit more technical with our analysis The reason why physics solvers like Euler’s method
can become unstable is that fundamentally, they are feedback systems whose outputs
from one iteration, here y and its derivative, are fed back into later iterations of the computation When the time step between frames is
too large compared to the parameters, it will start accumulating errors over time Beyond a critical threshold, these errors
will start to compound on themselves, quickly leading to catastrophic failure To compute this threshold, we’ll need to
organize the problem into a more standard form What we want to do is write the values
of our state variables at frame n+1 in terms of our state variables at frame n We can do this by substituting the first equation
into the second, so now both our equations have y and its derivative at frame n on the right-hand side Now let’s expand this and collect like terms This is a system of linear equations,
which we can write in matrix notation The system, written this way, is known
as the state-space representation This matrix A, known as the
state transition matrix, describes how each iteration of the state
variables influence the next iteration Intuitively, you can imagine
that the feedback will be stable If A doesn’t cause the state variables to grow if A was a number instead of a matrix, it would be easier to reason about
the effect that it has on the system For example, in this simpler system with only
a single state variable and no external forces, each iteration is equal to the
previous iteration scaled by A When the magnitude of A is less than
1, the magnitude of y at each iteration will be smaller than the previous iteration,
causing the system to stabilize over time When the magnitude of A is greater than 1,
the magnitude of y at each iteration will be larger than the previous iteration, so
the system will quickly grow beyond control This is what we’d like to avoid In our system, A is a 2x2 matrix, which doesn’t have a magnitude that can directly be compared to 1 Instead, it has what we can think of as
two separate magnitudes, called eigenvalues We won’t get into it here, but suffice to
say that both of these eigenvalues z1 and z2, which are computed by finding the two solutions to
this equation, must have a magnitude less than 1 for the system to settle over time This is computed like this Which expands to this quadratic polynomial of z Which we can solve using the quadratic formula Our system will be stable when the
magnitude of this expression is less than 1 Solving this inequality gives
us the following constraint, that the time step T must be less than the square
root of 4 times k2 plus k1 squared, subtract k1 In our code, we can compute this
maximum stable time step, T critical, and when running in-game, compare the time step against it If the time step is too large, we can divide it up into smaller steps
that are below the stability threshold Taking smaller steps requires
performing more computations per frame To avoid this, we might be able to get
away with slowing down the dynamics instead In this case, rather than constraining
T, we can solve for k2 and constrain that Clamping k2 to be above this value is not
physically correct, but recall that our goal here was just to prevent catastrophic failure,
not to produce an accurate physics simulation There are, of course, much more esoteric
places you can take this analysis, and in a previous draft of this
video, I did go a bit further For example, this frame-to-frame jittering
behavior that sneaks in when the frequency is sufficiently high, is caused by negative
eigenvalues, so if we also take that into account during our analysis, we can impose additional
restrictions to ensure it doesn’t happen In my own implementation, in case accuracy
is needed, I opt to use a method known as pole-zero matching to compute values for
k1 and k2 per-frame based on the time step This produces generally more accurate
results for very fast movement, but comes with this additional computation
cost that might not suit every application The idea behind using simple
parametric motion models like our f zeta r one extends
some interesting possibilities Just as an example, we could modulate
the values of these parameters to convey gameplay information, so
characters could move with different parameters depending on their state of awareness,
health, status effects, and so on This would help communicate the
situation to players through motion in a way that’s cheap and easy to iterate on In any case, I’ve spent long enough
working on this video instead of my game, so hopefully this has been an approachable
but substantial introduction to some interesting concepts, or maybe
a presentation of some applications of mathematics in an unusual but interesting context As always, thanks for watching
Damn, that robot looks so clean and feels so smooth. I especially like the shooting sfx.
I really like this video
I wish I knew how to convert a 3D model into such a nice looking raster
I have loved t3ssel8r's last several videos and have found inspiration in their work that I have brought into my own projects.
That being said I've noticed a disappointing trend of explanations for mathematical procedures that can only truly be appreciated by an audience who already knows and understands what is being demonstrated. This video was a neat watch but it comes off a tad masturbatory because the focus seems to be on demonstrating the author's understanding of the math rather than effectively communicating any information to the viewer.
Why abstract the delta time between frames (a common term that nearly all game developers know and understand) behind a variable
T
rather thandelta
ordt
? Why not give the constants names that explain the influence each has on the end result, rather thank1
,k2
,k3
? Is the audience for this intended to be video game developers? Why not communicate this information in a way that is effective for that audience?Richard Feynman was famously skilled in his ability to explain complex topics in ways that even children could understand. It takes great understanding of a complex topic to explain it and it takes an even greater understanding to explain it simply. As these things go, verlet integration is fairly simple and easy to both intuit and describe in practical terms. I don't think this video was a great explanation.
I stumbled upon your video from YouTube recommendations and I love it! Now that I am seeing you here I just wanted to say do more math related videos please!
I saw it yesterday, very good video on a topic that is rarely explained, well done.
Finally, those calculus classes are paying off.
Any tips/resources/recommended books for learning the math for this or just math for games in general? Used to be good at math in school but this is way way over my head
Am i the only one having a hard time converting math to code?