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

GLSurfaceView onDrawFrame中glBufferSubData修改顶点丢失问题

问题:GLSurfaceView Native层修改顶点缓冲区导致点丢失

问题描述

使用GLSurfaceView通过Native代码绘制三个点,原本运行正常,但在onDrawFrame中调用glBufferSubData修改点位置时,第一个点丢失,使用glMapBufferRange也存在同样问题。

原代码

Java层Renderer代码

private static class Renderer implements GLSurfaceView.Renderer {

    private final GLSurfaceView glSurfaceView;

    private Renderer(GLSurfaceView glSurfaceView) {
        this.glSurfaceView = glSurfaceView;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        NativeMethod.nSurfaceCreated(glSurfaceView.getContext().getAssets());
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        NativeMethod.nSurfaceChanged(width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        NativeMethod.nDrawFrame();
    }
}

Native层初始代码

JNIEXPORT void JNICALL
Java_xxx_NativeMethod_nSurfaceCreated(JNIEnv *env, jclass clazz, jobject asset_manager) {
    renderer = create_program_from_assets(env, asset_manager, "vertex_shader.glsl", "fragment_shader.glsl");

    glUseProgram(renderer);
    glClearColor(1.0F, 1.0F, 1.0F, 1.0F);

    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);

    glGenBuffers(1, vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vao[0]); // 错误行
    float vertices[] = {
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            0.0f, 0.5f, 0.0f
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void *) 0);
    glEnableVertexAttribArray(0);
}

JNIEXPORT void JNICALL
Java_xxx_NativeMethod_nSurfaceChanged(JNIEnv *env, jclass clazz, jint width, jint height) {
    glViewport(0, 0, width, height);
}

JNIEXPORT void JNICALL
Java_xxx_NativeMethod_nDrawFrame(JNIEnv *env, jclass clazz) {
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_POINTS, 0, 3);
}

修改后出现问题的nDrawFrame代码

JNIEXPORT void JNICALL
Java_xxx_NativeMethod_nDrawFrame(JNIEnv *env, jclass clazz) {
    glClear(GL_COLOR_BUFFER_BIT);
    float vertex_fr[] = {0.0F, 0.0F, 10.0F};
    glBufferSubData(GL_ARRAY_BUFFER, 0 , sizeof(vertex_fr), vertex_fr);
    glDrawArrays(GL_POINTS, 0, 3);
}

问题原因及修复方案

1. 致命错误:绑定VBO时误用VAO的ID

在nSurfaceCreated中,glBindBuffer(GL_ARRAY_BUFFER, vao[0]);这一行错误地将VAO(顶点数组对象)的ID传给了glBindBuffer,正确的参数应该是生成的VBO(顶点缓冲区对象)ID vbo[0]。VAO不是缓冲区对象,绑定错误的ID会导致后续所有缓冲区操作都指向无效对象,修改的数据根本没写入正确的VBO。

修复该行:

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // 替换为vbo[0]

2. 顶点Z值超出裁剪空间范围

修改后的顶点Z值为10.0f,而默认OpenGL裁剪空间的Z范围是[-1.0, 1.0],该点会被裁剪掉,导致看起来“丢失”。需要将Z值调整到有效范围内,比如0.0f:

float vertex_fr[] = {0.0F, 0.0F, 0.0F};

3. 确保绘制时绑定正确的VAO

虽然VAO会记录绑定的VBO状态,但在onDrawFrame中最好显式绑定目标VAO,避免上下文状态被意外修改:

JNIEXPORT void JNICALL
Java_xxx_NativeMethod_nDrawFrame(JNIEnv *env, jclass clazz) {
    glClear(GL_COLOR_BUFFER_BIT);
    glBindVertexArray(vao[0]); // 显式绑定正确的VAO
    float vertex_fr[] = {0.0F, 0.0F, 0.0F};
    glBufferSubData(GL_ARRAY_BUFFER, 0 , sizeof(vertex_fr), vertex_fr);
    glDrawArrays(GL_POINTS, 0, 3);
}

总结

问题并非无法在onDrawFrame中修改缓冲区,而是Native代码存在两处关键错误:绑定VBO时用错了ID,以及顶点Z值超出裁剪范围。修正后即可正常修改顶点位置。

内容的提问来源于stack exchange,提问作者L. Swifter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:33:24