OpenGL 顶点缓冲区对象,我可以访问顶点数据以用于其他用途(例如碰撞检测)吗?
我目前正在使用 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 的数组并将它们存储在 Vertex 数组对象中,该对象本质上是一个顶点数组缓冲对象。它们存储在 GPU 的内存中。然后删除原始指针。
我有兴趣访问保存在 pVert 指向的数组中的顶点位置。
现在我的问题围绕碰撞检测。我希望能够访问 GLTriangleBatch 的所有顶点的数组。我可以稍后使用某种 getter 方法通过 vertexBufferObject
获取它们吗?最好保留 pVerts 指针并使用 getter 方法来代替吗?我正在考虑性能方面,因为我希望将来实现 GJK 碰撞检测算法......
I'm currently using the GLTools classes that come along with the Superbible 5th edition. I'm looking in the GLTriangleBatch class and it has the following code:
// 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;
From what I understand the code passes the arrays that the pointers pVerts, pNorms, pTexCoords, pIndexes and stores them in a Vertex array object, which essentially is an array of vertex buffer objects. These are stored in memory on the GPU. The original pointers are then deleted.
I'm interested in accessing the vertex positions, which were held in the array pVert pointed to.
Now my question revolves around collision detection. I want to be able to access an array of all of the vertices of my GLTriangleBatch. Can I obtain them through the vertexBufferObject
at a later time using some sort of getter method? Would it be best to just keep the pVerts pointer around and use a getter method for that instead? I'm thinking in terms of performance, as I hope to implement a GJK collision detection algorithm in the future...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当用作顶点数据源时,缓冲区对象的存在是为了渲染的好处。从性能的角度来看,向后(读回数据)通常是不可取的。
您给出的 glBufferData 提示具有三种访问模式:DRAW、READ 和 COPY;这些告诉 OpenGL 你打算如何直接从缓冲区对象获取/检索数据。这些提示并不控制 OpenGL 应如何读取/写入它。这些只是提示;该 API 不强制执行任何特定行为,但违反这些行为可能会导致性能不佳。
DRAW 意味着您将把数据放入缓冲区,但不会从中读取数据。 READ 意味着您将从缓冲区读取数据,但不会写入数据(通常用于变换反馈或像素缓冲区)。 COPY 意味着您既不会直接从缓冲区读取也不会直接写入缓冲区。
请注意,没有“读和写”的提示。只有“写”、“读”和“都不写”。考虑一下直接将数据写入缓冲区然后开始从该缓冲区读取的想法是多么好的一个提示。
同样,提示是为了用户直接获取或检索数据。
glBufferData
、glBufferSubData
和各种映射函数都执行写入操作,而glGetBufferSubData
和映射函数都执行读取操作。无论如何,不,你不应该这样做。如果需要在客户端上使用位置数据,请在客户端内存中保留一份位置数据的副本。
此外,某些驱动程序完全忽略使用提示。相反,他们根据您实际使用它的方式来决定将缓冲区对象放置在哪里,而不是根据您所说的打算使用它的方式来决定。这对您来说会更糟,因为如果您开始从该缓冲区读取数据,驱动程序可能会将缓冲区的数据移动到速度不那么快的内存中。它可能会移出 GPU,甚至移入客户端内存空间。
但是,如果您坚持这样做,有两种方法可以从缓冲区对象读取数据。
glGetBufferSubData
是glBufferSubData
的逆。并且您始终可以映射缓冲区以进行读取而不是写入。Buffer objects, when used as sources for vertex data, exist for the benefit of rendering. Going backwards (reading the data back) is generally not advisable from a performance point of view.
The hint you give glBufferData has three access patterns: DRAW, READ, and COPY; these tell OpenGL how you intend to be getting/retrieving data from the buffer object directly. The hints do not govern how OpenGL should be reading/writing from/to it. These are just hints; the API doesn't enforce any particular behavior, but violating them may lead to poor performance.
DRAW means that you will put data into the buffer, but you will not read from it. READ means that you will read data from the buffer, but you will not write to it (typically for transform feedback or pixel buffers). And COPY means that you will neither read from nor write to the buffer directly.
Notice that there is no hint for "read and write." There is just "write", "read", and "neither." Consider that a hint as to how good of an idea it is to write data to a buffer directly and then start reading from that buffer.
Again, the hints are for the user directly getting or retrieving data.
glBufferData
,glBufferSubData
, and the various mapping functions all do writes, whileglGetBufferSubData
and mapping functions all do reads.In any case no, you should not do this. Keep a copy of the position data around in client memory if you need to use it on the client.
Also, some drivers ignore the usage hints entirely. They instead decide where to place the buffer object based on how you actually use it, rather than how you say you intend to use it. This will be worse for you, because if you start reading from that buffer, the driver may move the buffer's data to memory that is not as fast. It may be moved out of the GPU and even into the client memory space.
However, if you insist on doing this, there are two ways to read data from a buffer object.
glGetBufferSubData
is the inverse ofglBufferSubData
. And you can always map the buffer for reading instead of writing.