交错的 VBO 导致 glDrawArrays() 错误

Posted

技术标签:

【中文标题】交错的 VBO 导致 glDrawArrays() 错误【英文标题】:Interleaved VBO causing glDrawArrays() error 【发布时间】:2011-04-18 05:31:31 【问题描述】:

我最近将我的应用程序从使用 OpenGL ES 1.1 更改为 2.0,在此过程中,我决定使用 VBO 进一步优化我的代码。我认为我必须掌握与 ES 2.0 的主要区别,并且结果表明我在没有 VBO 的情况下正确地做事,但是我被一个问题难住了,这个问题只有在我尝试使用 VBO 时才会出现.

我使用一个包含顶点位置、颜色和大小的自定义结构(加上一点填充来对齐数据),然后在 VBO 中交错这个顶点数据。该数据用于渲染点精灵。问题是我在 glDrawArrays() 调用上得到了 EXC_BAD_ACCESS。这个错误的回溯如下:

#0  0x31fc7358 in gleRunVertexSubmitARM ()
#1  0x31fc87b2 in gleLLVMArrayFunc ()
#2  0x31fc872a in gleSetVertexArrayFunc ()
#3  0x31fbefcc in gleDrawArraysOrElements_ExecCore ()
#4  0x31fc4608 in glDrawArrays_IMM_Exec ()
#5  0x36ddaee2 in glDrawArrays ()
#6  0x0001cab8 in -[Renderer renderDrawingVertexBuffer:withSize:usingTexture:] (self=0x1783b0, _cmd=0x50fec, vboID=0, size=3584, drawTexture=5) at /Users/Stu/Documents/...
#7  0x000202f4 in -[EAGLView drawSmoothCurveFromPoints:endOfLine:] (self=0x195be0, _cmd=0x50d34, points=0x1956f0, endOfLine=1 '\001') at /Users/Stu/Documents/...
#8  0x0001e50c in -[EAGLView drawView:] (self=0x195be0, _cmd=0x50d8a, sender=0x0) at /Users/Stu/Documents/...
#9  0x0001e174 in -[EAGLView layoutSubviews] (self=0x195be0, _cmd=0x3297d4ac) at /Users/Stu/Documents/...
#10 0x326805fa in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#11 0x35efbf02 in -[NSObject(NSObject) performSelector:withObject:] ()
#12 0x333fbbb4 in -[CALayer layoutSublayers] ()
#13 0x333fb96c in CALayerLayoutIfNeeded ()

这是存储顶点数据的结构:

typedef struct 
    ISVertex2D vertex;     // Made up of 2 GLfloats.
    ISColor    color;      // Made up of 4 GLfloats.
    GLfloat    size;
    GLfloat    padding;
 ISPointSpriteData;

将一组数据存储在这些结构的数组中后,将数据发送到 VBO 并使用 glDrawArrays() 进行渲染:

[renderer prepareScene];
[renderer renderBackground];

glBindBuffer(GL_ARRAY_BUFFER, penVbo);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(ISPointSpriteData) * penVboSize, sizeof(ISPointSpriteData) * vertexCount, &vertexBuffer[0].vertex);

glBindTexture(GL_TEXTURE_2D, drawTexture);

glEnableVertexAttribArray(ATTRIB_VERTEX);
glEnableVertexAttribArray(ATTRIB_COLOR);
glEnableVertexAttribArray(ATTRIB_SIZE);
glDisableVertexAttribArray(ATTRIB_TEXTURE_COORD);
glUniform1i(uniforms[UNIFORM_IS_SPRITE], GL_TRUE);

glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(ISPointSpriteData), (void*)offsetof(ISPointSpriteData, vertex));
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(ISPointSpriteData), (void*)offsetof(ISPointSpriteData, color));
glVertexAttribPointer(ATTRIB_SIZE, 1, GL_FLOAT, GL_FALSE, sizeof(ISPointSpriteData), (void*)offsetof(ISPointSpriteData, size));

