I think this should be pretty simple but I can’t get my head around it. I set up my camera at an z value of 3000 to get a bigger distance to the things I render at the origin like this:
gluLookAt(ofGetWidth()/2.0, ofGetHeight()/2.0, 3000, ofGetWidth()/2.0, ofGetHeight()/2.0, 0, up.x, up.y, up.z);
the problem is that if I render something at the mouseCoordinates at z = 0 they don’t correspond to the window coordinates correctly. I want that mouseX and mouseY still represent the X and Y values representing my mouseCursor. Since I don’t turn the camera I don’t necessarily need them to be translated to 3D coordinates because the camera still looks from the front view. If anybody has an idea please tell me
The problem is that the camera has a perspective view so if you camera is 3000 pixels away from the place you are drawing then it is the same as if you hadn’t moved the camera but translated the object back in z space but 3000 pixels. And the further back something moves the closer it gets to the vanishing point.
In OF the dist that you changed is calculated with some trig so that the edges of the viewing volume line up with the edges of the window. If you manually change that things won’t line up how you expect. A better option might be to adjust the field of view parameter - that way you can change how wide your canvas is without loosing your coordinates.
Otherwise If you want to have the object follow the mouse position no matter what its depth is you can use gluProject and gluUnProject to transform the window coordiantes to world coordinates and back again.
I think you would need the unProject method - you would pass in the mouse x and mouse y, and it would give you back x y z for where the point would need to be so that it is drawn under the mouse.
Hope that helps!
thanks theo, I allready tried the unProject method but didn’t succeed so far. I think I will manage to do that though. I was just hoping there was a simpler method.
Okay, I didnt get it done on my own.
the code I tried in an empty OF document is:
double modelview, projection;
//get the projection matrix
glGetDoublev( GL_PROJECTION_MATRIX, projection );
//get the modelview matrix
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
//get the viewport
glGetIntegerv( GL_VIEWPORT, viewport );
//Read the window z co-ordinate
//(the z value on that point in unit cube)
glReadPixels( x, viewport-y, 1, 1,
GL_DEPTH_COMPONENT, GL_FLOAT, &z );
//Unproject the window co-ordinates to
//find the world co-ordinates.
gluUnProject( x, viewport-y, z, modelview,
projection, viewport, &objx, &objy, &objz );
but it gave me totally weird results. I also tried to replace the viewport-y part with y since OF allready changes the vie so that increasing y goes down.
(that part is only used because openGL increasing y goes up while glut window starts at top left)
Does anybody know how to fix this so it runs properly in OF?
I think this will work (haven’t tried it):
// instead of gluLookAt
GLdouble z_far = 3000;
glTranslate(0, 0, -z_far);
int w = ofGetWidth(), h = ofGetHeight();
GLdouble z_near = 10;
left = -w/(2*z_dist);
bottom = -h/(w*z_dist);
glfrustum(left, -left, bottom, -bottom, z_near, z_far);
glViewport(0, 0, ofGetWidth(), ofGetHeight());
// draw your stuff…
I think that should do the trick. The idea is, you translate the camera back to (0, 0, -3000). Then you set the viewing frustum so that (0, ofGetHeight()/2.0, 0) projects back to the top of the screen, and (ofGetWidth()/2.0, 0) projects back to the right of the screen.
Finally, call glViewport to map the normalized device coords to the actual screen coordinates.
You wouldn’t be using this to control, oh, say, [EDIT: top secret!], by any chance?
shhhh its a secret
Well thanks for the hint I will try that. Even though it would be awesome to get the unProject function to work because that would enable a whole new level of control.
Any ideas about how to get that function to work in OF?
I’m not 100% sure I’m following here (just taking a quick break from a dumb compiler problem), but this is the code I use to get the mouse position on a 3D plane, the function needs to be called AFTER you set the camera transform.
// Get's the 3d position of the mouse on the plane
// y=0 and puts it in the vector mousePosOnPlane
void ASeasonSpring::getMousePosOnPlane(int x, int y)
float dx, dy, dz = 0.0;
int ry = tmpViewport - y - 1;
gluES::gluUnProject( x, ry, 0.0,
tmpModelView, tmpProjection, tmpViewport,
&dx, &dy, &dz);
mouseRayPosition.x = dx;
mouseRayPosition.y = dy;
mouseRayPosition.z = dz;
dx = dy = dz = 0.0;
gluES::gluUnProject( x, ry, 1.0,
tmpModelView, tmpProjection, tmpViewport,
&dx, &dy, &dz);
mouseRayVector.x = dx;
mouseRayVector.y = dy;
mouseRayVector.z = dz;
mouseRayVector -= mouseRayPosition;
// pre calc this ??
CVector planeNormal = CVector(0.0, 1.0, 0.0);
CVector pointOnPlane = CVector(-1.0, 0.0, 0.0);
float planeDistance = PlaneDistance(&planeNormal, &pointOnPlane);
float tmpDist = RayIntersectPlane(&planeNormal, planeDistance, &mouseRayPosition, &mouseRayVector);
oldMousePosOnPlane.x = mousePosOnPlane.x;
oldMousePosOnPlane.y = mousePosOnPlane.y;
oldMousePosOnPlane.z = mousePosOnPlane.z;
mousePosOnPlane = mouseRayPosition + (mouseRayVector * tmpDist);
this is in the .h file:
mousePosOnPlane will end up with the position of the mouse on a plane with Y up.
Thanks guys, I think I allready got it to work. The code I posted above works perfectly fine I just messed up some other things.
I have another question though. The function gives me also the depth value of the window so if I use the directly everything I draw with those coordinates is really close to the camera which is what I actually want to avoid because it looks ugly and causes clipping issues. How can I push things further away without loosing the mousePosition?
EDIT: at hahakid, I am just seeing that your code should be doing what I want. I don’t have any ray/plane intersection classes though so I will try to do something from scratch.
If you use glUnproject, you don’t have to use the z value from the z-buffer – you can just pass in the z-coordinate of where you’d like to draw.
(btw, I’m working on the same top-secret project )
EDIT: brain fart alert – the z value has to be between 0 and 1. So for an arbitrary z, you would want to pass in (z-near)/far, where near and far are the distances to the near and far clipping planes
EDIT: wrong again: if you want to unproject a pt at a given z-value, you have to pass in
(1+((far+near)*z + 2*far*near)/((far-near)*z))/2
Hi kevin, I allready heard that, nice to meet you.
Well I thought the same but I can unfortunally only draw and the near or far z plane, nothing in between. Do you have skype or MSN?