Jump to content
  • Advertisement
Sign in to follow this  
usbman3

Quaternions

This topic is 2892 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 have been working on a skeletal animation editor. Most of the features are finished. The user can select a bone and rotate it around a global axis (x, y or z), but this doesn't work properly.

This function doesn't preserve original rotation if the bone has a parent (i.e. the bone is not the root bone). So if angle == 0 and bone->parent != NULL, the bone gets rotated (it shouldn't rotate then).

I don't actually understand quaternions. Can you tell me, what is happening and how I should change the code to make the rotation be always relative?

[php]
// bone is the selected bone
// the_axis is the index of the selected axis (0, 1, or 2)
// angle is in radians
// quaternion format is [x,y,z,w]
static void rotate_bone( Bone *bone, float angle )
{
float axis[3] = {0.0f};
float rotation[4];
float temp_quat[4];

// get rotation quaternion
axis[the_axis] = 1.0f;
axis_to_quat( axis, angle, rotation );

Bone *temp;
Bone *bones[80] = {NULL};
int cur_bone = 0;

// collect the bones in order
// todo: add some bounds checking to prevent overflow (although the test skeleton has just 17 bones)
for( temp=bone; temp; temp=temp->parent )
bones[cur_bone++] = temp;

// convert rotation quaternion to bone space
for( cur_bone--; cur_bone>0; cur_bone-- )
{
get_inverse_quat( bones[cur_bone]->quat, temp_quat );
multiply_quat( rotation, temp_quat );
}

// apply rotation
multiply_quat( bone->quat, rotation );

// normalize
normalize_quat( bone->quat );
}
[/php]

The bone struct:

struct Bone;
typedef struct Bone
{
int index;
char name[BONE_NAME_LEN];
float quat[4];
float offset[3];
float length;
struct Bone *parent;
struct Bone *children[MAX_BONE_CHILDREN];
} Bone;


Thanks for your replies (unless its "wib wab woo"). :)

Share this post


Link to post
Share on other sites
Advertisement
I randomly messed with it and finally got it working as it should:

static void rotate_bone_2( Bone *bone, float angle )
{
float axis[3] = {0.0f};
float rotation[4];
float inverse[4];
float boneRot[4];

// get rotation quaternion
axis[the_axis] = 1.0f;
axis_to_quat( axis, angle, rotation );

// get original bone rotation
memcpy( boneRot, bone->quat, sizeof(float)*4 );

Bone *temp;
Bone *bones[80] = {NULL};
int num_bones = 0;
int n;

// collect the bones in order
for( temp=bone; temp; temp=temp->parent )
bones[num_bones++] = temp;

// convert from bone space to world space
for( n=1; n<num_bones; n++ )
{
get_inverse_quat( bones[n]->quat, inverse );
memcpy( inverse, bones[n]->quat, sizeof(float)*4 );
multiply_quat( boneRot, bones[n]->quat );
}

// apply rotation
multiply_quat( boneRot, rotation );

// convert from world space to bone space
for( n=num_bones-1; n>0; n-- )
{
get_inverse_quat( bones[n]->quat, inverse );
multiply_quat( boneRot, inverse );
}

// normalize
normalize_quat( boneRot );
memcpy( bone->quat, boneRot, sizeof(float)*4 );
}


rotate_bone() converts the rotation quaternion to bone space and then multiplies the original rotation with it.
rotate_bone_2() converts the original rotation to world space, multiplies by rotation quaternion, and converts back to bone space.

But why only rotate_bone_2() works? Aren't they doing the same thing?

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.

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!