私はOpenGL ESプログラムでパフォーマンスのボトルネックが現れています。私はそれがうまくいくと思いました - VBO、textureatlas、すべてのdraw-callのためのバインディングをほとんど使わないなど。しかし、多くのスプライトを同時に使用すると、パフォーマンスが大きく低下します。私はボトルネックがCPUに縛られていることに気づいた(ちょっと驚いた)。より正確には、ボトルネックは、各矩形の4つの頂点(x1、y1、x2、y2、x3、y3、x4、y4)のスクリーンポジションを計算するメソッドに浪費される可能性があります。これは、コリジョン検出に使用されます。私がこのメソッドで行うことは、シェーダで何が行われたかを繰り返すことであり、MV乗算によって多くのCPUサイクルが発生すると私は考えています。OpenGL ES:シェーダから変換された頂点を取得
rhsVecは、上記のように頂点を格納する浮動小数点配列です。
これはボトルネックと思われるので、たとえばクリップ座標が計算されるときにシェーダの同じベクトルにどのようにアクセスできるのでしょうか?パイプラインの下のシェーダーによって生成された座標をクリップ座標またはそれ以上に優れたものにします。
onSurfaceCreated
final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
new String[] {"a_Position", "a_Color", "a_Normal", "a_TexCoordinate"});
textureHandle = TextureHelper.loadTexture(context);
GLES20.glUseProgram(mProgramHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
//mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
頂点変換(ボトルネック)を行う方法の頂点シェーダ
uniform mat4 u_MVPMatrix;
uniform mat4 u_MVMatrix;
varying vec2 v_TexCoordinate;
attribute vec4 position;
void main()
{
v_TexCoordinate = a_TexCoordinate
gl_Position = u_MVPMatrix * a_Position;
}
スニペット
private void calcPos(int index) {
int k = 0;
for (int i = 0; i < 18; i += 3) {
rhsVec[0] = vertices[0 + i];
rhsVec[1] = vertices[1 + i];
rhsVec[2] = vertices[2 + i];
rhsVec[3] = 1;
// *** Step 1 : Getting to eye coordinates ***
Matrix.multiplyMV(resultVec, 0, mModelMatrix, 0, rhsVec, 0);
// *** Step 2 : Getting to clip coordinates ***
float[] rhsVec2 = resultVec;
Matrix.multiplyMV(resultVec2, 0, mProjectionMatrix, 0, rhsVec2, 0);
// *** Step 3 : Getting to normalized device coordinates ***
float inv_w = 1/resultVec2[3];
for (int j = 0; j < resultVec2.length - 1; j++) {
resultVec2[j] = inv_w * resultVec2[j];
}
float xPos = (resultVec2[0] * 0.5f + 0.5f) * game_width;
float yPos = (resultVec2[1] * 0.5f + 0.5f) * game_height;
float zPos = (1 + resultVec2[2]) * 0.5f;
SpriteData sD = spriteDataArrayList.get(index);
switch (k) {
case 0:
sD.xPos[0] = xPos;
sD.yPos[0] = yPos;
break;
case 1:
sD.xPos[2] = xPos;
sD.yPos[2] = yPos;
break;
case 2:
sD.xPos[3] = xPos;
sD.yPos[3] = yPos;
break;
case 3:
sD.xPos[1] = xPos;
sD.yPos[1] = yPos;
break;
}
k++;
if (i == 3) {
i += 9;
}
}
この方法は、各スプライトのために呼び出され100回のスプライトで100回繰り返されます。おそらく、MV乗算は性能に匹敵するでしょうか?
この操作は、あなたのケースではあまりにも遅くはありませんでした。これは400の行列とベクトルの乗算ですか?可能であれば、スプライトの衝突にGPUを使うべきではありませんが、GPUからCPUにデータを転送する必要があります。この乗算が本当に遅すぎる場合、それは盗聴される必要がありますので、独自のものを作成する必要があります。 –
@MaticOblak - ご意見ありがとうございます。実際には私はそれを解決しました。ライブラリ関数を使う代わりに、頂点とボリュームを手動で行列乗算しました。フレームレートが上がり、問題は少なくとも部分的に解決されたようです。私はまだ遅いデバイスに留意して、55-60スプライト以下のスプライトを使用しています。私の銀河s7は100以上のスプライトを管理できますが、銀河のタブは扱えません – java
既に提供されている回答に加えて、[* always * ms単位の測定性能はfpsではありません](https://www.mvps.org/directx/articles/fps_versus_frame_time .htm)。 –