2

我有一个分层骨架,其中平移和旋转在全局空间中表示。我需要将骨架转换为局部坐标并再次返回。我对翻译没有任何问题,但我似乎无法让旋转工作。

最初,我有旋转矩阵,但我可以轻松地将它们转换为欧拉或四元数,并尝试使用它们。我正在使用 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);
        }
    }

我已经有一段时间遇到这个问题了,并且也尝试过保持矩阵模式并切换到欧拉角。谁能帮我弄清楚我做错了什么?

4

1 回答 1

4

使用矩阵还是四元数都没有关系。我建议不要在这里使用欧拉角。在我看来,问题在于您在转换为局部坐标时正在反转子四元数而不是父四元数,而在转换为全局坐标时您没有传播旋转。

考虑(假设方向应用于右侧的列向量):

q_1q_2q_3是链中三个物体的全局方向。如果我们想使用相对方向r_2r_3,那么您必须将父级的旋转从其后代中取出。所以我们可以看到q_2 = q_1 * r_2q_3 = q_1 * r_2 * r_3 = q_2 * r_3

求解你的相对值,你会得到r_3 = q_2' * q_3 和同样 的r_2 = q_1' * q_2(其中q_2'是矩阵或四元数逆)。

从另一个方向从全局转换为本地,您需要记住:

q_3 = q_1 * r_2 * r_3

所有的父方向都需要向下传播到最终的后代。因此,您要么需要使用递归来获取从子节点到根节点的所有方向变化,要么需要从父节点开始,在遍历子节点时传播/累积每个链接的所有方向变化。

As an afterthought, I suppose that you also need to be sure that the root node realizes that its relativePose is equal to its absolutePose. Otherwise you'll have problems.

于 2012-12-10T20:24:03.093 回答