You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

OpenGL渲染位图无显示问题求助(附MyGLSurfaceView代码)

OpenGL 位图无法显示问题排查与修复建议

我看了你贴的MyGLSurfaceView代码,目前这里的配置没什么明显问题——你正确初始化了OpenGL ES 2.0上下文,设置了渲染器并开启了按需渲染模式。不过因为你没贴完整的MyGLRenderer代码,大概率问题出在渲染器的位图加载、纹理绑定或者绘制逻辑上。下面给你梳理几个关键排查方向,还有一个可参考的示例代码:

关键排查点

  • 位图加载与纹理创建是否正确

    • 确保你在onSurfaceCreated(或合适的时机)用BitmapFactory.decodeResource正确加载了位图,检查资源ID是否正确、资源是否存在于res/drawable目录下。
    • 创建纹理时,必须调用glGenTextures生成纹理ID,然后用glBindTexture绑定,再通过glTexParameteri设置纹理过滤和环绕参数,最后用GLUtils.texImage2D把位图数据传入纹理。任何一步出错都会导致纹理无效。
  • 着色器程序是否正常工作

    • 顶点着色器需要传递顶点位置和纹理坐标到片段着色器,片段着色器要使用texture2D函数正确采样纹理。
    • 一定要检查着色器编译和程序链接状态:编译后用glGetShaderiv获取GL_COMPILE_STATUS,链接后用glGetProgramiv获取GL_LINK_STATUS,避免语法错误导致着色器失效。
  • 绘制流程是否完整

    • onDrawFrame中要先清除颜色缓冲区(glClear(GL_COLOR_BUFFER_BIT)),然后绑定纹理、启用顶点属性、设置顶点/纹理坐标,最后调用glDrawArraysglDrawElements绘制矩形(覆盖屏幕的两个三角形)。
    • 别忘了激活纹理单元(glActiveTexture(GL_TEXTURE0))并把纹理ID传递给片段着色器的sampler2D uniform变量。

参考示例Renderer代码

public class MyGLRenderer implements GLSurfaceView.Renderer {
    private Context mContext;
    private int mTextureId;
    private FloatBuffer mVertexBuffer;
    private FloatBuffer mTexCoordBuffer;
    private int mProgram;

    // 屏幕坐标系顶点(覆盖全屏的矩形)
    private static final float[] VERTEX_DATA = {
            -1.0f, 1.0f,
            -1.0f, -1.0f,
            1.0f, 1.0f,
            1.0f, -1.0f
    };

    // 对应纹理的坐标
    private static final float[] TEX_COORD_DATA = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f
    };

    private static final String VERTEX_SHADER =
            "attribute vec4 aPosition;\n" +
            "attribute vec2 aTexCoord;\n" +
            "varying vec2 vTexCoord;\n" +
            "void main() {\n" +
            "    gl_Position = aPosition;\n" +
            "    vTexCoord = aTexCoord;\n" +
            "}";

    private static final String FRAGMENT_SHADER =
            "precision mediump float;\n" +
            "varying vec2 vTexCoord;\n" +
            "uniform sampler2D uTexture;\n" +
            "void main() {\n" +
            "    gl_FragColor = texture2D(uTexture, vTexCoord);\n" +
            "}";

    public MyGLRenderer(Context context) {
        mContext = context;
        // 初始化顶点和纹理坐标缓冲区(必须用native字节序)
        mVertexBuffer = ByteBuffer.allocateDirect(VERTEX_DATA.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(VERTEX_DATA);
        mVertexBuffer.position(0);

        mTexCoordBuffer = ByteBuffer.allocateDirect(TEX_COORD_DATA.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(TEX_COORD_DATA);
        mTexCoordBuffer.position(0);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 设置清屏颜色为黑色
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        // 编译并链接着色器程序
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER);

        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);
        GLES20.glLinkProgram(mProgram);

        // 加载位图并创建纹理
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.your_bitmap);
        mTextureId = createTexture(bitmap);
        bitmap.recycle(); // 释放位图内存
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 设置视口大小为屏幕尺寸
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // 清除颜色缓冲区
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        // 使用当前着色器程序
        GLES20.glUseProgram(mProgram);

        // 获取着色器中的属性和Uniform位置
        int aPositionLoc = GLES20.glGetAttribLocation(mProgram, "aPosition");
        int aTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
        int uTextureLoc = GLES20.glGetUniformLocation(mProgram, "uTexture");

        // 启用顶点属性数组
        GLES20.glEnableVertexAttribArray(aPositionLoc);
        GLES20.glEnableVertexAttribArray(aTexCoordLoc);

        // 设置顶点坐标数据
        GLES20.glVertexAttribPointer(aPositionLoc, 2, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
        // 设置纹理坐标数据
        GLES20.glVertexAttribPointer(aTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, mTexCoordBuffer);

        // 激活纹理单元并绑定纹理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
        // 告诉着色器使用纹理单元0
        GLES20.glUniform1i(uTextureLoc, 0);

        // 绘制矩形(用TRIANGLE_STRIP模式,4个顶点)
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        // 禁用顶点属性数组
        GLES20.glDisableVertexAttribArray(aPositionLoc);
        GLES20.glDisableVertexAttribArray(aTexCoordLoc);
    }

    // 编译着色器的工具方法
    private int loadShader(int type, String shaderCode) {
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        // 检查编译错误
        int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
        if (compileStatus[0] == 0) {
            Log.e("GLRenderer", "Shader compile failed: " + GLES20.glGetShaderInfoLog(shader));
            GLES20.glDeleteShader(shader);
            return 0;
        }
        return shader;
    }

    // 创建纹理的工具方法
    private int createTexture(Bitmap bitmap) {
        int[] textureIds = new int[1];
        GLES20.glGenTextures(1, textureIds, 0);
        int textureId = textureIds[0];

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        // 设置纹理过滤参数,避免拉伸时出现锯齿
        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);
        // 设置纹理环绕模式,避免纹理坐标超出范围时出错
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        // 将位图数据上传到纹理
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        return textureId;
    }
}

你可以把自己的Renderer代码和这个示例对比,重点检查纹理创建、着色器逻辑和绘制流程这几个部分。如果还是不行,可以把完整的Renderer代码贴出来,我再帮你定位具体问题。

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

火山引擎 最新活动