2012-08-12 62 views
30

在幫助其他用戶提出有關Responding to Touch Events Android教程的問題後,我下載了源代碼,並對我所看到的內容感到非常困惑。該教程似乎無法確定是否要使用行向量或列向量,並且它看起來都與我混淆。Google的Android OpenGL教程是不正確的線性代數教學嗎?

在Android矩陣頁面上,他們聲稱他們的慣例是列向量/列主要,這是OpenGL的典型特徵。

我是對的,還是有我失蹤的東西?下面是它的相關位:

通過乘以mProjMatrix * mVMatrix創建一個MVPMatrix開始。到現在爲止還挺好。

// Set the camera position (View matrix) 
    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 

    // Calculate the projection and view transformation 
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0) 

接着,他們被追加旋轉到MVPMatrix的左側?這似乎有點奇怪。

// Create a rotation for the triangle 
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f); 

    // Combine the rotation matrix with the projection and camera view 
    Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0) 

上傳非調換順序。

GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 

最後在他們的着色器,矢量*矩陣乘法?

// the matrix must be included as a modifier of gl_Position 
    " gl_Position = vPosition * uMVPMatrix;" 

添加此一起,我們得到:

gl_Position = vPosition * mRotation * mProjection * mView; 

這是不是我的任何想象正確的。是否有任何解釋說我沒有看到這裏發生了什麼?

+2

對我來說有兩種可能性。這個例子是錯誤的,或者他們以不同的方式實現了矩陣運算。 [見](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/opengl/Matrix.java) – 2012-09-01 10:51:15

+0

你能否澄清一下問題,請嗎? – user1071136 2012-09-03 23:36:01

回答

25

作爲編寫OpenGL教程的人,我可以確認示例代碼是不正確的。具體地講,在着色器代碼的因素的順序應顛倒:

" gl_Position = uMVPMatrix * vPosition;" 

至於旋轉矩陣的應用,各因素的順序也應被顛倒,使得旋轉是最後一個因素。經驗法則是矩陣以從右到左的順序被應用,並且首先應用旋轉(它是「MVP」的「M」部分),所以它需要是最右邊的操作數。此外,你應該使用一個臨時矩陣以此計算,所推薦的伊恩·鎳劉易斯(看他的更完整的答案,下同):

float[] scratch = new float[16]; 
// Combine the rotation matrix with the projection and camera view 
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); 

感謝你打電話注意這個問題。我會盡快修復培訓課程和示例代碼。

編輯:此問題現已在下載的示例代碼和OpenGL ES培訓課程中得到糾正,包括對正確因素順序的評論。感謝您的反饋,夥計們!

+2

還有一個問題:Matrix.multiplyMM不檢查別名。如果您將其中一個輸入參數重新用作輸出參數,它將被覆蓋。 – 2012-09-07 00:28:47

+0

