2016-10-26 64 views
1

以.obj格式导入模型时,很多多边形共享顶点并因此耗尽内存,我想要执行的操作是仅保存唯一顶点来删除重复项。与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; 
} 

第一图像顶点

/// 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; 
    } 
}; 
} 

导入网眼

散列是当包括所有顶点。

enter image description here

这一次,当我只使用独特的顶点是。

enter image description here

任何想法?

回答

1

如果(unique_vertices.count(顶点)== 0){

unique_vertices [顶点] =网格。 顶点 .size();

mesh.indices.push_back(mesh。vertices .size());

mesh.vertices.push_back(vertex);

}

说明:索引是指向顶点位置的“指针”。为此,您需要获取编写顶点数据的索引,而不是索引数据的索引。

+0

是!毕竟这是这个问题!难怪它没有检查,因为索引总是按顺序排列(0,1,2,...,n)。 – Entalpi

1

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

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

+0

嗯..我找不到任何规范说顶点*是必需的*是唯一的。 :/ – Entalpi

+0

他们不是,但一个明智的网格创建者不会重复(如果你有重复,冗余占用更多的空间)。但是,这可能会发生,例如,如果您的网格由al STL文件转换而来,该文件具有重复性。 – Nic

+0

@Entalpi有可能您的网格具有相同的顶点xyz但不同的texCoord。某些纹理可能具有跳转到顶点的坐标,这需要重复使用不同纹理坐标的相同坐标。但是这应该是很少见的,它不应该解释你得到的渲染差异。只有编码错误,我可以看到的是当你读取从u坐标复制粘贴的纹理v坐标。 –

0

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