模型中的顶点重复消除

时间:2016-10-26 08:00:26

标签: c++ opengl hash

当以.obj格式导入模型时,许多多边形共享顶点,因此徒劳地消耗内存,我想要做的是仅通过保存唯一顶点来删除重复项。

哈希顶点

/// Template specialization for hashing of a Vec3
namespace std {
template<typename T>
struct hash<Vec3<T>> {
    void hash_combine(size_t &seed, const size_t &hash) const {
        seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }

    size_t operator() (const Vec3<T> &vec) const {
        auto hasher = hash<float>{};
        auto hashed_x = hasher(vertex.position.x);
        auto hashed_y = hasher(vertex.position.y);
        auto hashed_z = hasher(vertex.position.z);
        auto hashed_color_r = hasher(vertex.color.r);
        auto hashed_color_g = hasher(vertex.color.g);
        auto hashed_color_b = hasher(vertex.color.b);
        auto hashed_color_a = hasher(vertex.color.a);
        auto hashed_texcoord_x = hasher(vertex.texCoord.x);
        auto hashed_texcoord_y = hasher(vertex.texCoord.y);
        auto hashed_normal_x = hasher(vertex.normal.x);
        auto hashed_normal_y = hasher(vertex.normal.y);
        auto hashed_normal_z = hasher(vertex.normal.z);

        size_t seed = 0;
        hash_combine(seed, hashed_x);
        hash_combine(seed, hashed_y);
        hash_combine(seed, hashed_z);
        hash_combine(seed, hashed_texcoord_x);
        hash_combine(seed, hashed_texcoord_y);
        hash_combine(seed, hashed_normal_x);
        hash_combine(seed, hashed_normal_y);
        hash_combine(seed, hashed_normal_z);
        return seed;
    }
};
}

使用tinyobjcloader导入网格

Mesh Renderer::load_mesh_from_file(std::string filepath) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
auto success = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filepath.c_str());
if (!success) { SDL_Log("Failed loading mesh %s: %s", filepath.c_str(), err.c_str()); return Mesh(); }

std::unordered_map<Vertex<float>, size_t> unique_vertices{};
Mesh mesh{};
for (auto shape : shapes) { // Shapes
    size_t index_offset = 0;
    for (auto face : shape.mesh.num_face_vertices) { // Faces (polygon)
        for (auto v = 0; v < face; v++) {
            tinyobj::index_t idx = shape.mesh.indices[index_offset + v];
            Vertex<float> vertex{};
            float vx = attrib.vertices[3 * idx.vertex_index + 0];
            float vy = attrib.vertices[3 * idx.vertex_index + 1];
            float vz = attrib.vertices[3 * idx.vertex_index + 2];
            vertex.position = {vx, vy, vz};

            float tx = attrib.vertices[3 * idx.texcoord_index + 0];
            float ty = attrib.vertices[3 * idx.texcoord_index + 1];
            vertex.texCoord = {tx, ty};

            float nx = attrib.normals[3 * idx.normal_index + 0];
            float ny = attrib.normals[3 * idx.normal_index + 1];
            float nz = attrib.normals[3 * idx.normal_index + 2];
            vertex.normal = {nx, ny, nz};

            // These two lines work just fine (includes all vertices)
            // mesh.vertices.push_back(vertex);
            // mesh.indices.push_back(mesh.indices.size());

            // Check for unique vertices, models will contain duplicates
            if (unique_vertices.count(vertex) == 0) {
                unique_vertices[vertex] = mesh.indices.size();
                mesh.vertices.push_back(vertex);
                mesh.indices.push_back(mesh.indices.size());
            } else {
                mesh.indices.push_back(unique_vertices.at(vertex));
            }
        }
        index_offset += face;
    }
}

SDL_Log("Number of vertices: %lu for model %s", mesh.vertices.size(), filepath.c_str());
return mesh;
}

第一张图片是包含所有顶点的时间。

enter image description here

这是我只使用唯一顶点的时候。

enter image description here

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

从显示的图像中,它似乎是一个三角形顶点参考问题。

通常,obj format会收集一个唯一顶点列表,每个三角形只是一组与其三个顶点对应的三个索引。让我们假设,由于某种原因,你确实有顶点A和顶点B的重复,你决定消除顶点B.在这种情况下,你需要修改包含B的所有三角形的引用,并用A代替它们。 / p>

答案 1 :(得分:1)

if(unique_vertices.count(vertex)== 0){

unique_vertices [vertex] = mesh。顶点 .size();

mesh.indices.push_back(目的顶点 .size());

mesh.vertices.push_back(顶点);

}

说明:索引是&#34;指针&#34;到顶点位置。为此,您需要获取编写顶点数据的索引,而不是索引数据的索引。

答案 2 :(得分:0)

消除重复坐标不是一个好主意。例如,在网格之间的缝合区域中重复坐标以形成闭合的3D网格结构。在3D游戏中,采用低多边形网格结构以实现快速渲染,但除非另有说明,否则处理这些点云不再是一个大问题,因为强大的GPU和多核CPU系统正在使现实生活变得像现在这样的动画。 / p>