gluUnProject Question

I set gluPerspective(45.0f, 3.0f/ 2.0f, 0.1f, 400.0f), glViewport(0, 0, 1024, 768), gluLookAt(0.0f, 0.0f, 2.1f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f), the third parameter of gluUnProject is 0.5f. I think the objZ should have been -198f, but it was 1.9f. Could anyone tell me the reason?
Maybe it was my fault.

#include <windows.h>
#include <cstdio>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>

const int width = 1024;
const int height = 768;
const int bits = 32;

HDC hDC = NULL;
HGLRC hRC = NULL;
HWND hWnd = NULL;
HINSTANCE hInstance = NULL;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void ReleaseWindow();

bool keys[256];

GLuint g_FontListID;
HFONT hOldFont;
const int FONTHEIGHT = 32;

GLUquadricObj *sphere;

GLdouble x, y, z;
int x1, y1;

GLuint CreateGLFont(PSTR fontName, int height)
{
	GLuint fontListID;
	HFONT hFont;
	
	fontListID = glGenLists(256);
	
	hFont = CreateFont(height,
					  0,
					  0,
					  0,
					  FW_BOLD,
					  FALSE,
					  FALSE,
					  FALSE,
					  ANSI_CHARSET,
					  OUT_TT_PRECIS,
					  CLIP_DEFAULT_PRECIS,
					  ANTIALIASED_QUALITY,
					  DEFAULT_PITCH | FF_DONTCARE,
					  fontName);
	
	hOldFont = (HFONT)SelectObject(hDC, hFont);
	
	wglUseFontBitmaps(hDC, 0, 255, fontListID);
	
	return fontListID;
}

void PositionText(int x, int y)
{
	glPushAttrib(GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
	
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
			glLoadIdentity();
			
			glMatrixMode(GL_MODELVIEW);
			glPushMatrix();
				glLoadIdentity();
				
				y = height - FONTHEIGHT - y;
				
				glViewport(x - 1, y - 1, 0, 0);
			glPopMatrix();
			
			glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		
		glRasterPos4f(0.0f, 0.0f, 0.0f, 1.0f);
		
	glPopAttrib();
}

void printText(int x, int y, const char *str, ...)
{
	if (!str)
		return;
	
	char temp[1024];
	va_list argument;
	
	va_start(argument, str);
	
	vsprintf(temp, str, argument);
	
	va_end(argument);
	
	PositionText(x, y);
	
	glPushAttrib(GL_LIST_BIT);
		
		glListBase(g_FontListID);
		glCallLists(strlen(temp), GL_UNSIGNED_BYTE, temp);
	
	glPopAttrib();
}

void returnPos(int wx, int wy)
{
	GLdouble mvmatrix[16], projmatrix[16];
	GLint viewport[4];
	
	glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
	glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
	glGetIntegerv(GL_VIEWPORT, viewport);
	
	wy = viewport[3] - (GLint)wy - 1;
	
	gluUnProject((GLdouble)wx, (GLdouble)wy, 0.5f, mvmatrix, projmatrix, viewport, &x, &y, &z);	
}

void InitLight()
{
	GLfloat light_pos[] = { 0.0f, 0.0f, 1.0f, 1.0f };
	GLfloat light_ambient[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	
	glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
	//glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	//glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	//glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	
	GLfloat mat_ambient[] = { 0.8f, 0.2f, 0.5f, 1.0f };
	GLfloat mat_diffuse[] = { 0.6f, 0.2f, 0.3f, 1.0f };
	GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat mat_shininess[] = { 5.0f };
	GLfloat mat_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };
	
	glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
	glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
	//glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
	
	glEnable(GL_LIGHT0);
	//glEnable(GL_LIGHTING);
}

bool InitGL()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	
	glClearDepth(1.0f);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);
	glDepthRange(0.0f, 1.0f);
	
	glViewport(0, 0, width, height);	
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	gluPerspective(45.0f, (GLdouble)width / (GLdouble)height, 0.1f, 400.0f);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	InitLight();
	
	sphere = gluNewQuadric();
	
	g_FontListID = CreateGLFont("Arial", FONTHEIGHT);
	
	return true;
}

void DrawGLScene()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	
	gluLookAt(0.0f, 0.0f, 2.1f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
	
	glEnable(GL_LIGHTING);
	gluSphere(sphere, 0.5f, 30, 30 );
	glDisable(GL_LIGHTING);
	
	glColor3f(1.0f, 1.0f, 1.0f);
	printText(0, 0, "x = %.2f, y = %.2f, z = %.2f.", x, y, z);
	printText(0, FONTHEIGHT, "WX = %d, WY = %d", x1, y1);
}

