12

カメラのクォータニオンしかない場合、カメラのピッチを効率的に制限するにはどうすればよいですか? オイラー角に変換してからクォータニオンに戻す必要がありますか、それとも他の方法はありますか?

4

4 に答える 4

2

カメラにロールがない場合(一人称シューティングゲームなどの多くのゲームで一般的です)、解決策は簡単です。ロールがある場合は、追加の手順が必要です。ロールがない場合の対処方法から始め、ロールがある場合の対処方法を一般化します。

qcをカメラの回転とします。qcと同じヨーで、ただしピッチがゼロの回転をqyとします。ロールがない場合、カメラの回転はヨー回転とそれに続くピッチ回転です。

qc = qp * qy

ピッチ回転qpは、qyからqcへの回転として復元できます。

qp = qc * qy^-1

したがって、秘訣はqyを作成することです。これにより、qyを上記の方程式に代入して、qpを解くことができます。vcを、カメラのレンズを指す単位ベクトル、つまり「前方ベクトル」とします。vyを同じベクトルとしますが、水平面に投影され、正規化されます。最後に、カメラの回転qcがアイデンティティの回転である場合、v0を順方向ベクトルとします。v0をvyに回転させる回転は、ヨー回転です。角度は次のように指定できます。

yaw = asin(Norm(cross(v0, vy)))

対応するヨー回転は次のとおりです。

qy = { cos(yaw/2), up * sin(yaw/2) }

ここで、「上」は上方向の単位ベクトルであり、ヨー回転の軸とも呼ばれます。これを上記のqp=qy ^ -1 * qcに接続して、ピッチクォータニオンqpを取得します。最後に、qpから次のようにピッチ角を取得します。

pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]]))

ここで、「右」は正しい方向の単位ベクトルであり、ピッチ回転の軸とも呼ばれます。

私が言ったように、カメラにもロールがあると事態はより複雑になりますが、一般的な戦略は同じです。カメラの回転を回転コンポーネントの積として定式化し、必要なコンポーネント(この場合はピッチ)を分離します。たとえば、「ピッチ」を定義するために使用するオイラー系列が一般的なヨーピッチロールシーケンスである場合、qcを次のように定義します。

qc = qr * qp * qy

変数qxを、ピッチとロールの回転を組み合わせたものとして定義できます。

qx = qr * qp

これで、qcを次のように書くことができます。

qc = qx * qy

上記でqpを解決するために使用した手順をたどることにより、この形式でqxを解決する方法をすでに知っています。qxの定義を並べ替えると、次のようになります。

qp = qr^-1 * qx

qxを解いたばかりなので、ピッチ回転qpを解くには、ロールqrだけが必要です。以前と同じように、ベクトルを使用して構築できます。vcを再び順方向ベクトルとします。ロールは、このベクトルを中心とした回転になります。vuをカメラのアップベクトル(ワールド座標)とし、vu0をゼロロールのカメラのアップベクトルとします。グローバルアップベクトルをvcに垂直な平面に射影し、正規化することでvu0を構築できます。ロール回転qrは、vu0からvuへの回転です。この回転の軸は前方ベクトルvcです。ロール角は

roll = asin(Dot(vc, cross(vu0, vu)))

対応するクォータニオンは次のとおりです。

qr = { cos(roll/2), forward * sin(roll/2) }

ここで、「前方」はロール回転の軸です。

于 2010-08-17T23:18:54.223 に答える
1

ピッチは完全な回転の 1 つのコンポーネントにすぎないため、回転についてそのように考えたい場合は、可能であればオイラー角を使用して、ピッチを個別に保存することをお勧めします。

動きを制限する必要があるときにオイラー角に変換して元に戻すだけでは、うまく機能しない可能性があります。制限を超えたかどうか、およびどの方向にあるかを確認するには、最後のフレーム (ある場合) を覚えておく必要があるためです。

私が見ているように、クォータニオンの主なポイントは、そのような制限を気にする必要がないということです。すべてが特異点なしで機能します。なぜピッチを制限したいのですか?

于 2010-08-17T08:20:34.707 に答える
0

カメラ回転クォータニオンは、次のように定義できます。

vector A = [x, y, z] 
Q.x = A.x * sin(theta/2)
Q.y = A.y * sin(theta/2)
Q.z = A.z * sin(theta/2)
Q.w = cos(theta/2)

ここで、Aは位置、シータはカメラを回転させたい角度です(ピッチを調整します)。

したがって、クォータニオンを使用できる場合は、回転角に実際の角度をプラス/マイナスしても問題がないかどうかを毎回確認することで、ピッチ角を制限できます。

制限を次のように設定すると、変換を回避できると思います

+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2)

コサインは連続関数であるため、これは機能するはずです。

実際に使用しているコードを投稿できれば、もう少しお手伝いできます。

于 2010-08-10T11:11:09.453 に答える
0

私はパーティーに少し遅れるかもしれませんが、これが私がそれを解決した方法です:

        // "Up" = local vector -> rotation * Vector3.UnitY
        // "Forward" = local vector -> rotation * Vector3.UnitZ
        // "Right" = local vector -> rotation * Vector3.UnitX

    public void Rotate(Vector3 axis, float angle)
    {
        if (LerpRotation)
        {
            RotationTarget *= Quaternion.FromAxisAngle(axis, angle);
        }
        else
        {
            Rotation *= Quaternion.FromAxisAngle(axis, angle);
        }
        //Locking the Pitch in 180°
        float a = Vector3.CalculateAngle(Vector3.UnitY, Up);
        float sign = Math.Sign(Forward.Y);
        float delta = (float)Math.PI / 2 - a;
        if(delta < 0)
            Rotation *= Quaternion.FromAxisAngle(Right, delta * sign);
    }
于 2014-07-03T20:26:13.170 に答える