You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL ES中应用投影与相机视图后无法渲染三角形的问题求助

解决OpenGL ES中投影与相机视图导致三角形不显示的问题

从你的描述来看,核心问题确实出在矩阵变换的配置上——当你直接使用原始顶点坐标时三角形能正常显示,说明顶点数据、着色器编译链接、绘制流程本身是没问题的,只是矩阵把三角形"移出"了可视区域。下面一步步拆解问题并给出修复方案:

1. 最关键的问题:投影矩阵的ratio未正确初始化

你在onSurfaceCreated中计算projectionMatrix时用到了ratio,但这个变量没有赋值!而且你提到onSurfaceChanged从未被调用,而ratio(宽高比)必须基于Surface的实际尺寸计算才能生成正确的投影矩阵。如果ratio是默认值(比如0),Matrix.frustumM会生成一个x轴被压缩到0的投影矩阵,直接把三角形"挤没了"。

修复:把投影矩阵计算移到onSurfaceChanged中

onSurfaceChanged是专门用来处理Surface尺寸变化的回调,必须在这里计算宽高比和投影矩阵:

override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
    // 设置视口匹配Surface尺寸
    GLES20.glViewport(0, 0, width, height)
    // 计算正确的宽高比
    val ratio = width.toFloat() / height.toFloat()
    // 生成投影矩阵,调整near值让三角形处于可视范围内
    Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 1f, 10f)
}

同时要确保你的GLSurfaceView配置正确(比如在Activity中正确初始化、设置Renderer),这样onSurfaceChanged才会被触发。

2. 相机位置与裁剪平面的冲突

你当前的相机配置是:

Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)

这表示相机位于(0,0,-3),看向原点(0,0,0)。而你之前的frustumM设置near=3f,意味着近裁剪平面在相机前方3单位(相机空间的z=3),而三角形刚好在原点,处于近裁剪平面的边界上,很可能被OpenGL的裁剪机制过滤掉了。

修复:调整相机位置或裁剪平面范围

两种可选方案:

  • 方案A:移动相机位置:把相机移到(0,0,3),看向原点,这样原点在相机前方3单位,设置near=1f就能让三角形处于可视范围内:
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
  • 方案B:缩小near值:保持相机位置不变,把near改为1f,让近裁剪平面在相机前方1单位,这样原点(相机前方3单位)就处于1f-7f的可视区间内。

3. 优化draw函数的性能(可选但推荐)

你当前的draw函数每次都会调用glGetAttribLocation和glGetUniformLocation,这些查询操作比较耗时,应该把它们移到Triangle的初始化阶段,避免重复查询:

class Triangle {
    private lateinit var mProgram: Int
    private var positionHandle: Int = 0
    private var mColorHandle: Int = 0
    private var vPMatrixHandle: Int = 0
    // 其他成员变量...

    init {
        // 编译、链接顶点/片段着色器,得到mProgram
        // ...
        // 一次性获取所有句柄
        positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
        vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix")
    }

    fun draw(mvpMatrix: FloatArray) {
        GLES20.glUseProgram(mProgram)
        
        // 启用顶点属性数组并传递数据
        GLES20.glEnableVertexAttribArray(positionHandle)
        GLES20.glVertexAttribPointer(
            positionHandle,
            COORDS_PER_VERTEX,
            GLES20.GL_FLOAT,
            false,
            vertexStride,
            vertexBuffer
        )
        
        // 设置颜色和变换矩阵
        GLES20.glUniform4fv(mColorHandle, 1, color, 0)
        GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0)
        
        // 绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)
        
        GLES20.glDisableVertexAttribArray(positionHandle)
    }
}

验证步骤

  1. 先确认onSurfaceChanged被正常调用,可以在方法内添加日志打印宽高值。
  2. 检查ratio是否为正确的宽高比(比如竖屏时小于1,横屏时大于1)。
  3. 逐步恢复矩阵变换,确认三角形是否能正常显示。

内容的提问来源于stack exchange,提问作者beokay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:17:48