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”);
camGroundCol->add_solid(mPickerRay);
camGroundCol->set_from_collide_mask(BitMask32::bit(0));
camGroundCol->set_into_collide_mask(BitMask32::all_off());
camGroundNode = camera.attach_new_node(camGroundCol);
mCamGroundHandler = new CollisionHandlerQueue();
mGroundTraverse.add_collider(camGroundNode,mCamGroundHandler);
.
.
EventHandler &eventHandler = framework->get_event_handler();
eventHandler.add_hook(“mouse1”, ( EventHandler::EventCallbackFunction* )mouse1Event, this);
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