2016-10-26 91 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系統正在使像動畫一樣的現實生活成爲可能。