Sign in to follow this  
Hnefi

[RESOLVED] gluUnproject headaches

Recommended Posts

Hnefi    386
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]

Share this post


Link to post
Share on other sites
soconne    105
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.

Share this post


Link to post
Share on other sites
Hnefi    386
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?

Share this post


Link to post
Share on other sites
lightbringer    1070
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).

Share this post


Link to post
Share on other sites
Hnefi    386
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?

Share this post


Link to post
Share on other sites
lightbringer    1070
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.

Share this post


Link to post
Share on other sites
Hnefi    386
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!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this