2012-04-11 10 views
8

Tutte le esercitazioni che ho visto usano sempre un singolo oggetto, come un triangolo o un cubo. Ma non mi è chiaro come posso gestire autonomamente oggetti separati. Ho visto alcuni tutorial che si riferiscono alla pipeline di funzioni fisse e usano pushmatrix e popmatrix, ma con la pipeline programmabile queste funzioni sono sparite. Di seguito una funzione init e una funzione draw che disegna un singolo triangolo sullo schermo e lo ruota attorno all'asse Z. Qualcuno può mostrarmi il codice o persino pseudocodificare per aggiungere un secondo triangolo e ruotarlo indipendentemente dall'altro triangolo? Dì attorno ad un altro asse o nella direzione opposta?Trasforma oggetti in modo indipendente in OpenGL ES 2.0

qui sono:

int Init(ESContext* esContext) 
{ 
    UserData* userData = (UserData *)esContext->userData; 
    const char *vShaderStr = 
     "attribute vec4 vPosition; \n" 
     "uniform mat4 MVPMatrix;" 
     "void main()    \n" 
     "{       \n" 
     " gl_Position = MVPMatrix * vPosition;\n" 
     "}       \n"; 

    const char *fShaderStr = 
     "precision mediump float; \n" 
     "void main()    \n" 
     "{       \n" 
     " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n" 
     "}       \n"; 

    GLuint vertexShader; 
    GLuint fragmentShader; 
    GLuint programObject; 
    GLint linked; 
    GLfloat ratio = 320.0f/240.0f; 

    vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr); 
    fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr); 

    programObject = glCreateProgram(); 

    if (programObject == 0) 
     return 0; 

    glAttachShader(programObject, vertexShader); 
    glAttachShader(programObject, fragmentShader); 

    glBindAttribLocation(programObject, 0, "vPosition"); 
    glLinkProgram(programObject); 
    glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &linked); 

    if (!linked) 
    { 
     GLint infoLen = 0; 
     glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen); 

     if (infoLen > 1) 
     { 
      char* infoLog = (char *)malloc(sizeof(char) * infoLen); 
      glGetProgramInfoLog(programObject, infoLen, NULL, infoLog); 

      free(infoLog); 
     } 

     glDeleteProgram(programObject); 
     return FALSE; 
    } 

    userData->programObject = programObject; 

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 

    glViewport(0, 0, esContext->width, esContext->height); 
    glClear(GL_COLOR_BUFFER_BIT); 


    glUseProgram(userData->programObject); 

    userData->angle = 0.0f; 
    userData->start = time(NULL); 
    userData->ProjMatrix = PVRTMat4::Perspective(ratio*2.0f, 2.0f, 3.0f, 7.0f, PVRTMat4::eClipspace::OGL, false, false); 
    userData->ViewMatrix = PVRTMat4::LookAtLH(PVRTVec3(0.0f, 0.0f, -3.0f), PVRTVec3(0.0f, 0.0f, 0.0f), PVRTVec3(0.0f, 1.0f, 0.0f)); 
    return TRUE; 
} 



void Draw(ESContext *esContext) 
{ 
    GLfloat vVertices[] = {0.0f, 0.5f, 0.0f, 
          -0.5f, -0.5f, 0.0f, 
          0.5f, -0.5f, 0.0f}; 

    GLint MVPHandle; 
    double timelapse; 

    PVRTMat4 MVPMatrix = PVRTMat4::Identity(); 
    UserData* userData = (UserData *)esContext->userData; 

    timelapse = difftime(time(NULL), userData->start) * 1000; 
    if(timelapse > 16.0f) //Maintain approx 60FPS 
    { 
     if (userData->angle > 360.0f) 
     { 
      userData->angle = 0.0f; 
     } 
     else 
     { 
      userData->angle += 0.1f; 
     } 
    } 

    userData->ModelMatrix = PVRTMat4::RotationZ(userData->angle); 

    MVPMatrix = userData->ViewMatrix * userData->ModelMatrix; 
    MVPMatrix = userData->ProjMatrix * MVPMatrix; 

    MVPHandle = glGetUniformLocation(userData->programObject, "MVPMatrix"); 
    glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr()); 

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices); 
    glEnableVertexAttribArray(0); 

    glClear(GL_COLOR_BUFFER_BIT); 
    glDrawArrays(GL_TRIANGLES, 0, 3); 
    eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface); 
} 

risposta

6

Dopo aver disegnato il primo triangolo, generare una nuova matrice MVP con la nuova rotazione/posizione desiderata, caricarlo e quindi trascinare il triangolo una seconda volta. Puoi cambiare le uniformi tutte le volte che vuoi durante la scena.

Questo è simile a ciò che stanno facendo push e pop, stanno solo cambiando la matrice attiva prima di disegnare un dato oggetto.

Esempio pseudocodice:

MMatrix = identity; 
MVPMatrix = VPMatrix * MMatrix; 
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr()); 
glDrawArrays(GL_TRIANGLES, 0, 3); //draw triangle at 0,0,0 

MMatrix.translate(1,0,0); 
MVPMatrix = VPMatrix * MMatrix; 
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr()); 
glDrawArrays(GL_TRIANGLES, 0, 3); //draw triangle at 1,0,0 

MMatrix.translate(1,0,0); 
MVPMatrix = VPMatrix * MMatrix; 
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr()); 
glDrawArrays(GL_TRIANGLES, 0, 3); //draw triangle at 2,0,0 

..repeat for as many objects as you want.. 

Questo vi lascerà con tre triangoli, a (0,0,0), (1,0,0), e (2,0,0).

+0

Puoi essere un po 'più esplicito? Specificamente, se cambio il valore dell'uniforme MVPMatrix per includere una traduzione, come saprà disegnare una copia del triangolo nella nuova posizione e non solo spostare il triangolo esistente in quella posizione? – Legion

+1

Una volta inviato un triangolo tramite glDrawArrays, il gioco è fatto. Nessuna ulteriore modifica a nessuna variabile avrà alcun effetto su di essa. Una volta che qualcosa è stato reso non può essere 'spostato', quindi le modifiche a qualsiasi uniforme avranno effetto solo le chiamate effettuate dopo la modifica. Ho inserito un piccolo codice di esempio nella mia risposta per aiutarti a capire. – Tim

+0

@Legion aggiornato con nuovo commento e spiegazione – Tim