2012-11-20 20 views
8

Ho un renderer che implementa l'interfaccia GLSurfaceView.Renderer; una sottoclasse di GLSurfaceView e alcune classi che rappresentano i miei oggetti che voglio disegnare. Ho il codice da http://developer.android.com/training/graphics/opengl/motion.html Voglio espandere questo e aggiungere alcuni spostamenti lungo gli assi e non riesco a gestirlo. L'oggetto è solo ruotato. e qui è il mio codice:Trasformazioni della matrice Android OpenGL ES

public class NotMyCoolRenderer implements GLSurfaceView.Renderer { 

public GLShip mTriangle; 
private GLBackgroundStar mSquare; 

private final float[] mMVPMatrix = new float[16]; 
private final float[] mProjMatrix = new float[16]; 
private final float[] mVMatrix = new float[16]; 
private final float[] mModelMatrix = new float[16]; 
private final float[] tempMatrix = new float[16]; 

public void onDrawFrame(GL10 unused) { 
    // 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); 
    // Now moving on to triangle aka ship 
    Matrix.setIdentityM(mModelMatrix, 0); 
    Matrix.translateM(mModelMatrix, 0, 0.1f, 0f, 0); 
    Matrix.rotateM(mModelMatrix, 0, mTriangle.mAngle, 0, 0, -1.0f); 
    Matrix.multiplyMM(tempMatrix, 0, mVMatrix, 0, mProjMatrix, 0); 
    Matrix.multiplyMM(mMVPMatrix, 0, mModelMatrix , 0, tempMatrix , 0); 

    // Draw triangle 
    mTriangle.draw(mMVPMatrix); 
} 
public void onSurfaceChanged(GL10 unused, int width, int height) { 
    // Adjust the viewport based on geometry changes, 
    // such as screen rotation 
    GLES20.glViewport(0, 0, width, height); 

    float ratio = (float) width/height; 

    // this projection matrix is applied to object coordinates 
    // in the onDrawFrame() method 
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); 

} 

public class GLShip { 
    public volatile float mAngle; 
    private final String vertexShaderCode = 
     // This matrix member variable provides a hook to manipulate 
     // the coordinates of the objects that use this vertex shader 
     "uniform mat4 uMVPMatrix;" + 

     "attribute vec4 vPosition;" + 
     "void main() {" + 
     // the matrix must be included as a modifier of gl_Position 
     " gl_Position = uMVPMatrix * vPosition;" + 
     "}"; 


    public void draw(float[] mvpMatrix) { 
     // Add program to OpenGL environment 
     GLES20.glUseProgram(mProgram); 

     // get handle to vertex shader's vPosition member 
     mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 

     // Enable a handle to the triangle vertices 
     GLES20.glEnableVertexAttribArray(mPositionHandle); 

     // Prepare the triangle coordinate data 
     GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, 
            GLES20.GL_FLOAT, false, 
            vertexStride, vertexBuffer); 

     // get handle to fragment shader's vColor member 
     mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); 

     // Set color for drawing the triangle 
     GLES20.glUniform4fv(mColorHandle, 1, color, 0); 

     // get handle to shape's transformation matrix 
     mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 
     NotMyCoolRenderer.checkGlError("glGetUniformLocation"); 

     // Apply the projection and view transformation 
     GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 
     NotMyCoolRenderer.checkGlError("glUniformMatrix4fv"); 

     // Draw the triangle 
     GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); 

     // Disable vertex array 
     GLES20.glDisableVertexAttribArray(mPositionHandle); 
    } 
} 

