Vulkan中应用顶点索引

59 阅读2分钟

我们目前还未用索引缓冲呢。vertices向量包含许多重复的顶点数据,因为许多顶点是被包含在很多三角形中的。我们应该保存独一无二的顶点并使用索引缓冲来重用它们。有个比较直白的方法就是使用map或者unordered_map来保存这些独立顶点和各自的索引:

#include <unordered_map>
...
std::unordered_map<Vertex, uint32_t> uniqueVertices = {};
 
for (const auto& shape : shapes) {
    for (const auto& index : shape.mesh.indices) {
        Vertex vertex = {};
 
        ...
 
        if (uniqueVertices.count(vertex) == 0) {
            uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
            vertices.push_back(vertex);
        }
 
        indices.push_back(uniqueVertices[vertex]);
    }
}

每次我们从OBJ文件读取一个顶点,我们就检查是否已经看到过一样位置一样贴图坐标的顶点。如果没有就添加到vertices并存储其索引到uniqueVertices容器。之后我们添加新顶点的索引到indices。如果我们看到过一样的顶点,我们就找到它在uniqueVertices中的索引并存储到indices

现在程序还无法运行,因为我们使用用户自定义类型的结构体作为哈希表的key需要实现两个方法:相等性测试和哈希计算。前者容易实现,就是在Vertex结构体中重写==运算符:

bool operator==(const Vertex& other) const {
    return pos == other.pos && color == other.color && texCoord == other.texCoord;
}

Vertex的哈希方法需要指定std::hash模板明细来实现。哈希方法是个复杂的话题,推荐用下面的方法创建较好质量的哈希方法:

namespace std {
    template<> struct hash<Vertex> {
        size_t operator()(Vertex const& vertex) const {
            return ((hash<glm::vec3>()(vertex.pos) ^
                (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
                (hash<glm::vec2>()(vertex.texCoord) << 1);
        }
    };
}

这段代码放在Vertex之外,哈希方法使用要包含头文件:

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>

哈希方法是在gtx目录定义的,意味着它是实验性的,因此要定义GLM_ENABLE_EXPERIMENTAL来使用。

现在可以成功运行程序了,如果你检查了vertices大小,会发现它从一百五十万降低到了26万。这意味着每个顶点是被大约6个三角形重用的,这极大减少了GPU内存消耗。 ————————————————

原文链接:blog.csdn.net/u012911347/… 转载授权请联系原作者