Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: What's wrong with my OBJ Loader Code and a few things explained

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    14

    Post What's wrong with my OBJ Loader Code and a few things explained

    Hello,

    I am a newbe to OpenGL but have been coding C/C++ for years now and have decided to try my hand at Opengl ..

    I am currently trying to make my own obj model loader and viewer, have decided to ensure that I also learn as much as possible in regards to OpenGL I want to code the obj loader myself. Unfortunatly I am a bit confused about if I am doing it right and also how I would utilize the data once it is loaded into memory.. I have been reading LOADS of documentation on loading wavefront files however all of them seem to use 3rd party loaders and tools to do so and I want to do it all myself..

    Here is the class I created that loads and stores the data:
    Code :
    #include <fstream>
    #include <stdlib.h>
    const unsigned int MAXVERTEXES = 10000;
    const unsigned int MAXUVS = 10000;
    const unsigned int MAXNORMALS = 10000;
    const unsigned int MAXFACES = 100;
    const unsigned int SCALER = 10;
     
    class GraphicsStruc_Model
    {
    private:
        bool IsModelLoaded;
        unsigned int numVertexes, numUVS, numNormals, numFaces;
        float VERTEXES[MAXVERTEXES][2];
        float UVS[MAXUVS][2];
        float NORMALS[MAXNORMALS][2];
     
        unsigned int VERTEXES_INDEX[MAXFACES][2];
        unsigned int UVS_INDEX[MAXFACES][2];
        unsigned int NORMALS_INDEX[MAXFACES][2];
    public:
        GraphicsStruc_Model()
        {
            IsModelLoaded = false;
        }
     
        float GetVertex(int vertexNum, int xYZ)
        {
            return VERTEXES[vertexNum][xYZ]/SCALER;
        }
     
        float GetUV(int uvNum, int xYZ)
        {
            return UVS[uvNum][xYZ]/SCALER;
        }
     
        float GetNormal(int normalNum, int xYZ)
        {
            return NORMALS[normalNum][xYZ]/SCALER;
        }
     
        unsigned int GetFaces_Verticies(int faceNum, int xYZ)
        {
            return VERTEXES_INDEX[faceNum][xYZ];
        }
     
        unsigned int GetFaces_Uvs(int faceNum, int xYZ)
        {
            return UVS_INDEX[faceNum][xYZ];
        }
     
        unsigned int GetFaces_Normals(int faceNum, int xYZ)
        {
            return NORMALS_INDEX[faceNum][xYZ];
        }
     
        bool GetIsModelLoaded()
        {
            return IsModelLoaded;
        }
     
        unsigned int GetNumberVertextes()
        {
           return numVertexes;
        }
     
        unsigned int GetNumberNormals()
        {
           return numNormals;
        }
     
        unsigned int GetNumberFaces()
        {
            return numFaces;
        }
     
        bool LoadModel(char* modelLocation)
        {
     
            std::ifstream fileHandle;
            std::string readStr;
            unsigned int index, CountN, CountM, vertexCount, uvCount, normalCount, faceCount;
     
            fileHandle.open(modelLocation);
     
            if (fileHandle)
            {
                CountN = vertexCount = uvCount = normalCount = 0;
                while (std::getline(fileHandle, readStr))
                {
                    //Load Vertexes first
                    if (readStr.substr(0, 2) == "v ")   //Vertexes
                    {
                        readStr.erase(0,2);
     
                        CountN = 0;
                        while (CountN < 3)
                        {
                            if (CountN == 2)
                                index = readStr.length();
                            else
                                index = readStr.find(" ", 0);
     
                            VERTEXES[vertexCount][CountN] = atof(readStr.substr(0, index).c_str());
                            readStr.erase(0, index+1);
                            ++CountN;
                        }
                        ++vertexCount;
                    }
                    else if (readStr.substr(0,2) == "vt")   //UVS
                    {
                        readStr.erase(0,2);
     
                        CountN = 0;
                        while (CountN < 3)
                        {
                            if (CountN == 2)
                                index = readStr.length();
                            else
                                index = readStr.find(" ", 0);
     
                            UVS[uvCount][CountN] = atof(readStr.substr(0, index).c_str());
                            readStr.erase(0, index+1);
                            ++CountN;
                        }
                        ++uvCount;
                    }
                    else if (readStr.substr(0,2) == "vn")   //NORMALS
                    {
                        readStr.erase(0,2);
     
                        CountN = 0;
                        while (CountN < 3)
                        {
                            if (CountN == 2)
                                index = readStr.length();
                            else
                                index = readStr.find(" ", 0);
     
                            NORMALS[normalCount][CountN] = atof(readStr.substr(0, index).c_str());
                            readStr.erase(0, index+1);
                            ++CountN;
                        }
                        ++normalCount;
                    }
                    else if (readStr.substr(0,2) == "f ")   //FACES
                    {
                        readStr.erase(0,2);
     
                        CountN = CountM = 0;
     
                        while (CountN < 3)
                        {
                            while (CountM < 3)
                            {
     
                                if (CountM == 0) //VERTEXES
                                {
                                    index = readStr.find("/", 0);
                                    VERTEXES_INDEX[vertexCount][CountN] = atoi(readStr.substr(0, index).c_str());
                                }
                                else if (CountM == 1) //UVS
                                {
                                    index = readStr.find("/", 0);
                                    UVS_INDEX[vertexCount][CountN] = atoi(readStr.substr(0, index).c_str());
                                }
                                else if (CountM == 2) //NORMALS
                                {
                                    index = readStr.find(" ", 0);
                                    NORMALS_INDEX[vertexCount][CountN] = atoi(readStr.substr(0, index).c_str());
                                }
                                readStr.erase(0, index+1);
                                ++CountM;
                                ++faceCount;
                            }
                            ++CountN;
                        }
                    }
                }
                fileHandle.close();
                IsModelLoaded = true;
     
                numVertexes = vertexCount;
                numUVS = uvCount;
                numNormals = normalCount;
                numFaces = faceCount;
            }
            else
                IsModelLoaded = false;
            return IsModelLoaded;
        }
    };

    And also the wavefront file I am trying to load (it should be a simple cube I explorted from Blender):
    Code :
    # Blender v2.67 (sub 1) OBJ File: ''
    # www.blender.org
    o Cube
    v 1.000000 -1.000000 -1.000000
    v 1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 1.000000
    v -1.000000 -1.000000 -1.000000
    v 1.000000 1.000000 -0.999999
    v 0.999999 1.000000 1.000001
    v -1.000000 1.000000 1.000000
    v -1.000000 1.000000 -1.000000
    vn 0.000000 -1.000000 0.000000
    vn -0.000000 1.000000 0.000000
    vn 1.000000 -0.000000 0.000001
    vn -0.000000 -0.000000 1.000000
    vn -1.000000 -0.000000 -0.000000
    vn 0.000000 0.000000 -1.000000
    vn 1.000000 0.000000 -0.000000
    s off
    f 1//1 2//1 3//1
    f 5//2 8//2 7//2
    f 1//3 5//3 6//3
    f 2//4 6//4 3//4
    f 3//5 7//5 4//5
    f 5//6 1//6 4//6
    f 4//1 1//1 3//1
    f 6//2 5//2 7//2
    f 2//7 1//7 6//7
    f 6//4 7//4 3//4
    f 7//5 8//5 4//5
    f 8//6 5//6 4//6

    I have tried quite a few exaples of how to implement it online without 3rd party tools however everything I have tried renders incorrectly..

    If someone would be kind enough to verify that this code is correct and tell me how to implement the data into opengl I would be eternally greatful.

    Many Thanks

    Doctrorzeus

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    749
    Code :
       float VERTEXES[MAXVERTEXES][2];
        float UVS[MAXUVS][2];
        float NORMALS[MAXNORMALS][2];

    Why do positions and normals only have two components, you need three to store x,y,z.

    There is one difficulty with OBJ files in that they use multiple indices (one for each vertex attribute) where OpenGL only supports a single index that is used for all vertex attributes. There are many posts (e.g. here) on this forum with solutions.
    Without seeing how you use that data to actually render anything it is hard to say why it does not render correctly - have you verified that the data is loaded the way you expect it to be?

  3. #3
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    14
    Quote Originally Posted by carsten neumann View Post
    Code :
       float VERTEXES[MAXVERTEXES][2];
        float UVS[MAXUVS][2];
        float NORMALS[MAXNORMALS][2];

    Why do positions and normals only have two components, you need three to store x,y,z.

    There is one difficulty with OBJ files in that they use multiple indices (one for each vertex attribute) where OpenGL only supports a single index that is used for all vertex attributes. There are many posts on this forum with solutions.
    Without seeing how you use that data to actually render anything it is hard to say why it does not render correctly - have you verified that the data is loaded the way you expect it to be?
    Thankyou very much for the reply ..

    I use each array as the following e.g:

    VERTEXES[VertixNumber][xyz];

    The second array (2) is used as x,y and z.. I.e. x=0, y=1, z=2...

    I ran the data through a breakpoint when it was loaded and it all seemed to look fine, the issue seems to be just using it.

    Thanks for the link, I will take a look and have a search!

    DoctorZeus

  4. #4
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    14
    Sorry but after doing a bit of searching I am still unsure about faces..

    I know how to plot the verticies and normals (UVS are for textures which in this case is N/A because there are none).

    By using glVertex3f() and glNormal3f().

    However I am unsure exacly how faces can be used with verticies and normals?

    Sorry to be a bother but I still don't quite see the relationship..

    Thanks

    DoctorZeus

  5. #5
    Member Regular Contributor
    Join Date
    Jan 2011
    Location
    Paris, France
    Posts
    250
    You can for example take a look at http://en.wikibooks.org/wiki/OpenGL_...orial_Load_OBJ or http://devernay.free.fr/hacks/glm about how to implement the handling of the .OBJ format
    Last edited by The Little Body; 07-10-2013 at 02:49 PM.
    @+
    Yannoo

  6. #6
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    490
    Quote Originally Posted by doctorzeus View Post
    I use each array as the following e.g:

    VERTEXES[VertixNumber][xyz];

    The second array (2) is used as x,y and z.. I.e. x=0, y=1, z=2...
    In which case, the second dimension needs to be 3, not 2. The value used in the declaration is the number of elements, not the highest valid index. The latter is one less than the former (e.g. if the number of elements is 3, valid indices are 0, 1 and 2).

  7. #7
    Junior Member Regular Contributor
    Join Date
    Apr 2012
    Location
    Los Angeles
    Posts
    187
    Quote Originally Posted by doctorzeus View Post
    ... I am unsure exacly how faces can be used with verticies and normals.
    If I understand your question, you do not seem to know what a line like f 1//1 2//1 4//2 means in an obj file. It defines one of the triangles making up the cube. 'f' stands for 'face'. This particular face is a triangle made up of vertices 1,2, and 4 (indices into the vertex data you've read in). Since you seem to be able to plot points, I assume you understand what these indices mean. To plot points you use glBegin (GL_POINTS) followed by glVertex commands. To plot a triangle you could use glBegin (GL_TRIANGLES) or glBegin (GL_POLYGON). This is the most basic way to plot a polygon. Once you get this down and start dealing with large amounts of polygons you may want to use other ways to display your polygonal objects.

  8. #8
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    14
    Thanks for the replies, been very helpful and the obj loader works properly now , however I am still having a few difficulties implementing it..

    Why doesn't this work?
    Code :
    void AddObjectToRender(GraphicsStruc_Model *pTR)
        {
                    for (unsigned int i=0; i < pTR->GetNumberFaces()-3; i++)
    		{
    			glBegin(GL_TRIANGLES);
    			glVertex3f(pTR->GetVertex(pTR->GetFaces_Verticies(i,0)-1,0), pTR->GetVertex(pTR->GetFaces_Verticies(i,1)-1,1), pTR->GetVertex(pTR->GetFaces_Verticies(i,2)-1,2));
    			glVertex3f(pTR->GetVertex(pTR->GetFaces_Verticies(i+1,0)-1,0), pTR->GetVertex(pTR->GetFaces_Verticies(i+1,1)-1,1), pTR->GetVertex(pTR->GetFaces_Verticies(i+1,2)-1,2));
    			glVertex3f(pTR->GetVertex(pTR->GetFaces_Verticies(i+2,0)-1,0), pTR->GetVertex(pTR->GetFaces_Verticies(i+2,1)-1,1), pTR->GetVertex(pTR->GetFaces_Verticies(i+2,2)-1,2));
    			glEnd();
    		}
    }

    Many Thanks

    DoctorZeus
    Last edited by doctorzeus; 08-02-2013 at 03:49 PM.

  9. #9
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Posts
    749
    Why doesn't this work?
    It's very difficult to say anything other than "because apparently it's wrong" in reply to such a question - please give details what does not work. One thing I can see from looking at the code is that the third glVertex call should probably use i+2 instead of i+1. Also, why are you using glVertex3d when your values are floats? That just causes a conversion to double for the glVertex3d call and then is converted back to float by OpenGL.

  10. #10
    Junior Member Newbie
    Join Date
    Jul 2013
    Posts
    14
    Quote Originally Posted by carsten neumann View Post
    It's very difficult to say anything other than "because apparently it's wrong" in reply to such a question - please give details what does not work. One thing I can see from looking at the code is that the third glVertex call should probably use i+2 instead of i+1. Also, why are you using glVertex3d when your values are floats? That just causes a conversion to double for the glVertex3d call and then is converted back to float by OpenGL.
    Thanks for the Reply..

    Oops yes I just realized that I kinda made that sound like a quiz question (which was not my intent) :P ..

    I corrected those thanks for realizing that..

    Basically all the triangles when rendered are clearly connected in an incorrect way i.e:
    Click image for larger version. 

Name:	INCORRECTRENDER.jpg 
Views:	60 
Size:	38.4 KB 
ID:	1091
    (suppose to be three wine glasses..

    Which leads me to assume that I am implementing the data incorrectly through the AddObjectToRender() method..

    Many Thanks

    DoctorZeus

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •