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



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

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

在我看来,选项1将非常占用内存,但速度要快得多。由于选项2涉及大量的文件读取,(并且因为大多数对象中的顶点数量变得非常大)这将会慢得多,但内存消耗更少。

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

我计划使用OpenGL和GLFW来渲染对象

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

无论如何你必须将这些顶点存储到内存中。但是不需要2D数组,顺便说一句,这会导致两个指针间接指向,从而严重影响性能。只需为您的数据使用一个简单的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>;

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

同样适用于三角形/面。每个三角形通常由三个顶点索引组成。也应该存储在数组中。

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

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

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

你不需要一个二维数组。你的模型应该被三角化,然后你可以简单地使用gluts obj loader加载obj文件。简单地存储点,面和法线在3个单独的数组/缓冲区。这里有一个示例,您可以这样做,但如果您想快速完成,您应该使用二进制格式。

这是一个相当不错的原型解决方案,运行一个脚本,生成用于OpenGL或您首选的渲染API的数组。pl是一个perl脚本,您需要安装perl,可以在这里找到。GitHub链接在这里。

当运行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);
*/

最新更新