Bone Animation (2)

Started by
7 comments, last by Calin 3 years, 12 months ago

I wrote a basic routine to rotate bones based on a predefined frames. It works but not exactly as I expect, as things are now the time to reach the next frame depends on the difference of rotation magnitude between the frames. i.e reaching from frame with rotation 0.2 to frame with rotation 0.8 will take twice as long as reaching from 0.2 to 0.4. I`m looking for a transition between keys that always takes the same amount of time. Bellow is my code

VOID Animate( float time, BoneKeys* Bone, int Base, AnimSetup * Setup, int BoneIndex)
{
  /* StringCchPrintfA(message, 1024, " Rot1 %f BoneCh 0 keys base +1 %f ", Bone[0].Rot1, Bone[0].Keys[Base +1].x);
   MessageBoxA(NULL, message, "Textures.exe", MB_OK);*/
   if (Setup[BoneIndex].firstrun)
   {
       Bone[BoneIndex].Rot1 = Bone[BoneIndex].Keys[0].x;
       Setup[BoneIndex].firstrun = false;
   }
   
       if ((Bone[BoneIndex].Rot1*10  > Bone[BoneIndex].Keys[Setup[BoneIndex].Base +1].x *10 - 1) &amp;amp;amp;&amp;amp;amp; (Bone[BoneIndex].Rot1*10 < Bone[BoneIndex].Keys[Setup[BoneIndex].Base +1].x*10 + 1))
       {
           if(Setup[BoneIndex].Base +1 < 10)
               Setup[BoneIndex].Base = Setup[BoneIndex].Base + 1;
       }
       else
       {
           

           if(Bone[BoneIndex].Keys[Setup[BoneIndex].Base].x < Bone[BoneIndex].Keys[Setup[BoneIndex].Base +1].x)
           {
               Bone[BoneIndex].Rot1 = Bone[BoneIndex].Rot1 + time;
               
           }
           if (Bone[BoneIndex].Keys[Setup[BoneIndex].Base].x > Bone[BoneIndex].Keys[Setup[BoneIndex].Base + 1].x)
           {
               Bone[BoneIndex].Rot1 = Bone[BoneIndex].Rot1 - time;
               
           }
       }


}

    if (firstrun)
       {
           BKeys[0].Keys[0].x = -1.4; //right arm
           BKeys[0].Keys[1].x = -0.8;
           BKeys[0].Keys[2].x = -0.4;
           BKeys[0].Keys[3].x = 0.0;
           BKeys[0].Rot1 = 0;
           BKeys[1].Keys[0].x = 0.8; //right shoulder
           BKeys[1].Keys[1].x = 0.8;
           BKeys[1].Keys[2].x = -0.2;
           BKeys[1].Keys[3].x = -0.5;
           BKeys[1].Keys[4].x = -0.7;
           BKeys[1].Rot1 = 0;
           firstrun = false;

           for (int i = 0; i < 8; i++)
           {
               InitSetup(&amp;amp;ASetup[0], i);

           }
           
       }
       
       Animate(nms,&amp;amp;BKeys[0],2,&amp;amp;ASetup[0],0);
       Animate(nms, &amp;amp;BKeys[0], 2, &amp;amp;ASetup[0], 1);

My project`s facebook page is “DreamLand Page”

Advertisement

Bone[BoneIndex].Rot1 = Bone[BoneIndex].Rot1 + time;

This means you change the current state (Rot1), but this is how simulation works, not animation.
Imagine some small error from floating point inaccuracy drifts in - there would be no way to remove this error.

Animation in it's simple form means to interpolate between given keyframes, so the result does not depend on actual stat but only on the keyframes, e.g.:

bone.rot = keyframe0.rot * u + keyframe1.rot * (1-u);

This way bone.rot becomes a linear combination of the two keyframes no matter what value it had before. If u is between 0 and 1 it is a interploation, if it's outside it becomes an extrapolation which we do not want here.

So how do we get u from time, and how do we get the two keyrames?

Usually we have keyframes with time and value (e.g. rotation or translation):

const int numKF = 3;
keyframes kf[3];
kf[0].time = 0; kf[0].rot = 1;
kf[1].time = 2; kf[1].rot = 5;
kf[2].time = 3; kf[2].rot = 9;

We could then search for the first frame from given time by looping through the sequence, and interpolate with the frame after that:

float time = 2.5f;
int left;
for (left=0; left<numKF-1; left++)
	if (kf[left].time >= time) break;
int right = left+1;
float u = (time - kf[left].time) / (kf[right].time - kf[left].time);
float currentRotation = kf[left].rot * (1-u) + kf[right].rot * u;

From this you get linear interpolation, so the animated values look like line segments (time being the horizontal axis here):

That's not great but good for a start.

To get nice curves (green) you could later extend this to use for example a catmull com spline which uses 4 keyframes not just two.

But for real animation the behavior of curves is modeled by artists, so the keyframes have additional information about how they behave.

To get rid of the searching for the actual keyframe we can resample the animation at uniform intervals to make new keyframes e.g. each 0.1 seconds. If we do this densely enough, even linear interpolation becomes good enough, but at the cost of more memory. Usually animation software has options to export data this way.

