Android OpenGL ES每帧更新VBO数据

时间:2016-11-05 14:58:20

标签: android opengl-es

每帧更新VBO数据的最佳方法是什么?目前我在每帧调用glBufferData并使用null后使用glBufferSubData,并且我不能达到超过25fps而不会出现奇怪的口吃。

我的主要目标是以50fps的速度在两张图像之间切换。

以下是一些代码:

public void onDrawFrame(GL10 glUnused) {
    endTime = System.currentTimeMillis();
    dt = endTime - startTime;
    if (dt < 20)
        try {
            Thread.sleep(20 - dt);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    startTime = System.currentTimeMillis();

    ...some matrix operations

    render();
}

void render() {
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, floatbuffer.capacity() * BYTES_PER_FLOAT,
                    null, GLES20.GL_STREAM_DRAW);

    ...a bunch of if statements

   if(side==1) {
       GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, floatbuffer.capacity() * BYTES_PER_FLOAT,floatbuffer);
       side = 0;
    } else {
       GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, floatbuffer2.capacity() * BYTES_PER_FLOAT, floatbuffer2);
       side = 1;
    }

    GLES20.glVertexAttribPointer(positionAttribute, POSITION_DATA_SIZE_IN_ELEMENTS, GLES20.GL_FLOAT, false, STRIDE, 0);
    GLES20.glEnableVertexAttribArray(positionAttribute);

    GLES20.glVertexAttribPointer(colorAttribute, COLOR_DATA_SIZE_IN_ELEMENTS, GLES20.GL_FLOAT, false, STRIDE, (POSITION_DATA_SIZE_IN_ELEMENTS) * BYTES_PER_FLOAT);
    GLES20.glEnableVertexAttribArray(colorAttribute);

    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
    GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_SHORT, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}

我还尝试设置多个vbo,每个都有自己的数据,这些数据不会改变,并且在我想要显示的vbo上调用glBindBuffer,我仍然注意到这种口吃。

我对OpenGL有点新意,所以我不清楚最好的方法。我知道将数据从CPU传输到GPU可能存在瓶颈。有没有更有效的方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

值得注意的是,几乎所有Android平台都使用vsync将最终帧缓冲区扫描锁定到显示控制器更新频率的某个倍数,以避免在扫描输出期间撕掉输出。

通常显示器将是60FPS面板,因此您需要每16.6 ms从应用程序中获取一次新的更新。如果你错过了一个vsync截止日期(你可以保证20分钟的休眠时间),那么你至少会得到一些小的口吃,其中一个帧必须显示多个帧以桥接输入帧序列中的间隙。应用程序无法控制哪个帧重复,因此您无法提前更正。

如果您的应用程序是,例如,45FPS,那么您将在显示控制器上看到最终输出帧序列,看起来像1,1,2,3,3,4,5,5,6等。 (例如,显示器必须每1/60秒扫描一帧,然后运行最新的帧)。显示时间与应用程序正在使用的第二步的确切1/45不匹配,因此这将在视觉上抖动输出动画。

唯一真正的解决方法是在面板扫描输出时间的多倍上发射帧(例如60FPS = 16.6ms,30FPS = 33.3ms,20FPS = 50ms)。