Skip to content

Heck Animation Baking

Swifter edited this page Nov 5, 2024 · 1 revision

Prerequisites

Explanation

The baking system is used to generate a new animation from an old one by sampling it at small intervals.

The reason this could be useful is that you get to define what happens at every moment, when usually you're relying on the game to interpolate the animation.

  • Note: It is unlikely you will be using the baking system directly, as it's usually used internally for much easier and user friendly solutions like rm.emulateParent (see Transform-Utilities). But it's still important to understand what is happening when I say an animation is "baked"!

Let's look at an example.

We want to rotate a wall around it's center. The issue is that the wall's anchor point is somewhere on the edge of it, not in the center.

If we just try a start and end point, it'll end up like this:

alt text

Instead, we need to include more points in our animation to describe our path more accurately.

alt text

The more points, the more accurate the animation.

Usage

The rm.bakeAnimation function will take in an animated Transform, and return a new one which has been generated by sampling the first one at small intervals.

Code Example
const animation: rm.AnimatedTransform = {
    position: [[0, 0, 0, 0], [0, 10, 0, 1, 'easeInOutExpo']],
}

rm.bakeAnimation(animation)
/*
{
  position: [
    [ 0, 0, 0, 0 ],
    [ 0, 0.007636299408441899, 0, 0.03225806451612903 ],
    ...
  ],
  rotation: [
    [ 0, 0, 0, 0 ],
    [ 0, 0, 0, 0.03225806451612903 ],
    ...
  ],
  scale: [
    [ 1, 1, 1, 0 ],
    [ 1, 1, 1, 0.03225806451612903 ],
    ...
  ]
}
*/

For every new frame that gets baked, you can optionally provide a callback to edit the frame. You'll be passed the following structure:

{
    position: rm.Vec3
    rotation: rm.Vec3
    scale: rm.Vec3
    time: number
}

You can edit it however you want and that's how it will end up in the final animation.

Code Example
const animation: rm.AnimatedTransform = {
    position: [[0, 0, 0, 0], [0, 10, 0, 1, 'easeInOutExpo']],
}

rm.bakeAnimation(animation, transform => {
    transform.position[1] += 10
})
/*
{
  position: [
    [ 0, 10, 0, 0 ],
    [ 0, 10.007636299408441899, 0, 0.03225806451612903 ],
    ...
  ],
  rotation: [
    [ 0, 0, 0, 0 ],
    [ 0, 0, 0, 0.03225806451612903 ],
    ...
  ],
  scale: [
    [ 1, 1, 1, 0 ],
    [ 1, 1, 1, 0.03225806451612903 ],
    ...
  ]
}
*/

You can also pass in animation settings as the third parameter to change how the animation is generated.

Code Example
const animationSettings = new rm.AnimationSettings()
animationSettings.bakeSampleFrequency = 5
animationSettings.optimizeSettings.disabled = true

const animation: rm.AnimatedTransform = {
    position: [[0, 0, 0, 0], [0, 10, 0, 1, 'easeInOutExpo']],
}

rm.bakeAnimation(animation, undefined, animationSettings)
/*
{
  position: [
    [ 0, 0, 0, 0 ],
    [ 0, 0.15625, 0, 0.25 ],
    [ 0, 5, 0, 0.5 ],
    [ 0, 9.84375, 0, 0.75 ],
    [ 0, 10, 0, 1 ]
  ],
  rotation: [
    [ 0, 0, 0, 0 ],
    [ 0, 0, 0, 0.25 ],
    [ 0, 0, 0, 0.5 ],
    [ 0, 0, 0, 0.75 ],
    [ 0, 0, 0, 1 ]
  ],
  scale: [
    [ 1, 1, 1, 0 ],
    [ 1, 1, 1, 0.25 ],
    [ 1, 1, 1, 0.5 ],
    [ 1, 1, 1, 0.75 ],
    [ 1, 1, 1, 1 ]
  ]
}
*/

The fourth parameter defines the "domain" of the animation. This describes the minimum and maximum time the animation should take place.

Code Example
const animation: rm.AnimatedTransform = {
    position: [[0, 0, 0, 0], [0, 10, 0, 1, 'easeInOutExpo']],
}

rm.bakeAnimation(animation, undefined, undefined, { min: 0.5, max: 1 })
/*
{
  position: [
    [ 0, 3.998191155582921, 0, 0.4838709677419355 ],
    [ 0, 9.331637688393082, 0, 0.6451612903225805 ],
    ...
  ],
  rotation: [
    [ 0, 0, 0, 0.4838709677419355 ],
    [ 0, 0, 0, 0.5161290322580645 ],
    ...
  ],
  scale: [
    [ 1, 1, 1, 0.4838709677419355 ],
    [ 1, 1, 1, 0.5161290322580645 ],
    ...
  ]
}
*/

By default, this is just the minimum and maximum time of all the points combined.

Clone this wiki locally