OpenGL顶点缓冲区对象,我可以访问顶点数据以用于其他用途,例如碰撞检测吗?

Posted

技术标签:

【中文标题】OpenGL顶点缓冲区对象,我可以访问顶点数据以用于其他用途,例如碰撞检测吗?【英文标题】:OpenGL Vertex buffer object, can I access the vertex data for other uses such as collision detection? 【发布时间】:2011-09-19 04:35:23 【问题描述】:

我目前正在使用 Superbible 第 5 版附带的 GLTools 类。我正在查看 GLTriangleBatch 类,它有以下代码:

// Create the master vertex array object
glGenVertexArrays(1, &vertexArrayBufferObject);
glBindVertexArray(vertexArrayBufferObject);


// Create the buffer objects
glGenBuffers(4, bufferObjects);

#define VERTEX_DATA     0
#define NORMAL_DATA     1
#define TEXTURE_DATA    2
#define INDEX_DATA      3

// Copy data to video memory
// Vertex data
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[VERTEX_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pVerts, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, 0);

// Normal data
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[NORMAL_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_NORMAL);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pNorms, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_NORMAL, 3, GL_FLOAT, GL_FALSE, 0, 0);

// Texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[TEXTURE_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*2, pTexCoords, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_TEXTURE0, 2, GL_FLOAT, GL_FALSE, 0, 0);

// Indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[INDEX_DATA]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*nNumIndexes, pIndexes, GL_STATIC_DRAW);

// Done
glBindVertexArray(0);

// Free older, larger arrays
delete [] pIndexes;
delete [] pVerts;
delete [] pNorms;
delete [] pTexCoords;

// Reasign pointers so they are marked as unused
pIndexes = NULL;
pVerts = NULL;
pNorms = NULL;
pTexCoords = NULL;

据我了解,代码传递指针 pVerts、pNorms、pTexCoords、pIndexes 的数组并将它们存储在顶点数组对象中,该对象本质上是顶点缓冲区对象的数组。这些存储在 GPU 的内存中。然后删除原始指针。

我有兴趣访问顶点位置,它们保存在 pVert 指向的数组中。

现在我的问题围绕着碰撞检测。我希望能够访问我的 GLTriangleBatch 的所有顶点的数组。我可以稍后使用某种 getter 方法通过vertexBufferObject 获取它们吗?最好只保留 pVerts 指针并为此使用 getter 方法吗?我在考虑性能方面,因为我希望将来实现一个 GJK 碰撞检测算法......

【问题讨论】:

【参考方案1】:

缓冲区对象在用作顶点数据的来源时,是为了渲染的利益而存在的。从性能的角度来看,向后(读回数据)通常是不可取的。

你给 glBufferData 的提示有三种访问模式:DRAW、READ 和 COPY;这些告诉 OpenGL 你打算如何直接从缓冲区对象获取/检索数据。这些提示并不支配 OpenGL 应该如何读取/写入它。这些只是提示; API 不强制执行任何特定行为,但违反它们可能会导致性能不佳。

DRAW 表示您将数据放入缓冲区,但不会从中读取。 READ 意味着您将从缓冲区读取数据,但不会写入(通常用于变换反馈或像素缓冲区)。而 COPY 意味着您既不会直接读取缓冲区,也不会直接写入缓冲区。

请注意,没有“读写”的提示。只有“写”、“读”和“都没有”。考虑一下直接将数据写入缓冲区然后开始从该缓冲区读取的想法。

同样,提示适用于用户直接获取或检索数据。 glBufferDataglBufferSubData 和各种映射函数都是写的,而glGetBufferSubData 和映射函数都是读的。

无论如何不,你不应该这样做。如果您需要在客户端上使用位置数据,请在客户端内存中保留一份位置数据的副本。

此外,一些驱动程序完全忽略了使用提示。相反,他们根据您实际使用它的方式来决定放置缓冲区对象的位置,而不是您说您打算如何使用它。这对您来说会更糟,因为如果您开始从该缓冲区读取,驱动程序可能会将缓冲区的数据移动到速度不那么快的内存中。它可能会被移出 GPU 甚至进入客户端内存空间。

但是,如果您坚持这样做,有两种方法可以从缓冲区对象中读取数据。 glGetBufferSubDataglBufferSubData 的倒数。而且您始终可以将缓冲区映射为读取而不是写入。

【讨论】:

谢谢!那个回复很有帮助!我将保留 pVert 指针以便稍后访问顶点数据。 @user785259:只保留指针是不够的。您实际上必须保留分配的内存,即不是delete[]free(...) 它。即使在释放内存之后,您可能仍然拥有 C 中的指针,这也是无效的。也许您来自垃圾收集语言,然后丢弃指针实际上意味着释放内存,是的,这是理智的语义。但这是您正在处理的 C++,所有这些挑剔都是不可避免的必要性。

以上是关于OpenGL顶点缓冲区对象,我可以访问顶点数据以用于其他用途,例如碰撞检测吗?的主要内容,如果未能解决你的问题,请参考以下文章

iOS OpenGL ES 2.0 VBO 顶点数限制:一旦超过,CPU 受限

顶点缓冲区对象(删除进程)opengl

OpenGL复制顶点缓冲区对象

使用统一缓冲区对象进行批量渲染

OpenGL顶点数组对象不记录VBO和IBO绑定

在OpenGL中,除非我再次重新指定顶点属性,否则为啥我的缓冲区对象不会绘制?