0

カメラにクォータニオンを実装する際に問題が発生しました。OpenGLで3Dスペースシューターを作成していますが、ジンバルロックを回避する必要があります。1つの軸だけで回転させると問題ありませんが、ピッチとヨーの両方を適用すると、奇妙な動作になります。私の回転角は私のマウスの入力を使用しています。

ここで、ViewMatrixを計算し、フレームごとに更新します

Matrix4x4 camera::GetViewMat()
{
    m_rotation.AddX((oInput.MousePosition.GetY() - oInput.PrevMousePosition.GetY()) * m_sensitivity * dt);
    m_rotation.AddY((oInput.MousePosition.GetX() - oInput.PrevMousePosition.GetX()) * -m_sensitivity * dt);

    Matrix4x4 oTranslateOrigin, oRotate, oView;
    oView.SetIdentity();

    //constructor creates a quaternion from an AxisAngle, the constructor will be shown below
    Quaternions pitch = Quaternions(m_rotation.GetX() * Utility::DegToRad(), Vector3(1, 0, 0));
    Quaternions yaw = Quaternions(m_rotation.GetY() * Utility::DegToRad(), Vector3(0, 1, 0));

    //update orientation with the new quaternion times its current orientation
    ori = ori * yaw * pitch;

    //convert quaternion to matrix, also shown below
    oRotate = ori.ToMatrix();
    oTranslateOrigin.BuildTranslate(-m_camPosition.GetX(), -m_camPosition.GetY(), -m_camPosition.GetZ());

    oView = oRotate * oTranslateOrigin;

    return oView;
}

ProjectionMatrixを初期化します

Matrix4x4 camera::GetProjMat(float fFieldOfViewY, float fAspectRatio, float fNearZ, float fFarZ)
{
    // Transposed version of D3DXMatrixPerspectiveFovRH
    float fYScale = 1 / tanf( fFieldOfViewY / 2.0f );
    float fXScale = fYScale / fAspectRatio;
    memset( &m_projMat, 0, sizeof( Matrix4x4 ) );
    m_projMat.Set(0, 0, fXScale);
    m_projMat.Set(1, 1, fYScale);
    m_projMat.Set(2, 2, fFarZ / ( fNearZ - fFarZ ));
    m_projMat.Set(2, 3, ( fNearZ * fFarZ ) / ( fNearZ - fFarZ ));
    m_projMat.Set(3, 2, -1.0f);
    return m_projMat;
   }

これは、AxisAngleのクォータニオンを作成するコンストラクターの1つです。

Quaternions::Quaternions(float angle, Vector3& axis)
{
    FromAxisAngle(angle, axis);
}

void Quaternions::FromAxisAngle(float angle, Vector3& axis)
{
    float halfAngle = angle * ((float)PI/360.0f);
    float sin = sinf(halfAngle);

    this->w = cosf(halfAngle);
    this->x = axis.GetX() * sin;
    this->y = axis.GetY() * sin;
    this->z = axis.GetZ() * sin;
}

Matrix4x4 Quaternions::ToMatrix()
{
    Normalize();
    Matrix4x4 mat;
    mat.SetIdentity();

    mat.Set(0, 0, 1.0f - 2*(this->y * this->y) - 2*(this->z * this->z));
    mat.Set(0, 1, 2*(this->x*this->y) - 2*(this->w*this->z));
    mat.Set(0, 2, 2*(this->x * this->z) + 2*(this->w * this->y));

    mat.Set(1, 0, 2*(this->x * this->y) + 2*(this->w * this->z));
    mat.Set(1, 1, 1.0f - 2*(this->x * this->x) - 2*(this->z * this->z));
    mat.Set(1, 2, 2*(this->y * this->z) - 2*(this->w * this->x));

    mat.Set(2, 0, 2*(this->x * this->z) - 2*(this->w * this->y));
    mat.Set(2, 1, 2*(this->y * this->z) + 2*(this->w * this->x));
    mat.Set(2, 2, 1.0f - 2*(this->x * this->x) - 2*(this->y * this->y));

    return mat;
}

それが私がしていることです。

皆さんは私を正しい方向に導いてくれますか?

4

2 に答える 2

0

この行のためですか:

ori = ori * yaw * pitch;

順序が間違っていますか?

openGL関数を使用すると、いつでもカメラマトリックスを回転させることができます。スタックにキャマーマトリックスがあることを確認してください。

glRotate(angle, 1, 0, 0);
glRotate(angle, 0, 1, 0);

この関数でポイントを見ることができます:

void gluLookAt( GLdouble eyeX , GLdouble eyeY , GLdouble eyeZ , 
                GLdouble centerX , GLdouble centerY , GLdouble centerZ , 
                GLdouble upX , GLdouble upY , GLdouble upZ );

目の位置、ターゲット(中央)の位置、およびカメラのアップベクトルが必要な場所。

于 2012-08-18T04:45:34.553 に答える
0

これは、クォータニオンによるジンブル ロックを回避するために実行したいことです。さらに、OpenGL固有のコードをいくつか含めて、正しい方向に導くことを願っています. まず、キーをローテーションにマップします。

W - Pitch up(x rot)
S - Pitch down(x rot)
A - Yaw left(y rot)
D - Yaw Right(y rot)
Q - Roll left(z rot)
E - Roll right(z rot)

あなたが望むのは、これらが押されたときに正しい回転を呼び出すことだけです. たとえば、ユーザーが W を押すと、x を中心に 1 度回転するクォータニオンを作成するだけで済みます。クォータニオン クラスを使用してそれを行います。

a = EulerToQuat(angle,0,0);
cameraOri = cameraOri * a;

明らかに、他のコントロールについても同じことを行います! 最後に行う必要があるのは、OpenGL の回転コマンドを使用して、世界を正しく回転させることです。クォータニオンを角度と軸に変換するのが読みやすくて良い方法です。

m_frustumCamera->getQuat().GetAxisAngle(axis,angle);
angle = (float)(angle * radToDeg);  
glRotatef(angle,axis.x,axis.y,axis.z);  
glTranslatef(-1*m_frustumCamera->getPos().x,-1*m_frustumCamera->getPos().y,-1*m_frustumCamera->getPos().z);

機能するクォータニオン クラスがない場合は、http: //www.wolframalpha.com/をお勧めします。 これにより、すべての関数が正しい応答を返すようになります。

于 2012-08-18T11:02:02.990 に答える