如何解决渲染多个网格相同的 VBO+ 相同 EBO 中的所有索引OpenGL
我试图通过将所有顶点数据存储在同一个 VBO 中来最小化 GPU 上的内存碎片。 使用 Assimp 解析 .obj 节点并提取所有网格数据后,我分配了两个大缓冲区,可以包含所有内容并将所有内容转储到其中(一个顶点数组和另一个索引数组)。使用 glDrawArrays 可以很好地呈现所有数据,但这不是我想要获得的结果。
struct vertex_data
{
glm::vec3 Position;
glm::vec3 normal;
glm::vec2 TexCoords;
};
uint32_t TotalVertices = 0;
uint32_t TotalIndices = 0;
uint32_t TotalMeshes = Model->NextMeshToLoad;
if (TotalMeshes != 0)
{
for (uint32_t MeshOffset = 0;
MeshOffset < TotalMeshes;
++MeshOffset)
{
mesh *Mesh = Model->Meshes + MeshOffset;
uint32_t MeshTotalVertices = Mesh->NextVertexData;
uint32_t MeshTotalIndices = Mesh->NextIndice;
TotalVertices += MeshTotalVertices;
TotalIndices += MeshTotalIndices;
}
vertex_data *CombinedVertexData = PushArray(Arena,TotalVertices,vertex_data);
uint32_t *Combinedindices = PushArray(Arena,TotalIndices,uint32_t);
uint32_t CombinedVertexDataOffset = 0;
uint32_t CombinedindicesOffset = 0;
for (uint32_t MeshOffset = 0;
MeshOffset < TotalMeshes;
++MeshOffset)
{
mesh *Mesh = Model->Meshes + MeshOffset;
uint32_t MeshTotalVertices = Mesh->NextVertexData;
memcpy_s(CombinedVertexData + CombinedVertexDataOffset,TotalVertices * sizeof(vertex_data),Mesh->VertexData,MeshTotalVertices * sizeof(vertex_data));
CombinedVertexDataOffset += MeshTotalVertices;
uint32_t MeshTotalIndices = Mesh->NextIndice;
memcpy_s(Combinedindices + CombinedindicesOffset,TotalIndices * sizeof(uint32_t),Mesh->Indices,MeshTotalIndices * sizeof(uint32_t));
CombinedindicesOffset += MeshTotalIndices;
}
Model->CombinedVertexData = CombinedVertexData;
Model->CombinedindicesData = Combinedindices;
Model->CombinedVertexDataSize = TotalVertices;
Model->CombinedindicesDataSize = TotalIndices;
Model->DataStatus = model_data_status::PENDING_UPLOAD;
Model->NextMeshToLoad 存储下一个可以存储网格的空数组位置。它还表示存储网格的当前大小 - 不要与为数组分配的最大大小混淆。
Mesh->NextVertexData 和 Mesh->NextIndice 的工作方式相同,但对于每个网格的一部分。
将数据上传到 GPU:
if (Model->DataStatus == model_data_status::PENDING_UPLOAD)
{
glGenVertexArrays(1,&Model->VertexArrayObject);
glGenBuffers(1,&Model->VertexBufferObject);
glGenBuffers(1,&Model->ElementBufferObject);
glBindVertexArray(Model->VertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER,Model->VertexBufferObject);
glBufferData(GL_ARRAY_BUFFER,Model->CombinedVertexDataSize * sizeof(vertex_data),Model->CombinedVertexData,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,Model->ElementBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,Model->CombinedindicesDataSize * sizeof(uint32_t),&Model->CombinedindicesData[0],GL_STATIC_DRAW);
glEnabLevertexAttribArray(0);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(vertex_data),0);
glEnabLevertexAttribArray(1);
glVertexAttribPointer(1,(void *)(sizeof(glm::vec3)));
glEnabLevertexAttribArray(2);
glVertexAttribPointer(2,2,(void *)(2 * sizeof(glm::vec3)));
glBindVertexArray(0);
}
问题是每个网格都有不同/单独的材料。这迫使我为每个网格发出单独的绘制调用(需要设置不同的统一属性 + 绑定不同的纹理)。我部分知道每个网格的顶点和索引大小,所以我想我可以只调用 glDrawElements 并使用第 4 个参数作为 ELEMENT_ARRAY_BUFFER 的偏移量:
glBindVertexArray(Model->VertexArrayObject);
uint32_t IndicesOffset = 0;
uint32_t MeshesSize = Model->NextMeshToLoad;
for (uint32_t MeshIndex = 0;
MeshIndex < MeshesSize;
++MeshIndex)
{
mesh *Mesh = Model->Meshes + MeshIndex;
uint32_t IndicesDataSize = Mesh->NextIndice;
glDrawElements(GL_TRIANGLES,IndicesDataSize,GL_UNSIGNED_INT,(void *)(IndicesOffset * sizeof(uint32_t)));
IndicesOffset += Mesh->NextIndice;
}
glBindVertexArray(0);
不幸的是,这似乎不起作用...我的数据仅部分呈现,我无法理解为什么会发生这种情况。我检查了从 .obj 文件加载的数据,它很好。我还检查了合并的顶点数据和合并的索引数据......它就在那里。但是我的网格并不全都在屏幕上:((我启用了线框模式,所以我可以更好地想象问题)
如果我尝试对合并的顶点数据调用 glDrawArrays,则一切正常:
此时,组合的顶点和索引数组都注册了 57174 个元素的大小。 OpenGL 是否不可能在内部将索引偏移正确映射到顶点数据并正确渲染?如果我为每个网格使用一个 VBO + EBO,那么一切都很好,所以我知道我收到的数据没有损坏(进一步由合并顶点数据上的 glDrawArrays 证明)。我一直在阅读和尝试各种解决方案,但没有任何效果......几乎在我的智慧尽头。真的很感激一些帮助!谢谢!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。