我注意到纹理图的大小确实对 OpenGL ES 2 应用程序有影响。图集的大小为 2048 X 2048,在三星 Galaxy S7 上使用时,性能几乎与每秒 60 帧一致。即使是 4096 X 4096 也可以,虽然可能会损失一些性能,但不会太多。
如果我现在在三星 Galaxy S3 上编译和运行相同的应用程序,那么如果我使用 2048 X 2048 的纹理图,帧率真的很差。绘制一个框架大约需要 25 毫秒。但是,如果我将纹理图集减小到 1024 X 1024,性能将会提高很多 - 每秒 60 帧。
那么我应该根据设备使用不同大小的纹理图的结论是什么?但究竟大小如何与设备相关联?屏幕尺寸也许?例如 - 屏幕尺寸为 720 X 1280 我使用 1024 X 1024 纹理图,而 1440 X 2560 和 2048 X 2048 纹理图?
还是我的来源有问题?到目前为止,我不知道如何跟踪假设 100 个共享同一个帧缓冲区的精灵。相反,每个精灵都有自己的缓冲区,在 onDrawFrame 中,我为每个缓冲区进行了单独的绘制调用。但我猜 bindBuffer 比 bindTexture 快?
或者我如何将位图加载到 OpenGL 有问题吗?我正在使用国旗
Bitmap.Config.RGB_565
但没有性能提升。
渲染器源
public MyGLRenderer(Context context) {
this.context = context;
nSprites = 75;
alienUvs = new float[16][12 * nSprites];
bgUvs = new float[12];
vertices = new float[18 *nSprites];
verticesBG = new float[18];
vertexBuffer= new FloatBuffer[nSprites];
vertexBufferBG = new FloatBuffer[1];
// The indices for all textured quads
indices = new short[nSprites*6];
uvBufferAlien = new FloatBuffer[16]; // antalet frames
uvBufferBG = new FloatBuffer[1];
bufferId = new int[16 + nSprites + 2]; // 16 stycken för aliens, nsprites antal för punkterna
modulo = 2;
start = System.currentTimeMillis();
//slumpa x o y
xPos = new float[nSprites];
yPos = new float[nSprites];
for (int i = 0; i < nSprites; i++) {
Random r = new Random();
xPos[i] = (float)(r.nextDouble()-0.5) * 6;
r = new Random();
yPos[i] = (float)(r.nextDouble()-0.5) * 6;
}
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
vertexBuffer = GLData.createVertices(nSprites, vertices);
vertexBufferBG[0] = GLData.createVerticesBG(verticesBG);
GLData.createUvsData(nSprites, alienUvs, uvBufferAlien);
uvBufferBG[0] = GLData.createUvsDataBG(bgUvs);
GLData.createVertexBufferObject(vertexBuffer, vertexBufferBG, nSprites, uvBufferAlien, uvBufferBG, bufferId.length, bufferId);
createCamera();
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// inlästa shaderprogram (källkod i strängform)
final String vertexShader = getVertexShader();
final String fragmentShader = getFragmentShader();
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"});
//skapa texture
textureHandle = TextureHelper.loadTexture(context);
GLES20.glUseProgram(mProgramHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
game_width = width;
game_height = height;
GLES20.glViewport(0, 0, width, height);
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1f;
final float far = 20.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
@Override
public void onDrawFrame(GL10 unused) {
int rest = 0;
if (modulo > 0) {
rest = frameCntr % modulo;
}
if (rest == 0) {
bitmapIndex++;
}
if (bitmapIndex == 16) {
bitmapIndex = 0;
}
frameCntr++;
//uvs, 16 bilder
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId[bitmapIndex]);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, 0);
for (int i = 0; i < nSprites; i++) {
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, xPos[i], yPos[i], -8f);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId[16 + i]);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, 0);
draw();
}
//mease framerate
long stop = System.currentTimeMillis();
nbFrames++;
if (stop - start >= 1000) {
System.out.println("" + (float)1000 / nbFrames);
nbFrames = 0;
start += 1000;
}
}
private void draw() {
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);
}
纹理助手
public class TextureHelper {
public static int[] loadTexture(Context context) {
int[] texturenames = new int[1];
GLES20.glGenTextures(1, texturenames, 0);
int resId = context.getResources().getIdentifier("aliens", "drawable", context.getPackageName());
//Bitmap bmp = BitmapDecoder.decodeSampledBitmapFromResource(context.getResources(), resId, 960, 928);
//Bitmap bmp = BitmapDecoder.decodeSampledBitmapFromResource(context.getResources(), resId, 780, 1280);
Bitmap bmp = BitmapDecoder.decodeSampledBitmapFromResource(context.getResources(), resId, 2048, 2048);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
bmp.recycle();
return texturenames;
}
}
位图解码器(片段)
protected static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inDither = true;
//options.inScaled = false;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return Bitmap.createScaledBitmap( BitmapFactory.decodeResource(res, resId, options), reqWidth, reqHeight, true);
}