Weighted animations from animation group ? (with web example)

Dear guys,

I have a nasty problem. I have a 3dmodel of a mole with some animation. The model initially came as an fbx with separate .fbx-es for animation.

So I had to load them in in blender and bake some of the animations to 1 line

Now I have a .glb file with the mesh and its animations in it.

walk: frame 1 -> 33
idle: frame 34 -> 81
push: frame 82 -> 113
fidget: frame 114 -> 222
celebrating: frame 223 -> 269

I made some basic code at My try (getting stuck)

Here you can see that the model is loaded perfectly and starts all of its animations directly.
I tried some code to only play the idle animation

var idleAnim = scene.beginWeightedAnimation(skeletons[0], 34, 81, 1, true);

But still the animation just keeps playing completely.

If I look at the scene explorer, then I see an Animation group called Action and there thewhole scene runs from floats 0,00 to 8,97 and gives me an animation count of 312 .

Can I somehow use this to do weighted (or other) animations on my mesh? Or is the animation not correctly in my .glb file ?

I hope somebody could see this just by having a peek at the inspector for my loaded scene at My try (getting stuck)

I’m learning and get stuck here. Not knowing if this should work or not.

Kind regards,
Thanks for any help offered.

Bart

Hi educa,

Unfortunately I can’t experiment to prove this is right without a Playground, but it looks like the frame numbers you’re expecting might have changed. If, in the Scene Explorer, you look in the Animation Groups at “Action,” the “Current frame” slider traverses from 0 to 8.97, not from 1 to 269.

While I’m not exactly sure what might have caused this (I’m far from an expert on 3D models or animations), my guess is that the number being called “frame” has somehow been converted to seconds for this model. Try playing around with the from/to numbers you’re giving your function. The current numbers you’re giving it, 34 and 81, are both outside of the (0, 8.97) range; I’d try give it a range from something like 4 to 6, just to see if that makes it play only part of the animation, which might reveal something more about what’s going on.

Edit: With regards to what happened to turn the frame numbers into seconds, it just occurred to me that 269 divided by 30 is 8.97. Did your original animation happen to be at 30 frames per second?

Can I create a playground with my own model??

Absolutely! You just have to host it somewhere where the Playground can get to it. There are other ways, of course, but I usually host mine in a Git repository using GitHub Pages. It takes a little setup the first time, but after that you can host whatever you want there just by pushing to a repository. Here’s an example of a Playground that displays a model hosted on my GitHub Pages site (line 5).

We even have a doc for that: Using External Assets - Babylon.js Documentation

I created the playground (tnx for the extra info Deltakosh)

https://playground.babylonjs.com/#IRJ10K#2

Unfortunately it still looks like the model plays all its animations instead of just a range. I thought I changed the range from 1.1 to 2.7 seconds but still see everything play instead of only the IDLE part.

Maybe it wouldn’t be a bad idea to set in blender animation speeds at 1 fps so each frame would also be a second, but I guess that will not solve the core of my problem.

Based on the guess that the animation position is at seconds / 30 , I guess animations should be at

walk: frame 0.0 -> 1.1
idle: frame 1.1 -> 2.7
push: frame 2.7 -> 3.77
fidget: frame 3.77 -> 7.4
celebrating: frame 7.4 -> 8.97

Anyone have an idea ? Maybe by tweaking the playground a little ? I must be doing something elementary wrong there.

Kind regards,
Bart

Dug into this a little bit, and from what I can tell you’re code looks just fine.

As a comparative example, here’s one of our playground examples from the Babylon101 Animations section:

https://www.babylonjs-playground.com/#IQN716#106

Notice how it loops the desired frame range.

How did you create the mole.glb? Was it an export out of Blender? What happens if you baked out the animation keys and then exported?

The other thing that’s super strange here is that the frame range is different between what I see when importing the .glb into Blender, vs. what’s loaded into Babylon…

By default, Babylon is assuming frames, not seconds for weighted animations.

