2016-10-02 182 views
0

我有一個圓形物體,我想沿着它自己的軸旋轉一個扇形物體。圍繞軸旋轉物體

我可以改變任何方向的旋轉,即dx, dy, dz使用我的變換矩陣。

下它的代碼:

Matrix4f matrix = new Matrix4f(); 
matrix.setIdentity(); 
Matrix4f.translate(translation, matrix, matrix); 
Matrix4f.rotate((float) Math.toRadians(rx), new Vector3f(1,0,0), matrix, matrix); 
Matrix4f.rotate((float) Math.toRadians(ry), new Vector3f(0,1,0), matrix, matrix); 
Matrix4f.rotate((float) Math.toRadians(rz), new Vector3f(0,0,1), matrix, matrix); 
Matrix4f.scale(new Vector3f(scale,scale,scale), matrix, matrix); 

我的頂點代碼:

vec4 worldPosition = transformationMatrix * vec4(position,1.0); 
vec4 positionRelativeToCam = viewMatrix*worldPosition; 
gl_Position = projectionMatrix *positionRelativeToCam; 


Main Game Loop: 



    Object.increaseRotation(dxf,dyf,dzf); 

但是,它不是沿着它自己的軸旋轉。我在這裏錯過了什麼? 我想要這樣的東西。請幫助

enter image description here

+1

見[4×4認識同質變換矩陣(http://stackoverflow.com/a/28084380/2521214)子彈**#5 **,並尋找本地之間差並在那裏進行全球輪換。 – Spektre

+1

@Spektre會在回答中解釋需要做些什麼改變我也面臨類似問題 –

+0

問題中的代碼太少,而不是問題的出現位置。數學的應用是正確的。所以我的猜測是,轉換矩陣無法正確加載到着色器的制服中。 – datenwolf

回答

1

你應該擺脫歐拉角這一點。

  1. 對象/網格幾何

    你需要知道你的對象是如何在其本地空間爲主。例如,讓這個假設:

    geometry

    因此,在這種情況下,主轉動軸周圍z。如果您的網格已定義爲旋轉軸未與任何軸對齊(x,yz),或者中心點不是(0,0,0),則會導致出現問題。補救措施是更改網格幾何圖形或創建一個特殊的常數變換矩陣M0,該變換矩陣將將網格物體LCS(局部座標系)中的所有頂點變換爲軸對齊的另一個頂點,並且軸的旋轉中心爲零也是旋轉軸。

    在後者的情況上對象矩陣M任何操作將這樣來完成:

    M'=M.M0.operation.Inverse(M0) 
    

    或反向或逆(取決於你的矩陣/頂點乘法和行/列順序慣例)。如果你有你的網已經集中,然後軸對準剛剛做這個:

    M'=M.operation 
    

    operation是變換的增量變化(例如旋轉矩陣)的矩陣。 M是對象當前變換矩陣#2M'是應用operation後的新版本。

  2. 對象變換矩陣

    你需要一個變換矩陣每個對象你知道的。這將持有你的對象的位置和方向LCS,因此它可以被轉換成世界/場景GCS(全球座標系)或其父對象LCS

  3. 圍繞其局部軸旋轉你的對象旋轉

    正如Understanding 4x4 homogenous transform matrices爲標準的OpenGL矩陣convetions提到你需要這樣做:

    M'=M*rotation_matrix 
    

    其中M是當前對象變換矩陣,M'是旋轉後的新版本。這是你變得不同的東西。您正在使用歐拉角rx,ry,rz,而不是逐漸積累旋轉。你不能以任何理智和穩健的方式用歐拉角來做到這一點!即使許多現代遊戲和應用程序仍在努力實現它(並且失敗多年)。

那麼怎樣做才能擺脫歐拉角:

  1. 你必須有持續性/全局/靜態矩陣M每個對象,而不是每本地實例

    所以你需要初始化它只需要一次而不是每幀清除它。

  2. 動漫更新應用需要

    這樣操作:

    M*=rotation_around_z(angspeed*dt); 
    

    angspeed[rad/second]或您的風扇轉速[deg/second]dt的時間[seconds]經過。例如,如果您在計時器中這樣做,則dt是計時器間隔。對於可變時間,您可以測量流逝的時間(這取決於平臺,我通常使用PerformanceTimers或RDTSC)。

    可以疊加在其本身上(例如你的粉絲也可以回頭更多的操作和將圍繞y軸覆蓋更大的面積。

    對於對象的直接控制(通過鍵盤,鼠標或操縱桿)只需添加之類的東西:

    if (keys.get(38)) { redraw=true; M*=translate_z(-pos_speed*dt); } 
    if (keys.get(40)) { redraw=true; M*=translate_z(+pos_speed*dt); } 
    if (keys.get(37)) { redraw=true; M*=rotation_around_y(-turn_speed*dt); } 
    if (keys.get(39)) { redraw=true; M*=rotation_around_y(+turn_speed*dt); } 
    

    哪裏keys是我的鑰匙圖保持開/關狀態,在鍵盤(這樣我就可以同時使用多個鍵)此代碼只是控制與箭頭對象中的每個鍵有關的詳細信息。該主題參見相關質量保證:

    Computer Graphics: Moving in the world

  3. 保留準確性

    隨着增量變化有失去精度的RISC由於浮點錯誤。因此,在您的矩陣類中添加一個計數器,計數它已被更改的次數(應用增量操作),以及是否有一些常量計數(例如128次操作)對矩陣進行歸一化。

    要做到這一點,你需要確保矩陣的正交性。所以eaxh軸矢量X,Y,Z必須垂直於其他兩個,它的大小必須是單位。我這樣做:

    1. 選擇主軸這將有方向不變。我選擇Z軸,因爲這通常是我的網格中的主軸(觀察方向,旋轉軸等)。所以才讓這個矢量單元​​
    2. 利用叉積來計算其他兩個軸系所以X = (+/-) Z x YY = (+/-) Z x X也歸他們太多X = X/|X|Y = Y/|Y|(+/-)在那裏,因爲我不知道你的座標系慣例,叉積可以產生與你的原始方向相反的矢量,所以如果方向相反,改變乘法順序或否定結果(這是在編碼時間不在運行時完成的! )。

    這裏例如C++我的正交規範化是如何做的:

    void reper::orto(int test) 
         { 
         double x[3],y[3],z[3]; 
         if ((cnt>=_reper_max_cnt)||(test)) // here cnt is the operations counter and test force normalization regardless of it 
           { 
           use_rep();    // you can ignore this 
           _rep=1; _inv=0;   // you can ignore this 
           axisx_get(x); 
           axisy_get(y); 
           axisz_get(z); 
           vector_one(z,z); 
           vector_mul(x,y,z);  // x is perpendicular to y,z 
           vector_one(x,x); 
           vector_mul(y,z,x);  // y is perpendicular to z,x 
           vector_one(y,y); 
           axisx_set(x); 
           axisy_set(y); 
           axisz_set(z); 
           cnt=0; 
           } 
         } 
    

    axis?_get/set(a)先手/從/到你的矩陣設置a爲軸心。所述vector_one(a,b)返回a = b/|b|vector_mul(a,b,c)返回a = b x c