[RESOLVED] gluUnproject headaches

Started by
7 comments, last by Hnefi 16 years, 9 months ago
I got me a scene which essentially consists of a perspective-viewed flat plane along which objects are dispersed in a random fashion. There is nothing between these objects. The plane is the xy-plane and I view it along the z axis from a camera with arbitrary coordinates. I want to be able to pick objects with the mouse and do stuff to them. So I try to use gluUnproject, but it keeps giving me the wrong coordinates. Nothing I've tried works. The code is below; any ideas what might be wrong?
void Session::SelectSystem(int x, int y){
	static GLdouble modelmatrix[16];
	static GLdouble projmatrix[16];
	static GLint viewport[4];

	glGetDoublev(GL_MODELVIEW_MATRIX, modelmatrix);
	glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
	glGetIntegerv(GL_VIEWPORT, viewport);

	GLdouble tx, ty, tz;
	GLdouble z;
	glReadPixels(x, viewport[3]-y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);

	gluUnProject(x, y, z, modelmatrix, projmatrix, viewport, &tx, &ty, &tz);
}
[Edited by - Hnefi on July 8, 2007 1:05:53 PM]
-------------Please rate this post if it was useful.
Advertisement
Your code is perfectly fine. Are you rendering in wireframe mode? Are you making sure to call SelectSystem after everything is rendered to the screen? If the depth buffer is blank then you'll definitely get odd values.
Author Freeworld3Dhttp://www.freeworld3d.org
Hmm. I'm using SDL and SelectSystem is triggered during a mouseclick event. It's possible that this event is triggered before the render loop. I'll try to synch it and see what happens. ETA: Synching it didn't work. Placed the code directly after I finished rendering the world and got identical result.

Is there otherwise a way to unproject screen coordinates to a plane, parallell to the camera and a given distance from it without doing the linear algebra manually?
-------------Please rate this post if it was useful.
To be honest, I've never gotten this to work with glReadPixels() either. It always threw weird numbers at me, no matter what I did. But there is another way - you can call gluUnProject() twice, with z-coords of 0 and 1. You can then construct a ray (well, a line segment really) between the two points and collide this ray with your geometry (and if there are no collisions, I find the intersection with the y=0 plane). This works fine, assuming this isn't some issue with SDL. I can post some code if you like (it's a bit long and in Java).
That might work. Beats projecting everything onto the screen, anyway.

As far as I understand, the "z" coordinate in gluUnProject is the normalized z-buffer. Does that mean that with a viewport that goes from 1 to 1000 in the z direction, a z=0 means, in world coordinates relative to the camera, world_z = 1 and z=1 => world_z = 1000?
-------------Please rate this post if it was useful.
Is GL_DEPTH_TEST enabled?

glEnable(GL_DEPTH_TEST);


I think that this might solve the problem.
It's enabled. Switching it on or off makes no difference.
-------------Please rate this post if it was useful.
Quote:Original post by Hnefi
That might work. Beats projecting everything onto the screen, anyway.

As far as I understand, the "z" coordinate in gluUnProject is the normalized z-buffer. Does that mean that with a viewport that goes from 1 to 1000 in the z direction, a z=0 means, in world coordinates relative to the camera, world_z = 1 and z=1 => world_z = 1000?


Exactly, it goes between the near and far plane. The difference of the results is the direction of the ray (in camera space, if I'm not mistaken), and the origin is at the camera.
Success! The final code (before cleanup, obviously) ended up looking like this, with the result of the mouse coordinates in z = 0 being stored in rx and ry:
void Session::SelectSystem(int x, int y){	static GLdouble modelmatrix[16];	static GLdouble projmatrix[16];	static GLint viewport[4];	glGetDoublev(GL_MODELVIEW_MATRIX, modelmatrix);	glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);	glGetIntegerv(GL_VIEWPORT, viewport);	static GLdouble x1, y1, z1, x2, y2, z2, rx, ry;	gluUnProject(x, viewport[3]-y, 0, modelmatrix, projmatrix, viewport, &x1, &y1, &z1);	gluUnProject(x, viewport[3]-y, 1, modelmatrix, projmatrix, viewport, &x2, &y2, &z2);	z1 -= screen->camera->GetPos().z;	x1 -= screen->camera->GetPos().x;	y1 += screen->camera->GetPos().y;	double t = z2/z1;	rx = x2 - x1*t;	ry = y2 - y1*t;	if(z2 - z1*t > 0.01 || z2 - z1*t < -0.01)		Error(true, 0, "Crud!");}

The viewport[3]-y is most likely due to the fact that I translate my camera thusly:
void Camera::Translate() const{	glTranslated(-pos.x, pos.y, -pos.z);}


So there we go. Finally a working unproject. Thanks for all your help guys!
-------------Please rate this post if it was useful.

This topic is closed to new replies.

Advertisement