【问题标题】:C++ obj loader texture coordinates messed upC ++ obj loader纹理坐标搞砸了
【发布时间】:2018-02-23 14:37:38
【问题描述】:

我用 C++ 编写了一个简单的 obj 解析器,它可以加载顶点、索引和纹理坐标(这就是我需要的所有数据)。

函数如下:

Model* ModelLoader::loadFromOBJ(string objFile, ShaderProgram *shader, GLuint texture)
    {
        fstream file;

        file.open(objFile);
        if (!file.is_open())
        {
            cout << "ModelLoader: " << objFile << " was not found";
            return NULL;
        }

        int vertexCount = 0;
        int indexCount = 0;
        vector<Vector3> vertices;
        vector<Vector2> textureCoordinates;
        vector<Vector2> textureCoordinatesFinal;
        vector<unsigned int> vertexIndices;
        vector<unsigned int> textureIndices;

        string line;
        while (getline(file, line))
        {
            vector<string> splitLine = Common::splitString(line, ' ');

            // v - vertex
            if (splitLine[0] == "v")
            {
                Vector3 vertex(stof(splitLine[1]), stof(splitLine[2]), stof(splitLine[3]));
                vertices.push_back(vertex);
                vertexCount++;
            }
            // vt - texture coordinate
            else if (splitLine[0] == "vt")
            {
                Vector2 textureCoordinate(stof(splitLine[1]), 1 - stof(splitLine[2]));
                textureCoordinates.push_back(textureCoordinate);
            }
            // f - face
            else if (splitLine[0] == "f")
            {
                vector<string> faceSplit1 = Common::splitString(splitLine[1], '/');
                vector<string> faceSplit2 = Common::splitString(splitLine[2], '/');
                vector<string> faceSplit3 = Common::splitString(splitLine[3], '/');

                unsigned int vi1 = stoi(faceSplit1[0]) - 1;
                unsigned int vi2 = stoi(faceSplit2[0]) - 1;
                unsigned int vi3 = stoi(faceSplit3[0]) - 1;
                unsigned int ti1 = stoi(faceSplit1[1]) - 1;
                unsigned int ti2 = stoi(faceSplit2[1]) - 1;
                unsigned int ti3 = stoi(faceSplit3[1]) - 1;

                vertexIndices.push_back(vi1);
                vertexIndices.push_back(vi2);
                vertexIndices.push_back(vi3);
                textureIndices.push_back(ti1);
                textureIndices.push_back(ti2);
                textureIndices.push_back(ti3);

                indexCount += 3;
            }
        }

        // rearanging textureCoordinates into textureCoordinatesFinal based on textureIndices
        for (int i = 0; i < indexCount; i++)
            textureCoordinatesFinal.push_back(textureCoordinates[textureIndices[i]]);

        Model *result = new Model(shader, vertexCount, &vertices[0], NULL, texture, indexCount, &textureCoordinatesFinal[0], &vertexIndices[0]);
        models.push_back(result);

        return result;
    }

如您所见,我考虑了 1 - texCoord.y(因为 blender 和 opengl 使用不同的纹理坐标系)。 我还在while循环之后根据纹理索引排列纹理坐标。

但是,我尝试渲染的模型的纹理搞砸了。这是一个例子:

纹理搞砸了

我什至用一个立方体尝试过它,我用搅拌机把自己打开并应用了一个非常简单的砖纹理。在 1 或 2 个面中,纹理很好并且可以工作,然后在其他一些面上,1 个三角形的纹理正确,而其他的则出现拉伸(与上图相同)。

【问题讨论】:

    标签: c++ opengl wavefront


    【解决方案1】:

    要定义一个网格,只有一个索引列表来索引顶点属性。顶点属性(在您的情况下是顶点和纹理坐标)形成一个记录集,由这些索引引用。

    这导致,每个顶点坐标可能在列表中出现多次,每个纹理坐标可能在列表中出现多次。但是每个顶点和纹理坐标的组合都是独一无二的。

    使用vertexIndicestextureIndices 创建唯一的顶点和纹理坐标对(verticesFinaltextureCoordinatesFinal)。
    创建新的attribute_indices,用于索引这些对。
    使用临时容器attribute_pairs 来管理唯一对并识别它们的索引:

    #include <vector>
    #include <map>
    

    // input
    std::vector<Vector3> vertices;
    std::vector<Vector2> textureCoordinates;
    std::vector<unsigned int> vertexIndices;
    std::vector<unsigned int> textureIndices;
    

    std::vector<unsigned int> attribute_indices;  // final indices
    std::vector<Vector3> verticesFinal;           // final vertices buffer
    std::vector<Vector2> textureCoordinatesFinal; // final texture coordinate buffer 
    

    // map a pair of indices to the final attribute index
    std::map<std::pair<unsigned int, unsigned int>, unsigned int> attribute_pairs; 
    
    // vertexIndices.size() == textureIndices.size()
    for ( size_t i = 0; i < vertexIndices.size(); ++ i )
    {
        // pair of vertex index an texture index
        auto attr = std::make_pair( vertexIndices[i], textureIndices[i] );
    
        // check if the pair aready is a member of "attribute_pairs"
        auto attr_it = attribute_pairs.find( attr );
    
        if ( attr_it == attribute_pairs.end() )
        {
            // "attr" is a new pair
    
            // add the attributes to the final buffers
            verticesFinal.push_back( vertices[attr.first] );
            textureCoordinatesFinal.push_back( textureCoordinates[attr.first] );
    
            // the new final index is the next index
            unsigned int new_index = (unsigned int)attribute_pairs.size();
            attribute_indices.push_back( new_index );
    
            // add the new map entry 
            attribute_pairs[attr] = new_index;
        }
        else
        {
            // the pair "attr" already exists: add the index which was found in the map
            attribute_indices.push_back( attr_it->second );
        }
    } 
    

    注意顶点坐标的数量(verticesFinal.size())等于纹理坐标的数量(textureCoordinatesFinal.size())。但是索引的数量 (attribute_indices.size()) 完全不同。

    // verticesFinal.size() == textureCoordinatesFinal.size()
    Model *result = new Model(
        shader, 
        verticesFinal.size(),
        verticesFinal.data(),
        NULL, texture,
        attribute_indices.size(),
        textureCoordinatesFinal.data(),
        attribute_indices.data() );
    

    【讨论】:

    • 非常感谢,我不知道我是如何在脑海中混淆的,以至于我无法理解我没有正确地重新排序 textureCoordinates 数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-16
    • 1970-01-01
    相关资源
    最近更新 更多