Having re-worked the XML level and model file formats to be far prettier and more adaptable for the future and built the core systems for handling editor objects etc. I moved onto the new graphical display for the level editor.
AAII uses a sort of 2.5D isometric view, which means some sort of coordinate transformation has to be done converting mouse coords to in-game 3D coords. Luckily for me I had the full glu libraries available since I was developing the editor in OSX rather than iPhone (there's actually iPhone versions of gluUnProject around the web if you care to find them) and this meant I could simply use gluUnProject rather than do the maths manually (although it's actually not the trickiest maths if you've got time).
Perhaps it was from working too late whilst fatigued but this coordinate conversion has managed to eat up a good few hours of time. It's very important to set up the correct OpenGL state before using gluUnProject if you want to get any sense out of it. I spent a lot of time searching around for examples for this function and whilst they are out there, they didn't take into account various things and often left users still stumbling to get it working for their own situations. So here is some commented code, highlighting the key things, which I hope helps anyone else who is finding screen to object space coordinate conversion using this function a nightmare.
// Enable depth test glEnable(GL_DEPTH_TEST); glDepthMask(1); glDepthFunc( GL_LEQUAL ); glViewport(0, 0, backingWidth, backingHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(35, backingWidth/backingHeight, 1.0, 1000.0); //Push the gluLookAt projection matrix onto the stack glMatrixMode(GL_PROJECTION); glPushMatrix(); gluLookAt(m_fcamEyeX-65.0f, m_fcamEyeY-65.0f, 100.0, m_fcamEyeX, m_fcamEyeY, 0.0f, 1.0f, 5.0f, 0.0f); // Update and render the scene Update(); Render(); if(mouseClicked) { // Remember this must be done after rendering our scene as otherwise // there will be no polygons there to detect depth for! MouseToOpenGLCoords(); }
So next I check if the mouse was clicked that frame and if so convert it's coordinates to OpenGL world coordinates. We need to call glReadPixels to supply the zDepth of the polygon that was clicked on in the view. Clicking on empty space will result in a zDepth of 1.0 i.e. maximum depth of the view frustum.
void MouseToOpenGLCoords() { GLdouble dMatrix[16]; GLdouble dProjection[16]; GLint iViewport[4]; GLfloat m_fDepth; // We need to grab the projection and model view matrices along with the viewport // for the conversion glGetDoublev(GL_PROJECTION_MATRIX, dProjection); glGetDoublev(GL_MODELVIEW_MATRIX, dMatrix); glGetIntegerv(GL_VIEWPORT, iViewport); m_fWindow[0] = m_mousePoint.x; m_fWindow[1] = m_mousePoint.y; // Read the zDepth of the coordinate where the screen was clicked. Will simply return // 1.0 if you don't click on a polygon. glReadPixels(m_fWindow[0],m_fWindow[1],1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&m_fDepth); // use gluUnProject to get the OpenGL world coordinates gluUnProject(m_fWindow[0], m_fWindow[1], m_fDepth, dMatrix, dProjection, iViewport, &m_dOpenGLCoord1[0], &m_dOpenGLCoord1[1], &m_dOpenGLCoord1[2]); }
No comments:
Post a Comment