OpenGL顶点缓冲对象,我能否访问顶点数据以进行其他用途,例如碰撞检测?

7

我目前正在使用Superbible第五版附带的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个回答

8

缓冲区对象在作为顶点数据源时存在是为了渲染的好处。从性能角度来看,反向读取数据通常不可取。

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

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

请注意,没有“读和写”的提示。只有“写”,“读”和“都不是”。考虑到将数据直接写入缓冲区然后开始从该缓冲区读取的好主意程度,这是一个提示。

再次强调,这些提示是针对用户直接获取或检索数据的。glBufferData、glBufferSubData 和各种映射函数都进行写入,而 glGetBufferSubData 和映射函数都进行读取。

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

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

但是,如果你坚持这样做,有两种方法可以从缓冲区对象中读取数据。glGetBufferSubData 是 glBufferSubData 的反向操作。并且你总是可以将缓冲区映射为读取而不是写入。


1
谢谢!那个回答非常有帮助!我会保留pVert指针以便稍后访问顶点数据。 - kbirk
@user785259:仅保留指针是不够的。实际上,您必须保留已分配的内存,即不要使用delete[]free(...)释放它。即使在释放内存后,您仍然可能在C中拥有指针,那么该指针就无效了。也许您来自一个垃圾收集语言,那么丢弃指针实际上意味着释放内存,是的,这是合理的语义。但是,您正在处理的是C ++,所有这些吹毛求疵都是不可避免的必要性。 - datenwolf

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