eugene.litvinov Posted August 11, 2011 Share Posted August 11, 2011 We have animation graph for our simple character, it based on Unigine::AnimationTree (without any changes). All works fine, but we need use events for realization next pattern: our character has set of idle animations, and any next idle animation must play only when previous was ended (first and last frames in all idle animations is identical). We try to use next events: <animation_graph> <!-- список idle-анимаций --> <combiner type="switch"> <inputs> <input name="case" type="function">Source::Ongots::getIdleState</input> </inputs> <switch> <case value="0"> <combiner type="animation"> <inputs> <input name="speed" type="const" shift="0.5">30</input> </inputs> <events> <event on="active" callback="Source::Ongots::setAnimationState"> <arg type="const">0</arg> </event> <event on="deactive" callback="Source::Ongots::setAnimationState"> <arg type="const">1</arg> </event> <event on="blend_in_finish" callback="Source::Ongots::setAnimationState"> <arg type="const">2</arg> </event> <event on="blend_out_finish" callback="Source::Ongots::setAnimationState"> <arg type="const">3</arg> </event> <event on="blend_in_start" callback="Source::Ongots::setAnimationState"> <arg type="const">4</arg> </event> <event on="blend_out_start" callback="Source::Ongots::setAnimationState"> <arg type="const">5</arg> </event> <event on="update" callback="Source::Ongots::setAnimationState"> <arg type="const">6</arg> </event> </events> <animation start="0" end="-1">source/models/creature/ongots/idle_01.sanim</animation> </combiner> </case> <case value="1"> <combiner type="animation"> <inputs> <input name="speed" type="const" shift="0.5">30</input> </inputs> <events> <event on="active" callback="Source::Ongots::setAnimationState"> <arg type="const">0</arg> </event> <event on="deactive" callback="Source::Ongots::setAnimationState"> <arg type="const">1</arg> </event> <event on="blend_in_finish" callback="Source::Ongots::setAnimationState"> <arg type="const">2</arg> </event> <event on="blend_out_finish" callback="Source::Ongots::setAnimationState"> <arg type="const">3</arg> </event> <event on="blend_in_start" callback="Source::Ongots::setAnimationState"> <arg type="const">4</arg> </event> <event on="blend_out_start" callback="Source::Ongots::setAnimationState"> <arg type="const">5</arg> </event> <event on="update" callback="Source::Ongots::setAnimationState"> <arg type="const">6</arg> </event> </events> <animation start="0" end="-1">source/models/creature/ongots/idle_02.sanim</animation> </combiner> </case> <default> <combiner type="null"/> </default> </switch> </combiner> </animation_graph> But in callback passed 2,3,6 - blend_in_finish, blend_out_finish, update - every frame. We thought, that every frame must pass only 6, and 2 and 3 must passed only when one animation ends and starts. What are we doing wrong? How it can be done? Thanks. Link to comment
Guest anet Posted August 18, 2011 Share Posted August 18, 2011 The problem is that in previous version of animation tree sources there was different behavior: blend_in_finish and blend_out_finish events were called once. But if we had very low fps this events would never be called at all. So it was decided to call this events every frame to be sure that it will be called at least once. We could not find better solution. To detect if currently played animation is finished you could try to call ObjectMeshSkinned method getFrameTime(). To access ObjectMeshSkinned used inside character call getSkin() method. Link to comment
eugene.litvinov Posted December 29, 2011 Author Share Posted December 29, 2011 To detect if currently played animation is finished you could try to call ObjectMeshSkinned method getFrameTime(). To access ObjectMeshSkinned used inside character call getSkin() method. ObjectMeshSkinned::getFrameTime float getFrameTime() Description Returns the time value passed to the last setFrame() call. Return value Time value. And what is this value? Time elapsed since last animation was changed? What is the pattern, getFrameTime() value will be reset to zero each time when animation starts to play again? And one more question: do you have any way to determine what name (or file name) of animation currently playing? Link to comment
ulf.schroeter Posted December 30, 2011 Share Posted December 30, 2011 The problem is that in previous version of animation tree sources there was different behavior: blend_in_finish and blend_out_finish events were called once. But if we had very low fps this events would never be called at all. So it was decided to call this events every frame to be sure that it will be called at least once. We could not find better solution. I am quite sure that for real-world complex character animation sequences a better solution for this problem is absolutely mandatory. The current workaround just pushes the basic problem to user code level...but just my personal gut feeling Link to comment
Guest anet Posted January 10, 2012 Share Posted January 10, 2012 I am quite sure that for real-world complex character animation sequences a better solution for this problem is absolutely mandatory. The current workaround just pushes the basic problem to user code level...but just my personal gut feeling Yes, Ulf, you are right, it is not a good solution. It is planned to update current animation system in future. Link to comment
Guest anet Posted January 10, 2012 Share Posted January 10, 2012 And what is this value? Time elapsed since last animation was changed? What is the pattern, getFrameTime() value will be reset to zero each time when animation starts to play again? And one more question: do you have any way to determine what name (or file name) of animation currently playing? You can get current animation file name by calling ObjectMeshSkinned::getAnimation(). See this link: https://developer.un...tAnimation Sorry, but my previous answer was incorrect. This pattern will not work for current animation tree version. Everything you can get inside character inherited from this high-level system is only animation file and frame time for the last combiner applied. Link to comment
eugene.litvinov Posted January 17, 2012 Author Share Posted January 17, 2012 Ok, thanks. I'm trying to implement next pattern now: when one animation is ended I wan't to play next animation (all start-end of animations is equals, so it must looks smooth), for this I want do next: get length of current animation, calculate (and accumulate time of playing current animation), when this timie >= than length time I'll change animation, I'm trying to understand what of this data I can get from ObjectMeshSkinned, so I'm playing with next data: ObjectMeshSkinned skin = getSkin(); string animationName = skin.getAnimation(); // current animation name, now it's clear float frameTime = skin.getFrameTime(); // is this delta time from last blended frame (time for one frame update)? float frameIndex = skin.getFrame(); // this is always 0, why? float frameCount = skin.getNumFrames(); // this is all frames... in seconds? Can I use next code: durationIdleAnimation += frameTime; // change random animation if (frameTime >= frameCount) { _stateIdle = 1 + Math::round(::rand() * (IDLE_ANIMATION_COUNT - 1)); } Because result looks incorrect... perhaps I use this parameters in wrong way? Link to comment
Guest anet Posted January 18, 2012 Share Posted January 18, 2012 ObjectMeshSkinned::getFrameTime() returns a previously set frame time. ObjectMeshSkinned::getFrame() does not return anything, it decomposes a frame from previously set bone transformations. Note that ObjectMeshSkinned::getFrame() is a function that returns void, that is why you always get 0. ObjectMeshSkinned::getNumFrames() returns number of frames, how many of them you have in the animation file. Note, that all of these functions work with currently set animation layer. So you also have to call ObjectMeshSkinned::setLayer() to be able to get information about other layers. Here is example of usage from tropics (playing gull animation). As you can see frame time accumulates animation time. And when animation reaches its end it becomes equal or higher than total number of frames.But if you don't reset it to zero, frame time will continue to increase. And appropriate animation frame (between 0 and number of frames) will be set. Link to comment
Guest anet Posted January 18, 2012 Share Posted January 18, 2012 Sorry I have some problems with editing posts on the forum. You can find example in tropics.cpp, lines 223-228 Link to comment
eugene.litvinov Posted January 19, 2012 Author Share Posted January 19, 2012 Sorry I have some problems with editing posts on the forum. You can find example in tropics.cpp, lines 223-228 Ok, thanks for example... But actually I don't want to use ObjectMeshSkinned::setLayer() and ObjectMeshSkinned::setFrame() directly, because I use yours animation system with complex animation graph, so I need only one thing: in my update() method (actually in method getIdleState() - I call it in animation graph combiner switch) I want determine current animation (I can do this with ObjectMeshSkinned::getAnimation()) and I want determine when animation is ended (in this case I want change variable _stateIdle that will "move" switch combiner in different case animation). I try this: if (skin.getFrameTime() >= skin.getNumFrames()) { _stateIdle += 1; skin.setFrame(0.0f); } but this pattern doesn't work correct, some time skin.getFrameTime() reset automatically, event when if (skin.getFrameTime() >= skin.getNumFrames()) this is not true, I think this is happen because animation graph changes layers automatically. So now I see only one decision - hard code all animation's decorations, and calculating playing time of current animation, then this time more than length, then I change animation, it looks bad, and I afraid we will have no 100% synchronization, any suggestions? Thanks. Link to comment
manguste Posted February 6, 2012 Share Posted February 6, 2012 You are right here, in order to have this functionality you'll have to customize Character system (or switch to setting animation via ObjectMeshSkinned directly). Sorry, it seems there's no other way. Link to comment
Recommended Posts