Wednesday, May 25, 2011

Loading .obj in OpenGL

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.