Click on 3D object and PlaneNode

Hi, it’s me again.

I’m still working on the same project and I’m now stuck with two problems. The first one concern PlaneNodes and the other one is about clicking on a 3D object.

  1. I wanted to use PlaneNode to create a sort of “base” on my scene by putting a texture on it. I tried this :
Planef plan(LPoint3f(0,0,0),LPoint3f(0,1,0),LPoint3f(1,0,0));
    PlaneNode* planenode = new PlaneNode("ground");
    planenode->set_plane(plan);

    Filename filename = Filename("Myfile.png");
    Texture * tex = TexturePool::load_texture(filename);
    NodePath nodepath(planenode);
    tex->set_wrap_u(Texture::WM_repeat);
    tex->set_wrap_v(Texture::WM_repeat);
    nodepath.set_texture(tex);
    nodepath.reparent_to(_win_fr->get_render());

But unfortunately, it doesn’t seems to work. Do you have any solution ?

  1. I’ve also been trying to “click” on 3D objects and I came up with this :
CollisionTraverser myTraverser = CollisionTraverser("ctraverser");
        CollisionNode* pickerNode = new CollisionNode("mouseRay");
        NodePath pickerNP = _win_fr->get_camera_group().attach_new_node(pickerNode);
        pickerNode->set_from_collide_mask(GeomNode::get_default_collide_mask());
        CollisionRay* pickerRay = new CollisionRay();
        pickerNode->add_solid(pickerRay);
        CollisionHandlerQueue* myHandler = new CollisionHandlerQueue();
        myTraverser.add_collider(pickerNP, myHandler);
        pickerRay->set_from_lens(_camera, x, y);

        myTraverser.traverse(_win_fr->get_render());

       if(myHandler->get_num_entries() > 0)
       {
            std::cout<<"it works"<<std::endl;
            myHandler->sort_entries();
            NodePath pickedObj = myHandler->get_entry(0)->get_into_node_path();
            return PandaEntity::get(pickedObj.node());
       }
       else{
            std::cout<<"nope"<<std::endl;
            return NULL;
       }

But again, it doesn’t work. Any suggestion ?

Thank you again,
Quentin.

No one has even just a clue of how I could solve these problems ? I’ve been working on it the whole day and I diddn’t came up with anything.

Hi

I don’t know about using the PlaneNode to create a ground plane to use as the base of your scene. I tried your code and can’t see anything.

Here is another method using card maker:

    CardMaker cm("ground");
    cm.set_frame(0.,512.,0.,512);
    PT(PandaNode) card = cm.generate();

    Filename filename = Filename("Myfile.png");
    Texture * tex = TexturePool::load_texture(filename);
    NodePath nodepath(card);
    nodepath.set_p(-90.);
    tex->set_wrap_u(Texture::WM_repeat);
    tex->set_wrap_v(Texture::WM_repeat);
    nodepath.set_texture(tex);
    nodepath.reparent_to(_win_fr->get_render()); 

I use GeoMipTerrain for my scene base and use the get_elevation function to find the z value on the terrain, but since you are making a flat world then maybe CardMaker is okay.

As for the picking, I don’t see how you set your x and y; but here is how I do it:

Viewer::Viewer(PandaFramework *fw, QtGUI *gui){
.
.
  mPickerRay = new CollisionRay(0., 0., 0., 0., 1., 0.);
  PT(CollisionNode) camGroundCol = new CollisionNode("mPickerRay");
  camGroundCol->add_solid(mPickerRay);
  camGroundCol->set_from_collide_mask(BitMask32::bit(0));
  camGroundCol->set_into_collide_mask(BitMask32::all_off());
  camGroundNode = mCameraNode.attach_new_node(camGroundCol);
  mCamGroundHandler = new CollisionHandlerQueue();
  mGroundTraverse.add_collider(camGroundNode,mCamGroundHandler);
.
.
}


bool Viewer::getPick(NodePath &hitNode,LPoint3f &hitPt,float &minDist){

  bool pickOk = false;
  float xsize =  (float)window->get_graphics_window()->get_x_size();
  float ysize =  (float)window->get_graphics_window()->get_y_size();

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

  int yy = ysize - mMouseY;

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

  mPickerRay->set_from_lens(window->get_camera(0), xp, yp);
  mGroundTraverse.traverse(mRootNode);
  CollisionEntry *entry;
  
  if(mCamGroundHandler->get_num_entries()){
    pickOk = true;
    LVecBase3f pos = mCameraNode.get_pos();
    mCamGroundHandler->sort_entries();
    entry = mCamGroundHandler->get_entry(0);
    hitPt = entry->get_surface_point(mRootNode);
    hitNode = entry->get_into_node_path();
    minDist = (hitPt - pos).length();
    printf("hit node:%s  pt:%f %f %f\n",hitNode.get_name().c_str(),hitPt.get_x(),hitPt.get_y(),hitPt.get_z());
  }

  return(pickOk);

}

any model that you want to be pickable should have its collide mask set the same as the CollisionNode,
in my case I use model_node.set_collide_mask(BitMask32::bit(0));

Note, for the record, that a PlaneNode is used to describe a plane as a mathematical concept; it is not normally visible and doesn’t work with setTexture() and whatnot. If you want to make a visible polygon for a floor plane, either load the intended polygon from an egg file, or use something like CardMaker to create a visible polygon.

David