多骨旋转之谜

时间:2012-12-04 16:21:28

标签: xna rotation quaternions 3d-modelling

我正在使用四元数和XNA蒙皮模型示例(现在几周......)。我从一些开源传感器板上收到了两套四元数,这些天你可以在网上购买。我能够编写一些代码,以便我收到这些四元数,并且我能够用它们旋转四肢。现在我的问题如下。我在我的例子中使用右上臂和右下臂,我可以单独旋转它们。我的初始位置是下面描述的那个,这是完美的。

http://i.imgur.com/c7qei.png“初始位置”

现在,当我想向右旋转我的右臂时,我应该拥有我的最终位置,如下图所示。但不知何故,结果是左边的一个位置,但是我真正的“物理”手臂指向前方。

http://i.imgur.com/tXCp6.png“理想的最终位置(右),真正的错误位置(左)”

有些下臂如何不能补偿上臂的旋转。我相信我错过了一小步。在下面我已经把我正在使用的代码的关键部分

    protected override void Update(GameTime gameTime)
    {
        HandleInput();

        UpdateCamera(gameTime);

        // Read gamepad inputs.
        float initposition = currentGamePadState.ThumbSticks.Right.X;
        float armRotation = Math.Max(currentGamePadState.ThumbSticks.Right.Y, 0);

        // these quaternions are received from bluetooth
        Upper.Z = Fq1;
        Upper.Y = -Fq2;
        Upper.X = -Fq3; // set 1 quaternions
        Upper.W = Fq4;
        //***************************

        forearm.Z = Uq1;
        forearm.Y = -Uq2;
        forearm.X = -Uq3;
        forearm.W = Uq4; // set 2 quaternions





        // set initial position
        if (initialpos == true)
        {
            initposition = 0.9f;
            R_forTransform = Matrix.CreateRotationY(initposition);

            R_forarminderinit = skinningData.BoneIndices["R_UpperArm"];
            L_forTransform = Matrix.CreateRotationY(-initposition);
            L_forTransform = Matrix.CreateRotationX(-initposition);
            L_forTransform = Matrix.CreateRotationZ(-initposition);
            L_forarminderinit = skinningData.BoneIndices["L_UpperArm"];

         }


        // Create rotation matrices for the upper and lower arm bones.

        Matrix upperarmTransform = Matrix.CreateFromQuaternion(Upper);
        Matrix forearmTransform = Matrix.CreateFromQuaternion(forearm);



        animationPlayer.GetBoneTransforms().CopyTo(boneTransforms, 0);
        if (initialpos == true)
        {
            boneTransforms[R_forarminderinit] = R_forTransform * boneTransforms[R_forarminderinit];
            boneTransforms[L_forarminderinit] = L_forTransform * boneTransforms[L_forarminderinit];
        }

        int forearmindex = skinningData.BoneIndices["R_Forearm"];
        int upperarmindex = skinningData.BoneIndices["R_UpperArm"];
        boneTransforms[upperarmindex] = upperarmTransform * boneTransforms[upperarmindex];
        boneTransforms[forearmindex] = (forearmTransform) * boneTransforms[forearmindex];
        animationPlayer.UpdateWorldTransforms(Matrix.Identity, boneTransforms);
        animationPlayer.UpdateSkinTransforms();
        UpdateBoundingSpheres();
        base.Update(gameTime);
    }

我想问你是否可以帮助我解开这个谜团。我希望我在描述我的问题时尽可能清楚。此外,我想提前感谢您的努力。

此致

戴夫

1 个答案:

答案 0 :(得分:0)

在我看来,你有一些混合参考框架。这就是我认为我所看到的:

您的外部传感器报告其相对于世界的方向。另一方面,渲染代码处理上臂参考系中的下臂。

如果我们假设初始方向为 q_u = [0,0,0,1] q_l = [0,0,0,1] ,则你旋转你的手指向前,新的方向都是 [0,.707,0,.707] ,或类似的东西,因为两个手臂段经历了π/的旋转2 相对于世界

渲染手臂时,通过 q_u 旋转整个手臂(不仅仅是上臂)。这是有道理的,因为你想确保肘部保持连接。但是你将下臂旋转 q_l 并且它已经旋转了两倍,因为它保持了肩膀的旋转。如果你的手臂伸直,但转动你的身体,你会看到同样的事情发生:上臂会旋转身体旋转量,下臂会旋转那么多。

处理此问题的最简单方法可能是从 q_l 中删除 q_u 。如果 q_k 是下臂相对向上臂的旋转,那么 q_k = q_u' * < strong> q_l 其中 q_u'是反四元数(只是否定w组件)。