2016-10-22 8 views
2

私はアークボールスタイルのカメラを実装しようとしています。 glm :: lookAtを使用して、カメラをターゲットに向けたままにして、方位/傾斜角を使って球を回転させて球の表面を回ってビューを回転させます。90°方位角で反転するアールボールカメラ

私は、方位角が90度に近づくとビューが上下逆さまになる問題に遭遇しています。

  1. ゲット投影とビューmartrices:

    はここに関連するコードです。メインループ

    void Visual::updateModelViewProjection() 
    { 
        model = glm::mat4(); 
        projection = glm::mat4(); 
        view = glm::mat4(); 
    
        projection = glm::perspective 
         (
         (float)glm::radians(camera.Zoom), 
         (float)width/height, // aspect ratio 
         0.1f, // near clipping plane 
         10000.0f // far clipping plane 
         ); 
    
        view = glm::lookAt(camera.Position, camera.Target, camera.Up); 
    } 
    
  2. マウス移動イベント、カメラの回転のための

    void Visual::cursor_position_callback(GLFWwindow* window, double xpos, double ypos) 
    { 
        if (leftMousePressed) 
        { 
         ... 
        } 
    
        if (rightMousePressed) 
        { 
         GLfloat xoffset = (xpos - cursorPrevX)/4.0; 
         GLfloat yoffset = (cursorPrevY - ypos)/4.0; 
    
         camera.inclination += yoffset; 
         camera.azimuth -= xoffset; 
         if (camera.inclination > 89.0f) 
          camera.inclination = 89.0f; 
         if (camera.inclination < 1.0f) 
          camera.inclination = 1.0f; 
    
         if (camera.azimuth > 359.0f) 
          camera.azimuth = 359.0f; 
         if (camera.azimuth < 1.0f) 
          camera.azimuth = 1.0f; 
    
         float radius = glm::distance(camera.Position, camera.Target); 
         camera.Position[0] = camera.Target[0] + radius * cos(glm::radians(camera.azimuth)) * sin(glm::radians(camera.inclination)); 
         camera.Position[1] = camera.Target[1] + radius * sin(glm::radians(camera.azimuth)) * sin(glm::radians(camera.inclination)); 
         camera.Position[2] = camera.Target[2] + radius * cos(glm::radians(camera.inclination)); 
    
         camera.updateCameraVectors(); 
        } 
    
        cursorPrevX = xpos; 
        cursorPrevY = ypos; 
    } 
    
  3. 計算カメラの向きベクトル

    void updateCameraVectors() 
    { 
        Front = glm::normalize(Target-Position); 
        Right = glm::rotate(glm::normalize(glm::cross(Front, {0.0, 1.0, 0.0})), glm::radians(90.0f), Front); 
        Up = glm::normalize(glm::cross(Front, Right)); 
    } 
    

で実行し、私はそれが関連していますかなり確信しています私のカメラの右のベクトルを計算する方法は、私はどのように補償するかを理解することはできません。

誰もこれまでに遭遇したことはありますか?助言がありますか?

+0

'Right'計算では、' Front'が '(0、1、0)'と同一直線上にある場合、 'Front'と'(0,1,0) 'の積を取ります。ゼロベクトルを正規化すると、奇妙な動作につながる可能性があります。 – mlkn

答えて

1

lookAtをカメラの回転に使用するのはよくある間違いです。貴方はするべきではない。後方/右/上方向は、のビューマトリックスの列です。あなたがすでにそれらを持っているなら、lookAtも必要ない。あなたの計算のやり直しを試みる。一方、lookAtは、最初にそれらのベクトルを見つけるのを助けません。

は、代わりに、その列からそれらのベクトルを並進及び回転の組成物として最初のビュー行列を構築し、次いで抽出:

void Visual::cursor_position_callback(GLFWwindow* window, double xpos, double ypos) 
{ 
    ... 
    if (rightMousePressed) 
    { 
     GLfloat xoffset = (xpos - cursorPrevX)/4.0; 
     GLfloat yoffset = (cursorPrevY - ypos)/4.0; 

     camera.inclination = std::clamp(camera.inclination + yoffset, -90.f, 90.f); 
     camera.azimuth = fmodf(camera.azimuth + xoffset, 360.f); 

     view = glm::mat4(); 
     view = glm::translate(view, glm::vec3(0.f, 0.f, camera.radius)); // add camera.radius to control the distance-from-target 
     view = glm::rotate(view, glm::radians(camera.inclination + 90.f), glm::vec3(1.f,0.f,0.f)); 
     view = glm::rotate(view, glm::radians(camera.azimuth), glm::vec3(0.f,0.f,1.f)); 
     view = glm::translate(view, camera.Target); 

     camera.Right = glm::column(view, 0); 
     camera.Up = glm::column(view, 1); 
     camera.Front = -glm::column(view, 2); // minus because OpenGL camera looks towards negative Z. 
     camera.Position = glm::column(view, 3); 

     view = glm::inverse(view); 
    } 
    ... 
} 

次に図及びupdateModelViewProjectionupdateCameraVectorsから方向ベクトルを算出するコードを削除します。

免責事項:このコードはテストされていません。どこかでマイナス記号を修正する必要があるかもしれませんし、操作の順序が違うかもしれませんし、規則が違うかもしれません(Zが上がっているか、Yが上がっている、など...)。

+0

ありがとうございます!これははるかに簡単です。私は思っていますが、glmの目的は何ですか::終わりに反対ですか?それがなくてもうまくいくように思えますが、私はただ何も見つからないようにしたいと思っています – lmoyn

+0

@lmoyn:世界空間の右/上/下/位置ベクトルは、カメラ空間から世界に変換する行列の列ですスペース*(列ベクトルを仮定)。しかし、ビューマトリックスは、通常、ワールド空間からカメラ空間への変換を意図しています*。したがって、逆:私は最初にカメラ - >ワールド変換を計算し、ベクトルを抽出します(必要ない場合はこのステップはオプションです)。次に、行列を逆変換してワールド - >カメラ変換を取得します。もしそれが間違っていると言うなら、おそらく 'glm :: translates/rotate'の順序が間違っているからでしょう。それらを逆にしてみてください。 – ybungalobill

+0

私はglmを使いません。なぜなら、私は行列乗算の明示的な順序を使う​​他のライブラリを好む理由があります。glmとは異なり、 'glm :: rotate(M、...)) 'は、' M * R'または 'R * M'を返しても、回転行列' R'を計算します。この点でも、文書化さえ曖昧です。私はそれが「R * M」であると仮定しました。そうでなければ、すべてが逆の順序で行われなければなりません。 – ybungalobill

関連する問題