3

現在の向き (クォータニオン) と現在の位置を使用して、カメラのビュー マトリックスを作成しています。

void Camera::updateViewMatrix()
{
    view = glm::gtx::quaternion::toMat4(orientation);

    // Include rotation (Free Look Camera)
    view[3][0] = -glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position);
    view[3][1] = -glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position);
    view[3][2] = -glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position);

    // Ignore rotation (FPS Camera)
    //view[3][0] = -position.x;
    //view[3][1] = -position.y;
    //view[3][2] = -position.z;

    view[3][3] = 1.0f;
}

クォータニオンからマトリックスへの計算が正しい答えを与えているとは思えないという点で、これには問題があります。カメラの移動は期待どおりに機能しますが、回転すると正しく動作しません。

現在のマウスの位置と画面の中心との差を利用してカメラを回転させています (フレームごとにマウスの位置をリセットします)

int xPos;
int yPos;
glfwGetMousePos(&xPos, &yPos);

int centreX = 800 / 2;
int centreY = 600 / 2;

rotate(xPos - centreX, yPos - centreY);

// Reset mouse position for next frame
glfwSetMousePos(800 / 2, 600 / 2);

回転はこのメソッドで行われます

void Camera::rotate(float yawDegrees, float pitchDegrees)
{
    // Apply rotation speed to the rotation
    yawDegrees *= lookSensitivity;
    pitchDegrees *= lookSensitivity;

    if (isLookInverted)
    {
        pitchDegrees = -pitchDegrees;
    }

    pitchAccum += pitchDegrees;

    // Stop the camera from looking any higher than 90 degrees
    if (pitchAccum > 90.0f)
    {
        //pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = 90.0f;
    }

    // Stop the camera from looking any lower than 90 degrees
    if (pitchAccum < -90.0f)
    {
        //pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = -90.0f;
    }

    yawAccum += yawDegrees;

    if (yawAccum > 360.0f)
    {
        yawAccum -= 360.0f;
    }

    if (yawAccum < -360.0f)
    {
        yawAccum += 360.0f;
    }

    float yaw = yawDegrees * DEG2RAD;
    float pitch = pitchDegrees * DEG2RAD;

    glm::quat rotation;

    // Rotate the camera about the world Y axis (if mouse has moved in any x direction)
    rotation = glm::gtx::quaternion::angleAxis(yaw, 0.0f, 1.0f, 0.0f);

    // Concatenate quaterions
    orientation = orientation * rotation;

    // Rotate the camera about the world X axis (if mouse has moved in any y direction)
    rotation = glm::gtx::quaternion::angleAxis(pitch, 1.0f, 0.0f, 0.0f);

    // Concatenate quaternions
    orientation = orientation * rotation;
}

正しい向きでクォータニオンを正しく連結していますか?

ピッチの累積にも問題があり、視界が±90度ではなく±5度に制限されます。その原因は何ですか?

編集:

範囲が[-90、90]になるように、ピッチ累積の問題を解決しました。glm は軸角度にベクトルではなく度を使用し、クォータニオン連結の乗算の順序が正しくないことが判明しました。

// Rotate the camera about the world Y axis
// N.B. 'angleAxis' method takes angle in degrees (not in radians)
rotation = glm::gtx::quaternion::angleAxis(yawDegrees, 0.0f, 1.0f, 0.0f);

// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref rotation, ref orientation)
orientation = orientation * rotation;

// Rotate the camera about the world X axis
rotation = glm::gtx::quaternion::angleAxis(pitchDegrees, 1.0f, 0.0f, 0.0f);

// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref orientation, ref rotation)
orientation = rotation * orientation;

残っている問題は、ビュー マトリックスの回転によって、描画されたオブジェクトが回転しているように見え、通常の FPS カメラのように見えないことです。

問題を説明するために、YouTube にビデオをアップロードしました。マウスを動かしてカメラの向きを変更しましたが、代わりに三角形が回転しているように見えます。

カメラの向きの問題を示す YouTube ビデオ

編集2:

