使用 OpenGL ES 2.0 的 GLSurfaceView 为某些用户显示空白屏幕
GLSurfaceView using OpenGL ES 2.0 shows blank screen for certain users
我发布的 Android 游戏中有一个长期存在的问题,某些用户在 GLSurfaceView
游戏发生的地方看不到任何渲染。我从未能够在我自己的任何测试设备上重现该问题,因此调试起来非常困难。
最近,我能够与报告错误的用户之一一起工作,以便将其隔离为一小部分代码。不幸的是,此时它与基本教程示例并没有太大区别,所以我对可能出现的问题有些茫然。
下面的代码应该在屏幕中央绘制一个白色方块。它在我的测试设备上运行良好,但对于这个用户却失败了(并且可能对于向我报告了相同错误的许多其他用户也失败了)。
我已经尝试了一些不同的测试。用户可以看到背景颜色的变化,因此这不是所有 GL 调用的全面失败。此外,当我插入对 glCheckError 的额外调用时,我从未记录任何非零 return。
大家有什么想法或建议吗?
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GLSurfaceView view = (GLSurfaceView) findViewById(R.id.gl);
view.setEGLContextClientVersion(2);
view.setRenderer(new GLRenderer());
view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
view.requestRender();
}
private static class GLRenderer implements GLSurfaceView.Renderer {
public static final float SCALE = 480f;
private float ratio;
private int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private final float[] mVMatrix = new float[16]; // View matrix
private final float[] mPMatrix = new float[16]; // Projection matrix
private final float[] mVPMatrix = new float[16]; // V * P
private final float[] mMMatrix = new float[16]; // Object transformation matrix (position/rotation)
private final float[] mMVPMatrix = new float[16]; // VP * M
private final float[] foregroundColor = {1f, 1f, 1f, 1f};
private final float[] backgroundColor = {0f, 0f, 0f, 1f};
private static final int COORDS_PER_VERTEX = 3;
private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private final float[] points = {
-20, -20, 0,
-20, 20, 0,
20, -20, 0,
20, 20, 0
};
private final short[] drawOrder = {
0, 1, 2, 3
};
private final FloatBuffer vertexBuffer = buildFloatBuffer(points);
private final ShortBuffer drawListBuffer = buildShortBuffer(drawOrder);
private static FloatBuffer buildFloatBuffer(float[] array) {
FloatBuffer buffer = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
array.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(array)
;
buffer.position(0);
return buffer;
}
private static ShortBuffer buildShortBuffer(short[] array) {
ShortBuffer buffer = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
array.length * 2)
.order(ByteOrder.nativeOrder())
.asShortBuffer()
.put(array)
;
buffer.position(0);
return buffer;
}
private static final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private static final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], backgroundColor[3]);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
ratio = 1f * width / height;
GLES20.glViewport(0, 0, width, height);
Matrix.frustumM(mPMatrix, 0, -ratio * SCALE/2, ratio * SCALE/2, -SCALE/2, SCALE/2, 3, 7);
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0, 0, 0, 0, -1, 0);
Matrix.multiplyMM(mVPMatrix, 0, mPMatrix, 0, mVMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glUniform4fv(mColorHandle, 1, foregroundColor, 0);
draw(0, 0, 0);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
private void draw(float x, float y, float a) {
Matrix.setIdentityM(mMMatrix, 0);
Matrix.translateM(mMMatrix, 0, x, y, 0);
Matrix.rotateM(mMMatrix, 0, a, 0, 0, 1);
Matrix.multiplyMM(mMVPMatrix, 0, mVPMatrix, 0, mMMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false, VERTEX_STRIDE,
vertexBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,
drawListBuffer.capacity(), GLES20.GL_UNSIGNED_SHORT,
drawListBuffer);
}
}
}
driver 可能有问题。您可以联系 driver 公司并提交错误报告
问自己以下问题:
- phone 有不同的 driver 吗?它支持 OpenGL ES 2.0 吗?
- GL操作是否成功?即 glGetError() 曾经 non-zero?
- glClearColor 成功了吗?尝试将颜色清除为红色。你看到红屏了吗?
- 程序是否编译成功?
如果我将 Matrix.frustumM()
调用更改为 Matrix.orthoM()
,问题就会消失。除此之外,我仍然不确定为什么某些设备可以正常工作,而其他设备却不行。如果有人能更好地理解这里发生的事情,我愿意接受另一个答案,但现在我已经解决了我的问题。
我发布的 Android 游戏中有一个长期存在的问题,某些用户在 GLSurfaceView
游戏发生的地方看不到任何渲染。我从未能够在我自己的任何测试设备上重现该问题,因此调试起来非常困难。
最近,我能够与报告错误的用户之一一起工作,以便将其隔离为一小部分代码。不幸的是,此时它与基本教程示例并没有太大区别,所以我对可能出现的问题有些茫然。
下面的代码应该在屏幕中央绘制一个白色方块。它在我的测试设备上运行良好,但对于这个用户却失败了(并且可能对于向我报告了相同错误的许多其他用户也失败了)。
我已经尝试了一些不同的测试。用户可以看到背景颜色的变化,因此这不是所有 GL 调用的全面失败。此外,当我插入对 glCheckError 的额外调用时,我从未记录任何非零 return。
大家有什么想法或建议吗?
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GLSurfaceView view = (GLSurfaceView) findViewById(R.id.gl);
view.setEGLContextClientVersion(2);
view.setRenderer(new GLRenderer());
view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
view.requestRender();
}
private static class GLRenderer implements GLSurfaceView.Renderer {
public static final float SCALE = 480f;
private float ratio;
private int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private final float[] mVMatrix = new float[16]; // View matrix
private final float[] mPMatrix = new float[16]; // Projection matrix
private final float[] mVPMatrix = new float[16]; // V * P
private final float[] mMMatrix = new float[16]; // Object transformation matrix (position/rotation)
private final float[] mMVPMatrix = new float[16]; // VP * M
private final float[] foregroundColor = {1f, 1f, 1f, 1f};
private final float[] backgroundColor = {0f, 0f, 0f, 1f};
private static final int COORDS_PER_VERTEX = 3;
private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private final float[] points = {
-20, -20, 0,
-20, 20, 0,
20, -20, 0,
20, 20, 0
};
private final short[] drawOrder = {
0, 1, 2, 3
};
private final FloatBuffer vertexBuffer = buildFloatBuffer(points);
private final ShortBuffer drawListBuffer = buildShortBuffer(drawOrder);
private static FloatBuffer buildFloatBuffer(float[] array) {
FloatBuffer buffer = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
array.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(array)
;
buffer.position(0);
return buffer;
}
private static ShortBuffer buildShortBuffer(short[] array) {
ShortBuffer buffer = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
array.length * 2)
.order(ByteOrder.nativeOrder())
.asShortBuffer()
.put(array)
;
buffer.position(0);
return buffer;
}
private static final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private static final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], backgroundColor[3]);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
ratio = 1f * width / height;
GLES20.glViewport(0, 0, width, height);
Matrix.frustumM(mPMatrix, 0, -ratio * SCALE/2, ratio * SCALE/2, -SCALE/2, SCALE/2, 3, 7);
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0, 0, 0, 0, -1, 0);
Matrix.multiplyMM(mVPMatrix, 0, mPMatrix, 0, mVMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glUniform4fv(mColorHandle, 1, foregroundColor, 0);
draw(0, 0, 0);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
private void draw(float x, float y, float a) {
Matrix.setIdentityM(mMMatrix, 0);
Matrix.translateM(mMMatrix, 0, x, y, 0);
Matrix.rotateM(mMMatrix, 0, a, 0, 0, 1);
Matrix.multiplyMM(mMVPMatrix, 0, mVPMatrix, 0, mMMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false, VERTEX_STRIDE,
vertexBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,
drawListBuffer.capacity(), GLES20.GL_UNSIGNED_SHORT,
drawListBuffer);
}
}
}
driver 可能有问题。您可以联系 driver 公司并提交错误报告
问自己以下问题:
- phone 有不同的 driver 吗?它支持 OpenGL ES 2.0 吗?
- GL操作是否成功?即 glGetError() 曾经 non-zero?
- glClearColor 成功了吗?尝试将颜色清除为红色。你看到红屏了吗?
- 程序是否编译成功?
如果我将 Matrix.frustumM()
调用更改为 Matrix.orthoM()
,问题就会消失。除此之外,我仍然不确定为什么某些设备可以正常工作,而其他设备却不行。如果有人能更好地理解这里发生的事情,我愿意接受另一个答案,但现在我已经解决了我的问题。