2016-10-22 33 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 :: inverse的目的是什麼?它似乎沒有它更好的工作,我只是想確保我沒有丟失任何東西 – lmoyn

+0

@lmoyn:世界空間中的右/上/後/向量向量是從相機空間到世界的矩陣轉換列空間*(假設列向量)。但視圖矩陣通常意味着將*從世界空間轉換爲相機空間*。因此,反過來:我首先計算相機 - >世界變換,然後提取矢量(如果不需要它們,這一步是可選的),然後逆矩陣以獲得世界 - >相機變換。如果你說它看起來錯了,那可能是因爲我得到了'glm :: translates/rotate'的順序錯誤。嘗試顛倒它們。 – ybungalobill

+0

我不使用glm--其中一個原因是我更喜歡使用矩陣乘法的顯式順序的其他庫 - 與glm不同的是,glm :: rotate(M,...))'計算旋轉矩陣'R'是否返回'M * R'或'R * M'。即使他們的文檔在這方面含糊不清。我認爲它是它所做的'R * M',如果不是,那麼一切都必須以相反的順序完成。 – ybungalobill