我们目前还未用索引缓冲呢。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/… 转载授权请联系原作者