使用C ++解析Wavefront .obj文件

时间:2011-10-17 15:28:02

标签: c++ wavefront

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

  1. 创建一个顶点数量大小的二维数组。当一个面使用一个顶点时,从数组中获取它的坐标。
  2. 获取顶点列表的起始位置,然后当面使用顶点时,扫描线直到到达顶点。
  3. IMO,选项1将非常耗费内存,但要快得多。 由于选项2涉及大量文件读取(并且因为大多数对象中的顶点数量变得非常大),因此速度会慢得多,但记忆密集程度会降低。

    问题是:比较内存和速度之间的权衡,哪个选项更适合普通计算机? 而且,还有另一种方法吗?

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

5 个答案:

答案 0 :(得分:5)

  

IMO,选项1将非常耗费内存,但速度要快得多。

无论如何,你必须将这些顶点放入内存中。但是不需要2D阵列,BTW会导致两个指针间接,因此会受到重大影响。只需对数据使用简单的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>;

答案 1 :(得分:4)

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

与三角形/面相同。每个三角形通常由三个顶点索引的列表组成。那也应该存储在一个数组中。

您可能会发现VTK开源库中的OBJ阅读器非常有用:http://www.vtk.org/doc/nightly/html/classvtkOBJReader.html。我们使用它并且没有理由自己编写...直接使用VTK,或者您可能会发现学习源代码有助于进一步激发您自己读者的灵感。

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

这是一个相当不错的原型解决方案,运行一个脚本,生成用于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);
*/