C++ C++。obj解析器,解析问题,或使用OpenGL绘图

C++ C++。obj解析器,解析问题,或使用OpenGL绘图,c++,parsing,opengl,C++,Parsing,Opengl,我在绘制一些3d对象时遇到一些问题。我编写了一个非常简单的.obj解析器,我知道它不支持所有类型的.obj文件,但这很好,对我来说也不需要。我只需要在屏幕上正确渲染一些东西。这是我的解析器 Mesh * Loader::loadObj(char * path) { Mesh * objectMesh; vector<Vertex *> indexedVertices; vector<Vector3 * > normals; vector&

我在绘制一些3d对象时遇到一些问题。我编写了一个非常简单的.obj解析器,我知道它不支持所有类型的.obj文件,但这很好,对我来说也不需要。我只需要在屏幕上正确渲染一些东西。这是我的解析器

Mesh * Loader::loadObj(char * path) {
    Mesh * objectMesh;

    vector<Vertex *> indexedVertices;
    vector<Vector3 * > normals;
    vector<TextureCoordinate *> textureCoords;
    vector<vector<GLushort>> meshIndices;

    vector<GLushort> verticesIndexed;
    vector<GLushort> texturesIndexed;
    vector<GLushort> normalsIndexed;

    ifstream inFile;

    inFile.open(path);

    if (!inFile.good())
    {
        cerr << "Can't open texture file " << path << endl;
        return false;
    }

    std::cout << "Loading .obj file" << endl;

    while (!inFile.eof()) {
        string line;
        std::getline(inFile, line);

        if (line.substr(0, 2) == "v ") {//vertices
            std::vector<string> elements = Operations::split(Operations::trim(line.substr(3)), *" ");
            if (elements.size() > 1) {
                std::cout << "Loading vertex data: " << line << endl;
                Vertex * v = new Vertex(std::atof(elements.at(0).c_str()), std::atof(elements.at(1).c_str()), std::atof(elements.at(2).c_str()));
                indexedVertices.push_back(v);
            }
        }
        else if (line.substr(0, 2) == "vn") {//normals
            std::vector<string> elements = Operations::split(Operations::trim(line.substr(3)), *" ");
            std::cout << "Loading normal data: " << line << endl;
            if (elements.size() > 1) {
                Vector3 * v = new Vector3(std::atof(elements.at(0).c_str()), std::atof(elements.at(1).c_str()), std::atof(elements.at(2).c_str()));
                normals.push_back(v);
            }
        }
        else if (line.substr(0, 2) == "vt") {//tex coords
            std::cout << "Loading texture data: " << line << endl;
            std::vector<string> elements = Operations::split(Operations::trim(line.substr(3)), *" ");
            if (elements.size() > 1) {
                TextureCoordinate * t = new TextureCoordinate(std::atof(elements.at(0).c_str()), std::atof(elements.at(1).c_str()));
                textureCoords.push_back(t);
            }
        }
        else if (line.substr(0, 2) == "f ") {//faces / indices
            std::cout << "Loading face data: " << line << endl;
            std::vector<string> elements = Operations::split(Operations::trim(line.substr(2)), *" ");
            if (elements.size() > 1) {
                for (int i = 0; i < elements.size(); i++) {
                    std::vector<string> e = Operations::split(Operations::trim(elements.at(i)), *"/");
                    if (e.size() > 1) {
                        verticesIndexed.push_back(std::atof(e.at(0).c_str()) - 1);
                        texturesIndexed.push_back(std::atof(e.at(1).c_str()) - 1);
                        normalsIndexed.push_back(std::atof(e.at(2).c_str()) - 1);
                    }
                }
            }
        }
    }

    meshIndices.push_back(verticesIndexed);
    meshIndices.push_back(texturesIndexed);
    meshIndices.push_back(normalsIndexed);


    std::cout << "Face count: " << verticesIndexed.size() << " " << texturesIndexed.size() << " " << normalsIndexed.size() << endl;

    objectMesh = new Mesh(indexedVertices, normals, textureCoords, meshIndices);

    std::cout << "Vertices count: " << indexedVertices.size() << endl;
    std::cout << "Normals count: " << normals.size() << endl;
    std::cout << "Textures count: " << textureCoords.size() << endl;


    inFile.close();

    return objectMesh;

}
Mesh*Loader::loadObj(char*path){
网格*对象网格;
向量指数;
向量法线;
向量纹理词;
矢量网格指数;
向量垂直指数;
矢量纹理索引;
向量归一化指数;
河流充填;
填充。开放(路径);
如果(!infle.good())
{

cerr问题在于索引的使用方式。代码的相关关键部分是在网格中存储顶点、纹理坐标和法线索引的位置:

meshIndices.push_back(verticesIndexed);
meshIndices.push_back(texturesIndexed);
meshIndices.push_back(normalsIndexed);
然后使用这些索引绘制:

for (int i = 0; i < mesh->meshIndices.size(); i++) {
    glVertexPointer(3, GL_FLOAT, 0, mesh->indexedVertices[0]);
    glNormalPointer(GL_FLOAT, 0, mesh->normals[0]);
    glTexCoordPointer(2, GL_FLOAT, 0, mesh->textureCoords[0]);

    glDrawElements(GL_TRIANGLES, mesh->meshIndices[i].size(),
                   GL_UNSIGNED_SHORT, &mesh->meshIndices[i][0]);
}
然后,您可以使用未索引的属性,并使用
glDrawArrays()
在没有索引的情况下绘制它们

缺点是,这会复制共享顶点,因此会消耗更多内存,速度也会变慢

  • 您可以为顶点、纹理坐标和法线的索引的每个唯一组合创建一个OpenGL顶点。我以前的回答包含一些伪代码,说明了如何做到这一点:


  • 好的,谢谢,我会试着研究一下。但是,我不认为问题出在加载上。如果你看一下我的OP,我实际上用了不同的方法绘制了它。好的,你现在编辑到答案中的内容基本上与我建议的解决方案1相同。你一般不应该编辑问题来包含答案。gSO的oal是建立一个问题和答案的存储库,如果问题被编辑成包含答案中的解决方案,这是不起作用的。我被告知,我编辑的代码比使用顶点指针等更糟糕,因为它循环了很多次。不过我会删除它。
    meshIndices.push_back(verticesIndexed);
    meshIndices.push_back(texturesIndexed);
    meshIndices.push_back(normalsIndexed);
    
    for (int i = 0; i < mesh->meshIndices.size(); i++) {
        glVertexPointer(3, GL_FLOAT, 0, mesh->indexedVertices[0]);
        glNormalPointer(GL_FLOAT, 0, mesh->normals[0]);
        glTexCoordPointer(2, GL_FLOAT, 0, mesh->textureCoords[0]);
    
        glDrawElements(GL_TRIANGLES, mesh->meshIndices[i].size(),
                       GL_UNSIGNED_SHORT, &mesh->meshIndices[i][0]);
    }
    
    if (line.substr(0, 2) == "v ") {
        ...
        indexedVertices.push_back(v);
    } else if (line.substr(0, 2) == "vn") {
        ...
        indexedNormals.push_back(v);
    } else if (line.substr(0, 2) == "vt") {
        ...
        indexedTextureCoords.push_back(t);
    } else if (line.substr(0, 2) == "f ") {
        ...
        unindexedVertices.push_back(
            indexedVertices[std::atof(e.at(0).c_str()) - 1]);
        unindexedTextureCoords.push_back(
            indexedTextureCoords[std::atof(e.at(1).c_str()) - 1]);
        unindexedNormals.push_back(
            indexedNormals[std::atof(e.at(2).c_str()) - 1]);
    }