How to select an object using OpenGL






4.61/5 (17 votes)
This article explains how to select an object using OpenGL.
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!