Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OBJ file loader not reading faces correctly

I created a small OBJ file loader for use with OpenGL, but faces aren't being read at all. Before adding the face reader the program read everything just fine, so I'm a little stumped here. Here is my code:

void OBJLoader::LoadObjFile(std::string f,std::vector<float>& v,std::vector<float>& n,std::vector<float>& u)
{
std::ifstream file;
file.open(f);

OutputDebugStringA("OPENING FILE-\n");
OutputDebugStringA(f.c_str());
std::string vertex,normal,uv,face;

std::string data;
std::string data2;
std::string data3 = "";

uv = "vt";
normal = "vn";
vertex = "v";
face = "f";

std::size_t var1;
int i = 1;
int j = 1;
int k = 1;
bool loop = true;
int loopcount = 1;

std::vector<float> tV,tU,tN;

if(file.is_open())
{
    while(std::getline(file,data) && file.good())
    {

        var1 = data.find(vertex);
        if(var1 != std::string::npos && var1 < data.size() && data[1] == 0x20)
        {
            data3.append(data,2,std::string::npos);

            double v1,v2,v3;
            std::istringstream ss(data3);
            if(ss >> v1 >> v2 >> v3){ v.push_back((float)v1); v.push_back((float)v2); v.push_back((float)v3); i++;}
            else
            {
                OutputDebugStringA("Error reading vertex data.\n");
                std::stringstream ssc;
                ssc << loopcount;
                std::string str = ssc.str();
                OutputDebugStringA((char*)str.c_str());
                OutputDebugStringA("\n");

            }
            data3 = "";
            data2 = "";
        }

        var1 = data.find(normal);
        if(var1 != std::string::npos && var1 < data.size())
        {
            data3.append(data,3,std::string::npos);

            float v1,v2,v3;
            std::istringstream ss(data3);
            if(ss >> v1 >> v2 >> v3){ n.push_back((float)v1); n.push_back((float)v2); n.push_back((float)v3); j++;}
            else
            {
                OutputDebugStringA("Error reading normal data.\n");
                std::stringstream ssc;
                ssc << loopcount;
                std::string str = ssc.str();
                OutputDebugStringA((char*)str.c_str());
                OutputDebugStringA("\n");
            }
            data3 = "";
            data2 = "";
        }

        var1 = data.find(uv);
        if(var1 != std::string::npos && var1 < data.size())
        {
            data3.append(data,3,std::string::npos);

            float v1,v2,v3;
            std::istringstream ss(data3);
            if(ss >> v1 >> v2){ u.push_back((float)v1); u.push_back((float)v2); u.push_back((float)v3); k++;}
            else
            {
                OutputDebugStringA("Error reading UV data.\n");
                std::stringstream ssc;
                ssc << loopcount;
                std::string str = ssc.str();
                OutputDebugStringA((char*)str.c_str());
                OutputDebugStringA("\n");

            }
            data3 = "";
            data2 = "";

        }

        var1 = data.find(face);
        if(var1 != std::string::npos && var1 < data.size())
        {   
            data3.append(data,2,std::string::npos);
            std::istringstream ss(data3);

                for(int l = 0;l < data3.size();l++)
                {
                    if(data3[l] == '/') data3[l] = ' ';
                }

            std::istringstream ss(data3);
            unsigned int verts[9];
            char slashes[6];

                //if(ss >> verts[0] >> slashes[0] >> verts[1] >> slashes[1] >> verts[2] >> verts[3] >> slashes[2] >> verts[4] >> slashes[3] >> verts[5] >> verts[6] >> slashes[4] >> verts[7] >> slashes[5] >> verts[8])
            if (ss >> verts[0] >> verts[1] >> verts[2] >> verts[3] >> verts[4] >> verts[5] >> verts[6] >> verts[7] >> verts[8])
                else
                {
                    try
                    {
                    tV.push_back(v.at(verts[0]));
                    tV.push_back(v.at(verts[0]+1));
                    tV.push_back(v.at(verts[0]+2));

                    tU.push_back(u.at(verts[1]));
                    tU.push_back(u.at(verts[1]+1));
                    tU.push_back(u.at(verts[1]+2));

                    tN.push_back(n.at(verts[2]));
                    tN.push_back(n.at(verts[2]+1));
                    tN.push_back(n.at(verts[2]+2));
                    //
                    tV.push_back(v.at(verts[3]));
                    tV.push_back(v.at(verts[3]+1));
                    tV.push_back(v.at(verts[3]+2));

                    tU.push_back(u.at(verts[4]));
                    tU.push_back(u.at(verts[4]+1));
                    tU.push_back(u.at(verts[4]+2));

                    tN.push_back(n.at(verts[5]));
                    tN.push_back(n.at(verts[5]+1));
                    tN.push_back(n.at(verts[5]+2));
                    //
                    tV.push_back(v.at(verts[6]));
                    tV.push_back(v.at(verts[6]+1));
                    tV.push_back(v.at(verts[6]+2));

                    tU.push_back(u.at(verts[7]));
                    tU.push_back(u.at(verts[7]+1));
                    tU.push_back(u.at(verts[7]+2));

                    tN.push_back(n.at(verts[8]));
                    tN.push_back(n.at(verts[8]+1));
                    tN.push_back(n.at(verts[8]+2));
                    }
                    catch(std::out_of_range e)
                    {
                        OutputDebugStringA("Out of Range!\n");
                    }
                }
            }
            else
            {
                OutputDebugStringA("Invalid face data! Generic     Error!\n");
                std::stringstream ssc;
                std::stringstream ssc2;

                ssc << loopcount;
                std::string str = ssc.str();
                OutputDebugStringA((char*)str.c_str());
                OutputDebugStringA("\n");
            }

            data3 = "";
            data2 = "";
        }
        loopcount++;

    }

}
else
{

}
}

