【问题标题】:How do I properly update a vertex array in OpenGL Es 2.0?如何在 OpenGL Es 2.0 中正确更新顶点数组?
【发布时间】:2012-09-22 01:06:20
【问题描述】:

当我在 OpenGL 2.0 中更新 iOS 上的顶点数组时,原始顶点数据保留在屏幕上 - 即第一次刷新是持久的(我发送到 GPU 的初始点集每帧都会渲染),但是第 2 次、第 3 次、第 4 次、第 n 次刷新似乎都覆盖了相同的内存。

所以我在做:

vector<VertexType> rawDynamicData ;

glGenVertexArraysOES( 1, &va ) ;        CHECK_GL ;
glBindVertexArrayOES( va ) ;            CHECK_GL ;
glGenBuffers( 1, &vb ) ;                CHECK_GL ;
glBindBuffer( GL_ARRAY_BUFFER, vb ) ;   CHECK_GL ;

glBufferData( glBufferData(
  GL_ARRAY_BUFFER, //Specifies the target buffer object.
  rawDynamicData.size() * sizeof( VertexType ),
  &rawDynamicData[0],
  GL_DYNAMIC_DRAW  // I plan to update the data every frame
) ;  CHECK_GL ; 

在随后的帧中,我只是再次调用:

// update the data
glBufferData( glBufferData(
  GL_ARRAY_BUFFER, //Specifies the target buffer object.
  rawDynamicData.size() * sizeof( VertexType ),
  &rawDynamicData[0],
  GL_DYNAMIC_DRAW  // I plan to update the data every frame
) ;  CHECK_GL ; 

我也试过

//update the data
GLvoid* vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES); 
memcpy(vbo_buffer, &rawDynamicData[0], rawDynamicData.size()*sizeof(VertexType) );
glUnmapBufferOES(GL_ARRAY_BUFFER); 

但是两种方式,我都明白了:

白点是初始数据,红点是后续调用glBufferData的结果

所以这个问题有几个部分关于 OpenGL ES 2.0 中的动态 vbo:

  1. 创建动态顶点缓冲区的正确命令顺序是什么?其元素将在每一帧上完全更新

  2. 顶点缓冲区能否在帧之间增长?还是我必须刷新完全相同的大小?

  3. 我知道使用“客户端内存”指针,您可以在 OpenGL ES 2.0 中执行此操作(以避免 memcpy)还是已弃用,应仅使用顶点缓冲区?

【问题讨论】:

  • 赏金疯狂!

标签: ios opengl-es-2.0 vertex-buffer


【解决方案1】:

失火 #1

我发现an answer here 指向我使用glSubBufferData 来存放数组中的数据,而glBufferData 仅用于初始分配。最终这不起作用(如果 vb 太大,只会更新前 3 个元素),

所以,

glBufferData( glBufferData(
  GL_ARRAY_BUFFER, //Specifies the target buffer object.
  rawDynamicData.size() * sizeof( VertexType ),
  0, // NO INITIAL DATA
  GL_DYNAMIC_DRAW  // I plan to update the data every frame
) ;  CHECK_GL ; 

那么对于第一个后续更新:

// Update the whole buffer
glBufferSubData(GL_ARRAY_BUFFER, 0,
  rawDynamicData.size()*sizeof(VertexType), &rawDynamicData[0]) ;

这似乎行得通。

似乎。但它没有。

我唯一能做的就是退出使用顶点缓冲区并使用客户端内存顶点数组

如下所示:

// do all your vertex attrib/glVertexAttrib enable commands:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPC), &debugPoints->data[0].pos.x) ;
CHECK_GL ;
glEnableVertexAttribArray(0);  CHECK_GL ;

// ..do glVertexAttrib* for all attributes you have..

// then just flush your draw command
glDrawArrays(GL_POINTS, 0, debugPoints->data.size());  

简而言之,我发现将顶点缓冲区用于动态数据要么具有挑战性不支持。

【讨论】:

  • 你有没有想过这个问题?我遇到了同样的问题,它似乎有效,但没有。
  • 没有。但是顶点数组工作得非常好,它们非常快(可能是因为在 iOS 上,内存实际上是在 GPU 和 CPU 之间共享​​>)。我想看看 VB 与 VA 的性能测试。
  • 好吧,不幸的是,我一直回到这个问题。看了一个多月。你有没有遇到过任何问题,如果你操纵(变换)你的对象,它就会被毁容。我猜这是因为数组已更改,因此您尝试应用的转换没有所有正确的数据。你对如何解决这个问题有什么建议吗?
  • 我现在唯一使用 VB 的地方是模型只加载一次,之后就再也不会改变了。它们在转换下表现良好,您只是无法更改 实际顶点数据 而不会发生一些奇怪的事情。对于可变形几何体,我使用only 顶点数组。在绘制顶点数组之前,请务必使用如下行禁用顶点缓冲区: glBindBuffer( GL_ARRAY_BUFFER, 0 ) ; // DISABLE THE STUPID VERTEX BUFFER RAT POISON。我之前也被那个绊倒了。
  • 哦,看,3 个月后不幸在谷歌上找到了同样的答案。啊。我真的不认为有一种干净的方法可以动态更新顶点数组。
【解决方案2】:

对于那里的 Android 用户,我刚刚确认可以在 Android 上的 OpenGL ES 2.0 中使用顶点属性数组生成可变形几何体,并进行了一些测试。烦人的事情是您不能将指针传递给您自己的数组,而是必须使用 FloatBuffer(或类似类型)。示例代码:

初始化:

    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(
            // (number of coordinate values * 4 bytes per float)
            coords.length * 4);
    // use the device hardware's native byte order
    bb.order(ByteOrder.nativeOrder());

    // create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    // add the coordinates to the FloatBuffer
    vertexBuffer.put(coords);
    // set the buffer to read the first coordinate
    vertexBuffer.position(0);

绘图代码:

    // get handle to vertex shader's vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    checkGlError("glGetAttribLocation");

    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    checkGlError("glEnableVertexAttribArray");

    float newValue = (float) Math.sin((float) (frame++) / 1000) + 1;
    System.out.println(newValue);

    vertexBuffer.put(0, newValue);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, VERTEX_STRIDE, vertexBuffer);

【讨论】:

  • @juzzlin 你是说GLES20 在该设备上可用,但并非所有方法都受支持?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 1970-01-01
  • 2012-02-12
相关资源
最近更新 更多