Web Design,Programming,Mobile,iOS/Android,GameDev,IT Businness,eCommerce,Social Media

Advertisement

Thursday, 24 January 2013

OpenGL Backface Culling - Removing unseen faces to improve performance

15:16

OpenGL
OpenGL can be very useful if we know how to use it. But sometimes it can tire up our computer and eat performance resulting to slow application. No one likes this especially gamers. They want smooth games and  experience with 90 FPS during their gameplay. It is useful to know some pitfalls we should prevent when creating OpenGL applications.

There are many factors that reduce performance of your application, it depends on the code for example dynamically memory allocation and not freeing those resources, loading and displaying complex 3D meshes and scenes, calculating complex lighting algorithms etc. In this post i will discuss a very useful technique that OpenGL offers us to drastically improve performance of our applications. That is backface culling. Backface culling is a technique that slices up faces that are never seen.


For example if we know that an object is behind another object then we never see this back object but the computer still calculates its properties and wastes CPU and memory usage, then we can prevent this calculation by culling these faces or slicing up the entire object. However this does not remove the object from the scene thus it just removes the faces that are never seen. If we move back we can still see this object. Lets take this by an example. Imagine we have a cube in our scene. We know that a cube is made up of 6 faces. If we continually rotate this cube we notice that two the faces that are behind we never see them unless we do some extra effects and add a mirror behind. The computer still calculates these faces even if we dont see them.

OpenGL


Take a look at this picture. Faces marked with X are never seen unless we rotate the cube to see the backfaces but when we do so then we will not see the current fron taces, which means that everything that is behind we never see it but the computer calculates and this can be seen in wireframe mode by the lines that are added behind even though we dont see them in filled polygons mode.


There will be no problem with this cube even if we dont cull the faces but imagine with complex objects like houses with inner objects. It can eat your CPU. The cube above with culled faces would look something like this.

OpenGL



Notice how the back edges are removed and this means that the back faces are culled and are not calculated by the CPU. If we rotate the cube to see the back faces they will appear and the current front faces will be culled meaning that will be removed. There is a rule though when culling the faces. OpenGL must know in which direction vertices are connected to form a face. When you start creating a face you start by adding vertices for x y and z axes. And you continue to add until you form a face. You do the same thing for other faces. Thus you have a direction in which you build your object. This can be clockwise (CW) or counter clockwise (CCW). OpenGL as we said must know in which direction faces are build so it will know exactly what faces to remove.

OpenGL as we know is like a state machine. You do something you revert it. You enable something you disable something. And face culling can be enabled with function glEnable(GL_CULL_FACE) an d immediately below this command we specify the direction like this glFrontFace(GL_CCW) or glFrontFace(GL_CW) if we are building in clockwise.

To understand everything below you have sample program that demonstrates the cube above with culling enabled. Continually pres the c key on your keyboard to toggle face culling on and of so you can see the result. Also you can toggle the wireframe mode on and of by pressing the w key.


#include 
#include 
#include 


//Initialize OpenGL
void InitGL()
{
 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
 glShadeModel(GL_SMOOTH);                         
 glEnable(GL_DEPTH_TEST);                     
 glDepthFunc(GL_LEQUAL);
 glClearDepth(1.0f);
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  
  
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(45.0f, (GLfloat)640.0f / (GLfloat) 480.0f, 0.1f,100.0f);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();  
 
 
}

