微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

渲染多个网格相同的 VBO+ 相同 EBO 中的所有索引OpenGL

如何解决渲染多个网格相同的 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 文件加载的数据,它很好。我还检查了合并的顶点数据和合并的索引数据......它就在那里。但是我的网格并不全都在屏幕上:((我启用了线框模式,所以我可以更好地想象问题)

Partially rendered model using glDrawElements

如果我尝试对合并的顶点数据调用 glDrawArrays,则一切正常:

Fully rendered model using glDrawArrays

此时,组合的顶点和索引数组都注册了 57174 个元素的大小。 OpenGL 是否不可能在内部将索引偏移正确映射到顶点数据并正确渲染?如果我为每个网格使用一个 VBO + EBO,那么一切都很好,所以我知道我收到的数据没有损坏(进一步由合并顶点数据上的 glDrawArrays 证明)。我一直在阅读和尝试各种解决方案,但没有任何效果......几乎在我的智慧尽头。真的很感激一些帮助!谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。