我有很多来自好奇号漫游车上立体摄像机的3D模型,它们在火星上行驶。这些模型是从磁盘上同时异步加载多个模型的。现在,我需要将这些模型异步上传到GPU(在运行时),以防止渲染循环停滞不前。

现在上传模型的方式:

glGenVertexArrays(1, &_vaoID);
glGenBuffers(1, &_vbo);
glGenBuffers(1, &_ibo);

glBindVertexArray(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(Vertex), _vertices.data(), GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
    reinterpret_cast<const GLvoid*>(offsetof(Vertex, location)));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
    reinterpret_cast<const GLvoid*>(offsetof(Vertex, tex)));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
    reinterpret_cast<const GLvoid*>(offsetof(Vertex, normal)));

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size() * sizeof(int), _indices.data(), GL_STATIC_DRAW);

glBindVertexArray(0);

以及渲染方式:
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glDrawElements(_mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

现在,我每次在renderloop中将大约20个模型上载到GPU(当有模型从磁盘加载并准备上载到GPU时),而且这种方法的运行方式很多,应用程序停顿大约50-400ms,具体取决于模型的顶点/法线/索引的数量。

由于每个模型具有随机数量的顶点/法线/索引,并且需要连接到一个特定的纹理,因此VBO之间的Ping poning(更新一个,从一个读取)可能无法在当前管道中使用。

我正在寻找提高性能的任何解决方案。

编辑1

我现在已经成功创建了指向我的VBO和IBO的指针,但是我困惑于当缓冲区返回主线程时应该如何取消映射。我的第一个想法是像这样分别取消映射VBO和IBO:
`
for (int i = 0; i < _vertices.size(); i++) {
    _vertexBufferData[i] = _vertices.at(i);
}
glUnmapBuffer(GL_ARRAY_BUFFER);

for (int k = 0; k < _indices.size(); k++) {
    _indexBufferData[k] = _indices.at(k);
}
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);

但是我收到一条错误消息,说该缓冲区已经取消绑定(bind)或未映射。我是否只需要做第一个取消映射?

最佳答案

您描述的问题称为Buffer Object Streaming

简而言之,假设您触发了一个必须加载特定模型的触发器。然后:

  • 按照您的描述创建VAO和VBO,但尚未加载任何数据。为此,请使用glBufferStorage
  • 将缓冲区映射到您的内存中,并启动线程以用数据填充该缓冲区。该线程将完成所有耗时的磁盘I / O和映射内存区域的填充。
  • 工作线程完成后,通知主线程。
  • 在主线程中,一旦收到通知,请取消映射缓冲区并将VAO标记为已加载,以进行后续渲染。

  • 显然,在1和4之间,您的主线程将继续照常进行渲染,而不会渲染该未决的VAO。

    09-04 16:09
    查看更多