# Animation Timing

This topic is 3830 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I am looking for some way to: 1) Rotate from one orientation to another orientation in X seconds. 2) Rotate a given angle around the axis in object space in X seconds. 3) Move along an object axis at a speed of x units per second. 4) Move along a world axis at a speed of x units per second. I have a slerp function that takes 2 quaternions and a t, but don't really understand how to use it to achieve these two things. I also made a timer class based on QueryPerformanceCounter that gives me elapsed time as a double in seconds with the fractional part in tact. I eventually want to be able to script translation and rotations... I am little lost how to combine the timer and my transform methods.

##### Share on other sites
Motion is: position + direction*time.
===========================
So, given a world direction (axis if you prefer):

normalize(worldDirection); // ensures it's length is 1
// equation A
newPosition = originalPosition + worldDirection*float(elapsedTime);
===========================

Assuming directions are D3DXVECTOR3 objects -

Given an object axis (a local direction):

D3DXMATRIX objectMatrix; // set this matrix to your object's orientation in the world
normalize(objectDirection); // ensure it's length is 1
D3DXMatrixTransformNormal(&worldDirection,&objectDirection,&objectMatrix);
// use worldDirection to move per equation A above

===========================

To use quaternion slerping, you need two orientations at two different times.

If q1 is the orientation at time t1 and q2 is the orientation at time t2, then, at a time t ( t1 <= t <= t2 ):

q = slerp( q1, q2, (t-t1)/(t2-t1)); // q is the orientation at time t

There are various D3DXQuaternion functions for generating rotations about an axis. Generate q1 for how the object is oriented now (t1), and q2 for how you want the object to be oriented at time t2.

##### Share on other sites
Thanks Buckeye. I will give it a shot.

##### Share on other sites
Whoops. I forgot to put the speed in.
newPosition = originalPosition + worldDirection*speed*float(elapsedTime);

where speed is in "units/secs"

##### Share on other sites
I tryed carrying the same concept that buckeye game for slerp over to some concept code for translation.

After it works I am thinking of extending my simple3D object class to hold key frames with position, orientation, and times.

However, I cannot get interpolated translation to work correctly.
My cube starts at the top of the screen and then after 10 seconds, jumps to the middle, then smoothly moves downward to the desired position.

I cannot figure out why it is jumping!

Can anyone help?

void TestApp::PreRender(){      // Key frame positions   static D3DXVECTOR3 positions[] =    {      m_object3D->GetPosition(),      D3DXVECTOR3(  0.0f, -5.0f,  0.0f),   };   // Key frame times   static double times[] =    {      10.0,      30.0,   };   // Current key frame   static unsigned keyFrame = 0;   // Animation timer   //   // Note - Starts when it is constructed   static common_lib_cpisz::Timer timer_animation;   // Perform animations   double      ratio    = (timer_animation.GetElapsedTime() - times[keyFrame]) /                           (times[keyFrame + 1] - times[keyFrame]);   if( ratio < 0.0 )   {      // Do nothing, give things a second or two to initialize      // in case that is the problem...   }   else if( ratio < 1.0 )   {      D3DXVECTOR3 position = (positions[keyFrame + 1] - positions[keyFrame]) * ratio;      m_object3D->SetPosition(position);   }   else   {      ++keyFrame;   }}

I will also upload the entire solution (its not that huge)
to my FTP in case anyone needs to see more. Or ask and I can give more details.

Keep in same directory hierarchy as is
Open solution for EngineX
Run Development_Tests\SimpleObject3D

ftp://christopherpisz.is-a-geek.com/pub/programming/Projects/

It should not change for at least a couple days from this post time.

##### Share on other sites
I think I got it myself.
Sorry, I got lucky and came across some animation math on Google.

Here is my altered version for reference:

ratio = (current_time - start_frame_time) /         (end_frame_time - start_frame_time);if( ratio >= 0.0 && ratio <= 1.0 ){   position = (1.0 - ratio) * start_position + ratio * end_position;}

##### Share on other sites
From MSDN:

" The following illustrates how each element of a unit quaternion
relates to an axis-angle rotation where

q represents a unit quaternion (x, y, z, w),
axis is normalized,
theta is the desired CCW rotation about the axis):

q.x = sin(theta/2) * axis.x
q.y = sin(theta/2) * axis.y
q.z = sin(theta/2) * axis.z
q.w = cos(theta/2)"

I assume theta is radians?

For some reason my interpolated rotation does not spin one complete rotation around the objects's y axis. It only goes around maybe 90 degrees, but then returns to its original orientation.

