使用glOrthof在Android OpenGL ES 2中居中矩形崩溃求助
问题分析与解决方案
崩溃核心原因
- 着色器变量类型错误:将投影矩阵
u_Projection定义为attribute,但它属于全局统一的uniform变量,attribute是每个顶点独有的属性,类型不匹配会导致OpenGL内部状态异常,引发崩溃。 - 错误使用固定管线函数:
glOrthof是OpenGL 1.x固定管线的函数,OpenGL ES 2.0为可编程管线,无法通过该函数直接生成矩阵到你定义的projectionMatrix数组中,导致数组始终为初始全0值,传递给着色器后触发内存访问错误。 - Uniform设置时机与矩阵未初始化:
projectionMatrix数组未被填充有效矩阵数据,且glUniformMatrix4fv在onSurfaceChanged中调用时,可能程序尚未完成链接,后续绘制也未重新设置矩阵。
修复步骤
1. 修正顶点着色器变量类型
将attribute mat4 u_Projection改为uniform mat4 u_Projection,投影矩阵是所有顶点共用的全局参数:
attribute vec4 a_Position; uniform mat4 u_Projection; // 修正为uniform类型 void main(){ gl_Position = u_Projection * a_Position; }
2. 使用Android矩阵工具生成正交投影矩阵
替换glOrthof为Android提供的Matrix.orthoM方法,正确填充projectionMatrix数组,同时调整矩阵范围让矩形居中显示:
@Override public void onSurfaceChanged(GL10 gl10, int width, int height) { glViewport(0, 0, width, height); float rectWidth = 9f; float rectHeight = 14f; float aspectRatio = (float) width / height; // 以矩形中心为原点,计算初始边界 float left = -rectWidth / 2f; float right = rectWidth / 2f; float bottom = -rectHeight / 2f; float top = rectHeight / 2f; // 适配屏幕宽高比,保持矩形比例不变且居中 if (aspectRatio > rectWidth / rectHeight) { float scale = aspectRatio / (rectWidth / rectHeight); left *= scale; right *= scale; } else { float scale = (rectWidth / rectHeight) / aspectRatio; bottom *= scale; top *= scale; } // 生成正交投影矩阵到数组中 Matrix.orthoM(projectionMatrix, 0, left, right, bottom, top, -1f, 1f); // 获取uniform变量位置(确保program已链接完成) projectionMatrixLocation = glGetUniformLocation(program, U_PROJECTION); }
3. 在绘制流程中设置Uniform矩阵
将glUniformMatrix4fv移到onDrawFrame中,确保每次绘制前参数正确:
@Override public void onDrawFrame(GL10 gl10) { glClear(GL_COLOR_BUFFER_BIT); // 设置投影矩阵uniform glUniformMatrix4fv(projectionMatrixLocation, 1, false, projectionMatrix, 0); // 执行原有矩形绘制逻辑... }
4. 可选:调整顶点坐标到中心原点
如果不想修改投影矩阵范围,可直接将顶点坐标改为以矩形中心为原点,简化后续矩阵计算:
private float[] tableVerticesWithTriangles = { // Triangle 1 -4.5f, -7f, 4.5f, 7f, -4.5f, 7f, // Triangle 2 -4.5f, -7f, 4.5f, -7f, 4.5f, 7f };
对应的正交矩阵可简化为适配屏幕的标准范围:
Matrix.orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);
关键说明
- OpenGL ES 2.0中,
uniform用于传递全局不变参数(如矩阵、颜色),attribute用于传递每个顶点独有数据(如位置、纹理坐标),类型不可混用。 - 可编程管线中,所有矩阵需手动计算或通过工具类生成,无法依赖固定管线函数。
- Uniform变量需在绘制前设置,确保每次绘制时参数有效。
内容的提问来源于stack exchange,提问作者Quim PerVal
相关产品推荐
相关产品推荐

