Questions about animation

Hi! I have a few questions about how animations work in Armory. I don’t had used it before, so i have no idea about how it works. I plan to create a state machine if i see any possibility. But i also don’t know what is the point of a animation state machine yet. Is there any difference between a animation state machine (like the ones in unreal, unity, etc.) and a animation finite state machine or they are just the same? Any documentation about this would be of great help!

To illustrate what i am asking, see this blend file: https://drive.google.com/file/d/13_9OP2B4UpEapawibtfziDtnbi-hbSl6/view?usp=sharing

Controls: 'W' to walk, 'S' to idle, 'Shift' to run and 'Space' to jump.

I have only three questions yet:

  1. I see that the blending between the animations are not correct. Looks like the “previous animation” snaps to its end frame before get interpolated. What is wrong here? Do i need to make sure that this previous animation is in the last frame before blend to another?

  2. The two functions: play() and blend() works differently. Blend animation can be updated every frame and play animation must be used just a single time because it starts from the initial frame of the animation. Apparently is no blending when you play an animation trough blend() and after play another animation trough play(). Anyway to get it working?

  3. How do blending animations work if two animations (one with 10 frames and another with 60 frames) are blended? What is the frame of the animation then? Or this is literally two animations playing at the same time? If it is two animations at the same time, is possible to get the current frame of each one?

Thanks in advance!

2 Likes

Hey @knowledgenude,

I have only three questions yet:

That’s a lot more than three questions :wink:

Animation is a huge topic, although not an expert, here are my thoughts.

what is the point of a animation state machine

A state machine is required to properly organize and play animation according to input events. Say for example you have a Jump, Land, and a Forward animation. When the user inputs jump and immediately after that inputs forwards, it is the task of the state machine to handle these inputs. Like this: Play Jump animation(One complete cycle) → Play Land animation(One complete cycle) → Play Forward animation(Until new input).

Without a state machine, the animations cannot be handled properly since the animation will be switched immediately after the input.

Is there any difference between a animation state machine (like the ones in unreal, unity, etc.) and a animation finite state machine or they are just the same

Judging from the two terms mentioned here, I would say it has to do with looping. That is animation state machine will always have to stay at least in one animation state (Looping), until input is applied. In the case of an animation finite state machine, the animation can end after being played (No looping).

I see that the blending between the animations are not correct. Looks like the “previous animation” snaps to its end frame before get interpolated. What is wrong here? Do i need to make sure that this previous animation is in the last frame before blend to another?

I am not sure why this “snapping” happens here. I will have to look it in detail. But, in general, having at least one frame common or similar between the animation that you like to switch between gives a much better transition.

  1. The two functions: play() and blend() works differently. Blend animation can be updated every frame and play animation must be used just a single time because it starts from the initial frame of the animation. Apparently is no blending when you play an animation trough blend() and after play another animation trough play() . Anyway to get it working?

Again, need some time to check :wink:

How do blending animations work if two animations (one with 10 frames and another with 60 frames) are blended? What is the frame of the animation then? Or this is literally two animations playing at the same time? If it is two animations at the same time, is possible to get the current frame of each one?

Technically blending works per frame of animation. It may have more than one animation, but blending adds them up and normalizes according to the blend factor. So, yes in a way it is two animations playing at the same time.

Hope this helps.

Best Regards,
QC

4 Likes

Thanks for your help! You clarified a lot for me.

Here is an test file of the snapping happening:

Just change the animation from ‘W’ to ‘S’ and you will can see it snapping for the end frame (at least i think it is the end frame)

And the thing about play and blend animations at the same time:

(Press space while the animations are blending)

About the state machine it is more clearer for me when i try to setup the animations, like this blend example i need to set a boolean to avoid the blending happening while the animation is played :slight_smile: I think i am understanding its concept now.

Just let me know the things about the snap and blending and i think i will be able to start the SM. I also need to learn more about the classes, etc. but i guess i will learn in the process of doing this.

Another guess: I think they mean more or less the same. In computer science a finite-state machine is a state machine that only has a finite amount of states. As computers are always limited in memory/storage, there is no such thing as a real infinite-state machine on computers and for animation you probably only have a few states like running, jumping etc. anyways, just as mentioned above.

What I’m unsure about is the existence of start/end-states. I was teached that FSM (finite state machines) do always have a start (state where the execution begins) and an end state (if this state is reached, the entire machine stops), but there might be definitions that differ from that (animation state machines usually don’t end I guess?)

2 Likes

So I did some more tests and here are the results.

I used a much simpler animation setup so that it makes more sense when we watch:

The Setup: I have a simple cube with a single bone armature. There are four actions to this bone.

-PlusX: Bone moves along +Y axis
-PlusY: Bone moves along +X axis
-MinusX: Bone moves along -X axis
-MinusY: Bone moves along -Y axis.