Le mie aspettative sono che su ogni ridisegnare l'oggetto sarebbe essere ruotata di storpiare e traslare lungo l'asse Y da 1f. Posso vedere solo ruotando (anche se un po 'troppo). Ho effettivamente ricevuto alcune domande a riguardo: come applicare la mia matrice di traduzione e qual è la migliore pratica per dividere la funzionalità di opengl? Non dovrebbe il modelMatrix essere memorizzato nell'oggetto stesso piuttosto che nel renderer? Le operazioni della matrice dovrebbero essere eseguite nella classe di rendering? Li ho raggruppati insieme perché immagino che siano tutti correlati.

+0

Hmm. ancora nulla per spiegare come mProjMatrix è inizializzato. –

+0

Ecco un suggerimento finale: prova a replicare passo dopo passo le lezioni da http://learningwebgl.com/blog/?page_id=1217. Copre solo javascript, ma le differenze sono prossime al minimo. L'API è la stessa e la matematica a matrice è la stessa. In bocca al lupo! –

+0

@AkiSuihkonen In un altro [thread] (http://stackoverflow.com/questions/11925647/is-googles-android-opengl-tutorial-teaching-incorrect-linear-algebra) persone suggerite (per lo stesso codice dello stesso tutorial) usando 'gl_Position = uMVPMatrix * vPosition;' invece di 'gl_Position = vPosition * uMVPMatrix;'. Se seguo il suggerimento, non vedo affatto il mio triangolo –

risposta

17

Ive lavorato con l'esempio dalla formazione di Android, il seguente approccio finalmente funziona per me. (Basato su Android Training > Displaying Graphics with OpenGL ES > Adding Motion)

  1. Utilizzare la corretta vertex shader:

    private final String vertexShaderCode = 
    // This matrix member variable provides a hook to manipulate 
    // the coordinates of the objects that use this vertex shader 
    "uniform mat4 uMVPMatrix;" + 
    "attribute vec4 vPosition;" + 
    "void main() {" + 
    // the matrix must be included as a modifier of gl_Position 
    " gl_Position = uMVPMatrix * vPosition;" + 
    "}"; 
    
  2. Nella classe renderer:

    public class MyGL20Renderer implements GLSurfaceView.Renderer { 
    [...] 
    // create a model matrix for the triangle 
    private final float[] mModelMatrix = new float[16]; 
    // create a temporary matrix for calculation purposes, 
    // to avoid the same matrix on the right and left side of multiplyMM later 
    // see https://stackoverflow.com/questions/13480043/opengl-es-android-matrix-transformations#comment18443759_13480364 
    private float[] mTempMatrix = new float[16]; 
    [...] 
    
  3. applicare trasformazioni in onDrawFrame, iniziare con traduzione:

    public void onDrawFrame(GL10 unused) { 
    [...] 
    Matrix.setIdentityM(mModelMatrix, 0); // initialize to identity matrix 
    Matrix.translateM(mModelMatrix, 0, -0.5f, 0, 0); // translation to the left 
    
  4. Poi rotazione:

    // Create a rotation transformation for the triangle 
    long time = SystemClock.uptimeMillis() % 4000L; 
    float mAngle = 0.090f * ((int) time); 
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f); 
    
  5. combinate rotazione e traslazione, evita di utilizzare mModelMatrix

    "come la stessa matrice sul lato destro e sinistro multiplyMM "(vedi 2)

    // Combine Rotation and Translation matrices 
    mTempMatrix = mModelMatrix.clone(); 
    Matrix.multiplyMM(mModelMatrix, 0, mTempMatrix, 0, mRotationMatrix, 0); 
    
  6. combinate matrice modello con la proiezione e la macchina fotografica; ancora evitare di utilizzare mModelMatrix

    "come la stessa matrice sul lato destro e sinistro di multiplyMM" (vedi 2)

    // Combine the model matrix with the projection and camera view 
    mTempMatrix = mMVPMatrix.clone(); 
    Matrix.multiplyMM(mMVPMatrix, 0, mTempMatrix, 0, mModelMatrix, 0); 
    
  7. tracciare la forma

    // Draw shape 
    mTriangle.draw(mMVPMatrix); 
    

Grazie a tutti, per tutto l'input utile che ho potuto trarre da questo thread.

+1

Funziona perfettamente - l'unico tutorial che ho trovato mi ha aiutato. La ringrazio per la risposta! – Antinous

+1

Nel caso in cui aiuti qualcun altro a trovare questa risposta, la parte che non mi è sembrata ovvia è che Matrix.multiplyMM modifica il calcolo _during_ della matrice di destinazione, non dopo. Quindi, se vuoi moltiplicare il valore per rotazione, e metti il ​​risultato in mvp, andare a Matrix.multiplyMM (mMVPMatrix, 0, mMVPMatrix, 0, mModelMatrix, 0) metterà MMVPMatrix al volo, dando come risultato un calcolo strano. Questo è il motivo per cui il clone sopra funziona. Per i miei scopi, sono stato in grado di eseguire calcoli "a catena" ruotando tra due diverse matrici "scratch", ad esempio: http://pastebin.com/h7c9Ktg9 –

2

Se si desidera vedere il movimento, è necessario aggiornare mTriangle.mAngle ogni fotogramma (preferibilmente in funzione del tempo per combattere le differenze di velocità oi ritardi causati da altri processi ...).

Si noti che Matrix.setIdentityM (mModelMatrix, 0); ripristina tutte le rotazioni e le traduzioni accumulate a "zero" o effettivamente a Identity Matrix ... La stessa convenzione si applica a tutte le funzioni impostate su. Per accumulare tutte le trasformazioni, è necessario

  • setIdentity (modello);
  • tradurre (trans); // per ottenere l'origine della rotazione
  • ruotare (rotmatrix); // per accumulare la rotazione
  • translate (t2); // per ritradurre certa posizione migliore ...

Inoltre si dovrebbe tenere i valori di definizione dell'oggetto vettore [bue, oy, oz] tra ogni chiamata ed alimentarli a Matrix.translateM (mModelMatrix, bue, oy, oz, 0);

In genere una concatena tutte le matrici 'traduci, ruota, ridimensiona', ecc. Il prima possibile e le memorizza nella cache per oggetto, o gerarchicamente per un contenitore complesso con più oggetti e con un riquadro di delimitazione, in modo che più oggetti possano essere abbattuto quando si è dietro la fotocamera (o in genere al di fuori del frustum di visualizzazione).

Inoltre, in genere si mantiene una telecamera in movimento in una matrice e per fotogramma si moltiplica con la matrice di proiezione.

Si può iniziare con qualcosa di simile:

float Time = System.currentTimeMillis() * 0.01f; // 10 radians/second == fast! 
Matrix.translateM(mModelMatrix, Math.sin(Time)*2.0f, 0, 1f, 0); 
... 

Come notato Tim, non v'è alcuna matrice di proiezione coinvolti, il che significa che tutti i valori z si comportano in questo codice esattamente, anche se cambiano x & valori y farebbero una differenza.

Sarei tentato di dire che la matrice MVP significherebbe moltiplicare in M ​​* V * P = (M * V) * P = M * (V * P).

+0

Ho dimenticato di menzionare che il metodo di disegno è attivato dal mio EventListener, quindi suppongo, non ho ancora bisogno della funzione del tempo. Il mio triangolo ruota come previsto. Non si muove lungo gli assi. –

+0

Questo perché c'è questo * setRotate * invece di Matrix.rotateM. (o qualunque cosa sia nell'API Android GLES) –

+0

Ora ho 'Matrix.setIdentityM (mModelMatrix, 0); Matrix.setIdentityM (mMVPMatrix, 0); Matrix.translateM (mModelMatrix, 0, 1f, 0f, 0); Matrix.rotateM (mModelMatrix, 0, mTriangle.mAngle, 0, 0, -1.0f); Matrix.multiplyMM (tempMatrix, 0, mVMatrix, 0, mModelMatrix, 0); Matrix.multiplyMM (mMVPMatrix, 0, mProjMatrix, 0, tempMatrix, 0); 'e continua a vedere solo la rotazione attorno all'asse Z e nessun altro movimento. Grazie per il suggerimento con la traduzione degli oggetti all'origine. Affronterò questo problema dopo che l'ho gestito per spostare l'oggetto dall'origine. –

0

Nota che non stai applicando la matrice di proiezione al triangolo che stai disegnando, ciò potrebbe causare problemi.

dovrebbe probabilmente essere:

Matrix.multiplyMM(mMVMatrix, 0, mVMatrix, 0, mModelMatrix, 0); 
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVMatrix, 0); 
+0

non dovrebbe la prima riga essere 'Matrix.multiplyMM (mVMatrix, 0, mVMatrix, 0, mModelMatrix, 0)'? Se sì, posso ancora vedere solo la rotazione. Nessuna traduzione. –

+1

AFAIK Non è possibile avere la stessa matrice sul lato destro e sinistro del multiploMM: * Tuttavia, i valori dell'elemento risultato non sono definiti se gli elementi risultato si sovrappongono agli elementi lhs o rhs. *. Ho definito una nuova matrice lì, la matrice 'ModelView', per contenere il risultato temporaneo della moltiplicazione del modello vista *. – Tim

+0

ha fatto lo stesso di te - ha definito una matrice temporanea. Ancora lo stesso problema, come previsto. –