1
\$\begingroup\$

I'm struggling trying to get this to work like it should. Ive been able to make an obj loader that fits the glDrawArrays() call, with uv and facenormals, but when trying to modify it to fit glDrawElements() Im at a loss.

This is the code I have this far, the function takes the addresses of the vectors to be filled:

void objload3(string filename, vector<glm::vec3>&vertices, vector<glm::vec2>&texcords, vector<glm::vec3>&normals)
{
    size_t vertsize = 0; size_t texsize = 0; size_t normalsize = 0; size_t facesize = 0;  //ref size containers

    string line; string token;
    std::ifstream file(filename);

    if (file.is_open())
    {
        while (getline(file, line)) //count size
        {
            if (line.compare(0, 2, "v ") == 0)++vertsize;
            else if (line.compare(0, 2, "vt") == 0)++texsize;
            else if (line.compare(0, 2, "vn") == 0)++normalsize;
            else if (line.compare(0, 2, "f ") == 0)++facesize;
        }file.close();
    }

    //set size
    vector <glm::vec3>verticeref(vertsize);
    vector <glm::vec2>texkoordref(texsize);
    vector <glm::vec3>normalref(normalsize);

    vector<string>points(facesize * 3);

    //index filling counters                            
    size_t vcount = 0; size_t vtcount = 0; size_t vncount = 0; size_t fcount = 0; size_t refcount = 0;                                                             

     //fill reference vectors
    file.open(filename);
    if (file.is_open())
    {
        while (getline(file, line))
        {
            if (line.compare(0, 2, "v ") == 0) {
                istringstream s(line.substr(2));
                glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;
                verticeref[vcount++] = v;
            }

            else if (line.compare(0, 2, "vt") == 0) {
                istringstream s(line.substr(2));
                glm::vec2 v; s >> v.x; s >> v.y;
                texkoordref[vtcount++] = v;
            }

            else if (line.compare(0, 2, "vn") == 0) {
                istringstream s(line.substr(2));
                glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;
                normalref[vncount++] = v;
            }

            else if (line.compare(0, 2, "f ") == 0) {
                line.erase(0, 2);
                istringstream is(line);
                while (getline(is, token, ' '))points[fcount++] = token;
            }
        }file.close();
    }

    vector<int>indexref(3*points.size()); //faces allocation

//clean up faces information, convert to int
for (unsigned int a = 0; a <points.size(); ++a) {
    stringstream is(points[a]);
    while (getline(is, token, '/')) { indexref[refcount++] = stoi(token); }
    is.clear();
}

at this point, I would do this to fit it with the glDrawArrays() call:

vertices.resize(points.size());
texcords.resize(points.size());
normals.resize(points.size());

refcount = 0; //keep track of fill

for (size_t fillcount = 0; fillcount < points.size(); ++fillcount)
{
    vertices[fillcount] = verticeref[indexref[refcount++] - 1];
    texcords[fillcount] = texkoordref[indexref[refcount++] - 1];
    normals[fillcount] = normalref[indexref[refcount++] - 1];
}

But this fill doesnt take account of all the duplicate vertices, nor does it create an index. Im having problems understanding the logic behind the gldrawarrays call, and how to easily make an index and list of vertices/uv/normals to fill the vbos with.

Seems like something the 3Dmodel tool should do, but it doesnt? I cant juse use the list of faces already in obj export?

Some clarification would be much appreciated.

\$\endgroup\$
  • \$\begingroup\$ Why not use the original drawArrays version with a lost of indices from 0-n on a row, where n is the amount of vertices? It also allows you to make it flat shaded if you want to. \$\endgroup\$ – Bálint Apr 27 '16 at 21:15
  • \$\begingroup\$ I tried this, but its slower than the gldrawarrays. It loses out having to send duplicate information (where the points are) \$\endgroup\$ – Charlie Apr 27 '16 at 23:02
1
\$\begingroup\$

The answer turns out to be rather easy, altho lengthy, Instead of cleaning up faces (now called points) and preparing the list for gldrawarrays, I instead create a new list of unique faces/points as a base reference: Ill just post the entire function:

void objload4(string filename, vector<glm::vec3>&vertices, vector<glm::vec2>&texcords, vector<glm::vec3>&normals, vector<unsigned int>&xover)
{

size_t vertsize = 0; size_t texsize = 0; size_t normalsize = 0; size_t facesize = 0;  //ref size containers

string line; string token;
std::ifstream file(filename);

if (file.is_open())
{
    while (getline(file, line)) //count size
    {
        if (line.compare(0, 2, "v ") == 0)++vertsize;
        else if (line.compare(0, 2, "vt") == 0)++texsize;
        else if (line.compare(0, 2, "vn") == 0)++normalsize;
        else if (line.compare(0, 2, "f ") == 0)++facesize;
    }file.close();
}

//set size
vector <glm::vec3>verticeref(vertsize);
vector <glm::vec2>texkoordref(texsize);
vector <glm::vec3>normalref(normalsize);

vector<string>points(facesize * 3);

size_t vcount = 0; size_t vtcount = 0; size_t vncount = 0; size_t fcount = 0; size_t refcount = 0; //index filling count        

//fill reference vectors
file.open(filename);
if (file.is_open())
{
    while (getline(file, line))
    {
        if (line.compare(0, 2, "v ") == 0) {
            istringstream s(line.substr(2));
            glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;
            verticeref[vcount++] = v;
        }

        else if (line.compare(0, 2, "vt") == 0) {
            istringstream s(line.substr(2));
            glm::vec2 v; s >> v.x; s >> v.y;
            texkoordref[vtcount++] = v;
        }

        else if (line.compare(0, 2, "vn") == 0) {
            istringstream s(line.substr(2));
            glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;
            normalref[vncount++] = v;
        }

        else if (line.compare(0, 2, "f ") == 0) {
            line.erase(0, 2);
            istringstream is(line);
            while (getline(is, token, ' '))points[fcount++] = token;
        }
    }file.close();
}

//make ref sheet for faces
vector<string>pointsreference;
pointsreference = points;
std::sort(pointsreference.begin(), pointsreference.end());
vector<string>::iterator it = std::unique(pointsreference.begin(), pointsreference.end());
pointsreference.erase(it, pointsreference.end());

xover.resize(points.size());

for (unsigned int a = 0; a < points.size();++a) //fill crossover index
    {
        for (unsigned int b = 0; b < pointsreference.size(); ++b)
        {
            if (pointsreference[b] == points[a])xover[a] =b;//make list of references for points
        }
    }

vector<int>indexref(pointsreference.size()*3); //faces allocation

//clean up faces information, convert to int
for (unsigned int a = 0; a <pointsreference.size(); ++a) {
    stringstream is(pointsreference[a]);
    while (getline(is, token, '/')) { indexref[refcount++] = stoi(token); }
    is.clear();
}

vertices.resize(indexref.size()/3); //final vertices now has right size
texcords.resize(indexref.size() / 3);
normals.resize(indexref.size() / 3); //in fact they all do

refcount = 0; //keep track of fill

for (size_t fillcount = 0; fillcount < indexref.size()/3; ++fillcount)
{
    vertices[fillcount] = verticeref[indexref[refcount++] - 1];
    texcords[fillcount] = texkoordref[indexref[refcount++] - 1];
    normals[fillcount] = normalref[indexref[refcount++] - 1];
}

//all vectors are now aligned with vertices and are unique, xover should define list of indices that are now aligned (for vbo use and gldrawelements)
}

call the function like this;

objload4(filename, vertices, texcords, normals, xover);//fill existing vectors

The breakthrough was realizing I needed a reference with unique values, make a xover index for faces, then apply the xover to the aligned indexes. (aligned with unique, if that makes sense).

Either way this approach is cheap, fast and it works

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.