void SetupPixelFormat()
{
	int pixel;
	
	static PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(pfd),
		1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		bits,
		0, 0, 0, 0, 0, 0, 0, 0,
		32,
		8, 8, 8, 8,
		32,
		0,
		0,
		PFD_MAIN_PLANE,
		0,
		0, 0, 0
	};
	
	hDC = GetDC(hWnd);
	pixel = ChoosePixelFormat(hDC, &pfd);
	SetPixelFormat(hDC, pixel, &pfd);
	hRC = wglCreateContext(hDC);
	wglMakeCurrent(hDC, hRC);
}

void FullScreen()
{
	DEVMODE dm;
	
	memset(&dm, 0, sizeof(dm));
	
	dm.dmSize = sizeof(dm);
	dm.dmPelsWidth  = width;
	dm.dmPelsHeight = height;
	dm.dmBitsPerPel = bits;
	dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
	
	ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
	//ShowCursor(FALSE);
}

bool CreateGLWindow()
{
	WNDCLASS wc;
	RECT rect;
	
	SetRect(&rect, 0, 0, width, height);
	hInstance = GetModuleHandle(NULL);
	
	wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);;
	wc.hbrBackground = NULL;
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "OpenGL";
	
	if (!RegisterClass(&wc))
	{
		return false;
	}
	
	AdjustWindowRectEx(&rect, WS_POPUP, FALSE, WS_EX_APPWINDOW);
	
	hWnd = CreateWindowEx(WS_EX_APPWINDOW,
						  "OpenGL",
						  "",
						  WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
						  0, 0,
						  rect.right - rect.left, rect.bottom - rect.top,
						  NULL,
						  NULL,
						  hInstance, NULL);
	
	if (!hWnd)
	{
		return false;
	}
	
	SetupPixelFormat();
	FullScreen();
	
	ShowWindow(hWnd, SW_SHOW);
	SetForegroundWindow(hWnd);
	SetFocus(hWnd);
	
	if (!InitGL())
	{
		ReleaseWindow();
		
		return false;
	}
	
	return true;
}

void ReleaseWindow()
{
	ChangeDisplaySettings(NULL, 0);
	ShowCursor(TRUE);
	
	wglMakeCurrent(NULL, NULL);
	wglDeleteContext(hRC);
	ReleaseDC(hWnd, hDC);
	DestroyWindow(hWnd);
	UnregisterClass("OpenGL", hInstance);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance,
				   PSTR lpCmdLine, int nCmdShow)
{
	bool done = false;
	MSG msg;
	
	if (!CreateGLWindow())
	{
		return 0;
	}
	
	while (!done)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		
		else
		{
			DrawGLScene();
			SwapBuffers(hDC);
			
			if (keys[VK_ESCAPE])
			{
				done = true;
			}
		}
	}
	
	glDeleteLists(g_FontListID, 256);
	ReleaseWindow();
	
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
		case WM_SYSCOMMAND:
		{
			switch (wParam)
			{
				case SC_MONITORPOWER:
				case SC_SCREENSAVE:
				{
					return 0;
				}
			}
			
			break;
		}
		
		case WM_KEYDOWN:
		{
			keys[wParam] = true;
			
			return 0;
		}
		
		case WM_KEYUP:
		{
			keys[wParam] = false;
			
			return 0;
		}
		
		case WM_MOUSEMOVE:
		{
			x1 = (int)LOWORD(lParam);
			y1 = (int)HIWORD(lParam);
			
			returnPos(x1, y1);
			
			return 0;
		}
	}
	
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

Screen-space z’s are non-linear in eye-space, so a value of 0.5 is not likely to give expected results unless you bear this in mind.

Here’s an equation that relates the screen-space z, Zs, to the eye-space z, Ze:

Zs = (f + n) / (f - n) - 2 f n / (f - n) 1 / Ze,

where n and f are the zNear and zFar parameters to glFrustum()/gluPerspective(). This will map eye-space z’s to [-1,1], provided they’re within the near and far frustum bounds. You can follow this with a depth range mapping of your choice. By default, OpenGL will map this range to [0,1]; you could do likewise with Zs = (Zs + 1) / 2.

As an example, let’s say you have a zNear of 1, a zFar of 1000, and you want to know the screen-space z of something in between, say 500.

Zs = (f + n) / (f - n) - 2 f n / (f - n) 1 / Ze
= (1001) / 999 - 2000 / 999 1 / 500
~ .998

Zs = (Zs + 1) / 2
~ (.998 + 1) / 2
~ .999

Not what one might expect.