顶点缓冲区未更新

时间:2017-01-21 14:22:16

标签: android opengl-es java-native-interface buffer-overflow

大家好我有一个用opengles绘制的立方体。 每次我调用重绘功能时,我都会使用此代码更新coordinate_buffer

floatBuffer.position(0);

floatBuffer.put(coordinates);
floatBuffer.position(0);

问题在于,在不同的设备上(大多数设备都有api版本22或更高版本),第一个元素没有更新,因此我可以看到在第一个元素停留在第一个位置时移动的其余顶点。 另一个问题是,当我放置坐标时,有时会发生java.nio.BufferOverflowException。我认为错误仍然存​​在于这些被称为60次的代码行中。

非常感谢。

2 个答案:

答案 0 :(得分:0)

1)确保您提供正确偏移的绘制调用(glDrawArrays / glDrawElements)。
2)Buffer.put()和.get()方法根据传输的元素数量来增加位置。如果此类传输超出限制,Buffer.put()方法将返回BufferOverflowException。 确保您没有传递对于此缓冲区而言太大的数组。 此外,如果您只想在3D空间中移动整个对象,则使用矩阵计算顶点着色器中的最终顶点位置。

答案 1 :(得分:0)

嗯,除了 java.nio.BufferOverflowException 以外,我也遇到了类似的问题。我使用的OpenGL library非常易于使用,并具有许多预制的形状,例如:圆形,矩形,图像,三角形等。

我正在使用 Images 类在OnTouch事件中为多个图像生成新坐标,并且在
处出现了异常错误,看起来像是随机的 * updateBuffers()方法。

fun updateBuffers() {

    // init buffer for vertices
    var byteBuffer: ByteBuffer = ByteBuffer.allocateDirect(coordinatesOpenGL.size * 4)
    byteBuffer.order(ByteOrder.nativeOrder())
    vertexBuffer = byteBuffer.asFloatBuffer()
    vertexBuffer.put(coordinatesOpenGL)
    vertexBuffer.position(0)
     
    ...
}

一个明显的原因是,当我们使用数组 coordinatesOpenGL.size 的大小使用方法 ByteBuffer.allocateDirect()分配字节缓冲区的大小时,数组大小发生一些变化。在单线程环境中,这种情况不太可能发生,因此我当时的结论是,OpenGL表面线程之外还有另一个线程正在对该方法进行调用。

要确定是否是这种情况,我在方法中记录了当前线程的ID和名称,因此在调用它时会收到一条消息。这是记录当前线程的ID和名称的代码:

Log.i("msg", "${Thread.currentThread().id}  ${Thread.currentThread().name}")

然后在日志中,我看到主线程也在调用此方法,当多个线程同时调用它并且都对ByteBuffer进行了更改时,就会发生溢出错误。

2020-12-16 05:54:12.461 26477-26516/com.slaviboy.test I/msg: 3074  GLThread 3074
2020-12-16 05:54:13.383 26477-26516/com.slaviboy.test I/msg: 3074  GLThread 3074
2020-12-16 05:54:13.401 26477-26516/com.slaviboy.test I/msg: 3074  GLThread 3074
2020-12-16 05:54:14.080 26477-26516/com.slaviboy.test I/msg: 3074  GLThread 3074
2020-12-16 05:54:14.097 26477-26477/com.slaviboy.test I/msg: 2  main
2020-12-16 05:54:14.098 26477-26516/com.slaviboy.test I/msg: 3074  GLThread 3074
2020-12-16 05:54:14.116 26477-26516/com.slaviboy.test I/msg: 3074  GLThread 3074

然后我意识到,由于我在OnTouch事件中设置了图像的坐标,因此代码在主线程上运行,因此我不得不将代码包装并在OpenGL表面线程中执行。

这是我用于在OpenGL表面线程而不是主线程中运行代码的代码:

override fun onTouch(surfaceView: View, event: MotionEvent): Boolean {

    if (surfaceView is GLSurfaceView) {

       // run the code in the OpenGL surface thread
       surfaceView.queueEvent(Runnable {
           touch(event)
       })
    }

    return consumedTouchEvent
}

因此,如果遇到类似问题的问题,我想您首先检查是否有另一个线程进行相同的调用。