2
votes

I have an obj file and have succesfully loaded the object to opengl without using the normals given.
This is how it looks:
tree without normals
The format of the file is:

v x y z
vn x y z
f x//x' y//y' z//z'

The displaying function of the mesh is like that:

glBegin(GL_TRIANGLES);
for all faces
{
    glVertex3f(.., .., ..);
    glVertex3f(.., .., ..);
    glVertex3f(.., .., ..);
}
glEnd();

And the result is this:
enter image description here

I've read that the object might look flat due to the default normal vector that OpenGL uses for lighting equations.
This could be solved with normals. The normals given are 780 and the vertices 155.

I've tried using glNorm before each glVertex3f call but the obj looks completely weird (lines, etc).

What should I do?

EDIT #1: This is how I read the file:

void loader(class mesh &tree)
{
int vx1, vx2, vx3, vn1, vn2, vn3;
ifstream file;
string line;
point vec, norm;
face tempface;

file.open("tree.obj"); 
if (file.is_open() == true)
{
    while(getline(file, line) )
    {
        if (line.substr(0,2) == "") continue;
        else if (line.substr(0, 2) == "v ")
        {
            istringstream numbers(line.substr(2));
            numbers >> vec.x >> vec.y >> vec.z;
            tree.vectors.push_back(vec);
        }
        else if (line.substr(0,2) == "vn")
        {
            istringstream numbers(line.substr(2));
            numbers >> norm.x >> norm.y >> norm.z;
            tree.normals.push_back(norm);
        }
        else if (line.substr(0,2) == "f ")
        {
            face f;
            line = line.substr(2,line.length());
            for (string::iterator it = line.begin(); it != line.end(); ++it)
            {
                if (*it == '/')
                {
                    //erase both of the "//"
                    line.erase(it);
                    line.erase(it);
                    //add a space between the numbers
                    line.insert(it, ' ');
                }
            }
            istringstream inp(line);
            inp >> f.vert_indices[0] >> f.norm_indices[0] >> f.vert_indices[1] >> f.norm_indices[1] >> f.vert_indices[2] >> f.norm_indices[2];
            tree.faces.push_back(f);
        }
        else 
            continue;
    }
    file.close();
}
}

And this is how I am displaying it:

    void mesh::displayMesh()
{
    glPushMatrix();
    glBegin(GL_TRIANGLES);
    for(vector<face>::const_iterator it = faces.begin();
        it != faces.end(); ++it)
    {
        //glVertex3f(normals[it->norm_indices[0] -1 ].x, normals[it->norm_indices[0] -1 ].y, normals[it->norm_indices[0] -1 ].z);
        glVertex3f(vectors[it->vert_indices[0] -1 ].x, vectors[it->vert_indices[0] -1 ].y, vectors[it->vert_indices[0] -1 ].z);
        //glVertex3f(normals[it->norm_indices[1] -1 ].x, normals[it->norm_indices[1] -1 ].y, normals[it->norm_indices[1] -1 ].z);
        glVertex3f(vectors[it->vert_indices[1] -1 ].x, vectors[it->vert_indices[1] -1 ].y, vectors[it->vert_indices[1] -1 ].z);
        //glVertex3f(normals[it->norm_indices[2] -1 ].x, normals[it->norm_indices[2] -1 ].y, normals[it->norm_indices[2] -1 ].z);
        glVertex3f(vectors[it->vert_indices[2] -1 ].x, vectors[it->vert_indices[2] -1 ].y, vectors[it->vert_indices[2] -1 ].z);
    }
    glEnd();
    glPopMatrix();
}

The function displayMesh is called within Render function of openGL and the loader function is called into Setup OpenGL function and the mesh tree object is a global variable.

EDIT #2: This how the tree looks with the normals:
tree with normals Also this is the code of the setup function of OpenGL.

2
If you open your OBJ with Blender (or other 3D editor/viewer) it is displayed correctly?Vinícius Gobbo A. de Oliveira
Adding only glNormal3f calls before your glVertex3f functions won't have an effect unless you enable both OpenGL lighting glEnable(GL_LIGHTING) and at least one light, e.g., glEnable(GL_LIGHT0). Lighting will be computed with all of the default lighting settings for materials, light colors, etc.radical7
@ViníciusGobboA.deOliveira: Yes, I opened it in Blender and it appears much better that when I loaded it with opengl.Chris
@radical7: Also, I have enabled lighting in my code glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); and still nothing. I've updated the question and added two pictures.Chris
It looks to me like you are reading some of the vertices wrongly. Are you certain that every line in the file has the format you are reading? That there is nothing unusual about any of the lines in the obj file?jcoder

2 Answers

0
votes

Shouldn't you have the following in your draw code instead?

glNormal3f(normals[it->norm_indices[0] -1 ].x, normals[it->norm_indices[0] -1 ].y, normals[it->norm_indices[0] -1 ].z);
glVertex3f(vectors[it->vert_indices[0] -1 ].x, vectors[it->vert_indices[0] -1 ].y, vectors[it->vert_indices[0] -1 ].z);
glNormal3f(normals[it->norm_indices[1] -1 ].x, normals[it->norm_indices[1] -1 ].y, normals[it->norm_indices[1] -1 ].z);
glVertex3f(vectors[it->vert_indices[1] -1 ].x, vectors[it->vert_indices[1] -1 ].y, vectors[it->vert_indices[1] -1 ].z);
glNormal3f(normals[it->norm_indices[2] -1 ].x, normals[it->norm_indices[2] -1 ].y, normals[it->norm_indices[2] -1 ].z);
glVertex3f(vectors[it->vert_indices[2] -1 ].x, vectors[it->vert_indices[2] -1 ].y, vectors[it->vert_indices[2] -1 ].z);

EDIT: oops, you realized that already

If you want to check if the normals are correct, color each vertex according to it's normal. Use glColor3f but supply the normals.

0
votes

when you use erase it invalidates the iterator

//erase both of the "//"
it = line.erase(it);
it = line.erase(it);
//add a space between the numbers
it = line.insert(it, ' ');

however you can erase once and then replace

//erase both of the "//"
it = line.erase(it);
//add a space between the numbers
*it = ' ';