View Full Version : Calculating 3d Point
Blake
2004.01.06, 06:31 AM
hey all, im having trouble calculating the ground point that i click on by using the mouse x,y and my cameras x,y,z and rotation x. The cameras rotation x is 60 and the camera's y is 10, any help would be VERY appreciated
Jason Colman
2004.01.06, 06:40 AM
Are you using OpenGL ? If so you can use gluUnproject(). There is a first rate example of how to use this here (http://openglforums.com/forums/viewtopic.php?p=2017)
Blake
2004.01.06, 06:46 AM
Are you using OpenGL ? If so you can use gluUnproject(). There is a first rate example of how to use this here (http://openglforums.com/forums/viewtopic.php?p=2017)
thanks for the reply but im still lost ;)
Jason Colman
2004.01.06, 08:04 AM
You reveal nothing :ninja:
If indeed you are using OpenGL, you need look no further than the last 10 lines of that code sample.
You have much to learn young padawan etc :)
Blake
2004.01.07, 04:04 AM
okay i got this
GLdouble ox=0.0,oy=0.0,oz=0.0;
GLint viewport[4];
GLdouble modelview[16],projection[16];
GLfloat wx=x,wy,wz;
glGetIntegerv(GL_VIEWPORT,viewport);
y=viewport[3]-y;
wy=y;
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
glGetDoublev(GL_PROJECTION_MATRIX,projection);
glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&wz);
gluUnProject(wx,wy,wz,modelview,projection,viewpor t,&ox,&oy,&oz);
but what does each line do? :sneaky:
Fenris
2004.01.07, 08:24 AM
Let's work it backwards. You want to convert a click on-screen to a position in your 3D-world.
The last line, gluUnproject does this for you. However, it needs four things:
The click in 3D-space
The model view matrix
The projection matrix.
The viewport.
So, how the heck do we convert a click on the 2D screen into a click in 3-space? Well, we just take the depth buffer value at the point where you clicked. The glReadPixels line does that for you. Now, we have wx, wy, and wz, which represents the click in three dimensions. So far, so good.
Then, we need the viewport, model view matrix and the projection matrix. The glGetDoublev and glGetIntegerv calls does that for us. So, we have the ingredients for the magic formula. Pass them all to gluUnproject, and it'll spit out the 3D coordinates in your scene in the three last arguments, ox, oy, oz.
So, in total, this function becomes:
void Make2DPositionInto3DPosition (float x, float y, float *ox, float *oy, float *oz)
{
GLint viewport[4];
GLdouble modelview[16],projection[16];
GLfloat wx=x,wy,wz;
glGetIntegerv(GL_VIEWPORT,viewport);
y=viewport[3]-y;
wy=y;
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
glGetDoublev(GL_PROJECTION_MATRIX,projection);
glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&wz);
gluUnProject(wx,wy,wz,modelview,projection,viewpor t,&ox,&oy,&oz);
}
In short, to use this little function, just do this:
Point mousePos;
float click3DPos [3];
GetMouseLoc (&mousePos);
Make2DPositionInto3DPosition (mousePos.x, mousePos.y, &click3DPos[0], &click3DPos[1], &click3DPos[2]);
// Use click3DPos to draw something at that position
Blake
2004.01.07, 07:17 PM
okay this is the code that i have
NSPoint mouseLoc = [ self currentMousePosition ];
[ self make2DPositionInto3DPosition:mouseLoc.x y:mouseLoc.y ox:&mouse3DPositions[ 0 ] oy:&mouse3DPositions[ 1 ] oz:&mouse3DPositions[ 2 ] ];
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glBegin( GL_QUADS );
glVertex3d( 0, 0, 0 );
glVertex3d( mouse3DPositions[ 0 ], 0, 0 );
glVertex3d( mouse3DPositions[ 0 ], 0, mouse3DPositions[ 2 ] );
glVertex3d( 0, 0, mouse3DPositions[ 2 ] );
glEnd();
GLint viewport[4];
GLdouble modelview[16],projection[16];
GLfloat wx=x,wy,wz;
glGetIntegerv(GL_VIEWPORT,viewport);
y=viewport[3]-y;
wy=y;
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
glGetDoublev(GL_PROJECTION_MATRIX,projection);
glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&wz);
gluUnProject(wx,wy,wz,modelview,projection,viewpor t,&ox,&oy,&oz);
but i keep getting "Warning: pass agr 7-9 (7, 8 and 9) of 'gluUnProject' from incompatable pointer type" am i just missing something?
Edit: ive tried float and GLfloat for mouse3DPositions[ 3 ]
Blake
2004.01.08, 07:08 AM
anybody know whats wrong?
NCarter
2004.01.08, 07:11 AM
Looks like the error is caused by the ox, oy, oz parameters to gluUnProject(). How are they defined?
Blake
2004.01.08, 04:33 PM
i have tried them as float mouse3DPositions[ 3 ] and GLfloat mouse3DPositions[ 3 ]
NCarter
2004.01.08, 05:58 PM
i have tried them as float mouse3DPositions[ 3 ] and GLfloat mouse3DPositions[ 3 ]
Eh? But your code says this:
gluUnProject(wx, wy, wz, modelview, projection, viewport, &ox, &oy, &oz);
Where are ox, oy, and oz coming from?
EDIT: I've just spotted this line, but I don't understand it:
[ self make2DPositionInto3DPosition:mouseLoc.x y:mouseLoc.y
ox:&mouse3DPositions[ 0 ] oy:&mouse3DPositions[ 1 ] oz:&mouse3DPositions[ 2 ] ];
What does make2DPositionInto3DPosition look like?
Blake
2004.01.09, 01:37 AM
- (void) make2DPositionInto3DPosition:(float)x y:(float)y ox:(GLfloat *)ox oy:(GLfloat *)oy oz:(GLfloat *)oz
{
GLint viewport[4];
GLdouble modelview[16],projection[16];
GLfloat wx=x,wy,wz;
glGetIntegerv(GL_VIEWPORT,viewport);
y=viewport[3]-y;
wy=y;
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
glGetDoublev(GL_PROJECTION_MATRIX,projection);
glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&wz);
gluUnProject(wx,wy,wz,modelview,projection,viewpor t,&ox,&oy,&oz);
}
[ self make2DPositionInto3DPosition:mouseLoc.x y:mouseLoc.y ox:&mouse3DPositions[ 0 ] oy:&mouse3DPositions[ 1 ] oz:&mouse3DPositions[ 2 ] ];
NCarter
2004.01.09, 04:24 AM
Two things:
gluUnProject() is defined like this...
int gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz,
const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4],
GLdouble *objx, GLdouble *objy, GLdouble *objz );
Notice that objx, objy and objz are GLdoubles, not GLfloats! You can implicitly cast a float to a double, but you can't make a double pointer point at a float - you'll need to pass actual GLdoubles for those parameters.
Secondly (and I could be wrong here because I'm not good at reading Objective-C), it looks like you're trying to pass the address of the ox, oy and oz pointers to gluUnProject(). Since ox, oy and oz are already pointers to floats (or doubles, rather ;) ), you don't need the ampersands:
gluUnProject(wx, wy, wz, modelview, projection, viewport, ox, oy, oz);
Blake
2004.01.09, 06:40 AM
yea removing the &'s fixed it, now i have it in 3d space and now the math begins...
Blake
2004.01.12, 01:10 AM
okay im stuck now, i have the positions of the mouse in the 3d world but now how do i convert this to the ground? the camera sits 10 above the ground and is angled at 60 degrees on its x axis
any advice?
Jason Colman
2004.01.12, 07:47 AM
The 3D coord you have got corresponds to the point where you click with the mouse. So if you click on the ground, the 3D coord will be on the ground too! And this will work however your camera is oriented!
Fenris
2004.01.12, 08:06 AM
And if you really need to snap that position down onto the ground, then just set the Y coordinate to whatever height the ground is at the 3D point's XZ position.
Blake
2004.01.12, 03:17 PM
well it seems as if the cords that it is giving me is like its just putting the mouse right in front of the camera lens (so to speak)
Johan
2004.01.12, 04:12 PM
What you need to do is trace a ray from the screen to the ground plane. This is what I'm doing in Beach Pong. (for full source see the uDevGame source thread)
ray_t getRayFromScreenCoords(int sx, int sy, int sw, int sh) {
ray_t ray;
GLdouble modelview[16], projection[16];
GLdouble x, y, z;
GLint viewport[4];
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
gluUnProject(sx, sh - sy, 0.0,
modelview, projection, viewport,
&x, &y, &z);
ray.origin = vvector( (float)x, (float)y, (float)z );
gluUnProject(sx, sh - sy, 1.0,
modelview, projection, viewport,
&x, &y, &z);
ray.direction.x = x - ray.origin.x;
ray.direction.y = y - ray.origin.y;
ray.direction.z = z - ray.origin.z;
vnormalize(&ray.direction);
return ray;
}
float intersectPlane(plane_t* p, ray_t* r) {
float d = vdot(p->normal, r->direction);
if (d != 0) {
float t = vdot(p->position, p->normal) - vdot(r->origin, p->normal) / d;
if (t > 0.0001f) return t;
}
return -1.0;
}
vec_t getPickingPoint(int x, int y) {
vec_t picking;
plane_t plane;
float t;
ray_t ray;
plane.position = vvector(0, 0, 0);
plane.normal = vvector(0, 1, 0);
ray = getRayFromScreenCoords(x, y, getScreenWidth(), getScreenHeight());
t = intersectPlane(&plane, &ray);
picking.x = ray.origin.x + (ray.direction.x * t);
picking.y = ray.origin.y + (ray.direction.y * t);
picking.z = ray.origin.z + (ray.direction.z * t);
return picking;
}
With this method you can easily pick spheres, triangles, etc too.
.johan
Fenris
2004.01.12, 06:44 PM
well it seems as if the cords that it is giving me is like its just putting the mouse right in front of the camera lens (so to speak)
Then you're misinterpreting the Z value... Hang on, I'll check my sources.
void bmMouse::GetClick3D (GLdouble *x, GLdouble *y, GLdouble *z)
{
GLdouble modelView [16];
GLdouble projection[16];
GLint viewPort [4];
float outZ;
glReadBuffer(GL_FRONT);
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewPort);
glReadPixels(this->mouseX, this->mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &outZ);
gluUnProject(this->mouseX, this->mouseY, outZ, modelView, projection, viewPort, x, y, z);
}
Make sure that outZ is a float. Also, make sure you enable depth writes and all that. What is the Z value you get back from glReadPixels if you check it in the debugger?
Blake
2004.01.12, 08:29 PM
Then you're misinterpreting the Z value... Hang on, I'll check my sources.
void bmMouse::GetClick3D (GLdouble *x, GLdouble *y, GLdouble *z)
{
GLdouble modelView [16];
GLdouble projection[16];
GLint viewPort [4];
float outZ;
glReadBuffer(GL_FRONT);
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewPort);
glReadPixels(this->mouseX, this->mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &outZ);
gluUnProject(this->mouseX, this->mouseY, outZ, modelView, projection, viewPort, x, y, z);
}
Make sure that outZ is a float. Also, make sure you enable depth writes and all that. What is the Z value you get back from glReadPixels if you check it in the debugger?
thanks a ton, i think that i wasnt doing glReadPixels and thats what was causing it to be all funny
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.