PDA

View Full Version : gluUnProject Question



_student
06-01-2005, 09:12 AM
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, &amp;x, &amp;y, &amp;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, &amp;pfd);
SetPixelFormat(hDC, pixel, &amp;pfd);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
}

void FullScreen()
{
DEVMODE dm;

memset(&amp;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(&amp;dm, CDS_FULLSCREEN);
//ShowCursor(FALSE);
}

bool CreateGLWindow()
{
WNDCLASS wc;
RECT rect;

SetRect(&amp;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(&amp;wc))
{
return false;
}

AdjustWindowRectEx(&amp;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(&amp;msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&amp;msg);
DispatchMessage(&amp;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);
}

plasmonster
06-01-2005, 08:53 PM
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.