2016-08-23 76 views
0

我想在OpenGL中製作一個可控制的球。我使用我自己的矩陣類來轉換對象矩陣,但我似乎無法獲得旋轉權。我總是以球繞着局部軸旋轉結束。 這就是它現在的樣子https://gfycat.com/LongKindBassethound。長線是本地軸。圍繞世界軸的旋轉對象OpenGL

所以當球向前移動時,下一個側面的移動將是錯誤的。即使世界在矩陣類的功能,可以讓周圍的任何軸旋轉:

Matrix& Matrix::rotationAxis(const Vector& Axis, float Angle) { 
const float Si = sin(Angle); 
const float Co = cos(Angle); 
const float OMCo = 1 - Co; 
Vector Ax = Axis; 
Ax.normalize(); 

m00= (Ax.X * Ax.X) * OMCo + Co; 
m01= (Ax.X * Ax.Y) * OMCo - (Ax.Z * Si); 
m02= (Ax.X * Ax.Z) * OMCo + (Ax.Y * Si); 
m03= 0; 

m10= (Ax.Y * Ax.X) * OMCo + (Ax.Z * Si); 
m11= (Ax.Y * Ax.Y) * OMCo + Co; 
m12= (Ax.Y * Ax.Z) * OMCo - (Ax.X * Si); 
m13= 0; 

m20= (Ax.Z * Ax.X) * OMCo - (Ax.Y * Si); 
m21= (Ax.Z * Ax.Y) * OMCo + (Ax.X * Si); 
m22= (Ax.Z * Ax.Z) * OMCo + Co; 
m23= 0; 

m30= 0; 
m31= 0; 
m32= 0; 
m33= 1; 

return *this; 
} 

我覺得這個我可以把世界上方向向量,並將其轉化爲對象的局部空間,然後周圍的結果旋轉。我真的不知道該怎麼做,(球*世界矢量矩陣?這是行不通的)。我真的想避免四元數,但是如果我不能這樣做,我也會很欣賞這方面的建議。

編輯:更多信息

轉移代碼。正如你所看到的,我嘗試了不同的方法,都做同樣的事情...所以毫不奇怪,它不起作用。與我以前嘗試嘗試使用glRotatef

Matrix transM, rotX, rotZ; 
rotationX = straight; 
rotationZ = side; 
if (velocity != Vector(0, 0, 0)) { 
    velocity.X = -0.0005 * DeltaTime; 
    velocity.X = clamp(velocity.X, 0, FLT_MAX); 

    velocity.Z = -0.0005 * DeltaTime; 
    velocity.Z = clamp(velocity.Z, 0, FLT_MAX); 
} 

velocity.X += speed * -side * DeltaTime; 
velocity.Z += speed * straight * DeltaTime; 
transM.translation(velocity.X, 0, velocity.Z); 

if (velocity.Z != 0 || velocity.X != 0) { 
    //http://mathworld.wolfram.com/EulerAngles.html 
    //http://gamedev.stackexchange.com/questions/67199/how-to-rotate-an-object-around-world-aligned-axes 

    Vector localAxisX = m_Ball * Vector(1, 0, 0); 
    Vector localAxisZ = m_Ball * Vector(0, 0, 1); 
    rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime); 
    rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime); 
    //rotX.rotationX(0.5* M_PI * straight * DeltaTime * 3); 
    //rotZ.rotationZ(0.5* M_PI * side * DeltaTime * 3); 
    //Matrix fullRotation.rotationYawPitchRoll(Vector(0, 0.5* M_PI * straight * DeltaTime, 0.5* M_PI * side * DeltaTime)); 
    m_Ball = transM * m_Ball * (rotX*rotZ); 
} 
else { 
    m_Ball = transM * m_Ball; 
} 

抽獎代碼(顯然註釋掉現在)

