# How to calculate the difference between 2 quaternions?

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

## Recommended Posts

I need to convert some local basis with respect to the world space
back into the world space, say the world space is y-up,
and the local space basis is oriented arbitrarily in the world space.
I want the local space to align with the world space.
And let's say it is a skeleton system. For each bone, there is an offset
matrix which is relative to the world space.
So that I need to get the difference between this canonical world space
and this arbitrarily oriented local basis together, so that they can be compared,
and I want all local space to be y-up.
I want to get the difference between the quaternion of the offset matrix of the bone
and quaternion of the world basis.
How do I go about calculating this difference?

##### Share on other sites
You want: q2 = q1 * delta_q
<=>
delta_q = inverse(q1)*q2
<=> (assumption you have only unit quaternions)
delta_q = conjugation(q1)*q2

That's it, create the conjuagation and multiply it with the other quaterion to get the difference. From the difference you can extract the angle and rotation vector if needed.

##### Share on other sites

Hello,
Just one off-topic question.
I notice that the bone offset matrices are stored in the meshcontainer data structure.
If the mesh is rigged and it is a continuous mesh, some frames may or may not have a meshcontainer.
Then I don't have access to the offset matrix. I wonder why the offset matrix should be placed in

Edited by lucky6969b

##### Share on other sites
>Then I don't have access to the offset matrix. I wonder why the offset matrix should be placed in

Skeletal animation works on bone basis, that is, the mesh must be in bone space. E.g. if you want to animate an eye with a eye bone, the eye center must be at position 0,0,0 in the space of the eye-bone. When you look at the mesh, the eyes are most likely far away from the center position, therefor the offset matrix moves the eye from its original position in the mesh (mesh/model space) to 0,0,0 (bone space).

Now you could use this to animate two different mesh with the same animation data, even if the eyes of each mesh are at different position due to each mesh having its own offset matrix for the eye. The offset matrix ensures, that the mesh parts are at the right position, so that the animation data can be used independently of the mesh.

Thought, in general different meshes will have different bone structures and animation data, but this is the basic idea why the offset matrix is part of the mesh instead of the animation data.

##### Share on other sites

In here, as the offset matrix is not attached to the frame, and as it is a continuous mesh.

Is it still possible to find its offset matrix?

struct FRAME : public D3DXFRAME
{
D3DXMATRIX matCombined;
};

struct MESHCONTAINER : public D3DXMESHCONTAINER
{
~MESHCONTAINER()
{
}
LPDIRECT3DTEXTURE9*  ppTextures;       // array of textures, entries are NULL if no texture specified

// SkinMesh info
LPD3DXMESH                pOrigMesh;
LPD3DXATTRIBUTERANGE    pAttributeTable;
DWORD                    dwNumAttributeGroups;
DWORD                    dwNumInfl;
DWORD                    dwNumBones;
LPD3DXBUFFER            pBoneCombinationBuf;
D3DXMATRIX**            ppBoneMatrixPtrs;
D3DXMATRIX*                pBoneOffsetMatrices;

// for software skinning
D3DXMATRIX*                pBoneMatrices;
DWORD                    dwNumPaletteEntries;

bool                    bUseSoftwareVP;
DWORD                    dwAttributeSW;     // used to denote the split between SW and HW if necessary for non-indexed skinning
};