Any help is appreciated!

Also here is the OBJ file I am using:

 v 0.000 0.000 0.000
 v 1.000 0.000 0.000
 v 1.000 1.000 0.000
 v 0.000 0.000 0.000
 v 0.000 1.000 0.000
 v 1.000 1.000 0.000
 vt 0.000 0.000
 vt 1.000 0.000
 vt 1.000 1.000
 vn 0.000 0.000 1.000

 f 1/7/10 2/8/10 3/9/10
 f 4/7/10 5/8/10 6/9/10

OK, I fixed the slash issues, but now this block of code is causing std::out_of_range excpetions:

                tV.push_back(v.at(verts[0]));
                tV.push_back(v.at(verts[0]+1));
                tV.push_back(v.at(verts[0]+2));

                tU.push_back(u.at(verts[1]));
                tU.push_back(u.at(verts[1]+1));
                tU.push_back(u.at(verts[1]+2));

                tN.push_back(n.at(verts[2]));
                tN.push_back(n.at(verts[2]+1));
                tN.push_back(n.at(verts[2]+2));
                //
                tV.push_back(v.at(verts[3]));
                tV.push_back(v.at(verts[3]+1));
                tV.push_back(v.at(verts[3]+2));

                tU.push_back(u.at(verts[4]));
                tU.push_back(u.at(verts[4]+1));
                tU.push_back(u.at(verts[4]+2));

                tN.push_back(n.at(verts[5]));
                tN.push_back(n.at(verts[5]+1));
                tN.push_back(n.at(verts[5]+2));
                //
                tV.push_back(v.at(verts[6]));
                tV.push_back(v.at(verts[6]+1));
                tV.push_back(v.at(verts[6]+2));

                tU.push_back(u.at(verts[7]));
                tU.push_back(u.at(verts[7]+1));
                tU.push_back(u.at(verts[7]+2));

                tN.push_back(n.at(verts[8]));
                tN.push_back(n.at(verts[8]+1));
                tN.push_back(n.at(verts[8]+2));
like image 703
Nick Ellas Avatar asked Dec 26 '13 17:12

Nick Ellas


1 Answers

It seems that parsing from istream using >> does not work as you are expecting. Did you notice it automatically skips whitespace when parsing vertices, normals and uvs? Yet for faces you try to parse every character. You also want non-whitespace slashes as delimiters.

How about this approach https://stackoverflow.com/a/1895584/642532 ? One answer suggest telling the stream to treat commas (in your case slashes) as whitespace so you can parse faces just as easily as vertices. Another answer suggest using a string tokenizer like StrTk http://www.partow.net/programming/strtk/index.html or Boost.

like image 131
Jonas Bötel Avatar answered Oct 21 '22 08:10

Jonas Bötel