2017-07-14 3 views
1

私は自分のopengl 2.0のゲームでパフォーマンスに問題があります。フレームレートは、私がゲームを変えるまでうまかった。 64種類の爆発ゲーム(レンガ)。私が今望んでいるのは、ボールが直ちに除去されないレンガに当たったときです。ステータスが変わり、テクスチャを変更するか、より正確にはアトラスのUV座標が含まれます。私はテクスチャクラスを持っており、ループの外側を呼び出すのではなく、ループ内のすべてのテクスチャに対してGLES20.bindBuffer()を呼び出すだけです。以前の私は、すべての図形の同じUV-COORDがあったが、今、私はそれはレンガのステータスに応じて変更し、私はOpenGL ES 2.0:頻繁にbindbufferを使用したパフォーマンス低下

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); 
} 

私は、パフォーマンスの低下に理由を理解してループ内でバインディングを使用する必要がある理由thatsのすべてですGPUへのbindbuffer呼び出しが、この問題を回避する方法はありますか?

答えて

1

オブジェクトごとにバッファーをバインドすることですが、1つのオブジェクトを描画するために2つのバッファーを使用していることもあります。また、renderメソッドの開始時にバッファをアンバインドするための冗長呼び出しがある場合は、単にそれを削除します。

多くの場合(すべての場合があります)、パフォーマンスを向上させるためにインターリーブされた頂点データが必要です。したがって、使用する

{ 
    position, 
    textureCoordinates 
} 

を1つのバッファに入れてください。

2つの同じオブジェクトの状態があり、2つ目は頂点座標は変更されますが、位置座標は変更されません。バッファが比較的大きい場合(私はそうではないと仮定します)、2つの間で位置データを共有することは意味があります。とにかく、このような共有のために私はあなたではなくあなたのバッファ構造が同じバッファの別の部分に二次テクスチャ座標を置くことも、別のバッファを使用するか、

{ 
    position, 
    textureCoordinates, 
    secondaryTextureCoordinates 
} 

として使用を示唆しています。

したがって、頂点バッファが比較的小さい場合は、「アトラス」プロシージャを使用することをお勧めします。あなたの場合は、バッファのサイズを2倍にして、すべての座標(重複した位置)を入れて、この頂点データを入れて、ある部分が次々と存在するようにすることです。

私はあなたの現在の図面でそれを簡単に行うことができ、描画呼び出しごとにバインドされたバッファの数を0に減らすことができると仮定します。これで、2番目の部分があります。ここでは、描画された各要素の属性ポインタを設定するだけで、使用するテクスチャ座標を制御できるようになります。これは、あなたのケースでは避けることができる冗長な呼び出しを再度表示します:

データ構造はバッファ内で一貫しているので、ポインタを一度より多く設定する理由はありません。バッファがバインドされている場合は、先頭に1回だけ設定し、描画呼び出しではオフセットを使用して、バッファのどの部分が実際に使用されているかを制御してください。GLES20.glDrawArrays(GLES20.GL_TRIANGLES, offset, 6)

適切に行われている場合、あなたのdrawメソッドは次のように見えるはずです。

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); 
} 

これは、すべてのバインディングを削除し、唯一の行列演算を保持し、通話を描きます。パイプラインに他の図面がある場合は、ループの前にバッファバインディングが必要です。そうでない場合は、初期化の一部として配置することができます。どちらの場合も、呼び出しを大幅に減らす必要があります。

ここにメモを追加するには、冗長な呼び出しを避けるためにOpenGLの状態を追跡する別のオブジェクトを使用することが一般的です。 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferID..の代わりにcontextObject.bindVertexBuffer(bufferID)のようなものを呼び出すと、bufferIDが以前の呼び出しと同じかどうかを確認できます。そして、そうであれば、実際の束縛は行われません。そのようなシステムを作成して使用すると、冗長な呼び出しは効果がないので、バッファバインドと呼ばれる場所とオブジェクト設定の残りの部分でほとんど違いはありません。それでも、この手順だけでは最適な状態にはならないので、まだ両方を必要とします。

+0

ありがとうございます - 私はこれをさらに調べます。私は問題をキャッチすると思う – java

1

バッファをバインドして、すべてのオブジェクトを同じUV-sで同時に描画できます。各ブリックを反復処理する代わりに、同じUV-sを使用するすべてのオブジェクトを反復処理します。

また、一度にすべてを描画するようにオブジェクトをバッチ処理してみてください。インデックスバッファオブジェクトを使用すると、これが役に立ちます。

+0

良いアイデア:) :) :) – java