交错排列的VBO导致glDrawArrays()错误

3

我最近将我的应用程序从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()调用的最后一个参数显然指向数据而不是偏移量。我错过了什么?我认为这段代码并不特别复杂,所以我只能想到我在某个地方犯了一个愚蠢的错误。

谢谢

2个回答

4
问题已解决:

我的代码有一些问题,其中并非所有问题都可以从问题列表中看出。我将概述主要问题:

  • 在未列出的代码中,我正在创建VBOs(Vertex Buffer Objects)的实用程序函数。在此函数中,我错误地传递了缓冲区的GLuint句柄(我试图在返回void的函数中通过引用传递它)。为了使其更易读,我将该函数更改为仅初始化其自己的句柄并返回它。这停止了程序在glDrawArrays()行崩溃(可能尚未初始化的值必须已经分配给其他缓冲区)。

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

  • 每次绘制调用后没有取消绑定VBOs。每帧首先绘制背景纹理,然后绘制VBOs的内容。通过保留VBOs绑定到下一个背景渲染,我显然导致了OGL的一些困扰!这不仅是黑屏的原因,也是绘制调用之间大的延迟的原因。

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


0
你可能需要使用glDrawElements而不是glDrawArrays。因为glDrawArrays不允许跳跃或跳过。它从一组连续的顶点中读取。
"glDrawArrays()从启用的数组中读取顶点数据,直接穿过数组而不跳过或跳跃。因为glDrawArrays()不允许在顶点数组周围跳跃,所以你仍然需要为每个面重复共享的顶点。"

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


我不需要在数据中跳跃或跳过。我正在渲染点精灵,所以我只需要让glDrawArrays()遍历我的连续顶点数据即可。 - Stuart
此外,我应该补充说,我成功地将苹果的GLES2Sample示例应用程序适配为使用VBO,方式与我在这里尝试的方式非常相似。 - Stuart
我相信你已经将顶点数据以结构体的形式保存了。这意味着顶点数据在内存中并不是连续存在的。每个顶点数据之间都有一个 sizeof(ISPointSpriteData) 的间隔。你试过使用 glDrawElements 吗? - Ramya Maithreyi
我不太确定你的意思,抱歉。数据是交错的,并且结构中的所有数据都在着色器中使用。因此,在每组顶点数据的开头之间有一个sizeof(ISPointSpriteData)的间隙,但是在其中的所有数据都是必需的,并且由glDrawArrays()读取。我认为。抱歉,我对内存的真正低级理解不是很好。顺便说一句,我尝试过glDrawElements,但它并没有影响我的问题。 - Stuart
今天我一直在尝试各种方法,最终解决了这个问题。除此之外,我还没有在绘制调用后解除绑定VBOs。我已经在另一个答案中发布了完整的解释。非常感谢你的帮助。 - Stuart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接