When the bone moves, it takes the cube with it.

Case 1:

animation.play('PlusY', null, 0.0); //(Action, onComplete(), blendTime)

The animation starts and moves towards +Y

Case 2:

animation.play('PlusX', null, 0.0); //(Action, onComplete(), blendTime)


The animation starts and moves towards +X

Case 3:

animation.play('PlusY', null, 0.0); //(Action, onComplete(), blendTime)
animation.play('PlusX', null, 1.5); //(Action, onComplete(), blendTime)

OR

animation.play('PlusY', null, 0.0); //(Action, onComplete(), blendTime)
//After 2 Seconds
animation.play('PlusX', null, 1.5); //(Action, onComplete(), blendTime)

When using blend > 0, Both the actions PlusY(Previous action) and PlusX(Current action) start together from frame 0, regardless of the previous frame/time with blend factor of 1. The blend factor reduces progressively down to 0.0 in 1.5 seconds.

The Example used here

3 Likes

It has the same purpose than visual programming. The idea is to give you a layer of abstraction from the if/else/if/else if/else/ += delta that you would normally see when implementing animations transitions yourself by hand. Instead it gives you an intuitive representation of what your logic does and some basic tools to work with so you can concentrate in what’s important. I think with logic nodes already existing with strong support, probably a lot of code could be reused for this purpose, since they are pretty similar.

Though, probably one tricky part to implement in blender would be some kind of reactiveness, to have an idea what your logic is doing without playing your project in armory every time. Blender is getting ton of work in the node department, so I would suggest checking it out to see what and how they are doing it since they are planning a similar thing if I recall correctly, but not sure.

3 Likes

So i think is better to understand an animation state machine as a simple method to control the animations…

I am trying to follow the concept of this guy https://www.youtube.com/watch?v=z5dOzYKB3Qo but this may be different from what is a animation state machine as we see in other engines. What i am not understanding is what exactly a animation state machine should control. The animations frames? O just if statements? I will explain better…

So basically i need to check what animation is playing in the time i try to play another and if the another animation don’t has a “bridge” to the another state then the animation is not played (also is a way to prevent the animation to be played twice). But this will not need the player controls to be guided by the animations? See the image:

The ‘Jump’ animation can’t be played but the player object will may jump anyway if the logic is not controlled by the animation state…

This is not easy to understand without use, so if anyone has experience using this, please explain not only the functionality but the relation with the game logic.

Another observation: looks like the blend() function is more flexible than the play() function, it allows you to control the blending between the animations without start it from the begin. Unfortunately it is limited to two animations, this is why i think this animation state should have control over the frames. I personally think that the blending must include the active animation (as play() do).

Like this: Active blend to the first anim before first anim blend to the second anim (Active(“Floating”) -> “Idle”, “Walk”).

Anyway there is something wrong happening with the play() function. Even the templates as FP, TP and platform are snapping between the animations. See how it works fine in Lubos demo: https://www.youtube.com/watch?v=5UwGfDsybfg

1 Like

This is not easy to understand without use, so if anyone has experience using this, please explain not only the functionality but the relation with the game logic.

In most cases, the game logic controls the animation state, not the other way around. If it were an AI system with realtime feedback and so on, then the animation state may affect the game logic.

The ‘Jump’ animation can’t be played but the player object will may jump anyway if the logic is not controlled by the animation state…

If that happens, then, that is just a bad state machine.

looks like the blend() function is more flexible than the play() function, it allows you to control the blending between the animations without start it from the begin

Yes, the blend function can start from any time step. To start blending of two animations from a particular frame, you may use something like this:

var animation = object.animation;
if (animation == null) animation = object.getParentArmature(object.name);

var startFrame = 10;
animation.update(startFrame*Scene.active.raw.frame_time); // Set start time

animation.blend(action1, action2, 0.5); // Start Blending

Have a look at the PlayActionFromNode here

Unfortunately it is limited to two animations, this is why i think this animation state should have control over the frames.

Yes, This is a limitation in iron. Due to this, 2D blending like in Unity (Blend Trees) are not possible. Only 1D blending is possible.

Anyway there is something wrong happening with the play() function. Even the templates as FP, TP and platform are snapping between the animations. See how it works fine in Lubos demo:

I am not sure if Lubos used the play() or the blend() methods. Besides, Armory and iron has changed a lot since then.

3 Likes

Thanks again! I am testing it a lot, i don’t like to bother with questions but i think it is a lost of time trying to figure out things that people may already know…

As you said, blend() work in any time step differently from play(). Using play, is possible to blend the active action to another one. But… play() is snapping to the last frame of the action. Let consider that Lubos has used another trick to blend the animations or used the blend() function (what i don’t think is probably because he played a third animation, then…).