void Camera::rotate(float yawDegrees, float pitchDegrees)
{
    // Apply rotation speed to the rotation
    yawDegrees *= lookSensitivity;
    pitchDegrees *= lookSensitivity;

    if (isLookInverted)
    {
        pitchDegrees = -pitchDegrees;
    }

    pitchAccum += pitchDegrees;

    // Stop the camera from looking any higher than 90 degrees
    if (pitchAccum > 90.0f)
    {
        pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = 90.0f;
    }
    // Stop the camera from looking any lower than 90 degrees
    else if (pitchAccum < -90.0f)
    {
        pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = -90.0f;
    }

    // 'pitchAccum' range is [-90, 90]
    //printf("pitchAccum %f \n", pitchAccum);

    yawAccum += yawDegrees;

    if (yawAccum > 360.0f)
    {
        yawAccum -= 360.0f;
    }
    else if (yawAccum < -360.0f)
    {
        yawAccum += 360.0f;
    }

    orientation = 
        glm::gtx::quaternion::angleAxis(pitchAccum, 1.0f, 0.0f, 0.0f) * 
        glm::gtx::quaternion::angleAxis(yawAccum, 0.0f, 1.0f, 0.0f);
}

EDIT3:

次の乗算順序により、カメラは独自の軸を中心に回転しますが、間違った方向を向くことができます。

    glm::mat4 translation;
translation = glm::translate(translation, position);

view = glm::gtx::quaternion::toMat4(orientation) * translation;

EDIT4:

以下が機能します(回転後の位置に基づいて平行移動行列を適用します)

// Rotation
view = glm::gtx::quaternion::toMat4(orientation); 

// Translation
glm::mat4 translation;
translation = glm::translate(translation, -position);

view *= translation;

ただし、各方向軸でドット積を機能させることはできません

// Rotation
view = glm::gtx::quaternion::toMat4(orientation); 

glm::vec3 p(
    glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position),
    glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position),
    glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position)
    );

// Translation
glm::mat4 translation;
translation = glm::translate(translation, -p);

view *= translation;
4

1 に答える 1

4

明確な答えを得るには、viewOpenGL に行列と頂点を実際にどのように提供しているかを示すコードが必要になると思います。ただし、この症状は、行列の順序が正しくない場合によく見られます。

いくつかの変数を考えてみましょう
。Vは、カメラの現在の向きの逆 (四元数) を表します。
Tは、カメラの位置を保持する平行移動行列を表します。これは、4 番目の列を下るカメラの位置を否定した単位行列である必要があります (列ベクトルを右乗算していると仮定します)。
Uは向きの変化の逆数を表します。
pはワールド空間の頂点を表します。
: 変換はカメラではなく頂点に適用されるため、すべての行列は逆行列ですが、最終結果は同じです。

デフォルトでは、OpenGL カメラは負の z 軸を見下ろす原点にあります。ビューが変化しない場合 ( U==I )、ワールド座標からカメラ座標への頂点の変換はp'=TVpになります。最初にカメラの向きを合わせ (ワールドを反対方向に回転させて)、次にカメラを位置に移動させます (ワールドを反対方向にシフトさせます)。

Uを置く場所がいくつかあります。UをVの右側に配置すると、一人称視点の動作が得られます。マウスを上に動かすと、現在表示されているものがカメラを中心に下向きに回転します。マウスを右に動かすと、ビューにあるものはすべてカメラを中心に左に回転します。

UをTVの間に置くと、カメラはカメラの軸ではなく、ワールドの軸に対して相対的に回転します。これは奇妙な動作です。Vがたまたまカメラを横にオフにした場合、マウスを上下に動かすと、世界が「ピッチ」または「ヨー」ではなく「ロール」のように見えます。

UをTの左に置くと、カメラはワールドの原点を中心にワールドの軸を中心に回転します。これは、カメラが原点から離れているほど、カメラがワールドを高速で飛行するようになるため、さらに奇妙になる可能性があります。ただし、回転は原点を中心に行われるため、カメラがたまたま原点を見ていると、そこにあるオブジェクトが回転しているように見えます。これは、カメラの位置を回転させるために内積をとっているため、あなたが見ているもののようなものです。

pitchAccum[-90,90] 以内に収まるようにチェックしますが、その事実を利用する部分をコメントアウトしています。これは私には奇妙に思えます。

ピッチを左に乗算し、ヨーを右に乗算する方法により、四元数があまり役に立たなくなります。彼らはあなたのオイラー角を保持しているだけです。方向の変更が他の場所から来ていない限り、単にそう言ってorientation = glm::gtx::quaternion::angleAxis(pitchAccum*DEG2RAD, 1.0f, 0.0f, 0.0f) * glm::gtx::quaternion::angleAxis(yawAccum*DEG2RAD, 0.0f, 1.0f, 0.0f);、古い方向を完全に上書きすることができます。

于 2012-08-28T16:14:21.717 に答える