# convert the mouse's 2d point to a 3d point in the game world

I’m having a trouble to convert the mouse’s 2d point to a 3d point in the game world.
i read about collisions detection, but i want to avoid that because i just want the mouse point without checking all the other objects in my “world”.

i have a terrain, and i just want to convert the mouse coords to a 3d point, where the mouse clicked, on the terrain.
here is the code for the terrain:

terrain = new GeoMipTerrain(“mySimpleTerrain”);
terrain->set_heightfield(Filename(mydir+"/map.png"));
terrain->set_bruteforce(true);
terrain->get_root().reparent_to(window->get_render());

thank you very much.

A single point onscreen corresponds to an infinite number of points in the world: all the points that line along the line from the eyepoint through the point onscreen. This is why most people solve this problem with collision detection; by running a ray from the eyepoint through the point onscreen, you can determine which point on the terrain that ray collides with. This is the most general, and often the simplest, solution.

Note that you can perform a collision against the terrain only without bothering to test the other objects in the world. You can do this either by restricting the bitmask of your terrain to a unique bit, or by ensuring the terrain is parented to a node by itself, and running the traversal from that node only.

Other non-collision solutions are possible, but they require specialized information about the shape of your terrain. For instance, if you know your terrain is perfectly flat, you can solve it by computing the intersection of that ray with the XY plane.

David

first,thank very much for the reply!

second, if i will parente my terrain to a node, dosn’t it return just the object that the ray collide with(the entire terrain)
or it will return the (x,y,z), colliding point with the terrain?

The collision system returns all kinds of information about the collision, including the (x, y, z) position of the point of intersection.

David

I’m doing the same sort of thing in my program, but I pick on the whole scene and get whatever is closest to the camera, and then I point the camera there.

Here are some of the lines of code that does the mouse pick, notice that the mouse x and y need to be converted to values between -1 and 1 to be used with the call set_from_lens() on the pick ray.

Hope this can help:

In my class include file:

``````CollisionTraverser mGroundTraverse;
PT(CollisionHandlerQueue) mCamGroundHandler;
PT(CollisionRay) mPickerRay;

static void mouse1Event(CPT_Event ev, void *data);
``````

In the cpp file:

Class Constructor:

window = framework->get_window(0);
mRootNode = window->get_render();

mPickerRay = new CollisionRay(0., 0., 0., 0., 1., 0.);
PT(CollisionNode) camGroundCol = new CollisionNode(“PickerRay”);
camGroundNode = camera.attach_new_node(camGroundCol);
mCamGroundHandler = new CollisionHandlerQueue();
.
.
EventHandler &eventHandler = framework->get_event_handler();

Left mouse click event function:

////////////////////////////////////////////////////////
void Viewer::mouse1Event(CPT_Event ev, void *data) {
////////////////////////////////////////////////////////

Viewer v = (Viewer)data;
.
.
v->mMouseX = v->window->get_graphics_window()->get_pointer(0).get_x();
v->mMouseY = v->window->get_graphics_window()->get_pointer(0).get_y();

float xsize = (float)v->window->get_graphics_window()->get_x_size();
float ysize = (float)v->window->get_graphics_window()->get_y_size();

int yy = ysize - v->mMouseY;

float xp = 2.(float)v->mMouseX/xsize - 1.;
float yp = 2.
(float)yy/ysize - 1.;

v->mPickerRay->set_from_lens(v->window->get_camera(0), xp, yp);
v->mGroundTraverse.traverse(v->mRootNode); // traverse the whole scene
CollisionEntry *entry;
printf(“num_entries:%d\n”,v->mCamGroundHandler->get_num_entries());
if(v->mCamGroundHandler->get_num_entries()){
NodePath hitNode;
LPoint3f pt,hitPt;;
float dist,minDist=999999.;
for(int i = 0; i < v->mCamGroundHandler->get_num_entries();i++){
entry = v->mCamGroundHandler->get_entry(i);
pt = entry->get_surface_point(v->mRootNode);
dist = (pt - pos).length();
if(dist < minDist){
// I want the first thing hit, closest to camera
minDist = dist;
hitPt = pt;
hitNode = entry->get_into_node_path();
}
}
printf(“hit node:%s pt:%f %f %f\n”,hitNode.get_name().c_str(),
hitPt.get_x(),hitPt.get_y(),hitPt.get_z());
// I point camera to look where mouse clicked
v->camera.look_at(hitPt);
}

any nodes being traversed by the CollisionTraverser that you want pickable should have set_collide_mask() called on them as mentioned in previous post; in my case I have a Terrain class and I set the mask on the terrain node, thus: mTerrain->getNode().set_collide_mask(BitMask32::bit(0));

sorry, looks like my cut and past lost indents,
but it’s just to give you an idea