# 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.

## 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)
// 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 on other sites
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?

1. 1
2. 2
Rutin
17
3. 3
4. 4
5. 5

• 13
• 26
• 10
• 11
• 9
• ### Forum Statistics

• Total Topics
633735
• Total Posts
3013596
×