【问题标题】:Parsing a Wavefront .obj file using C++使用 C++ 解析 Wavefront .obj 文件
【发布时间】:2011-12-09 09:46:22
【问题描述】:

在尝试解析波前 .obj 文件时,我想到了两种方法:

  1. 创建一个顶点数大小的二维数组。当一个面使用一个顶点时,从数组中获取它的坐标。
  2. 获取顶点列表的起始位置,然后当人脸使用顶点时,扫描线直到到达顶点。

IMO,选项 1 将占用大量内存,但速度更快。 由于选项 2 涉及大量文件读取,(并且由于大多数对象中的顶点数量变得非常大),这将慢得多,但内存密集度较低。

问题是:比较内存和速度之间的权衡,哪个选项更适合普通计算机? 还有,有没有替代方法?

我打算使用 OpenGL 和 GLFW 来渲染对象。

【问题讨论】:

  • 虽然它只处理相当有限的子集,但您可能想看看我在previous answer 中发布的一些代码以获得灵感。

标签: c++ wavefront


【解决方案1】:

IMO,选项 1 将占用大量内存,但速度更快。

无论如何,您都必须将这些顶点放入内存。但是不需要二维数组,顺便说一句,这会导致两个指针间接,从而对性能造成重大影响。只需对您的数据使用简单的std::vector<Vertex>,向量索引就是随附人脸列表的索引。

因评论而编辑

class Vertex
{
    union { struct { float x, y, z }; float pos[3] };
    union { struct { float nx, ny, nz }; float normal[3] };
    union { struct { float s, t }; float pos[2] };
    Vertex &operator=();
}

std::vector<Vertex>;

【讨论】:

  • 但是如何存储 x、y 和 z 坐标?
【解决方案2】:

通常您将顶点列表读入数组。解析 ASCII 文本非常慢;加载文件时只执行一次,然后将所有内容存储在内存中的数组中。

三角形/面也是如此。每个三角形通常由三个顶点索引的列表组成。这也应该存储在一个数组中。

您可能会发现 VTK 开源库中的 OBJ 阅读器很有用:http://www.vtk.org/doc/nightly/html/classvtkOBJReader.html。我们使用它并且没有理由自己编写......直接使用VTK,或者您可能会发现研究源代码对您自己的读者有进一步的启发。

在我看来,OBJ 文件的主要缺点之一是使用 ASCII。由于字符串解析,如果 3D ASCII 文件(无论是 STL、PLY、OBJ 等)是 ASCII,则加载速度非常慢。二进制格式文件要快得多,如果性能存在问题,则应始终使用:良好二进制格式的加载时间是瞬时的。

【讨论】:

  • "一个好的二进制格式的加载时间是瞬时的。"您在哪里购买那些零寻道、无限带宽的磁盘驱动器?我也想要一些! :)
  • 也许我应该将其表述为“快几个数量级”。可以像磁盘驱动程序将文件内容复制到 RAM 中一样快地读取二进制文件。我们经常使用可以存储为 ASCII 或二进制文件的浮点数矩阵。对于相同的值/矩阵大小,二进制的加载/保存不到一秒钟,而 ASCII 的加载/保存需要半分钟。 (我们使用 C++ 文件流类来转换为/从 ASCII 转换)。 ASCII 格式仅用于调试....
  • (不只是我们;尝试在 MeshLab 中打开/保存 3D 文件并比较 ASCII 与二进制的性能。差异明显不同。)
  • +1 用于 VTK 参考。他们的OBJ 加载方法比我使用的方法简单 10 倍
【解决方案3】:

只需将它们加载到数组中。内存应该不是问题。您的系统(通常)拥有比 GPU 更多的内存。如果您遇到内存问题,您可能正在加载一个过于详细的模型。 (我半假设您将使用 OpenGL 制作游戏。如果您对如此大的模型文件有特殊需求,您仍然需要找到一种方法来加载适当的块。)

【讨论】:

    【解决方案4】:

    您不需要二维数组。你的模型应该是三角测量的,然后你可以简单地使用 gluts obj loader 加载 obj 文件。只需将点、面和法线存储在 3 个单独的数组/缓冲区中。有一个示例如何做到这一点here,但如果你想快速做到这一点,你应该选择二进制格式。

    【讨论】:

    • .obj 不是我生成的,它也包含四边形。另外,二维数组是因为一维指的是顶点数,另一维存储x,y,z坐标。
    • @viraj:顶点编号应该用作数组的索引。这就是它的用途。
    • 另外,在从 ascii 文件中读取浮点值时,我不能使用 in &gt;&gt; number 其中 in 是 ifstream 对象而 number 是浮点数吗?
    • 读取四边形时,只需将其转换为 2 个三角形(即添加 6 个索引而不是 4 个;注意面缠绕)。无论如何,你迟早必须这样做。
    【解决方案5】:

    这是一个相当不错的原型设计解决方案,运行一个脚本来生成用于 OpenGL 或您喜欢的渲染 API 的数组。 obj2opengl.pl 是一个 perl 脚本,你需要安装 perl,你可以找到 here。 GitHub 链接是here

    在运行 perl 脚本时,您可能会在第 154 行收到关于 if(defined(@center)) 的运行时错误。将其替换为if(@center)

    从示例中,一旦使用数据生成头文件,您就可以使用它,如下所示:

    /*
    created with obj2opengl.pl
    
    source file    : ./banana.obj
    vertices       : 4032
    faces          : 8056
    normals        : 4032
    texture coords : 4420
    
    
    // include generated arrays
    #import "./banana.h"
    
    // set input data to arrays
    glVertexPointer(3, GL_FLOAT, 0, bananaVerts);
    glNormalPointer(GL_FLOAT, 0, bananaNormals);
    glTexCoordPointer(2, GL_FLOAT, 0, bananaTexCoords);
    
    // draw data
    glDrawArrays(GL_TRIANGLES, 0, bananaNumVerts);
    */
    

    【讨论】:

      猜你喜欢
      • 2019-10-18
      • 2012-02-08
      • 2012-08-20
      • 2013-04-24
      • 2016-08-27
      • 2012-07-14
      • 2010-10-19
      • 2012-02-05
      • 1970-01-01
      相关资源
      最近更新 更多