Sum

= Time Stretch Curve =

Windows
MacOS
Linux

References

Module

Engine

Header

/Engine/Source/Runtime/Engine/Classes/Animation/TimeStretchCurve.h

Include

#include "Animation/TimeStretchCurve.h"

Syntax

Sum
(
    dTO_i
)

Remarks

= Time Stretch Curve =

= What is it? The Time Stretch Curve is an optional float curve that montages can use to define where a montage is allowed to speed up or slow down. Let's say we have a montage of default play time T_Original. We now want that montage to play for a different T_Target play time Typically we would uniformly play rate the animation to reach that goal.

The Time Stretch Curve allows doing the same thing but non uniformly, by defining which regions can be play rated more or less.

The Curve values are normalized. So a Curve value of 0 means "don't play rate this". And a Curve value of 1 means "play rate this the most". Intermediate values will be weighted accordingly.

Imagine the following scenario, you have a character attacking with a staff. The animation is authored with holds after striking. Let's say the character levels up over the course of the game, and his attacks are getting faster and faster (play time is shorter).

By using a Time Stretch Curve, most of the time compression could happen during the holds. So the strikes look mostly unaffected. This allows using a single animation, and scaling it for very different desired play times.

= How does it work? Given a Montage of length T_Original, and a float curve C. Curve C is sampled over N segments of fixed time 'SamplingTimeStep'. Each element, C_i is normalized. 0 <= C_i <= 1 and 0 <= i <= N.

We have Sum(SamplingTimeStep) = T_Original = N * SamplingTimeStep SamplingTimeStep = T_Original / N

Given a different length T_Target, C remaps positions from T_Target to T_Original according to the following function: dTO = dT_i * U * (1 + S * C_i) where: Sum(dTO) = T_Original Sum(dT_i) = T_Target U = UniformPlayRate S = Curve Scale Factor C_i = sampled curve value, constant over the interval dTO

dTO is fixed, based on the chosen 'SamplingTimeStep', but in practice we can combine consecutive segments that have the same C_i value.

We would like U to be 1 (or -1) as much as possible. Meaning the Curve should do all the remapping whenever possible. U(niformPlayRate) should only come into play when C can't remap T_Target to T_Original on its own. This can happen when trying to speed up the animation, but the Curve is not enough to reach that time compression. In that event, uniform scaling kicks in.

We call PR_i (or OverallPlayRate for Segment i) PR_i = U * (1 + S * C_i) dTO = dT_i * PR_i

We also want PR_i > 0, that is it should never backtrack or pause during playback of animation. A Montage can still play in reverse with U < 0.

= How is T_Target defined? When we play a Montage with a PlayRate of PR, we assume this means: T_Target = T_Original * PR So this system does not change the interface for playing a montage.

If a curve is not defined, the mapping is defined as: dTO_i = dT_i * U

If a a curve is defined: dTO_i = dT_i * U * (1 + S * C_i)

We can see that no curve means S == 0. Also if we're not scaling the montage, T_Target == T_Original, we also have S == 0.

So, this makes the curve completely optional. And it seamlessly integrates with the current montage interface. If you want playback time to be half, that means playing the montage with a play rate of 2. If there is a TimeStretchCurve, it will be used. But regardless or using a curve or not, play back time is guaranteed.

= Finding U and S = Ideally, we could figure out what U and S are given a T_Target play time. Unfortunately, the math for this is very complex.

We update the montage position like this: dTO_i = dT_i * U * (1 + C_i)

We sum this over the N time segments: Sum(dTO_i) = Sum(dT_i * U * (1 + C_i)) /** = Time Stretch Curve =

= What is it? The Time Stretch Curve is an optional float curve that montages can use to define where a montage is allowed to speed up or slow down. Let's say we have a montage of default play time T_Original. We now want that montage to play for a different T_Target play time Typically we would uniformly play rate the animation to reach that goal.

The Time Stretch Curve allows doing the same thing but non uniformly, by defining which regions can be play rated more or less.

The Curve values are normalized. So a Curve value of 0 means "don't play rate this". And a Curve value of 1 means "play rate this the most". Intermediate values will be weighted accordingly.

Imagine the following scenario, you have a character attacking with a staff. The animation is authored with holds after striking. Let's say the character levels up over the course of the game, and his attacks are getting faster and faster (play time is shorter).

By using a Time Stretch Curve, most of the time compression could happen during the holds. So the strikes look mostly unaffected. This allows using a single animation, and scaling it for very different desired play times.

= How does it work? Given a Montage of length T_Original, and a float curve C. Curve C is sampled over N segments of fixed time 'SamplingTimeStep'. Each element, C_i is normalized. 0 <= C_i <= 1 and 0 <= i <= N.

We have Sum(SamplingTimeStep) = T_Original = N * SamplingTimeStep SamplingTimeStep = T_Original / N

Given a different length T_Target, C remaps positions from T_Target to T_Original according to the following function: dTO = dT_i * U * (1 + S * C_i) where: Sum(dTO) = T_Original Sum(dT_i) = T_Target U = UniformPlayRate S = Curve Scale Factor C_i = sampled curve value, constant over the interval dTO

dTO is fixed, based on the chosen 'SamplingTimeStep', but in practice we can combine consecutive segments that have the same C_i value.

We would like U to be 1 (or -1) as much as possible. Meaning the Curve should do all the remapping whenever possible. U(niformPlayRate) should only come into play when C can't remap T_Target to T_Original on its own. This can happen when trying to speed up the animation, but the Curve is not enough to reach that time compression. In that event, uniform scaling kicks in.

We call PR_i (or OverallPlayRate for Segment i) PR_i = U * (1 + S * C_i) dTO = dT_i * PR_i

We also want PR_i > 0, that is it should never backtrack or pause during playback of animation. A Montage can still play in reverse with U < 0.

= How is T_Target defined? When we play a Montage with a PlayRate of PR, we assume this means: T_Target = T_Original * PR So this system does not change the interface for playing a montage.

If a curve is not defined, the mapping is defined as: dTO_i = dT_i * U

If a a curve is defined: dTO_i = dT_i * U * (1 + S * C_i)

We can see that no curve means S == 0. Also if we're not scaling the montage, T_Target == T_Original, we also have S == 0.

So, this makes the curve completely optional. And it seamlessly integrates with the current montage interface. If you want playback time to be half, that means playing the montage with a play rate of 2. If there is a TimeStretchCurve, it will be used. But regardless or using a curve or not, play back time is guaranteed.

= Finding U and S = Ideally, we could figure out what U and S are given a T_Target play time. Unfortunately, the math for this is very complex.

We update the montage position like this: dTO_i = dT_i * U * (1 + C_i)

We sum this over the N time segments: Sum(dTO_i) = Sum(dT_i * U * (1 + C_i)) /**

Help shape the future of Unreal Engine documentation! Tell us how we're doing so we can serve you better.
Take our survey
Dismiss