void RenderMesh(const CMesh& mesh, const Shot& shot, float time, float scale) {

FRAME* frame = (FRAME*)mesh.GetFrameRoot();

stdext::hash_map<FRAME, Joint*, FrameHasher> boneMap = mesh.m_BoneMap;

D3DXMATRIX iden;
// sets to identity first, so that it has a reference frame
d3d::m_pDevice->SetTransform(D3DTS_WORLD, D3DXMatrixIdentity(&iden));

// local or world?
shot.skeleton->Evaluate(shot.motion, time, zero_vector, identity_quaternion,
&Joint::world_position);

//UpdateFrame(frame, &iden);

for (auto& b : boneMap)
{
if (b.second && b.second->parent)
{
// world rotation
const Vector& parent_position = b.second->parent->world_position;
const Vector& position = b.second->world_position;

if (position != parent_position)
{
double d, x_rot, y_rot;

const Vector& p1 = parent_position;
const Vector& p2 = position;

Vector v = p2 - p1;
v.polar(d, x_rot, y_rot);

// transform
D3DXMATRIX matFinal, matRot, RotY, RotX;

D3DXMatrixRotationY(&RotY, y_rot);
D3DXMatrixRotationX(&RotX, x_rot);

// it is world matrix for this bone, it will be copied once it is in the canconical space
matRot = RotY * RotX;

//////////////////////////////////////////////////////////
// move the source skeleton into canconial space
// hence normalize the bone

// q? = qinit RG?1 q RG

// local rotation;
D3DXQUATERNION qInit;

// global rotation inversed
D3DXQUATERNION RGInv;

// align to cananical global frame, say y-up
D3DXQUATERNION q;

// global rotation
D3DXQUATERNION RG;

FRAME* f = (FRAME*)D3DXFrameFind(frame, b.first.Name);

D3DXQuaternionRotationMatrix(&qInit, &f->TransformationMatrix);

D3DXQuaternionRotationMatrix(&RG, &f->matCombined);

D3DXQuaternionInverse(&RGInv, &RG);

// say the cananical global frame is y-up
// we get the difference Quaternion(1,0,0,0) [No Rotation]
// around Y axis

D3DXQUATERNION cancanicalQ;

D3DXVECTOR3 cancanicalV(0, 1, 0);

D3DXQuaternionRotationAxis(&cancanicalQ, &cancanicalV, 0);

// find the difference between the basis of the local frame and this quaternion

//////////////////////////////////////////////////
// move the bvh into the canconical space
MESHCONTAINER *meshcontainer = (MESHCONTAINER*)f->pMeshContainer;

const D3DXMATRIX* offsetMat = meshcontainer->pBoneOffsetMatrices;

D3DXQUATERNION offsetQuat;

D3DXQuaternionRotationMatrix(&offsetQuat, offsetMat);

// q2 = q1 * delta_q
// where q2 is canconical and q1 is the offset matrix and the delta_q is the adjustment

// delta_q = conjugation(q1)*q2

D3DXQUATERNION delta_q;

D3DXQUATERNION conjQ;

// if q2 = canconical quat and q1 = offset
//q2 = q1 * delta_q
D3DXQuaternionConjugate(&conjQ, &offsetQuat);

delta_q = conjQ * cancanicalQ;

q = qInit * RGInv * delta_q * RG;

//D3DXMATRIX matRot;
//D3DXMatrixIdentity(&matRot);

//D3DXMatrixRotationQuaternion(&matRot, &finalQuat);

// todo: normalize the bvh

D3DXMATRIX matTrans;
D3DXMATRIX matScale;
// check
D3DXMATRIX matRot2;
D3DXMatrixIdentity(&matTrans);
D3DXMatrixIdentity(&matScale);
D3DXMatrixIdentity(&matRot2);
const D3DXMATRIX& TransformationMatrix = f->TransformationMatrix;

D3DXVECTOR3 pos, scale;
D3DXQUATERNION quat;
D3DXMatrixDecompose(&scale, &quat, &pos, &TransformationMatrix);

D3DXMatrixTranslation(&matTrans, pos.x, pos.y, pos.z);
D3DXMatrixScaling(&matScale, scale.x, scale.y, scale.z);
D3DXMatrixRotationQuaternion(&matRot2, &quat);

D3DXMATRIX finalMat = matScale * matRot * matTrans;

// if this is the case, I have to scale the mesh
// otherwise, scale the bvh
f->TransformationMatrix = finalMat;
}
}

}

UpdateFrame(frame, &iden);

// render all frames
RenderFrame(frame);
}

Edited by lucky6969b

##### Share on other sites

Hello Ashaman73,

Do you know why the target mesh is still not retargeted?

Thanks

Jack