void Ball::draw(float DeltaTime) { 
    glPushMatrix(); 
    glMultMatrixf(m_Ball); 
    if(rotationX) 
    glRotatef(0.5* M_PI * rotationX * DeltaTime, 1.0, 0.0, 0.0); 
    if(rotationZ) 
    glRotatef(0.5* M_PI * rotationZ * DeltaTime, 0.0, 0.0, 1.0); 
    g_Model_ball.drawTriangles(); 
    glPopMatrix(); 
    drawAxis(); 
} 
+1

請將您的驅動程序代碼從您調用此函數的位置發佈出來,其次,您是否有此要求來調整您自己的旋轉功能?如果沒有,你可以使用glRotatef() –

+0

編輯更多信息 – lega

+0

請看看這篇文章,瞭解OpenGL轉換如何工作https://open.gl/transformations –

回答

1

我用四元輕鬆處理複合旋轉和避免萬向節鎖定強烈建議。

https://en.wikipedia.org/wiki/Gimbal_lock

確定與問候你的評論和視頻,你要圍繞着球的中心旋轉。看起來你在m_Ball中積累你的旋轉,但做一個奇怪的transM乘法。你也可能在積累翻譯transM

儘量不要混合您的翻譯和旋轉,並避免在m_Ball中累積它們。你可以做這樣的事情。

//transformation matrix 
transM.translation(velocity.X, 0, velocity.Z); 

//accumulate translations in m_BallT 
m_BallT = transM * m_BallT; 

//final Rotation 
Matrix rotation = rotX * rotZ; 

//accumulate rotations in m_BallR 
m_BallR = rotation * m_BallR; 

//now compute your final transformation matrix from accumulated rotations and translation 
m_Ball = m_BallT * m_BallR; 

注意如何m_BallR只是旋轉積累。後乘法將確保在m_BallR累積旋轉後應用新的rotation。最後翻譯到m_BallT累積的最終位置。您的球將圍繞其中心旋轉並根據m_BallT移動。

您也可以簡單地替換您的m_BallR上的轉換組件,以避免額外的矩陣乘法。

+0

我編輯了我的帖子。如果我正確地理解你,我很確定我已經做好了準備。 – lega

+0

我不認爲你正在這樣做,從你的球中提取世界空間位置,用旋轉矩陣旋轉那個位置矢量,然後將球移動到新的位置。不要將複合旋轉矩陣與球的矩陣相乘。 – Harish

+0

https://gfycat.com/BowedCaringArkshell這是我使用你的方法時的結果。我的目標是這樣的:https://gfycat.com/LongKindBassethound適當的旋轉 – lega

0
Vector newPos(m_Ball.translation().X + velocity.X, terrainNoise.GetHeight(m_Ball.translation().X, m_Ball.translation().Z) + 0.5, m_Ball.translation().Z + velocity.Z); 

rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime * abs(velocity.Z) * 100); 
rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime * abs(velocity.X) * 100); 

m_Rotation = (rotX*rotZ); 

m_Ball = (m_Ball.invert() * m_Rotation).invert(); 


m_Ball.m03 = newPos.X; 
m_Ball.m13 = newPos.Y; 
m_Ball.m23 = newPos.Z; 

這是我在閱讀由@Spektre提供的this鏈接後想出的解決方案。基本上,您只需將球的ModelMatrix反轉到世界位置,進行旋轉,然後將其轉換回本地空間。

您必須在旋轉之前設置newPos向量,否則會影響將來的轉換。

+0

您可以通過分別累積旋轉和平移來避免矩陣求逆。它會更有效率。由於您無論如何都會覆蓋平移向量,因此實際上只會反轉旋轉和任何比例。 – Harish

+0

@Harish在事實上不是更高效,它有很多原因是相反的......而且你不能以這種方式疊加任意轉換。因爲它只是'轉置()',所以在b正反轉矩陣上真的很容易... – Spektre

+0

@Spektre如果你做A =(A'x B)',你說它比A = B x A更有效率?我在這裏錯過了什麼?你在第一個案子中沒有積累?無論A'=轉置(A)還是沒有變化,你仍然在以不同的方式積累旋轉。 – Harish