Jump to content
  • Advertisement
Sign in to follow this  
brekehan

Animation Timing

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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 this post


Link to post
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.

Download cpisz_common_lib and EngineX_2.56
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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




Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!