This topic is 3882 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

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 on other sites
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 on other sites
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 on other sites
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 on other sites
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 on other sites
Is GL_DEPTH_TEST enabled?

glEnable(GL_DEPTH_TEST);

I think that this might solve the problem.

Share on other sites
It's enabled. Switching it on or off makes no difference.

Share on other sites
Quote:
 Original post by HnefiThat 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 on other sites
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!