My best guess it seems like something odd is happening in the export of the .glb file?

Sorry if this isn’t super helpful, but it’s definitely odd.

I first put all the animations one after the other in the NLA editor in blender.

I was able to put them all sequentially in 1 NlaTrack and in blender they play absolutely perfect one after the other. They do this in 269 frames.

The range in dope sheet is also setup with start at 1 and end at 269

Then I baked the NlaTrack

And then I just exported to .glb with the built in exporter in blender 2.82a
(I tried the .babylon exporter too but that gave me strange results)

Nothing else has actually be done.

@educa thanks for the scene, I can see an issue with how you’re trying to invoke animations on the miko skeleton via:|

var walkAnim = scene.beginWeightedAnimation(skeletons[0], 0.0, 1.1, 0.0, true);

Unfortunately, glTF animations exist in scene, rather than on the specific objects that are to be animated, there does not seem to be a way to reference the animation group from the skeleton you want to animate…but perhaps @Deltakosh knows better than I :slight_smile:, it seems somewhat untuitive to use two different workflows based on Animation vs AnimationGroup…

After importing the glTF we can see that the scene now contains an AnimationGroup with the entire animation track:

In addition, the first animation track in the glTF automatically plays, which seems to explain why everything is playing in sequence here…

we can stop this behavior via manually stopping this animation track via {animationGroup}.stop() (@bghgary, is there any other workaround for this behavior?)

Also, since our glTF contains only a single animation track, I believe we must “subdivide” it to play the individual animations in it, requiring us to manipulate the animation group to get our desired behaviors. I guess one can also clone() the animation groups to get proper additive animation behavior as well, at the cost of memory.

check this playground for my best guess as to how to effectively control these animations off of a single animation track:

https://playground.babylonjs.com/#IRJ10K#3

The gist of it is that I define helper functions to call {animationGroup}.start() based off of the frame times I want to use:

            let playIdleAnimation = function(){
                mikoAnimations.stop();
                mikoAnimations.start(true, 1.0, 1.1, 2.7, false);
            };
1 Like

It’s not a workaround, but a feature!

You can get at the loader using the technique here: https://doc.babylonjs.com/how_to/load_from_any_file_type#advanced-usage

Then, set the animationStartMode to NONE.

1 Like

@Drigax this is superb news. THANK YOU very much …

I had a look at the code and tweaked some of the animation timings (which is a detail of course, that has nothing to do with how well it works).

I see that now you actually stop all animations and then start another animation from the mikoAnimations array.

That means that if I have the mole in IDLE and then click on PUSH, the hands of the mole immediately jump forward in 1 single frame and then the push animation starts.

With weighted animation you can interpolate between them to get the hands moving in smaller steps/interpolations from the idle pose to the pushing pose/animation. Is that also possible with what you did here somehow ?

Not with this exact method, you’ll have to have multiple animation groups that you can adjust the weights of via {animationGroup}.setWeightForAllAnimatables() and a way to interpolate over an amount of time, where you slowly reduce the weights of the other animation groups, and increase the weight of your desired one. I’ll see if I can cook something up using setInterval() or something similar that will help me lerp over some timeframe.

@educa
Try this scene:
https://playground.babylonjs.com/#IRJ10K#6

In this i had to clone the animation groups, and add some extra logic to our before render loop to update the animation weightings and lerp between our desired weights.

The only thing missing is stopping/starting animations in a timely manner, and adjusting the weight shifting speed for each of your usecases, but is this is the type of functionality you’d expect?

2 Likes

YOU ROCK! Thank you in advance. Sorry for not getting back to you yesterday, but I didn’t manage to log in.

This seems to work very nicely and will be usefull for what I want to make. Thank you very much.
Is there a way I can reward you on this forum? I suppose ticking the “answer” checkbox on your answer is 1 step. And then liking the post. Is there anything else I can do on the forum ?

1 Like

Yup, a like and a solution tag is plenty thanks. Glad I could help :grin:.

2 Likes