在c ++中优化OBJ文件解析器

时间:2015-06-03 13:45:06

标签: c++ parsing opengl

我用c ++编写了一个OBJ文件解析器,但它确实有用。它可以将任何OBJ文件加载到模型中。然而它非常缓慢。加载一个低多边形模型最多可能需要十秒钟。有没有办法优化这个或者我的计算机是极低的?非常感谢任何帮助。

RawModel OBJLoader::loadModel(const std::string& filePath, Loader* loader)
{
    std::ifstream file(filePath);

    std::vector<glm::vec3> positions;
    std::vector<glm::vec2> uvs;
    std::vector<glm::vec3> normals;

    std::vector<unsigned int> indices;

    float* positionsArray = nullptr;
    float* uvsArray = nullptr;
    float* normalsArray = nullptr;
    unsigned int* indicesArray = nullptr;

    bool firstFace = true;

    std::string line;
    while (std::getline(file, line))
    {
    std::vector<std::string> currentLine = split(line, ' ');

    if (line[0] == 'v' && line[1] == ' ')
    {
    glm::vec3 pos(parseFloat(currentLine[1]), parseFloat(currentLine[2]), parseFloat(currentLine[3]));
    positions.push_back(pos);
    }
    else if (line[0] == 'v'  && line[1] == 't')
    {
    glm::vec2 uv(parseFloat(currentLine[1]), parseFloat(currentLine[2]));
    uvs.push_back(uv);
    }
    else if (line[0] == 'v'  && line[1] == 'n')
    {
    glm::vec3 norm(parseFloat(currentLine[1]), parseFloat(currentLine[2]), parseFloat(currentLine[3]));
    normals.push_back(norm);
    }
    else if (line[0] == 'f'  && line[1] == ' ')
    {
    if (firstFace)
    {
    uvsArray = new float[positions.size() * 2];
    normalsArray = new float[positions.size() * 3];
    firstFace = false;
    }

    std::vector<std::string> vert1 = split(currentLine[1], '/');
    std::vector<std::string> vert2 = split(currentLine[2], '/');
    std::vector<std::string> vert3 = split(currentLine[3], '/');

    processVertex(vert1, &indices, uvs, normals, uvsArray, normalsArray);
    processVertex(vert2, &indices, uvs, normals, uvsArray, normalsArray);
    processVertex(vert3, &indices, uvs, normals, uvsArray, normalsArray);
    }
    }

    positionsArray = new float[positions.size() * 3];
    indicesArray = new unsigned int[indices.size()];

    for (int i = 0; i < positions.size(); i++)
    {
    positionsArray[i*3] = positions[i].x;
    positionsArray[i*3+1] = positions[i].y;
    positionsArray[i*3+2] = positions[i].z;
    }

    for (int i = 0; i < indices.size(); i++) indicesArray[i] = indices[i];

    return loader->loadToVao(positionsArray, positions.size() * 3, indicesArray, indices.size(), uvsArray,positions.size()*2);
}

float parseFloat(const std::string& str)
{
return std::stof(str);
}

int parseInt(const std::string& str)
{
return std::stoi(str);
}

void  processVertex(std::vector<std::string> vertData, std::vector<unsigned         int>* indices, std::vector<glm::vec2> uvs, std::vector<glm::vec3> normals,
float* uvsArray, float* normalsArray)
{
unsigned int currentVertexPointer = parseInt(vertData[0]) - 1;
indices->push_back(currentVertexPointer);

glm::vec2 currentUv = uvs[parseInt(vertData[1]) - 1];
uvsArray[currentVertexPointer * 2] = currentUv.x;
uvsArray[currentVertexPointer * 2 + 1] = 1 - currentUv.y;

glm::vec3 currentNorm = normals[parseInt(vertData[2]) - 1];
normalsArray[currentVertexPointer * 3] = currentNorm.x;
normalsArray[currentVertexPointer * 3+1] = currentNorm.y;
normalsArray[currentVertexPointer * 3+2] = currentNorm.z;
}

std::vector<std::string> split(const std::string &str, const char &delim)
{
typedef std::string::const_iterator iter;
iter beg = str.begin();
std::vector<std::string> tokens;

while (beg != str.end()) {
//cout << ":" << beg._Myptr << ":" << endl;
iter temp = find(beg, str.end(), delim);
if (beg != str.end())
tokens.push_back(std::string(beg, temp));
beg = temp;
while ((beg != str.end()) && (*beg == delim))
beg++;
}

return tokens;
}

1 个答案:

答案 0 :(得分:1)

首先,明显的改进:

  • 通过(const)引用将向量vertData传递给processVertex
  • 尽可能通过clear来重用一个向量
  • 重写split以引用向量作为参数,并写入此向量而不是返回值

其次,先忘掉,然后使用分析器。例如,Linux上的gprof或Windows上的sleepy