为了用DirectX创建3D模拟,我必须导入ASCII-STL格式的巨大数据集。问题是,我的读者正在工作,但表现很糟糕。我与Autodesk Inventor STL导入程序进行了比较,两者的差异非常显著(5秒与1.5分钟)。我非常感谢为改进我的代码而提出的建议或想法。非常感谢。
此外,STL格式的效率非常低。对于每个面,顶点都单独列出。看起来如下:
刻面法线0 0.999229 0.0392606
外环
顶点-3173.54 1993.84-23184.5
顶点-3099.94 1993.84-23184.5
顶点-3099.94 2000-23341.5
端环
端面
结果是,在处理文件的过程中会出现多次顶点。我试着检查双顶点,但对于巨大的文件来说,这需要很长时间(迭代越来越长)。
这是我到目前为止的代码:
std::ifstream stlFile;
stlFile.open(mFilename);
if(!stlFile) // check if file can be found
{
MessageBox(0, "STL file not found.", 0, 0);
return false;
}
std::string ignore;
stlFile >> ignore >> ignore; //ignore header: solid t=x.xx
UINT index = 0;
int iIndex = 0;
int vIndex = 0;
WORD indexTmp = 0;
while(1)
{
stlFile >> ignore >> ignore; // ignore "normal"
if (ignore == "CUBE")
break;
float normal[3];
stlFile >> normal[0] >> normal[1] >> normal[2]; // read and save the face normal
stlFile >> ignore >> ignore; // ignore "outer loop"
for(int i = 0; i <= 2; ++i) // read the three vertices of a face
{
VERTEX vertexTmp;
vertexTmp.Normal.x = normal[0]; vertexTmp.Normal.y = normal[1]; vertexTmp.Normal.z = normal[2];
stlFile >> ignore >> vertexTmp.Pos.x >> vertexTmp.Pos.y >> vertexTmp.Pos.z;// >> ignore >> ignore;
//if (!ContainsVertexIndex(vertexTmp, vertices, indexTmp)) // return vertex index of double
//{
mVertices.push_back(vertexTmp); //save newly created vertex
indexTmp = vIndex; // create index reference to the new vertex
vIndex++; // increment index
//}
mIndices.push_back(indexTmp);
iIndex++; // increment index
}
stlFile >> ignore >> ignore; // endloop // endfacet
}
stlFile.close();
编辑:我将矢量更改为固定数组,但性能没有显著提高。任何其他建议。
我刚刚遇到这个问题,对您的速度问题有了一些了解。
您不应该将矢量用于这种类型的数据存储。由于您一直在检查向量中是否存在顶点,因此在向量上迭代会浪费大量时间。
一种更简单的方法是创建顶点的哈希图。这允许恒定的时间查找(这不是真正需要的)和插入,这是你的处理瓶颈所在。然后你的总运行时间将是O(n),其中n是处理的三角形数。
你需要能够散列你的VERTEX对象,这可以通过创建一个散列模板来完成。我发现使用Boost的哈希库最容易做到这一点,但你可以自己编写。
namespace std
{
template<>
struct hash<your_namespace::VERTEX>
{
typedef your_namespace::VERTEX argument_type;
typedef size_t result_type;
result_type operator()(const argument_type &v) const
{
result_type seed = 0;
boost::hash_combine(seed, v.X);
boost::hash_combine(seed, v.Y);
boost::hash_combine(seed, v.Z);
return seed;
}
}
}
Boost的hash_combine方法根据对变量进行散列的顺序创建唯一的散列。因此,X->Y->Z产生的哈希与Z->Y->X不同(因此,每个序列组合都产生一个唯一的输出)。
最后,使用地图数据结构来存储VERTEX数据对象。
// declaration
std::map<std::size_t, VERTEX> hashmap;
// adding VERTEX object
hashmap[std::hash<VERTEX>()(vObject)] = vObject;
使用这种方法,您不必担心每个坐标集插入多个坐标集,因为哈希坐标集可以推断出删除重复坐标集。因此,不再通过在矢量数据结构上循环来检查重复项。
希望这能有所帮助。我也遇到了同样的瓶颈问题,这将我的STL读取时间从几分钟减少到了几毫秒。