C ++ .obj解析器,解析问题或使用OpenGL绘图 [英] C++ .obj parser, issue with parsing, or drawing using OpenGL

查看:86
本文介绍了C ++ .obj解析器,解析问题或使用OpenGL绘图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having some trouble drawing some 3d objects. I wrote a very simple .obj parser and I know it doesn't support all types of .obj files but that's fine and for me it doesn't need to. I just need to get something rendering on the screen correctly. Here's my parser

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;

}

我相信这样可以正确解析数据,因为向量的结尾大小与文件中的数据匹配,例如,它将打印4700个顶点,并且文件中将有4700个顶点.

I believe this parses the data correctly, as the ending size of the vectors match the data in the file i.e. it would print 4700 vertices for example, and there would be 4700 vertices in the file.

我正在使用以下对象绘制对象

I'm drawing the object using the following

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);


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]);
}

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

为什么对象绘制不正确?

Why aren't the objects drawing correctly?

可以,但是速度非常慢

glBegin(GL_TRIANGLES);
for (int i = 0; i < mesh->meshIndices[0].size(); i++)//36
{

        glTexCoord2fv(&mesh->textureCoords[mesh->meshIndices[1][i]]->u);
        glNormal3fv(&mesh->normals[mesh->meshIndices[2][i]]->x);
        glVertex3fv(&mesh->indexedVertices[mesh->meshIndices[0][i]]->x);

}

推荐答案

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

The problem is with the way you use the indices. The related key parts of your code are where you store away the vertex, texture coordinate and normal indices in your mesh:

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

,然后在其中使用这些索引进行绘制:

and then where you use these indices to draw:

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]);
}

这是在绘制网格3次.一次带有顶点索引,一次带有纹理坐标索引,一次带有法线索引.这不可能很好地结束.您需要使用顶点,纹理坐标和位置的正确组合绘制一次.

What this is doing is draw the mesh 3 times. Once with the vertex indices, once with the texture coordinate indices, and once with the normal indices. This can't possibly end up well. You need to draw once, with the right combination of vertices, texture coordinates, and positions.

困难之处在于,OBJ格式为每个顶点属性(位置,纹理坐标,法线)使用单独的索引,而OpenGL仅支持为所有属性使用一组索引.

The difficulty is that the OBJ format uses separate indices for each vertex attribute (positions, texture coordinates, normals), while OpenGL only supports using a single set of indices for all the attributes.

有两种主要方法可以使此工作正常进行:

There are two main approaches to get this working:

  1. 请勿使用索引.这是通过在解析时应用索引查找,并构建新的数组来进行渲染而无需编制索引来完成的.使用以下命令草绘代码的关键部分:

  1. Do not use indexing. This is done by applying the index lookup while parsing, and building new arrays that you can then use for rendering without indexing. Sketching out the key parts of your code using this:

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]);
}

然后,您可以使用未索引的属性,并使用glDrawArrays()绘制没有索引的属性.

Then you can use the unindexed attributes, and draw them without indices, using glDrawArrays().

缺点是,它会复制共享的顶点,因此会消耗更多的内存,并且速度较慢.

The downside is that this replicates shared vertices, so it will consume more memory, and be slower.

您将为顶点,纹理坐标和法线的索引的每个唯一组合创建一个OpenGL顶点.我的较旧答案包含一些伪代码,显示了如何完成此操作: OpenGL-索引缓冲区困难.

You create an OpenGL vertex for each unique combination of indices for vertex, texture coordinate, and normal. My older answer here contains some pseudo-code showing how this can be done: OpenGL - Index buffers difficulties.

这篇关于C ++ .obj解析器,解析问题或使用OpenGL绘图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