# Any plans to support animation interpolation with cubic bezier?

Currently, babylon.js supports cubic hermite and step interpolation in animations.

The cubic hermite interpolation takes a number as a tangent value as a parameter, while the cubic bazier takes a 2D vector value, meaning that not only the tangent but also the length of the vector is involved in the interpolation.

Most 3D software now supports cubic beziers in animation. This means that you will need to implement cubic bezier interpolation to properly load animation assets from other software.
For personal reasons, I need a cubic bezier to load animation data from the MMD into the Animation container in babylon.js.

Below is a simple demo that shows the difference between the two interpolation methods:
cubic hermite spline demo
cubic bezier spline demo

The file formats we support when importing data (gltf, obj, stl) do not use cubic bezier interpolation.

The cubic bezier calculation is much heavier than the Hermit calculation (Iâ€™d say itâ€™s at least x10):

Bezier:

``````public static Interpolate(t: number, x1: number, y1: number, x2: number, y2: number): number {
// Extract X (which is equal to time here)
const f0 = 1 - 3 * x2 + 3 * x1;
const f1 = 3 * x2 - 6 * x1;
const f2 = 3 * x1;

let refinedT = t;
for (let i = 0; i < 5; i++) {
const refinedT2 = refinedT * refinedT;
const refinedT3 = refinedT2 * refinedT;

const x = f0 * refinedT3 + f1 * refinedT2 + f2 * refinedT;
const slope = 1.0 / (3.0 * f0 * refinedT2 + 2.0 * f1 * refinedT + f2);
refinedT -= (x - t) * slope;
refinedT = Math.min(1, Math.max(0, refinedT));
}

// Resolve cubic bezier for the given x
return 3 * Math.pow(1 - refinedT, 2) * refinedT * y1 + 3 * (1 - refinedT) * Math.pow(refinedT, 2) * y2 + Math.pow(refinedT, 3);
}
``````

Hermite:

``````public static Hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number): number {
const squared = amount * amount;
const cubed = amount * squared;
const part1 = 2.0 * cubed - 3.0 * squared + 1.0;
const part2 = -2.0 * cubed + 3.0 * squared;
const part3 = cubed - 2.0 * squared + amount;
const part4 = cubed - squared;

return value1 * part1 + value2 * part2 + tangent1 * part3 + tangent2 * part4;
}
``````

Whatâ€™s more, for Hermite, only the last line needs to be calculated for each component of a vector (this is what `Vector3.Hermite` does), whereas in the case of BĂ©zier, we have to reapply all the calculations for each x/y/z component of a vector.

In your case, itâ€™s probably best to resample the animation based on BĂ©zier curves and generate enough keyframes so that the final animation resembles the original, even if we donâ€™t use the same interpolation scheme.

2 Likes

The animation Iâ€™m dealing with is 3 minutes long and has thousands of tracks, so sampling it is not feasible.

Iâ€™m going to force the animation to support cubic bezier via an implementation that overrides an internal function,
and also provide a sampling method,
and a way to convert only the tangent values of the cubic bezier to cubic hermite parameters.

However, Iâ€™ve already overridden several internal functions and would like to avoid this risky approach if possible. so if I add the cubic bezier feature as a PR in babylon.js, will that be accepted? Or is this a useless add-on that would just increase the bundle size?

cc @sebavan.

By itself, I think itâ€™s always good to have a new feature, as long as it is not a perf / memory usage regression for existing code.

But for this one Iâ€™m not really sure, because even if we add this support, it will be difficult for users to leverage it because itâ€™s not used by any file format we support: you will have to create your own animation data by code. So, I fear that the feature wonâ€™t really be used (except by you!), but once itâ€™s in Babylon we would have to support it foreverâ€¦

First, there was a slight misunderstanding in our conversation: it is possible to implement a cubic hermite to receive a weighted tangent, and in the end, this gives the same degrees of freedom as a cubic bezier. What Iâ€™m essentially asking for is any interpolation method that has the same degrees of freedom as cubic bezier.

and itâ€™s hard to agree that cubic bezier interpolation is an uncommon method. The various software Iâ€™ve used all support tangents with weights (a.k.a. 2d vector tangents).

Here are some examples:

For animations in Unreal Engine, the interpolation is done with a spline consisting of a tangent and the weight value of the tangent

You can see that unity also supports â€śweighted tangentsâ€ť.

Blender also supports â€śbezierâ€ť interpolation.

In the case of AfterEffects, the tangent is also represented as a 2D vector, so we can assume that it will use either a cubic bezier or a cubic hermite that takes a weight.

And as you said, backward compatibility is very important in babylon.js and performance is also sensitive,

so I think we need to have enough discussions and the right people to implement such an important feature like adding an animation interpolation method (and there are many people in babylon.js who are much more professional than me),

so for the above reasons, I appeal to the need for this feature.

and itâ€™s hard to agree that cubic bezier interpolation is an uncommon method

I donâ€™t think I said that? I said that among the file formats we support for import, none support Bezier curves.

So, for most of the users, they wonâ€™t be able to use the feature because only a few fraction of people will be able to create their animation tracks by code.

But I do agree that the feature by itself could be good to have.

Thatâ€™s why I cc @sebavan on this topic, and I should probably also cc @Deltakosh, who is the mastermind behind the current animation system!

1 Like

Iâ€™m open to add but I may not have the time

