1

私はクォータニオンとXNAスキンモデルの例を使用しています(数週間前から......)。最近ネットで購入できるいくつかのオープンソースセンサーボードから2セットのクォータニオンを受け取りました。私はこれらのクォータニオンを受け取り、それらと一緒に手足を回転させることができるように、いくつかのコードを書くことができました。今私の問題は次のとおりです。私の例では右上腕と右下腕を使用しており、それらを別々に回転させることができます。私の最初の位置は下に描かれているもので、完璧です。

http://i.imgur.com/c7qei.png「初期位置」

これで、右腕を前方に回転させたいときに、この図の右側に示すように、最終的な位置を設定する必要があります。しかし、どういうわけか、結果は左の1つの位置になりますが、私の本当の「物理的な」腕は前を向いています。

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);
    }

この謎を解くのを手伝っていただけませんか。私は自分の問題をできるだけ明確に説明できたと思います。また、よろしくお願い申し上げます。

あなたのもの

デイブ

4

1 に答える 1

0

いくつかの参照フレームが混在しているように見えます。これが私が見ていると思うものです:

外部センサーは、世界に対する方向を報告します。一方、レンダリング コードは、上腕のリファレンス フレームで下腕を処理します。

初期の向きがq_u = [0,0,0,1]およびq_l=[0,0,0,1]であると仮定すると、腕を回転させて前方を指すと、新しい向きは両方とも[0,. 707,0,.707] 、またはそのようなものは、両方の腕のセグメントが世界に対してπ/2 の回転を経験したためです。

腕をレンダリングするときは、(上腕だけでなく) 腕全体をq_uだけ回転させます。エルボーが接続されたままであることを確認したいので、これは理にかなっています。しかし、前腕をq_lだけ回転させると、肩の回転が保持されているため、前腕は本来の 2 倍回転しています。腕をまっすぐに保ち、体を回転させると、同じことが起こることがわかります。上腕は体の回転量だけ回転し、下腕は再びその分だけ回転します。

おそらく、これに対処する最も簡単な方法は、q_lからq_uを削除することです。q_kが上腕に対する下腕の回転である場合、q_k = q_u' * q_lここで、q_u'は逆四元数です (wコンポーネントを否定するだけです)。

于 2012-12-05T15:45:11.423 に答える