void RenderMesh(const CMesh& mesh, const Shot& shot, float time, float scale) {

FRAME* frame = (FRAME*)mesh.GetFrameRoot();

stdext::hash_map<FRAME, Joint*, FrameHasher> boneMap = mesh.m_BoneMap;

D3DXMATRIX iden;
// sets to identity first, so that it has a reference frame
d3d::m_pDevice->SetTransform(D3DTS_WORLD, D3DXMatrixIdentity(&iden));

// local or world?
shot.skeleton->Evaluate(shot.motion, time, zero_vector, identity_quaternion,
&Joint::world_position);

FRAME* f = (FRAME*)D3DXFrameFind(frame, "Body01");
MESHCONTAINER *meshcontainer = (MESHCONTAINER*)f->pMeshContainer;
const D3DXMATRIX* offsetMat = meshcontainer->pBoneOffsetMatrices;
D3DXQUATERNION offsetQuat;
D3DXQuaternionRotationMatrix(&offsetQuat, offsetMat);

D3DXQUATERNION cancanicalQ;
D3DXMATRIX cancanialM;

D3DXVECTOR3 cancanicalV(0, 1, 0);

D3DXQuaternionRotationAxis(&cancanicalQ, &cancanicalV, 0);

D3DXMatrixRotationQuaternion(&cancanialM, &cancanicalQ);

// Should I just change the offset matrix to make it y-up by applying the difference
//meshcontainer->pBoneOffsetMatrices = &cancanialM;

//////////////////////////////////////////////////////////
// move the source skeleton into canconial space
// hence normalize the bone

// Get The Scale of the character and get the scale of the bvh
float heightOfCharacter = mesh.GetHeight();
float heightOfBVH = 137.0f;

if (heightOfCharacter <= 0.0f) {
return;
}

float scaleOfCharacter = heightOfBVH / heightOfCharacter;

for (auto& b : boneMap)
{
if (b.second && b.second->parent)
{
// world rotation
const Vector& parent_position = b.second->parent->world_position;
const Vector& position = b.second->world_position;

if (position != parent_position)
{
double d, x_rot, y_rot;

const Vector& p1 = parent_position;
const Vector& p2 = position;

Vector v = p2 - p1;
v.polar(d, x_rot, y_rot);

// transform
D3DXMATRIX matRot, RotY, RotX;

D3DXMatrixRotationY(&RotY, y_rot);
D3DXMatrixRotationX(&RotX, x_rot);

// bone's world matrix according to the bvh
matRot = RotY * RotX;

// find the t-pose or a-pose of the character
FRAME* fBone = (FRAME*)D3DXFrameFind(frame, b.first.Name);

// say the cananical global frame is y-up
// we get the difference Quaternion(1,0,0,0) [No Rotation]
// around Y axis

// q? = qinit RG?1 q RG

// local rotation;
D3DXQUATERNION qInit;

// global rotation inversed
D3DXQUATERNION RGInv;

// align to cananical global frame, say y-up
//D3DXQUATERNION q;

// global rotation
D3DXQUATERNION RG;

D3DXMATRIX matRotInv;

D3DXMatrixInverse(&matRotInv, NULL, &matRot);

// mesh's local transform
D3DXQuaternionRotationMatrix(&qInit, &matRotInv);

// mesh's global transform
D3DXQuaternionRotationMatrix(&RG, &matRot);

// mesh's global transform inversed
D3DXQuaternionInverse(&RGInv, &RG);

D3DXQUATERNION conjQ;

// mesh's offset matrix (only one for time being) conjugate
D3DXQuaternionConjugate(&conjQ, &offsetQuat);

// conjugate of offset Quaternion * canconical Q == the factor to multiply for differences
D3DXQUATERNION delta_q = conjQ * cancanicalQ;

// the difference between the orientation of the local bone and the delta_q
D3DXQUATERNION q = qInit * delta_q;

// now the orientation of the local bone in y-up space (
// the offset matrix is in canconcial identity state, before affected by bvh
D3DXQUATERNION finalQ = qInit * RGInv * q * RG;

// the matrix
D3DXMatrixRotationQuaternion(&matRot, &finalQ);

// assuming the bvh is y-up

D3DXMATRIX matTrans;
D3DXMATRIX matScale;

D3DXMatrixIdentity(&matTrans);
D3DXMatrixIdentity(&matScale);

const D3DXMATRIX& TransformationMatrix = fBone->TransformationMatrix;

D3DXVECTOR3 pos, vscale;
D3DXQUATERNION quat;
D3DXMatrixDecompose(&vscale, &quat, &pos, &TransformationMatrix);

D3DXVECTOR3 posScaled = pos;

D3DXMatrixTranslation(&matTrans, posScaled.x, posScaled.y, posScaled.z);

// okay
D3DXMatrixScaling(&matScale, vscale.x, vscale.y, vscale.z);

// offset now is identity, the bone relies just on this matrix
D3DXMATRIX finalMat = matRot *  matTrans;

if (strcmp(b.first.Name,"Bip001_L_UpperArm")==0 ||
strcmp(b.first.Name, "Bip001_R_UpperArm") == 0 ||
strcmp(b.first.Name, "Bip001_L_Forearm") == 0 ||
strcmp(b.first.Name, "Bip001_R_Forearm") == 0) { // ||
/*strcmp(b.first.Name, "Bip001_Spine")== 0 ||
strcmp(b.first.Name, "Bip001_Spine1") == 0 ||
strcmp(b.first.Name, "Bip001_Spine2") == 0 ||
strcmp(b.first.Name, "Bip001_Spine3") == 0 ||
strcmp(b.first.Name, "Bip001_L_Thigh") == 0) {*/
// now the skeleton is aligned to the bvh, copy the rotation matrix over
fBone->TransformationMatrix = finalMat;
}

}

}

}

UpdateFrame(frame, &iden);

// render all frames
RenderFrame(frame);
}

Edited by lucky6969b

• ### What is your GameDev Story?

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

• 15
• 10
• 11
• 9
• 9
• ### Forum Statistics

• Total Topics
634148
• Total Posts
3015794
×