So i need to know: is there any problem by in the state machine the next animation is played only after the first animation is completed OR it requires to blend the animation independently of the frame without snap? The second option i think may need some workarounds i don’t know yet, but maybe i can make some test by setting the start frame as you told me.

For the first option, it would be like this: https://drive.google.com/file/d/14SCMNqr2O43ayIBv8o0Y8hAyUTMuDsf5/view?usp=sharing

See that i play the jump animation when i press space, then when the jump is complete i call another function that play the next animation (idle in this case). This would happen even with looping animations. Sorry if this is bullshit, and feel free to point the right way!

I will talk more about the relation to the game logic when i give any step forward and abstract it more.

1 Like

Thanks again!

Welcome :grinning:

But… play() is snapping to the last frame of the action.

No. play() always starts from the first frame.

So i need to know: is there any problem by in the state machine the next animation is played only after the first animation is completed OR it requires to blend the animation independently of the frame without snap? The second option i think may need some workarounds i don’t know yet, but maybe i can make some test by setting the start frame as you told me.

I did not fully understand what you meant. So here I state what I think an animation state machine should achieve

  1. Play any animation at any point in game, from any given start frame.(With/ without looping) (No Blending)
  2. Switch between two animations at any frame depending on the input (With and Without blending)
  3. Seamlessly blend between two or more animations at any given frame with any given blend factor/s.
  4. Completely stop playing all animations.

See that i play the jump animation when i press space, then when the jump is complete i call another function that play the next animation (idle in this case). This would happen even with looping animations.

Yes, depending on the game, this may or may not be required.

2 Likes

Sorry it is because the end frame is the same as start frame so i get confused :smiley:

I think i already understood sufficient, thank you and everyone very much! I have hopes that i will post each step here in the process without stuck. Anyone please feel free to make suggestions!

All the best :slight_smile:

2 Likes

I still don’t know a way to even change the animations so i can’t move on yet…

The play() function does not works as i expected. Defining the frame to the last frame (to avoid snapping) kills the blending.

The blend() function also have a problem. It plays two animations but we can only get the first one. Then what would be better:

  1. The action returned depend on the factor (i.e. factor > 0.5 the blendAction is returned).
  2. Change the blendAction variable to public.

Other question: when you play a non loopable animation, it will freeze in the last frame, and if you play another, the non loopable action starts from beginning. It should not keep this particular animation freezed (loop only in its current frame)? Test file: https://drive.google.com/file/d/16pYpZSqxGKht--nq13NOte6akJ1NIJrS/view?usp=sharing

In the test file just play the jump action with ‘3’ and then play another in the end.

That’s okay, we could use play() and blend() methods in combination. When no blending is needed, we use play(). When blending is needed, we use blend() and slowly reduce the blend value over time, like in one of your previous examples.

A better and safer approach would be to add a new method, say getBlendAction() and then return the blendAction. If no blend action, then return null.

2 Likes

Currently i am just trying to create the possibility to do what is said here in Unreal state machine introduction https://www.youtube.com/watch?v=NYFeFUxU6DI , this was the best practice example i see because it combines a loop animation with a non loop animation and have a good complexity.

You said to use blend() and play() together but i can’t imagine a way to do that. One looks like breaks the another and they don’t have the same capabilities, in one you can set even the animation speed while you don’t have the control over the blending factor… But i have in mind that the state machine must check only the current state and the next state. So no matter for the state machine if the play() or the blend() functions will be used and should work for both.

I am trying to create a few animations and setup them without the state machine, to know what exactly things it should check. Here is a test file showing why i can’t get both working together: https://drive.google.com/file/d/1gUtTxUcpNtGSt8JrxgbHHbrR0cqQM2xx/view?usp=sharing

I don’t know how the animations should work, i only used animations before in BGE/UPBGE and in there you literally just use play every time you want and there will not have snapping… Unfortunately It is the only reference i have. In my opinion the user will only play the actions and the state machine will do the rest, but that is the main reason why i can’t move on, it is not working how i expect.

The only solution i can imagine is that Armory should stop from restarting the animations every time it is blended and just blend from the animations current frame.

What is happening currently is: You play a jump animation and the jump animation have a end frame (not a loop). When you play the landing animation then the jump animation will restart from beginning and will blend with the landing animation. I think this should not happen. but i don’t have experience to confirm. That is why i need some practice examples.

I am stuck because i need to know when the animation should end to go to another state, but this looks very subjective and i should keep the highest flexibility i can. Depending on the situation, waiting until the end frame will not be a good choice (i.e. for a idle with a lot of frames), in other words this method is limited.

