解析Wavefront OBJ文件格式

3

我希望将obj模型导入我的OpenGL程序中。我有一个类/数据格式,用于将属性数据传递到着色器:

class CustomVertex : public IVtxFmt
{
public:
  float m_Position[3];      // x, y, z      offset 0, size = 3*sizeof(float)    
  float m_Normal[3];        // nx, ny, nz;  offset 3
  float m_TexCoords[2];     // u, v         offset 6
  float m_Colour[4];        // r, g, b, a   offset 8
  float m_Tangent[3];       // r, g, b      offset 12
  float m_Bitangent[3];     // r, g, b      offset 15
};

我正在使用从互联网下载的一个小木屋模型进行工作。

这个小木屋有许多顶点、法线和纹理坐标定义,后面是一系列面的定义。

于是我的第一个想法是解析OBJ文件,最终得到:

vector<vertex>
vector<Normal>
vector<TexCoord>

这并不容易转换成我的CustomVertex格式,因为文件中可能定义了210个顶点、100个纹理坐标和80个法线。

在这种格式下,列表中有约390个面:

f 83/42/1 67/46/1 210/42/1 

我在文件中遇到了以下问题:
#
# object tile00
#

接下来是更多的顶点定义。

因此,我推断一个模型可能由几个子对象组成,每个子对象由若干个面定义;每个面由3个顶点/法线/纹理坐标索引值定义。

因此,为了得到一个CustomVertex向量,我认为需要执行以下操作:

创建并填充:

vector <vertex>
vector <normal>
vector <texcoord>

vector <indices>

我需要为面定义中的每个唯一的v/vn/vt三元组创建一个CustomVertex。
所以我考虑创建一个映射表:
std::vector<CustomVertex> and
std::map< nHashId, CustomVertex_index >

所以我的想法是,对于我遇到的每个v/vn/vt,我都会创建一个这个字符串的哈希值,例如nHashId = hash("80/50/1")*,并在映射中搜索该哈希值。如果不存在,则创建一个CustomVertex并将其添加到向量中,然后将新创建的哈希和CustomVertex_index添加到映射中。
*: 通过创建v/vn/vt字符串的哈希值,我正在创建一个与该字符串对应的唯一数字值,我希望在映射中比等效文本更快地进行搜索/比较。
如果我找到哈希的匹配项,则认为customvertex已经存在,而不是创建新的CustomVertex,我只需将CustomVertex_index条目添加到indices向量中并继续前进。
由于这似乎是一个计算上昂贵的练习,我猜我会将我的CustomVertex数组(和相应的indices数组)转储到磁盘上以供稍后检索,而不是每次解析obj文件。
在我提出问题之前,我可以指出,由于时间限制并且不想重新设计我的Vbo类(一个非常重要的任务),我被困在了CustomVertex格式中 - 我知道可以将属性分别提供给我的着色器,但我已经阅读过像我所拥有的CustomVertex一样交错数据可以增强性能。
那么我的问题是: 1.我的方法听起来合理还是疯狂?如果疯狂,请指出我错在哪里。
  1. 您能发现任何潜在问题吗?
  2. 有人做过这个并且可以推荐更简单的方法来实现我正在尝试的内容吗?

2
如果你可以对某个东西进行哈希,为什么不直接使用unordered_map呢?否则,你的方法看起来很好,也不会过于复杂。 - pmr
通过创建v/vn/vt字符串的哈希值,我创建了一个唯一的数字值,对应于该字符串,我希望在映射中搜索/比较比等效文本更快。 - fishfood
@lapin:这就是所谓的“过早优化”。只需比较索引(作为数字,而不是文本)。如果您的分析显示它很慢,请在那时解决它。 - Nicol Bolas
1
考虑到数据一开始就是字符串格式,并且需要比较所有3个索引,我并不确定使用字符串作为映射键是否是一个坏主意。但是如果你真的想创建一个整数哈希,我会从索引中创建那个哈希而不是字符串。我同意上面的评论,你应该从任何朴素版本开始,必要时再进行优化。 - JasonD
2个回答

0

不要创建“v/vn/vt”的字符串哈希,而是将v作为整数进行哈希。然后,您会得到一个包含所有共享相同v索引的“v/vn/vt”组合的桶。

如果发生哈希冲突(遇到相同的v),则应将冲突的组合与桶中的组合进行比较,以查看是否真的重复。如果不是,请记得将冲突的组合添加到桶中。


0
你能发现任何潜在问题吗?
除了哈希碰撞,你想说什么?因为我没有看到你的算法处理这个问题。
有人以前做过这个并可以推荐一个更简单的方式来达到我尝试的目标吗?
有一个更简单的方法:只需比较索引而不使用哈希。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接