//Draw function
void Draw()
{
 
 //Draw the cube
 glBegin(GL_QUADS);
  glVertex3f( 1.0f, 1.0f,-1.0f);          
  glVertex3f(-1.0f, 1.0f,-1.0f);         
  glVertex3f(-1.0f, 1.0f, 1.0f);          
  glVertex3f( 1.0f, 1.0f, 1.0f);

  
  glVertex3f( 1.0f,-1.0f, 1.0f);         
  glVertex3f(-1.0f,-1.0f, 1.0f);        
  glVertex3f(-1.0f,-1.0f,-1.0f);         
  glVertex3f( 1.0f,-1.0f,-1.0f); 
   
 
  glVertex3f( 1.0f, 1.0f, 1.0f);          
  glVertex3f(-1.0f, 1.0f, 1.0f);        
  glVertex3f(-1.0f,-1.0f, 1.0f);          
  glVertex3f( 1.0f,-1.0f, 1.0f);  
  
 
  glVertex3f( 1.0f,-1.0f,-1.0f);         
  glVertex3f(-1.0f,-1.0f,-1.0f);          
  glVertex3f(-1.0f, 1.0f,-1.0f);         
  glVertex3f( 1.0f, 1.0f,-1.0f);
  
  
  glVertex3f(-1.0f, 1.0f, 1.0f);          
  glVertex3f(-1.0f, 1.0f,-1.0f);          
  glVertex3f(-1.0f,-1.0f,-1.0f);          
  glVertex3f(-1.0f,-1.0f, 1.0f);   
  
  
        glVertex3f( 1.0f, 1.0f,-1.0f);          
        glVertex3f( 1.0f, 1.0f, 1.0f);          
        glVertex3f( 1.0f,-1.0f, 1.0f);  
        glVertex3f( 1.0f,-1.0f,-1.0f);  
    glEnd();
     
    
    SDL_GL_SwapBuffers();
}

//Udate function
void Update()
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity();
 
 //Move back in the -z axis to see the full cube
 glTranslatef(0.0,0.0,-7.0);
 
 //Rotate the cube 30 pixels in the y axis
 glRotatef(30.0, 0.0, 1.0, 0.0);
}

int main(int argc, char *argv[])
{
 //Init SDL
 SDL_Init(SDL_INIT_EVERYTHING);
 SDL_Surface *Screen;
 SDL_Event   Event;
 Screen = SDL_SetVideoMode(640,480,32, SDL_SWSURFACE | SDL_OPENGL);
 
 //Go to opengl init function
 InitGL();
 
 bool Running = true;
 bool culling = false;
 bool wireframe = false;
 
 //Enter the main loop and dont exit until running = false
 while(Running)
 {
  while(SDL_PollEvent(&Event))
  {
   switch(Event.type)
   {
    case SDL_QUIT:
     Running = false;
     break;
     
    case SDL_KEYDOWN:{
     //SDL functions for key handling
        Uint8* state=SDL_GetKeyState(NULL);
        if(state[SDLK_ESCAPE])
                    {
      Running = false;
      break;
                    }
                    
                    if(state[SDLK_w])
                    {
      if(wireframe == false){
       glPolygonMode(GL_FRONT, GL_LINE);
       glPolygonMode(GL_BACK, GL_LINE);
       wireframe = true;
       }
       else{
       glPolygonMode(GL_FRONT, GL_FILL);
       glPolygonMode(GL_BACK, GL_FILL);
       wireframe = false;
       }
      break;
                    }
                    
                    if(state[SDLK_c])
                    {
      if(culling == false)
      {
       //Enable face culling
       glEnable(GL_CULL_FACE);
       glFrontFace(GL_CCW);
       culling = true;
         }
         else
         {
       //Disable face culling
       glDisable(GL_CULL_FACE);
       culling = false;
      }
      break;
                    }
                }
   }
  }
  //Afer polling events update and draw objects onto the screen
  Update();
  Draw();
 }
 
 SDL_Quit();
 return 0;
}

As you can see the above code uses SDL for windowing platform meaning that you can compile this code on any platform but you have to install the SDL libraries. For example i compiled this on Ubuntu Linux and it works fine. You can also compile on windows but you have to install SDL libraries. If you dont know what SDL is follow this post and if you will learn what is SDL and how to configure it on visual studio for windows. Also in this post i explain how to configure SDL on ubuntu. And you can also read this post if you want to create your first SDL window. And as always thanks for reading.

Written by

Thank you for taking your time to browse through our blog. We try to build as much rich content base as we can. We focus in modern technologies, computer science design and business.

0 comments :

Post a Comment

 

© 2013 smartnoob . All rights resevered. Designed by Templateism