//----------------------------------------------------------------------------void TestApp::PreRender(){     // Timer   //   // Note - Starts when it is constructed   static common_lib_cpisz::Timer timer_animation;   double current_time = timer_animation.GetElapsedTime();   //----------------------------------------------   // Test smooth interpolated animation   //   // Begin - second 1   // End   - second 60   //   // TODO - The ideas in this test should be incorperated into the class   //        itself or a derived class, such that the class itself supports   //        this kind of interpolated animation given postions, orientations,   //        and times.   //----------------------------------------------      // Begin this test after one second has elapsed from the first frame rendered   if( current_time > 1.0 && current_time < 60.0 )   {      // Key frame positions      static D3DXVECTOR3 positions[] =       {         m_object3D->GetPosition(),         D3DXVECTOR3(  0.0f, -5.0f,  0.0f),         D3DXVECTOR3(  0.0f,  0.0f,  0.0f),         D3DXVECTOR3( -5.0f,  0.0f,  0.0f),         D3DXVECTOR3(  5.0f,  0.0f,  0.0f),      };      static D3DXQUATERNION orientations[] =       {         // The following illustrates how each element of a unit quaternion         // relates to an axis-angle rotation where         //         // q represents a unit quaternion (x, y, z, w),         // axis is normalized,         // theta is the desired CCW rotation about the axis):         //         // q.x = sin(theta/2) * axis.x         // q.y = sin(theta/2) * axis.y         // q.z = sin(theta/2) * axis.z         // q.w = cos(theta/2)         //         // I assume theta is radians?         D3DXQUATERNION( 0.0, 0.0, 0.0, 1.0 ),         D3DXQUATERNION( 0.0, 0.0, 0.0, 1.0 ),         D3DXQUATERNION( 0.0, sin( 2.0 / 2.0 ) * 1.0, 0.0, cos( 2.0 / 2.0) ),         D3DXQUATERNION( 0.0, 0.0, 0.0, 1.0 ),         D3DXQUATERNION( 0.0, 0.0, 0.0, 1.0 ),      };      // Key frame times      static double times[] =       {         10.0,         30.0,         40.0,         50.0,         60.0      };      // Current key frame      static unsigned keyFrame = 0;      // Perform animations      double      ratio    = (timer_animation.GetElapsedTime() - times[keyFrame]) /                              (times[keyFrame + 1] - times[keyFrame]);      if( ratio < 0.0 )      {         // Do nothing      }      else if( ratio <= 1.0 )      {         // Interpolate rotation         D3DXQUATERNION orientation;          D3DXQuaternionSlerp(&orientation, orientations + keyFrame, orientations + keyFrame + 1, ratio);         m_object3D->SetOrientation(orientation);         // Interpolate position         D3DXVECTOR3 position = (1.0 - ratio) * positions[keyFrame] + ratio * positions[keyFrame + 1];         m_object3D->SetPosition(position);      }      else      {         // Next key frame         ++keyFrame;      }   }}

If I change
D3DXQUATERNION( 0.0, sin( 2.0 / 2.0 ) * 1.0, 0.0, cos( 2.0 / 2.0) ),
to
D3DXQUATERNION( 0.0, sin( 2.0 * D3DX_PI / 2.0 ) * 1.0, 0.0, cos( 2.0 * D3DX_PI / 2.0) ),

It ceases to rotate at all.

##### Share on other sites
Oh, I think I get it.

I have to provide keyframes such that the rotation between key frames is less than 180 degrees? otherwise, it is impossible to know which way to rotate; CCW or CW?

2* PI radians is the same as 0, and that is why I was't seeing any rotation.

I was hoping for a way to simply tell my object "spin completely around 5 times in 10 seconds"

Any suggestions on doing something like that?
Or am I stuck providing extra key frames?

##### Share on other sites
Should
D3DXQuaternionSlerp(&orientation, orientations + keyFrame, orientations + keyFrame + 1, ratio);

be
D3DXQuaternionSlerp(&orientation, &orientations[keyFrame], &orientations[keyFrame + 1], ratio);
?

EDIT:
Quote:
 orientations + keyFrame is pointer arithmethic
Doh! You're correct.[oh]

[Edited by - Buckeye on July 26, 2008 3:55:40 PM]

##### Share on other sites
They are equivelent

orientations + keyFrame

is pointer arithmethic. orientations is a pointer to the first element of the array, because it is the array name. You can add and subtract pointers.

&(orientations[keyFrame])

is the address of the fetched element of the array

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

(You must login to your GameDev.net account.)

• 17
• 14
• 10
• 9
• 11
• ### Forum Statistics

• Total Topics
634094
• Total Posts
3015498
×

## Important Information

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!