2017-07-14 1 views
1

J'ai un problème de performance dans mon jeu opengl 2.0. Le framerate était bon jusqu'à ce que je fasse un changement dans le jeu. C'est une sorte de jeu de l'épidémie avec 64 formes (briques). Ce que je veux maintenant, c'est que lorsque la balle frappe une brique, elle ne soit pas immédiatement enlevée - elle change de statut et cela inclut le changement de texture ou plus correctement - la coordonnée uv de l'atlas. J'ai un textureatlas et ce que je fais est juste d'appeler GLES20.bindBuffer() pour chaque texture dans la boucle, au lieu d'appeler l'extérieur de la boucle. Plus tôt j'ai eu le même uv-coord pour toutes les formes, mais maintenant, je le change en fonction de l'état de briques et c'est pourquoi je dois utiliser la liaison dans la boucleOpenGL ES 2.0: Perte de performance à l'aide de bindbuffer fréquemment

private void drawShape() { 


    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboDataListLevelSprites.get(iName).getBuff_id_vertices()); 
    GLES20.glEnableVertexAttribArray(mPositionHandle); 
    GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, 0); 


    //used this snipped before when using the same image (uv-coords) for all bricks 
    /*GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboDataListLevelSprites.get(iName).getBuff_id_uvs()); 
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, 0); 
    */ 

    for (Iterator<BrickProperties> it = arrayListBricks.iterator(); it.hasNext();) { 



     BrickProperties bp = it.next(); 
     //now bindbuffer inside loop just too switch uv-coords of the atlas when its time to use another image 
     int buffIndexVal = bp.get_status_diff(); 
     GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, BrickProperties.get_buff_id_uvs()[buffIndexVal]); 
     GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 
     GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, 0); 


     Matrix.setIdentityM(mModelMatrix, 0); 
     Matrix.translateM(mModelMatrix, 0, bp.getTranslateData()[0], bp.getTranslateData()[1], bp.getTranslateData()[2]); 

     if (bp.get_status() == 0) { 
      it.remove(); 
     } 

     render(); 
    } 
} 


private void render() { 

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 
    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0); 
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6); 
} 

Je comprends la raison de la baisse de performance est d'autant appels bindbuffer au GPU mais comment pourrais-je contourner ce problème?

Répondre

1

C'est une chose que vous liez un tampon pour chaque objet, mais il y a une autre chose que vous utilisez 2 tampons pour dessiner un seul objet. Vous avez également un appel redondant pour découpler le tampon au début de votre méthode render, supprimez simplement cela.

Dans la plupart des cas (dans tous les cas), vous souhaitez obtenir des données de sommet entrelacées pour améliorer les performances. Donc, utiliser

{ 
    position, 
    textureCoordinates 
} 

dans un seul tampon.

Je vois dans votre cas que vous avez 2 états du même objet où le second va changer les coordonnées de vertex mais pas les coordonnées de position. Il pourrait être logique de partager les données de position entre les deux si le tampon est relativement grand (ce que je suppose ne l'est pas). En tout cas pour ce partage, je vous suggère d'utiliser plutôt votre structure tampon comme

{ 
    position, 
    textureCoordinates, 
    secondaryTextureCoordinates 
} 

puis utiliser un tampon séparé ou même de mettre la texture secondaire coordonne à une autre partie du même tampon. Donc, si les tampons de vertex sont relativement petits, je vous suggère d'utiliser la procédure "atlas". Pour votre cas cela signifierait créer deux fois la taille du tampon et mettre toutes les coordonnées (ayant la position dupliquée) et mettre ces données de sommet de façon à ce qu'il y ait une partie après l'autre. Je suppose que vous pouvez facilement le faire pour votre dessin courant et réduire efficacement le nombre de tampons liés à 0 par appel draw (vous avez seulement besoin de le lier à une initialisation). Maintenant, vous aurez la deuxième partie où vous allez définir les pointeurs d'attribut pour chacun des éléments dessinés juste pour que vous puissiez contrôler quelles coordonnées de texture sont utilisées. Cela présentera à nouveau des appels redondants qui peuvent être évités dans votre cas:

Étant donné que la structure de données est cohérente dans votre mémoire tampon, il n'y a vraiment aucune raison de définir les pointeurs plusieurs fois. Il suffit de les définir une fois au début lorsque le tampon est lié, puis d'utiliser le décalage dans l'appel draw pour contrôler quelle partie du tampon est réellement utilisée GLES20.glDrawArrays(GLES20.GL_TRIANGLES, offset, 6).

Si fait correctement votre méthode de tirage devrait ressemble à quelque chose comme:

for (Iterator<BrickProperties> it = arrayListBricks.iterator(); it.hasNext();) { 
    BrickProperties bp = it.next(); 

    Matrix.setIdentityM(mModelMatrix, 0); 
    Matrix.translateM(mModelMatrix, 0, bp.getTranslateData()[0], bp.getTranslateData()[1], bp.getTranslateData()[2]); 

    if (bp.get_status() == 0) { 
     it.remove(); 
    } 

    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0); 
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, bp.vertexOffset, 6); 
} 

Cela supprime toutes les liaisons et conserve uniquement les opérations de matrice et de tirer des appels. S'il y a d'autres dessins dans le pipeline, vous avez besoin de la liaison de tampon avant la boucle sinon vous pouvez le mettre dans le cadre de l'initialisation. Dans les deux cas, les appels doivent être réduits de manière significative.

Pour ajouter une note ici, il est courant d'avoir un autre objet qui suit les états openGL pour éviter les appels redondants. Au lieu d'appeler GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferID.. vous préférez appeler quelque chose comme contextObject.bindVertexBuffer(bufferID) qui permettrait de vérifier si le bufferID est le même que dans l'appel précédent. Et si c'est le cas, aucune liaison réelle ne serait faite. Si vous créez et utilisez un tel système, l'endroit où vous appelez la liaison de la mémoire tampon et le reste de la configuration de l'objet a peu d'importance car les appels redondants n'auront aucun effet. Cependant, cette procédure seule ne rendra pas votre situation optimale, vous aurez donc besoin des deux.

+0

Merci - Je vais regarder dans ce plus. Je pense que j'attrape le problème – java

1

Vous pouvez lier le tampon et dessiner tous les objets avec les mêmes UV-s à la fois. Au lieu d'itérer à travers chaque brique, parcourez tous les objets qui utilisent les mêmes UV-s.

De même, essayez de regrouper les objets afin de les dessiner tous en même temps. L'utilisation d'objets tampon d'index peut aider à cela.

+0

bonne idée :) :) :) – java