謝謝我正在尋找這個答案。 '''在'void main'之前應該添加'uniform mat4 uMVPMatrix',否則它會給clearColor一個空白屏幕。 – 2012-10-01 18:38:42

+0

我還發現'Matrix.multiplyMM(mMVPMatrix,0,mRotationMatrix,0,mMVPMatrix,0);'給出比重新排序的右旋轉變換。 'T(x)= A.x'和'multiplyMM(float [] result,int resultOffset,float [] lhs,int lhsOffset,float [] rhs,int rhsOffset)'。只有修復Vertex Shader才能爲我工作。 – 2012-10-01 18:56:16

10

本教程不正確,但許多錯誤要麼互相抵消,要麼在這個非常有限的環境中不明顯(以(0,0)爲中心的固定攝像機,僅Z軸旋轉)。旋轉是向後的,但是否則它看起來是正確的。(要明白爲什麼它是錯誤的,請嘗試使用較不重要的相機:例如設置眼睛並將其看作y = 1。)

使這種調試非常困難的一個原因是Matrix方法沒有對其輸入做任何別名檢測。教程代碼使您看起來像用與輸入和結果相同的矩陣調用Matrix.multiplyMM。這是不正確的。但是因爲實現每次乘以一列,所以如果右邊被重用(如在當前代碼中,其中mMVPMatrix是rhs和結果),如果左邊被重用,則不太明顯的是,某些情況是錯誤的。在寫入結果中的相應列之前讀取左邊的每列,所以即使LHS被覆蓋,輸出也是正確的。但是,如果右側與結果相同,則在完成讀取之前,其第一列將被覆蓋。

因此,教程代碼處於某種局部最大值:它看起來像是有效的,如果你改變了任何一件事情,它就會突然出現。這導致人們認爲錯誤,因爲它看起來,它可能是正確的。 ;-)

無論如何,這裏有一些替代代碼,得到我認爲是預期的結果。

Java代碼:

@Override 
public void onDrawFrame(GL10 unused) { 
    float[] scratch = new float[16]; 

    // Draw background color 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 

    // Set the camera position (View matrix) 
    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 

    // Calculate the projection and view transformation 
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0); 

    // Draw square 
    mSquare.draw(mMVPMatrix); 

    // Create a rotation for the triangle 
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f); 

    // Combine the rotation matrix with the projection and camera view 
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); 

    // Draw triangle 
    mTriangle.draw(scratch); 
} 

shader代碼:

gl_Position = uMVPMatrix * vPosition; 

注意:這些修補程序使投影正確的,但他們也反向旋轉的方向。這是因爲原始代碼以錯誤的順序應用了轉換。這樣考慮:不是順時針旋轉物體,而是逆時針旋轉相機。當您修復操作順序以便將旋轉應用於對象而不是相機時,對象將逆時針旋轉。這不是矩陣是錯的。這是用來創建矩陣的角度。

所以要得到'正確'的結果,你還需要翻轉mAngle的符號。

1

我工作的同樣的問題,這就是我發現:

我相信喬的樣本無誤後,
包括 在着色器代碼的因素順序是:

gl_Position = vPosition * uMVPMatrix; 

要驗證它只是嘗試旋轉三角形以相反的因子順序, 它會將三角形拉伸到消失點90度。

真正的問題似乎在setLookAtM函數。
在Joe的樣品的參數是:

Matrix.setLookAtM(mVMatrix, 0, 
    0f, 0f,-3f, 0f, 0f, 0f, 0f, 1f, 0f); 

這是完全邏輯爲好。
然而,由此產生視圖矩陣看起來怪我:

-1 0 0 0 
0 1 0 0 
0 0 -1 0 
0 0 -3 1 

我們可以看到,這個矩陣將反轉X座標, 由於第一件是-1,
這將導致左/右在屏幕上翻轉。
它也會反轉Z順序,但讓我們來關注X座標。

我認爲setLookAtM功能也正常工作。
但是,由於Matrix類不是OpenGL的一部分,因此它可以使用其他一些座標系統,例如
- 常規屏幕座標,Y軸指向下方。
這只是一個猜測,我沒有真正驗證。

可能的解決方案:
我們可以建立理想的視圖矩陣手動,
代碼:

Matrix.setIdentityM(mVMatrix,0); 
mVMatrix[14] = -3f; 

OR
我們可以嘗試給它 逆轉相機座標誘騙setLookAtM功能: 0,0,+ 3(而不是-3)。

Matrix.setLookAtM(mVMatrix, 0, 
    0f, 0f, 3f, 0f, 0f, 0f, 0f, 1f, 0f); 

結果視圖矩陣將是:

1 0 0 0 
0 1 0 0 
0 0 1 0 
0 0 -3 1 

這正是我們需要的。
現在相機的行爲與預期相同,
和示例正常工作。

+1

你說得對,只是修正着色器中操作數的順序會產生更糟的結果,而不是更好的結果。但那是因爲樣本存在多個問題。 – 2013-04-17 00:26:53

+0

我應該提到你的解決方案實際上是我嘗試的第一件事,因爲我確信我看到了一個習慣性問題。但即使它看起來不錯,它不是;嘗試移動和旋轉相機,你會很快看到爲什麼。我在下面發佈的代碼是正確的。 – 2013-04-17 00:47:34

2

我解決了這個問題,如下所示:

@Override 
public void onDrawFrame(GL10 unused) {  
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 

    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);   

    Matrix.setRotateM(mModelMatrix, 0, mAngle, 0, 0, 1.0f); 
    Matrix.translateM(mModelMatrix, 0, 0.4f, 0.0f, 0); 

    mSquare.draw(mProjMatrix,mViewMatrix,mModelMatrix); 
} 

@Override 
public void onSurfaceChanged(GL10 unused, int width, int height) { 
    ... 
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 99); 

} 

class Square { 

    private final String vertexShaderCode = 
     "uniform mat4 uPMatrix; \n" + 
     "uniform mat4 uVMatrix; \n" + 
     "uniform mat4 uMMatrix; \n" + 

     "attribute vec4 vPosition; \n" + 
     "void main() { \n" + 
     " gl_Position = uPMatrix * uVMatrix * uMMatrix * vPosition; \n" + 
     "} \n"; 

    ... 

    public void draw(float[] mpMatrix,float[] mvMatrix,float[]mmMatrix) { 

     ... 

     mPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uPMatrix"); 
     mVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uVMatrix"); 
     mMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix"); 

     GLES20.glUniformMatrix4fv(mPMatrixHandle, 1, false, mpMatrix, 0); 
     GLES20.glUniformMatrix4fv(mVMatrixHandle, 1, false, mvMatrix, 0); 
     GLES20.glUniformMatrix4fv(mMMatrixHandle, 1, false, mmMatrix, 0); 

     ... 
    } 
} 
0

沒有其他建議使用除了當前更新的Android示例代碼爲我工作的試圖移動三角形時以下。

以下鏈接包含答案。花了一天的時間找到它。張貼這裏幫助其他人,因爲我多次看到這篇文章。 OpenGL ES Android Matrix Transformations