I think this state machine (in the video below) was not made to use blend() function and the animations are too short, so i suspect the author used the method i said (wait until the animation complete a loop and then change the state) https://www.youtube.com/watch?v=z5dOzYKB3Qo

2 Likes

@knowledgenude

Thanks for the elaboration and the example, I now understand the issue here.

From what I gather here are the additional features we need in Iron’s animation class:

  1. A modified play() method to play animations from a particular frame. (So it does not snap to the first frame every time.). Like so:
//Modified play()
public function play(action: String,
                     startFrame: Int,
                     onComplete: Void->Void,
                     blendFactor: Double,
                     blendTime: Double,
                     speed: Double
                     loop: Bool)
{
 ...
 ...
}
  1. A new/m modified blend() method that not only combines two animations, but also plays the animations at a certain speed, with two different animations at two different start frames. Something like this:
//Modified blend()
public function blend(action1: String, 
                      action2: String, 
                      frameInAction1: Int, 
                      frameInAction2: Int, 
                      blendFactor: Double,
                      speed: Double)
{
 ...
 ...
}

Such modifications should solve most of the issues we have currently. Do you agree?

Best Regards,
QC

3 Likes

I agree with that and i already tried to set the animation frame after i play it, see what happens https://drive.google.com/file/d/1r9m04CDOb8BvumQ-7E4cu_cmCkvVGWQQ/view?usp=sharing

In the example the specific animation is not a looping, so it is not desirable it playing again. For looping animations the blending should happen on the active animation current frame instead of from both beginning. Maybe your solution could work, if i am wrong in the affirmation (in bold) below:

About the test file: Basically the animations starts from frame 1, and then the script set the frame back to the desired frame (the last before it resets) and the blending does not happens, i think the blending is not related to the pasted time but to the animation frames progression. So changing the frame manually is not working right unfortunately. Maybe if we only can set the frame without breaking the blend would be possible to control this behavior, but i still think that this must be simplified in a single function (play()).

Fortunately Armory can play two animations at the same time, but the control over them is lacking in a few parts. I have to make more tests to confirm that, but consider this steps:

  1. Play an “Idle” animation on init.

  2. Blend the Idle animation with another one, the script would be like:

    animation.play("Idle"); // plays only once
    animation.blend("Idle", "Walk"); adds a second animation and controls the blending between the two animations

So for me in this case would be awesome if the blend() function don’t start both animations from beginning but keep the Idle animation current frame and just “add” the walking animation with it independent progression. I think what would happen here is the animations starting from beginning but i will do tests to confirm.

Do you think this would be a good way to setup animations? You think this could be hard to implement?

We can even discuss another way to setup animations if you think it is a good idea to change this.

1 Like

Okay, I will be working on the modified play and blend functions, probably by tomorrow, then you may use the new methods and try out the animation cases you need. Then, we iteratively improve the animation class.

3 Likes

Alright, that is lovely, thank you!

I am already trying to create the State Machine (i think will be possible to just add the conditions related to animations later).

It is too much information (the entire state machine) and i am going to an area of Haxe i never have been before, but i think i understand the state machine 90%. What i still don’t understand is what is the transitions about. I see some state machines in the Haxe foundation site as reference (https://lib.haxe.org/t/statemachine/). The source code of them looks very similar, both have the transition thing but i still don’t get the point of it yet. Anyway i will just go step by step.

Currently i am trying to find out how to “manage” the override function method, but the Haxe reference does not have what i want to know (https://haxe.org/manual/class-field-overriding.html).

What i have is a class StateMachine with the functions onEnter, onUpdate, onExit. Then each state overrides these functions but there is no filter i can use to decide when these scripts should be called (i think adding/removing the trait is not a good idea). Also i would like to know what exactly the super() function do, because again the Haxe reference does not have nothing about it except https://haxe.org/manual/types-class-inheritance.html.

I will keep trying and searching but if anyone has some cool documentation or example, i would love to see :slight_smile:

1 Like

What do you need to know about overriding?

Also i would like to know what exactly the super()

super lets you run the constructor of the parent class your sub-class is extending. In your case, the State sub-class can call the constructor of StateMachine if you need to do so for initialization or other behavior. super must be called with the same number of parameters that the constructor requires.

1 Like

I mean how can i control the execution of each class, see the example: https://drive.google.com/file/d/1kq662AZOQOaiC9enmWI6gYc7h6zGXT3j/view?usp=sharing
In the example i have a trait that moves the cube, and another one that rotates the cube, so i want to decide which of this scripts is executed.

I think i should create another trait in the object and then do something with the class constructor, so this main trait would execute the function of the trait relative to the current state. For this i need to know how the class constructor works. I can’t find any explanation with example of this. :frowning:

Do you know what is the part of Armory source code that executes the trait attached to the object? I think it is easier for me to abstract by looking into how Armory do it.

1 Like