Do you have some cycles @noname0310 to do a PR?

1 Like

I am puzzled by this thread. I understand the point that no-one puts this on their export files. This could be implemented outside an import context though. I have my own animation system, mostly build right into my base Mesh class. I interpolate everything right in JS, except base finger bone matrices. Importing animation is stupid, IMO.

I also did some minor stealing of all those methods BJS uses to smooth out in-between animations, `Easing`, and made each of them one of my own `Pace` sub-classes with only minor arg switches (maybe cannot remember back to 2014).

Here is one which looks to me could be fashioned to work without the framework adding anything.

``````export class BezierCurvePace extends Pace {
constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1, mode = Pace.MODE_IN) {
super(mode);
}

/** @override */
protected _compute(currentDurationRatio : number): number {
return BABYLON.BezierCurve.Interpolate(currentDurationRatio, this.x1, this.y1, this.x2, this.y2);
}

public getClassName(): string { return "BezierCurvePace"; }
}
``````

Just call `BABYLON.BezierCurve.Interpolate()` somewhere.

1 Like

@Evgeni_Popov I apologize for not understanding the exact context of the conversation.

@Deltakosh First, Iâ€™ll create an implementation via function override in my project, and if it looks good, Iâ€™ll create a PR in babylon.js.

1 Like

Some skilled animators fully utilize interpolation curves to create a great look with minimal keyframes.

Itâ€™s hard to put into words, but the feel of these animations depends a lot on being able to get the tangent data intact.

I am not opposed to it as long as there are some easy way to export/import it. If not it becomes a feature only for your local system and in this case I would be more open to allow any kind of interpolation from external code. By this I mean you could provide the framework with what you are currently overriding. And when this gets more traction/tooling we can easily integrate back your overrides in the code.

1 Like

Iâ€™ve thought about having babylon.js provide an interface to allow users to implement custom interpolations themselves.

However, it seems difficult for the Animation Curve Editor to provide a UI for custom interpolation, so it seems better to embed bezier in babylon.js to support full functionality.

Which implementation do you think would be better?

Totally agree it might be hard for full edit support in Babylon.

Let s add @PatrickRyan to see what he thinks.

@noname0310 and @sebavan unless I am totally missing something in the context of this thread, donâ€™t we already support cubic bezier interpolation? Advanced Animation Methods | Babylon.js Documentation

I typically fall into the camp of needing to import animations through glTF so while I am authoring animation with cubic bezier in Maya, I typically have to bake my animation frames to keep the authored intention of the animation as passing through our exporter to glTF I tend to have not-great interpretation of the timeline. I get that in a super long animation baking frames can become very heavy in terms of file size, but this is the current limitation of glTF and so I need to make that tradeoff.

Idk jack about artist workflow, but it seems like a viable use case to have a gltf extension for it if you and the op are both having problems. I mean, Isnt gltf just a json file that can be arbitrarily extended?
Ie: vrmc https://github.com/vrm-c/vrm-specification/tree/master/specification/VRMC_vrm_animation-1.0

Or this project with several gltf extension transforms https://github.com/matrix-org/thirdroom/tree/main/src/asset-pipeline/extensions

Or even the babylon extension supporting microsofts rigid body spec (plus the ones already in the gltf loader) https://github.com/eoineoineoin/glTF_Physics_Babylon/deployments

Maybe its a chicken and egg problem, bc dcc tools wont export if no consumers and no consumer going to account for it when parsing to scene format if noone exporting it.

Informative:

Still, i think just leaving the specâ€™d gltf animation field null and putting a new arbitrary field is fair game

@PatrickRyan `Animation.setEasingFunction` applies a specific easing function to every keyframe, and if you apply a bezier to it, you can perform the bezier with a fixed tangent parameter for every frame.

The cubic bezier interpolation support here means that each keyframe can have a 2D vector as its tangent value, allowing for different shapes of bezier interpolation for each keyframe.

I think a glTF extension would be best, but it would have to be an official extension, otherwise it wonâ€™t be implemented by the DCC tools. And if itâ€™s not supported by the DCC tools, there wonâ€™t be an easy way to generate content using itâ€¦

Iâ€™m late to the party, but Iâ€™m not sure Iâ€™m following the thread well.

Babylon.js supports cubic spline interpolation in Hermite form. This form is more or less interchangeable with Bezier because it is easy to convert between the two forms.

According to wikipedia:

Cubic polynomial splines can be specified in other ways, the Bezier cubic being the most common. However, these two methods provide the same set of splines, and data can be easily converted between the BĂ©zier and Hermite forms; so the names are often used as if they were synonymous.

Regardless of which form the cubic spline takes in the code / serialized data, the editing of the spline is the same in the UI and depends on the user experience.

glTF is not required to store 1/3 tangent lengths. Iâ€™m not sure where the information from the answer comes from.

Given what I said, I canâ€™t see a reason why we need another form to store cubic splines in a glTF extension. glTF tries to store only one way to make it easier on the runtime to load.

1 Like

cubic hermite and bezier are interchangeable, but this is only possible when the cubic hermite is a weighted tangent. Currently, the cubic hermite interpolation in babylon.js does not support taking the weight (a.k.a. length of vector) of a tangent.

I donâ€™t think thereâ€™s any real difference in functionality between handling beziers or supporting hermite interpolation for weighted tangents.