Hello everybody! I have a problem about animator as title represented.
Actually, I achieved a blend effect of several animations which could be played at every specific timing. And I placed it in a animator’s state so I could play it simply by setting trigger. In order to calculate proper timing every time, the length of this state is needed. Every time I need to play it, the parameters differs but I know them before the timing. However, according to the official doc, the length of such a state can vary because of the contained blend tree and the parameters deciding the blend effect. So the length of a state is also different every time and I can only acquire it at Runtime.
I know if I can get the length through AnimatorStateInfo.length. But there are only two method can return a AnimatorStateInfo object, which is GetCurrentAnimatorStateInfo() and GetNextAnimatorStateInfo(). Both are not I need because I want to know the length before I set the trigger.
So there are my two questions:
Does anyone know the algorithm that Unity blend several animations through Blend Tree? Can I calculate the length of blend one by myself?
Why Unity did not offer a method like “GetAnimatorStateInfoByName”? Or does there exist a way to get AnimatorStateInfo object before enter state?
The user manual for my Animancer plugin has a table listing the interpolation algorithm used by each type of blend tree, but that’s only for the blend weights. I haven’t reverse engineered the speed/duration modifications Unity does and I’d be quite surprised if anyone else has. You might be able to get a good result by using one of my Animation Mixers and controlling the speed of each animation yourself instead of trying to figure out what Unity calculates. Animancer Lite would let you freely try it out in the editor so you can see how well it works before you decide if you want to buy it or not.
Because they focussed on making a user friendly editor UI and ended up with an inflexible monstrosity on the programming side. You can get access to some additional information in the editor by casting the RuntimeAnimatorController to a UnityEditor.AnimatorController and then serializing whatever you need separately, but I don’t think that would help you in this case.
I have viewed the manual page of Animancer Lite and there is a paragraph which caught my attention.
By being defined in the Unity Editor, Blend Trees are able to analyse their animations so that their walk cycles can be synchronised (right foot touch down and lift up at the same time, etc.), which is especially important for animations of different lengths. Unfortunately that analysis is not possible at runtime (and would be quite expensive to performance even if it was) so Animancer is unable to do the same thing in AnimationMixers.
Maybe it is the reason why both Unity and Animancer can not offer that analysis.
Thank u for reply! Well I think I should find a workaround.
That would cause it to update twice as fast for that frame since it won’t cancel the regular animation update. Even if you pass in 0, you’d still be doubling the performance cost of that object’s animation for that frame (more than that because regular animation updates are multi-threaded and manual ones aren’t).
It also fails to meet OP’s stated goals: “I want to know the length before I set the trigger.”
I’m not sure how you think you can just “get the required info and come back” because that’s not a thing Animator Controllers can do. You could grab the current state hash and time, evaluate, grab the info, then Play the current state hash, but that would leave you one frame behind where it would have been naturally and wouldn’t work properly if it was in the middle of a transition when you did that.
OP is setting a trigger so obviously he knows the name of the state that will play next. One can simply Play that state and update by a frame. The time it takes to update an animator by one frame is hardly anything at all. As to “getting back to where the animator state was” just replay the current animation by animator.Play(0, 0, 0); not leaving any frames behind, or if it was in the middle of a state, pass in the normalized time in the third parameter animator.Play(0, layerIndex, myNormalizedTime);
What’s the connection between that statement and the topic being discussed?
OP: “I want to know the length before I set the trigger.”
You: “You obviously know the name of the state that will play next.”
???
Or maybe performance is actually important to OP, we don’t know that, so all I can do is point out that your solution is extremely inefficient.
Like I said: “wouldn’t work properly if it was in the middle of a transition when you did that.” You can put it back anywhere in a single state, but you can’t put it back in the middle of a transition.
More than doubling the performance cost of a system just to access a value which should be easily accessible for free is extremely inefficient. That’s not an assumption, it’s a fact.
Will it cause OP performance problems? No one knows. All I can say is that it’s inefficient.
CrossFade only starts a transition.
If you were 50% of the way from State A to State B, CrossFade will start a new transition from 0%.
Then there’s also the fact that you also can’t check how long the current transition is going to take or how long it has left so you wouldn’t even be able to give CrossFade the correct fade duration.
And if you rely on any Animation Events or State Machine Behaviours, your “solution” would mess with them too.
You can, by adding the elapsed time from GetNextAnimatorStateInfo() and remaining time from GetCurrentAnimatorStateInfo() you’ll get the transition time
For this, one can create an "ignoreAnimationEvents" variable that will prevent animation events from updating stuffs.
You want me to prove that evaluating animations a second time in the same frame will double the cost of evaluating animations in that frame just so that you can say “that’s not inefficient, it’s hardly anything at all”? No, I don’t think I will waste my time on that. A sensible person wouldn’t need proof of such a simple concept. Trolling attempt failed.
GetNextAnimatorStateInfo can only tell you the current animation time. If it started at 0 and speed is always 1 then it will match the transition time, otherwise it won’t.
But either way, GetCurrentAnimatorStateInfo can’t tell you the remaining transition time.
And even if you had those values, CrossFade would still put you back at the start of the transition.
Me: “GetCurrentAnimatorStateInfo can’t tell you the remaining transition time.”
You: “it can: elapsedTime = …”
Uhhh … that’s not the remaining transition time.
So what? You need the elapsed transition time and remaining transition time to return to the same transition values. “Next animation time” is not either of those values so that’s a pointless correction.
Brilliant. Why double the performance cost of the character’s animation for a frame when you could quadruple it instead. Pure genius.
Update to get into the BlendTree and get its length.
Call Play to return to the previous State A then Update.
Call CrossFade to restart the transition to State B then Update.
Then the frame’s regular animation Update.
Your idea is pretty straightforward: store some values → Update to get what OP wants → do stuff to return the animator to the stored values. I’m confident that it’s not possible with Animator Controllers because they don’t give you access to the necessary values. But if you still think it’s actually possible, you could just write the code instead of posting half-baked snippets that don’t actually support your claim.
Remaining transition time is transitionDuration = totalTimeFromCurrent - (elapsedTimeFromCurrent - elapsedTimeFromNext). yeah maybe I explained it bad before but works.
Your confidence is frightening. You think I didnt try it, yet posting answers? Animator does provide you the values though for “that slight performance cost”. i explained the procedure, the code will vary based on purpose so no point in asking for code.
Edit: had a mistake putting “1” instead of “totalTime”
Oh look, another half-baked snippet which is missing key information and therefore fails to properly support your claim.
What’s elapsedTimeFromNext? Are you pretending that the time left in the current animation is the same as the time left in the transition? That would be true for an Exit Time transition only if it was set to end at the exact same time as the animation, but would be completely wrong for any other kind of transition (such as one started by CrossFade or any parameter based transition). If you would just post your code, I wouldn’t have to keep asking how you’re getting these values.
Yes, I think you didn’t try it and every time you comment without posting more than one line of code in one go reinforces the idea that you haven’t tried it.
It seems like a pretty simple situation to me. The character is some unknown percentage of the way into a transition from State A to State B and you need to get the length of a Blend Tree in State C without ruining the A->B transition. It’s really not that complicated so the code shouldn’t be that complicated either.
As expected, the way you’re calculating the fade duration makes no sense whatsoever.
You’re taking the number of seconds that have passed in the current animation and next animation and pretending that those values have some connection to the amount of time left in the transition, but they simply have nothing to do with each other.
For example:
The setup:
Both states have length 1.
State A is at time 0.2.
Start fading to State B over 0.3 seconds.
Wait 0.15 seconds.
State A Time = 0.35, State B Time = 0.15
Currently 50% of the way through a 0.3 second transition.
Now we run your code:
State A Time = 0.35 → elapsedTimeInCurrentState = 0.35
State B Time = 0.15 → elapsedTimeInNextState = 0.15
Now the character is 0% of the way through a 0.2 second transition.
Congratulations, the character is now in a completely different pose and will take 0.2 (Edit: actually 0.8, as per my next comment) seconds to finish a transition that was only supposed to last for 0.15 more seconds.
Actually, I forgot the 1 - part in the CrossFade call, so your new transition will actually take 0.8 seconds instead of the original 0.3 total or 0.15 remaining.
Yeah that example was assuming the end of transition is at the end of animation. Just noticed you said this before. Anyways, if the transition ends in the middle of first animation state, its still possible to reach the last state
Now you’re probably gonna say its not possible to get to the required state if there is an offset for the next animation state. In that case we’d have to store the offset as soon as the transition starts by using animator. IsInTransition(0)