Wednesday, May 25, 2011

Loading .obj in OpenGL

Update (Oct 10, 2014) :

I have updated this tutorial, I have included a git repository too. Please refer this site: http://netization.blogspot.in/2014/10/loading-obj-files-in-opengl.html



In this tutorial I explain how you can load .obj files into OpenGL. There also a working objloader.c file for download.

I wanted to load various .obj files to create various elements ranging from simple cubes to satellites, from car models to abstract 3d designs in my university project dealing with movement in a 3D environment. I searched the internet, I succeeded in getting .obj files but could not get a satisfactory loader using which complex objects could be loaded into my OpenGL program. I had plenty of .obj files but could not put into use as there was no loader.

Then I thought maybe I should understand the format of .obj files and design my own code to read information from .obj file and load it into the OpenGL program. I spent a few minutes understanding the format and a few more minutes to write the code to scan information from it. However I restricted my code only to read the vertex information and display it using GL_POINTS.

Try to understand the .obj format from here: http://www.royriggs.com/obj.html

After spending some time I was surprised at how nice the code worked and how well the object in .obj was loaded.


Here goes the loader:


void loadObj(char *fname)
{
     FILE *fp;
     int read;
     GLfloat x, y, z;
     char ch;
     car=glGenLists(1);
     fp=fopen(fname,"r");
     if (!fp)
     {
       printf("can't open file %s\n", fname);
       exit(1);
     }
     glPointSize(2.0);
     glNewList(car, GL_COMPILE);
    {
      glPushMatrix();
      glBegin(GL_POINTS);
      while(!(feof(fp)))
     {
       read=fscanf(fp,"%c %f %f %f",&ch,&x,&y,&z);
       if(read==4&&ch=='v')
       {
         glVertex3f(x,y,z);
       }
     }
     glEnd();
    }
    glPopMatrix();
    glEndList();
    fclose(fp);
}

This is a fully executable program with .obj file placed in the appropriate place.

/*
Tejus
Institution: JSSATE, Bangalore
Semester: 6
Year: 2011
www.objinopengl.blogspot.com
*/
//header


#include<GL/gl.h>
#include<GL/glut.h>
#include<stdio.h>


//globals


GLuint car;
float carrot;


//other functions and main
//.obj loader code


void loadObj(char *fname)
{
   FILE *fp;
   int read;
   GLfloat x, y, z;
   char ch;
   car=glGenLists(1);
   fp=fopen(fname,"r");
   if (!fp)
  {
    printf("can't open file %s\n", fname);
    exit(1);
  }
   glPointSize(2.0);
   glNewList(car, GL_COMPILE);
   {
    glPushMatrix();
    glBegin(GL_POINTS);
    while(!(feof(fp)))
    {
     read=fscanf(fp,"%c %f %f %f",&ch,&x,&y,&z);
     if(read==4&&ch=='v')
    {
     glVertex3f(x,y,z);
     }
   }
   glEnd();
   }
   glPopMatrix();
   glEndList();
   fclose(fp);
}
//.obj loader code ends here
void reshape(int w,int h)
{
   glViewport(0,0,w,h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective (60, (GLfloat)w / (GLfloat)h, 0.1, 1000.0);
   //glOrtho(-25,25,-2,2,0.1,100);
   glMatrixMode(GL_MODELVIEW);
}


void drawCar()
{
   glPushMatrix();
   glTranslatef(0,-40.00,-105);
   glColor3f(1.0,0.23,0.27);
   glScalef(0.1,0.1,0.1);
   glRotatef(carrot,0,1,0);
   glCallList(car);
   glPopMatrix();
   carrot=carrot+0.6;
   if(carrot>360)carrot=carrot-360;
}


void display(void)
{
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
drawCar();
glutSwapBuffers(); //swap the buffers
}


int main(int argc,char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(800,450);
glutInitWindowPosition(20,20);
glutCreateWindow("ObjLoader");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(display);
loadObj("data/elepham.obj");//replace porsche.obj with radar.obj or any other .obj to display it
glutMainLoop();
return 0;
}

You can also download from here. CLICK HERE TO DOWNLOAD OBJLOADER.

Sample screen shots of the objloader.

10 comments:

  1. Hey! Nice simple and sleek code, problem is it wont work for me. I mean it compiles without any error or anything but all i can see is 1 - 4 dots rotating depend on /obj file. Can you help me with that? Tried both on win7 and ubuntu

    ReplyDelete
  2. Same here buddy the object is way way smaller

    ReplyDelete
  3. Well it is designed to show only dots.
    and to increase the size replace your glTranslatef values with
    glTranslatef(0.0f,0.0f,-3.0f);

    ReplyDelete
  4. Omg, an obj loader that render points. Soo useful!

    ReplyDelete
  5. Do you know how to load faces.

    ReplyDelete
  6. Code is really useful.But i am having d same prob.When i change d .obj file its showing only few points.Also can anyone help me to load faces.

    ReplyDelete
  7. You have the code and can't look for the line with glTranslatef ... This actually works, and it DOES NOT SHOW only a few points...

    line 72, change -105 value to something smaller... or implement the callback function to vary that parameter...

    ReplyDelete
  8. Do u know how to load faces?

    I tried with ds

    glBegin(GL_TRIANGLES);
    glVertex3f(x1,y1,z1);
    glvertex3f(x2,y2,z2);
    glVertex3f(x3,y3,z3);
    glEndl()

    but its not working..

    ReplyDelete
  9. jst awesome............

    clean coding..and almost the shortest obj loader code...
    :)

    ReplyDelete
  10. The code is wrong. When you check if the file was opended correctly in sentence if(!fp) the cmd return "Can´t open file" always because the fopen function only returns a pointer to file if success or a pointer to NULL when it fails, the sentende !fp its !=0 and its always. The solution its to change if(!fp){... to if(fp==NULL).

    ReplyDelete