Ok, so the animation is not continuous there is no translation between keyframes you just jump from one key to another. This is so lame I`m almost disappointed, one more reason to switch to physics based animation asap. Thanks JoeJ for explaining this.

VOID Animate( BoneKeys* Bone, int Base, int BoneIndex)
{
   
       Bone[BoneIndex].Rot1 = Bone[BoneIndex].Keys[Base].x;
       //Setup[BoneIndex].firstrun = false;
   
}

Added = difference + Added;
       if (Added > dbFreq / 4)
       {
           switchanim = true;
       }
       if (switchanim)
       {
           switchanim = false;
           Added = 0;
           animationstage++;
           if (animationstage == 10)
           {
               animationstage = 0;
           }
       }
       if (firstrun)
       {
           BKeys[0].Keys[0].x = 0.25; //right arm
           BKeys[0].Keys[1].x = 0.50;
           BKeys[0].Keys[2].x = 0.75;
           BKeys[0].Keys[3].x = 0.;
           BKeys[0].Keys[4].x = 0.0;
           BKeys[0].Keys[5].x = 0.0;
           BKeys[0].Keys[6].x = 0.0;
           BKeys[0].Keys[7].x = 0.0;
           BKeys[0].Keys[8].x = 0.0;
           BKeys[0].Keys[9].x = 0.0;
           BKeys[0].Rot1 = 0;
           BKeys[1].Keys[0].x = 0.0; //right shoulder
           BKeys[1].Keys[1].x = 0.0;
           BKeys[1].Keys[2].x = 0.0;
           BKeys[1].Keys[3].x = 0.0;
           BKeys[1].Keys[4].x = 0.0;
           BKeys[1].Keys[5].x = 0.8;
           BKeys[1].Keys[6].x = 0.8;
           BKeys[1].Keys[7].x = 0.8;
           BKeys[1].Keys[8].x = 0.8;
           BKeys[1].Keys[9].x = 0.8;
           BKeys[1].Rot1 = 0;
           firstrun = false;

           for (int i = 0; i < 8; i++)
           {
               InitSetup(&amp;amp;ASetup[0], i);

           }
           
       }
       
       Animate(&amp;amp;BKeys[0], animationstage,0);
       Animate( &amp;amp;BKeys[0], animationstage, 1);

My project`s facebook page is “DreamLand Page”

Calin said:
Ok, so the animation is not continuous there is no translation between keyframes you just jump from one key to another. This is so lame I`m almost disappointed, one more reason to switch to physics based animation asap. Thanks JoeJ for explaining this.

It is continuous because you interpolate between two keyframes. But this does it not make it more interesting - it's still just playing back static data.
This makes animation in general a form of decoration but not gameplay, similar to background music.
In games it's often only the position and orientation of the entire character that matters for gameplay, while walking or running animations are only there to make it look good.
This does not even change if we make animation more interesting and challenging to implement, like mixing multiple animation tracks or using IK to adapt it to environment (e.g. tweak walking animation so feet touch sloped ground or stairs correctly).

So, is it lame? Is it a necessary evil? Is it the main obstacle to make a state of the art 1st / 3rd person game as a single person or small team?

IMO it's a yes to all of them. But for a strategy game it's much less of a problem. People do no really expect perfect motion capture here, units are often robots or vehicles, we see them as small points on screen and focus more on units than single characters. We have top down view which means we do not judge realism at at all because we are not used to observe people from top down in real life. So for RTS game, you can probably get acceptable results without a need for skilled animators or motion capture.

Not sure how physics would help here to ‘replace’ animation. It's surely useful to model things like impact of explosions, or even cool gameplay like units having to roll a huge ball over the level as a team, etc.
Physics is underutilized in all games, but in RTS it's even worse. So there's surely opportunity in using it…

my homework is done so I can go ranting (rant = me writing down more than two lines)

it's still just playing back static data.

This makes animation in general a form of decoration but not gameplay, similar to background music.


the alternative has short comings as well. The main problem is that you loose control of what`s happening in the scene. Like games rely a lot on predictibility ( e-sports especialy) it`s pretty much a game of math and probability the player does. Add physics into the formula and it`s all mayhem and chaos. Like for instance disengaging a unit from a fight takes time if it`s a physics driven combat. That time is pretty much lost, the unit becomes unresponsive for that span of time. My guess is that it becomes annoying after a while. Basically you have a cinematic game. A game with very independent characters/units where you give general orders.

My project`s facebook page is “DreamLand Page”

Calin said:
(rant = me writing down more than two lines)

Whow… deserves a like just for that ; )

About loosing determinism when moving to realistic movements… yeah sure. We could argue if physics are deterministic or not, but you are right in any case. Some genres would not work well, others might evolve to become something different and new.

But hings like that happened before for too. E.g., 3D shooters allow only terrible spatial oversight of the level, if we compare this to 2D action platformers from the days before 3D.
So we lost a lot with the introduction of 3D tech.

But we found a way to compensate the loss: Retro gaming. We still get nice 2D platformers, awesome pixel art and all this. So we have not really lost anything. We only increase diversity, and this also helps to target certain market segments and increase chance of success.

JoeJ said:
deserves a like just for that

thanks

My project`s facebook page is “DreamLand Page”

This topic is closed to new replies.

Advertisement