【问题标题】:OpenGL ES 2.0: The most efficient setup for a VBO with GL_STREAM_DRAW?OpenGL ES 2.0:带有 GL_STREAM_DRAW 的 VBO 最有效的设置?
【发布时间】:2011-11-10 07:21:48
【问题描述】:

我在 OpenGL ES 2.0 中使用顶点缓冲区对象 (VBO)。

我有一组永久存储在普通 RAM 中的顶点数据。原因是从头开始计算顶点位置的成本很高,但可以在最后一个位置添加一个 delta 以廉价地更新它。

要绘制的实际顶点数会随着时间迅速变化。在一帧中我可能有 1000 个,在接下来的 2500 个中。根据之前收到的建议,我现在指定整数 UPPER 作为将要绘制的顶点数的上限。我malloc 我的顶点和索引数据数组仅在启动时基于此值一次。

我将GL_STREAM_DRAW 使用提示传递给每个glBindBuffer 调用,以指示数据每帧都发生变化。

为了尽可能提高效率,我创建了以下设置:

// SETUP: Called only once.
glBindBuffer(GL_ARRAY_BUFFER,...);
glBufferData(GL_ARRAY_BUFFER,...); // Pass vertex data for UPPER vertices.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,...); // Pass index values 0 - (UPPER-1).
glEnableVertexAttribArray(...); // Setup vertex attributes.
glVertexAttribPointer(...);
glUseProgram(...); // Use program with custom shaders.
glUniformMatrix4fv(...); // Identify shader uniforms.

// UPDATE: Called when vertex data changes (on each frame).
glBindBuffer(GL_ARRAY_BUFFER,...);
glBufferSubData(GL_ARRAY_BUFFER,...); // Update VBO data.

// RENDER: Called on each frame.
glDrawElements(GL_TRIANGLES, numberOfVerticesThisFrame, ...); // Number of vertices and indices to be used is inherently specified in here.

但是,这与 glDrawElements 上的 EXC_BAD_ACCESS 中断,我知道这是由于我订购了 gl 命令。

我之前有一个类似的设置,它有效:

// UPDATE: Called when vertex data changes (on each frame).
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,...); // Pass index values 0 - (actual number of vertices to draw - 1)

// RENDER: Called on each frame.
glBindBuffer(GL_ARRAY_BUFFER,...);
glBufferData(GL_ARRAY_BUFFER,...); // Pass vertex data for actual number of vertices (not UPPER).
glEnableVertexAttribArray(...); // Setup vertex attributes.
glVertexAttribPointer(...);
glUseProgram(...); // Use program with custom shaders.
glUniformMatrix4fv(...); // Identify shader uniforms.
glDrawElements(GL_TRIANGLES, numberOfVerticesThisFrame, ...);

但是,此设置每帧需要更多的工作,并且如您所见,涉及更改 VBO 大小(因为它使用实际大小,而不是 UPPER),我被告知这是一个很大的性能消耗。

谁能解释一下我的新设置有什么明显的问题,最重要的是我必须glDrawElements之前的每一帧都调用哪些命令?我假设我可以提前准备所有可能的索引,然后将实际的顶点数传递给glDrawElements,这显然是错误的。

【问题讨论】:

  • OpenGL ES 2.0: Commands required just before glDrawElements with VBO 的可能副本。尽管标题提出了一个完全不同的问题,但实际文本对性能或效率并不感兴趣。它问的是他昨天做的同样的问题。
  • 您应该在原始问题中添加该详细信息,而不是创建新问题。
  • 我几乎没有睡觉,心情不好,对此我深表歉意。公平地说,你的一些 cmets 听起来很粗鲁。尽管如此,您的回答让我解决了我的问题,对此我非常感激。谢谢。

标签: performance opengl-es opengl-es-2.0 vbo


【解决方案1】:

要回答您在问题标题中提出的问题,对于流式顶点数据没有“最有效”的缓冲区对象设置。尤其是在 ES 2.0 上,它涵盖了广泛范围的不同硬件,每个都有自己的特点。

要回答有关您的代码为何停止工作的问题,很可能是因为您不尊重这些函数的实际作用。

例如,glUseProgram 导致给定程序对象成为任何后续 glDraw* 调用将使用的程序对象直到您再次调用 glUseProgram 将大多数 OpenGL 函数视为戳在全局状态,因为它就是这样工作的。 glUseProgram 正在设置一个全局变量,glDraw* 读取该变量以找出要使用的着色器。

因此,如果您想确保特定的绘制调用使用特定的着色器,那么您必须事先立即glUseProgram 该着色器。或者至少最近足够你知道你没有在其他地方改变它。通常,对象的渲染如下所示:

  • 建立渲染对象的顶点属性。
  • 设置当前程序,并更改任何每个对象的统一(矩阵等)。
  • 为程序绑定纹理(如果有)。
  • 为程序绑定其他状态,如果有的话。
  • 渲染。
  • 停用属性

第一步使用glEnableVertexAttribArrayglBindBufferglVertexAttribPointer。这些函数,就像glUseProgram 设置global 状态一样。您应该在使用对象渲染后使用glDisableVertexAttribArray,并且应该取消绑定您可能使用过的任何缓冲区。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多