1

現在、カメラを前後に動かしています。

gluLookAt 呼び出しで使用されるカメラ変数の値を変更する矢印キーのルーチンがあります。

gluLookAt(camera.ex,camera.ey, camera.ez,
    camera.cx,camera.cy,camera.cz,
    camera.x,camera.y,camera.z);


// Callback routine for non-ASCII key entry.
void specialKeyInput(int key, int x, int y)
{

if (key == GLUT_KEY_UP) camera.ez -= 0.1;
if (key == GLUT_KEY_DOWN) camera.ez += 0.1;
if (key == GLUT_KEY_LEFT) camera.cx -= 0.1;
if (key == GLUT_KEY_RIGHT) camera.cx += 0.1;

glutPostRedisplay();
}

これを行うことで直面している問題は、私が向いていても (左に言って)、上キーを押しても、正しい camera.ex 値ではなく、camera.ez 値をオフセットしていることです。 . だから私の質問は、OpenGL でカメラの動きをどのように処理するのですか?私が見ている「角度」を追跡し、いくつかのトリガーを実行する必要がありますか?

4

1 に答える 1

3

カメラの向きを追跡して、カメラを正しい座標系、つまりカメラに対してローカル (モデル空間) に移動する必要があります。また、ジンバル ロックを回避するには、クォータニオンの使用を開始する必要があります。クォータニオンを使用する理由は、オイラー角を扱う場合、正しい回転順序に従うことが重要です。そうしないと、必要なものが得られません。

glm ライブラリを使用した四元数ベースの一人称カメラ クラスの簡単な例を次に示します。

class Camera
{
public:
    void move(glm::vec3 directions, glm::vec2 rotations, float frametime);
    // ... constructors etc.
private:
    glm::mat4 view_;
    glm::vec3 camera_pos_;
    glm::quat camera_orientation_;
    const float camera_speed_;
}

// move directions - (forward/backward/0, left/right/0, up/down/0). each direction could be 1, -1 or 0
// rotations - (horizontal_amount, vertical_amount)
void Camera::move(glm::vec3 directions, glm::vec2 rotations, float frametime)
{
    auto pitch = glm::quat(glm::vec3(-rotations.y, 0, 0.f));
    auto yaw = glm::quat(glm::vec3(0, -rotations.x, 0.f));

    camera_orientation_ = glm::normalize(yaw * camera_orientation_ * pitch);

    auto camera_roll_direction = camera_orientation_ * glm::vec3(0, 0, -1);
    auto camera_pitch_direction = camera_orientation_ * glm::vec3(-1, 0, 0);

    // forward/backward move - all axes could be affected
    camera_pos_ += directions[0] * camera_roll_direction * frametime * camera_speed_;
    // left and right strafe - only xz could be affected    
    camera_pos_ += directions[1] * camera_pitch_direction * frametime * camera_speed_;
    // up and down flying - only y-axis could be affected
    camera_pos_.y += directions[2] * frametime * camera_speed_;

    view_ = glm::lookAt(camera_pos_, camera_pos_ + camera_roll_direction,
                        glm::cross(camera_roll_direction, camera_pitch_direction));
}

そして、次のように使用します。

main_loop()
{
    //...
    glm::vec2 rotation;
    glm::vec3 directions;
    rotation.x = get_mouse_move_x_offset();
    rotation.y = get_mouse_move_y_offset();

    if(is_key_pressed(KEY_D)) directions.y = -1;
    if(is_key_pressed(KEY_A)) directions.y = 1;
    if(is_key_pressed(KEY_W)) directions.x = 1;
    if(is_key_pressed(KEY_S)) directions.x = -1;
    if(is_key_pressed(KEY_E)) directions.z = 1; 
    if(is_key_pressed(KEY_Q)) directions.z = -1;

    cam.move(directions, rotation, frametime); 
}

yaw * camera_orientation_ * pitchワールド空間でヨー変換を適用し、モデル空間でピッチ変換を適用する必要があるため、乗算の順序は重要です。

四元数と回転の詳細については、このチュートリアルを読むことを検討してください。

于 2013-11-02T05:08:19.600 に答える