glDrawArrays(GL_POINTS, 0, vertexCount);     // <--- EXC_BAD_ACCESS

glDisableVertexAttribArray(ATTRIB_VERTEX);
glDisableVertexAttribArray(ATTRIB_COLOR);
glDisableVertexAttribArray(ATTRIB_SIZE);


[renderer presentScene];

这段代码在我放入 VBO 之前就可以工作,唯一的改变是 glVertexAttribPointer() 调用的最后一个参数显然指向数据而不是偏移量。我错过了什么?我不认为这段代码特别复杂,所以我只能认为我在某个地方犯了一个愚蠢的错误。

谢谢

【问题讨论】:

【参考方案1】:

问题已解决:

我的代码存在一些问题,问题中的列表中并非所有这些问题都显而易见。我将概述主要问题:

在未列出的代码中,我正在创建 效用函数中的 VBO。在 这个功能我错了 传递GLuint 句柄 缓冲区(我试图通过它 通过在一个函数中引用 返回无效)。为了利益 使这更具可读性我改变了 简单地初始化它的函数 自己的句柄并返回它。这 停止程序在 glDrawArrays() 行(大概是 未初始化的值必须已经有 被分配到另一个缓冲区 某处)。

出现了一个新问题 - 屏幕被绘制为黑色,并且绘制调用之间存在很大的延迟。这是由于...

之后不解除绑定 VBO 每个绘图调用。对于每一帧 首先绘制背景纹理, 其次是 VBO 的内容。 通过让 VBO 前往 下一个背景渲染,我是 明显导致OGL有点 适合!这不仅仅是原因 黑屏的,也是大的 绘制调用之间的延迟。

希望这对处于类似情况的其他人有所帮助!

【讨论】:

【参考方案2】:

您可能必须使用 glDrawElements 而不是 glDrawArrays。因为 glDrawArrays 不允许跳跃或跳过。它从一组连续的顶点中读取。

“glDrawArrays() 通过直接穿过数组而不跳过或跳跃来从启用的数组中读取顶点数据。因为 glDrawArrays() 不允许在顶点数组周围跳跃,所以您仍然必须在每个面上重复一次共享顶点。 "

http://www.songho.ca/opengl/gl_vertexarray.html

【讨论】:

我不需要跳转或跳过数据。我正在渲染点精灵,所以我只需要 glDrawArrays() 来遍历我的连续顶点数据。 此外,我应该补充一点,我成功地调整了 Apple 的 GLES2Sample 示例应用程序,以与我在这里尝试的方式大致相同的方式使用 VBO。 我相信你有结构格式的顶点数据。这意味着顶点数据不会连续存在于内存中。每个顶点数据都存在一个 sizeof(ISPointSpriteData) 间隙。你试过 glDrawElements 了吗? 我不完全确定您的意思,抱歉。数据是交错的,结构中的所有数据都在着色器中使用。因此,在每组顶点数据的开始之间存在 sizeof(ISPointSpriteData) 的差距,但我认为之间的所有数据都是必需的并由 glDrawArrays() 读取。抱歉,我对记忆的理解水平很低。顺便说一句,我确实尝试了 glDrawElements,它并没有影响我的问题。 我今天玩了很多东西,我解决了这个问题。除其他事项外,我并没有在 draw call 之后解除绑定 VBO。我在单独的答案中发布了完整的解释。非常感谢您的帮助。

以上是关于交错的 VBO 导致 glDrawArrays() 错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 glDrawArrays() 时如何获取 VBO 的长度以渲染所有顶点?

调用 glDrawArrays() 时的 OpenGL VBO Segfault

OpenGL 3.3 - glDrawArrays 后的无效操作错误 (1282)

使用 glDrawArrays 绘制多个模型

具有浮点和字节的交错式 VBO

VBO 中的交错是帮助还是阻碍性能?