我有一个等级骨架,其中翻译和&轮换以全球空间表示。我需要将骨架转换为本地坐标并再次返回。我对翻译没有任何问题,但我似乎无法让轮换工作。
最初,我有旋转矩阵,但我可以轻松地将它们转换为Euler或四元数,并尝试使用每个。我正在使用Irrlicht引擎数学库。
因此,我的代码遍历每个骨骼,只要骨骼具有下一个骨骼,就应用变换。
从全球到本地:
for(; iter != absolutePose.end(); iter++)
{
if(hierarchy->find(iter->boneID) != hierarchy->end())
{
BoneID parentNodeID = hierarchy[iter->boneID];
relativePose[iter->boneID].position.X = iter->position.X - absolutePose[parentNodeId].position.X;
relativePose[iter->boneID].position.Y = iter->position.Y - absolutePose[parentNodeId].position.Y;
relativePose[iter->boneID].position.Z = iter->position.Z - absolutePose[parentNodeId].position.Z;
////Rotation Part/////////
float pq[4] ={0.0,0.0,0.0,0.0};
MatrixToQuaternion(absolutePose[parentNodeId].orientation, pq);
irr::core::quaternion quat(q[0],q[1],q[2],q[3]);
irr::core::quaternion parentquat(pq[0],pq[1],pq[2],pq[3]);
quat = quat.makeInverse();
quat = quat*parentquat;
float newQuat[4] = {quat.X, quat.Y, quat.Z, quat.W};
QuaternionToMatrix(newQuat,relativePose[iter->first].orientation);
}
else // top bone
{
relativePose[iter->boneID].position.X = iter->position.X;
relativePose[iter->boneID].position.Y = iter->position.Y;
relativePose[iter->boneID].position.Z = iter->position.Z;
relativePose[iter->boneID].orientation = iter->second.orientation;
}
}
然后从本地到全球:
for(; iter != relativePose.end(); iter++)
{
absolutePose[iter->boneID].position.position = iter->position;
auto nextParent = hierarchy->find(iter->boneID);
while(nextParent != hierarchy->end())
{
absolutePose[iter->boneID].position.X += relativePose[nextParent->boneID].position.X;
absolutePose[iter->boneID].position.Y += relativePose[nextParent->boneID].position.Y;
absolutePose[iter->boneID].position.Z += relativePose[nextParent->boneID].position.Z;
////Rotation part///
float q[4] ={0.0,0.0,0.0,0.0};
MatrixToQuaternion(relativePose[iter->boneID].orientation, q);
float pq[4] ={0.0,0.0,0.0,0.0};
MatrixToQuaternion(relativePose[nextParent->boneID].orientation, pq);
irr::core::quaternion quat(q[0],q[1],q[2],q[3]);
irr::core::quaternion parentquat(pq[0],pq[1],pq[2],pq[3]);
quat = parentquat*quat;
float newQuat[4] = {quat.X, quat.Y, quat.Z, quat.W};
QuaternionToMatrix(newQuat,absolutePose[iter->boneID].orientation);
//////
nextParent = hierarchy->find(nextParent->boneID);
}
}
我一直有这个问题已经有一段时间了,并且还尝试保持矩阵模式并切换到欧拉角度。谁能帮我弄清楚我做错了什么?
答案 0 :(得分:4)
使用矩阵或四元数无关紧要。我建议不要在这里使用欧拉角。在我看来,问题是你在转换为局部坐标时反转子四元数而不是父元素,并且在转换为全局坐标时没有传播旋转。
考虑(假设方向适用于右侧的列向量):
q_1 , q_2 , q_3 是链中三个实体的全局方向。如果我们想要使用相对方向 r_2 和 r_3 ,那么您必须从其后代中取出父级的轮换。因此,我们可以看到 q_2 = q_1 * r_2 和 q_3 = q_1 * r_2 * r_3 = q_2 * r_3 。
解决您的相对值,您得到 r_3 = q_2' * q_3 ,同样 r_2 = < strong> q_1' * q_2 (其中 q_2'是矩阵或四元数的倒数。)
从另一个方向转换为全局转换为本地,您需要记住:
q_3 = q_1 * r_2 * r_3
所有父方向都需要传播到最后的后代。因此,您需要使用递归来获取从子项到根的所有方向更改,或者您需要从父项开始,在遍历子项时向每个链接传播/累积所有方向更改。
作为事后的想法,我想您还需要确保根节点意识到其relativePose
等于其absolutePose
。否则你会遇到问题。