Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

arpi23

Picking 3D position on terrain with mouse(OpenGL))

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, i have a problem! I am writing a RTS. And if i select a unit(with selection buffer) i want to send it to a location on terrain by clicking on it with the mouse. I don'know which algorithm to use. I have one but it is not accurate. Here is my code: ********************************************************** VECT3D nxTerrain:ickTerrain(int mousex,int mousey) { float depth[1]; GLdouble modelm[16], projm[16], pos[3]; int view[4]; VECT3D ret; glGetDoublev( GL_MODELVIEW_MATRIX, modelm ); glGetDoublev( GL_PROJECTION_MATRIX, projm ); glGetIntegerv( GL_VIEWPORT, (GLint*)view ); glReadPixels(mousex,mousex,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,depth); gluUnProject(mousex,mousey,depth[0],modelm,projm,(GLint*)view,&pos[0],&pos[1],&pos[2]); ret.x = (float)pos[0]; ret.y = (float)pos[1]; ret.z = (float)pos[2]; return ret; } ****************************************** HELP!!! please :-) [edited by - arpi23 on June 17, 2003 5:42:01 AM] [edited by - arpi23 on June 17, 2003 5:42:52 AM]

Share this post


Link to post
Share on other sites
Advertisement
Check out GL sections on picking and selection. I just recently got my "picking terrain position with mouse" routine working, and it was very simply using the OpenGL utilities.

Share this post


Link to post
Share on other sites
In my game I implemented both the OpenGL selection method and the method you are using. The OpenGL selection method was very slow. A quick glance at you code makes me think you''re missing a step directly after glReadPixels.

Here''s my code.

static POINT lMousePos;
GetCursorPos( &lMousePos );

glGetIntegerv( GL_VIEWPORT, lViewPort );

// Get the Z coordinate for the pixel location
glReadPixels( lMousePos.x, ( lViewPort[ 3 ] - lMousePos.y ),
1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
&lDepth );

int zdepth;
float lDistTermInv;
glGetIntegerv( GL_DEPTH_BITS, &zdepth );
switch ( zdepth )
{
case 16 :
lDistTermInv = (float) 1.5259018967e-5; // 65535
break;
default :
lDistTermInv = (float) 2.32830643708e-10; // 4294967295
break;
}

lDistance = ( float ) lDepth * lDistTermInv;

glGetDoublev( GL_MODELVIEW_MATRIX, lModelMatrix );
glGetDoublev( GL_PROJECTION_MATRIX, lProjMatrix );

gluUnProject( lMousePos.x, ( lViewPort[ 3 ] - lMousePos.y ),
lDistance, lModelMatrix, lProjMatrix, lViewPort,
&lPos[ 0 ], &lPos[ 1 ], &lPos[ 2 ] );

lTargetPos.x = lPos[ 0 ];
lTargetPos.y = lPos[ 1 ];
lTargetPos.z = lPos[ 2 ];

I hope this helps.


--
http://www.zmgames.com/

Share this post


Link to post
Share on other sites
Reading zbuffer is a simple solution with hardware caps. But I would prefer a 3D and software solution (test quadtree or grid, then triangles). Because what happens with objects above the terrain ? A house, a man, a tree etc ... Not what you wish. Maybe you can only chek the selection before any such object is drawn. But it's a bit awkward I think.

[edited by - Charles B on June 17, 2003 11:23:05 AM]

Share this post


Link to post
Share on other sites
What you can do is instead of using OpenGL selection buffer, you cast ray from the camera point of view (search google for ray picking) and then if your terrain has space partionning you test against the root node, and recursively go into your tree each time testing the ray against the bounding size of the node (ray / aabb collision).

When you found the leaf node colliding with the ray, you can then do a ray/triangle intersection for each triangles until you find the one that intersects the ray.

I find this method to be quite fast. And can be effectively be used with both OpenGL and directX with minor modifications (mainly with the transformation screen coordinates to world coordinates for the pick ray).



[edited by - dopeflow on June 17, 2003 1:03:52 PM]

Share this post


Link to post
Share on other sites
Hi! 3dcgi I implemented your code but it returns the position directly under the camera. i can''t understand.
here:
VECT3D nxTerrain::GetMousePos(void)
{
VECT3D ret;
POINT lMousePos;
int lViewPort[4];
GLdouble lModelMatrix[16], lProjMatrix[16], lPos[3];
float lDepth;
GetCursorPos(&lMousePos);
lMousePos.x=0;lMousePos.y=0;
glGetIntegerv( GL_VIEWPORT,lViewPort);
glReadPixels( lMousePos.x, ( lViewPort[ 3 ] - lMousePos.y ),
1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
&lDepth );
int zdepth;
float lDistTermInv;
float lDistance;
glGetIntegerv(GL_DEPTH_BITS,&zdepth);
switch (zdepth)
{
case 16 :
lDistTermInv = (float) 1.5259018967e-5; // 65535
break;
default :
lDistTermInv = (float) 2.32830643708e-10; // 4294967295
break;
}
lDistance = ( float ) lDepth * lDistTermInv;
glGetDoublev( GL_MODELVIEW_MATRIX, lModelMatrix );
glGetDoublev( GL_PROJECTION_MATRIX, lProjMatrix );
gluUnProject( lMousePos.x, ( lViewPort[ 3 ] - lMousePos.y ),
lDistance, lModelMatrix, lProjMatrix, lViewPort,
&lPos[ 0 ], &lPos[ 1 ], &lPos[ 2 ] );
ret.x = lPos[ 0 ];
ret.y = lPos[ 1 ];
ret.z = lPos[ 2 ];
return ret;
}


It is the full copy of your code!! (or not?)

Share this post


Link to post
Share on other sites
OH! i've got the problem!!!!
Check the line:
glReadPixels(mousex,mousex,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,depth)
HERE i used mousex twice istead of mousex,mousey!!!

now it works fine. Thank you guys for your help!

[edited by - arpi23 on June 18, 2003 7:44:04 AM]

Share this post


Link to post
Share on other sites
another solution would be to render the terrain flat shaded to an auxilary buffer, with no lighting or anything, and draw the triangles (or patches, or objects) with a unique colour (like their index in the list). Then you read the color back at the pixel, and it gives you the index of the triangle. This is purely a hardware method, But your method is fine

Share this post


Link to post
Share on other sites
quote:
Original post by arpi23
OH! i''ve got the problem!!!!
Check the line:
glReadPixels(mousex,mousex,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,depth)
HERE i used mousex twice istead of mousex,mousey!!!

now it works fine. Thank you guys for your help!


Ah. I missed that too. It''s easy to overlook those typos.


--
http://www.zmgames.com/

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!