65.9K
CodeProject is changing. Read more.
Home

How to select an object using OpenGL

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (17 votes)

Oct 30, 2003

CPOL

1 min read

viewsIcon

164340

downloadIcon

8968

This article explains how to select an object using OpenGL.

Sample Image

Introduction

I am Vietnamese and my English is not good. But I hope you will understand my article. I tried to write a game as my project in school. I decided to write it using 3D technique, and I used OpenGL for this. I looked for a way to select an object on a lot object overunder on 3D and I have found it. In this article I want to introduce you to how to do it.

Using the code

In this example I use MFC wizard. All my code was written on CView.

Add variables:

private:
    GLdouble gldAspect;
    GLsizei glnWidth, glnHeight;
    HGLRC hRC;
    Cube cube[4];
    double r;

Cube is defined in MyOpenGL.h.

Use "class wizard" for message map: WM_CREATE, WM_DESTROY, WM_EARSEBKGND, WM_LBUTTONDOWN, WM_PAINT, WM_SIZE, WM_TIMER.

On another article in CodeProject about OpenGL you can see the code for WM_SIZE and WM_PAINT, WM_CREATE (I use the code again! Thanks to the owner's code!).

Additionally, on WM_CREATE, init for some variables and start the timer for animation.

int CTry_OpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
     if (CView::OnCreate(lpCreateStruct) == -1)
          return -1;
     
     // TODO: Add your specialized creation code here
     hRC=SetUpOpenGL(m_hWnd);
     for(int i=0;i<4;i++) cube[i].x=i*2-3;
     r=0;
     SetTimer(1000,100,NULL);

     return 0;
}

Of course, kill timer in OnDestroy().

Timer:

void CTry_OpenGLView::OnTimer(UINT nIDEvent) 
{
     r+=5;
     if(r>=360) r=0;
     RedrawWindow();

     CView::OnTimer(nIDEvent);
}

In OnEraseBkgnd: delete all (if not, the screen will "flick").

And now, the code to pick an object:

void CTry_OpenGLView::OnLButtonDown(UINT nFlags, CPoint point) 
{
     // TODO: Add your message handler code here and/or call default
    GLuint selectBuf[BUFSIZE];
    GLint hits;
    GLint viewport[4];

     HDC hDC = ::GetDC(this->m_hWnd);
     wglMakeCurrent(hDC,hRC);

    glGetIntegerv (GL_VIEWPORT, viewport);
    glSelectBuffer (BUFSIZE, selectBuf);

    glRenderMode(GL_SELECT); // Enter the SELECT render mode
    glInitNames();
    glPushName(-1);

    glMatrixMode (GL_PROJECTION);
    glPushMatrix ();
    glLoadIdentity ();
    gluPickMatrix((GLdouble) point.x, 
          (GLdouble) (viewport[3] - point.y), 
          5.0, 5.0, viewport);
    gluPerspective(30.0,gldAspect,1.0,20.0);
    glMatrixMode(GL_MODELVIEW);
    PaintScreen(GL_SELECT);//function paint the objects.
    glPopMatrix ();
    glFlush ();

    hits = glRenderMode (GL_RENDER);

     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     glViewport(0,0,glnWidth,glnHeight);
     gluPerspective(30.0,gldAspect,1.0,20.0);
    
     /*for(int i=0;i<hits;i++)
     {
          cube[selectBuf[3+i*4]].selected= 
             !cube[selectBuf[3+i*4]].selected;
     }//select all (include the hide object)!
     */
     if (hits)
     {
          int n=0;double minz=selectBuf[1];
          for(int i=1;i<hits;i++)
          {
               if (selectBuf[1+i*4]<minz) 
                 {n=i;minz=selectBuf[1+i*4];}
          }
          cube[selectBuf[3+n*4]].selected=
              !cube[selectBuf[3+n*4]].selected;
     }//only select the object we see (nearest object)!

     wglMakeCurrent( NULL, NULL );
    ::ReleaseDC( this->m_hWnd, hDC );

     CView::OnLButtonDown(nFlags, point);
}

Points of interest

Is it easy, isn't it? My source has some wastes, I think. Thanks a lot if you can help me to remove it! ^_^

History

  • This is the first!