Sorry if this is a repeat, but I'm trying to figure out the implementation of SoRayPickAction in Open Inventor. I'm trying to implement it so that it will, when the mouse is clicked, select a particular node so then I can translate, rotate, etc. I have three nodes: desk, lamp, and frame (picture frame). However, I don't think that my code is at all right. I also have various methods such a MouseButtonCallback (which will check if the mouse is clicked and then use a navigator) and MouseMoveCallback (same idea). So here's the code that I have, but do you have any suggestions? Right now, well, it doesn't do anything.
SbViewportRegion viewport(400,300);
SoRayPickAction m(viewport);
m.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
m.apply(callback_node);
const SoPickedPoint *mpp = m.getPickedPoint();
if(mpp != NULL) {
std::cout << "test" << std::endl;
}
Might you also know of an action in OpenInventor that can "place" a node in the scene, i.e. place the lamp on top of the desk, frame on the wall, etc. Is it with paths? I don't even know what I'm looking for, unfortunately. Thanks so much for your help!!
Edit: How does this look? SoSeparator *desk2; SoSeparator *lamp2; SoSeparator *pic_frame2; SoSeparator *picked;
void MouseButtonCallback(void* data, SoEventCallback* node)
{
SoHandleEventAction* action = node->getAction();
const SoMouseButtonEvent* event = static_cast<const SoMouseButtonEvent*>(action- >getEvent());
Navigator* nav = static_cast<Navigator*>(data);
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
nav->OnMouseDown(event, action);
else
nav->OnMouseUp(event, action);
const SbViewportRegion & viewportRegion = action->getViewportRegion();
SoRayPickAction pickAction(viewportRegion);
SbVec2s mousePos = event->getPosition(viewportRegion);
pickAction.setPoint(mousePos);
pickAction.setPickAll(TRUE);
pickAction.setRadius(2.0F);
pickAction.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
pickAction.apply(node);
const SoPickedPoint *mpp = pickAction.getPickedPoint();
if(mpp != NULL) {
SoPath *path = mpp->getPath();
if(desk2 != NULL && path->containsNode(desk2))
{ //but this doesn't respond with cout when I try to test it :(
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
*picked = *desk2;
}
else if(lamp2 != NULL && path->containsNode(lamp2))
{
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
*picked = *lamp2;
}
else if(pic_frame2 != NULL && path->containsNode(pic_frame2))
{
if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton()))
*picked = *pic_frame2;
}
action->setHandled();
}
void MouseMoveCallback(void* data, SoEventCallback* node)
{
SoHandleEventAction* action = node->getAction();
const SoLocation2Event* event = static_cast<const SoLocation2Event*>(action->getEvent());
Navigator* nav = static_cast<Navigator*>(data);
nav->OnMouseMove(event, action);
const SbViewportRegion & viewportRegion = action->getViewportRegion();
SoRayPickAction pickAction(viewportRegion);
SbVec2s mousePos = event->getPosition(viewportRegion);
pickAction.setPoint(mousePos);
pickAction.setPickAll(TRUE);
pickAction.setRadius(2.0F);
pickAction.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
pickAction.apply(node);
const SoPickedPoint *mpp = pickAction.getPickedPoint();
if(mpp != NULL) {
SoPath *path = mpp->getPath();
if(desk2 != NULL && path->containsNode(desk2))
{
*picked = *desk2; //can't remember how to set pointers, will figure that out
}
else if(lamp2 != NULL && path->containsNode(lamp2))
{
*picked = *lamp2;
}
else if(pic_frame2 != NULL && path->containsNode(pic_frame2))
{
*picked = *pic_frame2;
}
}
action->setHandled();
}
(part of main method)
//desk
SoTransform *desk_transform = new SoTransform;
desk_transform->translation.setValue(SbVec3f(380,340,330));
SoSeparator* desk2 = new SoSeparator();
desk2->addChild(desk_transform);
desk2->addChild(desk);
root->addChild(desk2);
SoTransformerManip* picked_transform = new SoTransformerManip();
picked_transform->translation.setValue(SbVec3f(200,340,330));
SoSeparator* pick2 = new SoSeparator();
pick2->addChild(picked_transform);
pick2->addChild(picked);
root->addChild(pick2);
std::auto_ptr<btCollisionShape> picked_shape(new btBoxShape(btVector3(10.0f, 10.0f, 10.0f)));
CollisionEngine* picked_collision = new CollisionEngine(collision_world.get(), picked_shape.get());
picked_collision->translation_in.connectFrom(&picked_transform->translation);
picked_collision->rotation_in.connectFrom(&picked_transform->rotation);
picked_transform->translation.connectFrom(&picked_collision->translation_out);
You have the picked point. You then get an SoPath
as you guessed. Then see if the path contains a node you want to do something with.
SbViewportRegion viewport(400,300);
SoRayPickAction m(viewport);
m.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0));
m.apply(callback_node);
const SoPickedPoint *mpp = m.getPickedPoint();
if(mpp != NULL) {
std::cout << "test" << std::endl;
SoPath * path = pickedPoint->getPath();
if (deskSeparator != NULL && path->containsNode(deskSeparator)
{
}
else if (lampSeparator != NULL && path->containsNode(lampSeparator)
{
}
else if (radomeSeparator != NULL && path->containsNode(radomeSeparator)
{
if ( SoMouseButtonEvent::isButtonPressEvent( event, SoMouseButtonEvent::BUTTON2 )
|| ( SoMouseButtonEvent::isButtonPressEvent( event, SoMouseButtonEvent::BUTTON1 ) && event->wasShiftDown() ) )
{
modelPointMoving = true;
const SoDetail * detail = modelPickedPoint->getDetail( 0 );
int face = -1;
if ( detail && detail->isOfType( SoFaceDetail::getClassTypeId() ) )
{
const SoFaceDetail * faceDetail = static_cast<const SoFaceDetail *>( detail );
face = faceDetail->getFaceIndex();
}
updateStatusBar( face, point.getValue(), normal.getValue() );
graphicModel.postNote( pickedPoint );
break;
}
else if ( SoMouseButtonEvent::isButtonPressEvent( event, SoMouseButtonEvent::BUTTON1 ) )
{
}
else if ( SoMouseButtonEvent::isButtonReleaseEvent( event, SoMouseButtonEvent::BUTTON1 ) )
{
}
}
}
You'll eventually want to connect the pick ray to the mouse position sort of like this:
// Set an 2-pixel wide region around the pixel.
SbVec2s mousePosition = event->getPosition( viewportRegion );
pickAction.setPoint( mousePosition );
pickAction.setPickAll( TRUE );
pickAction.setRadius( 2.0F );
This is done before you .apply()
the pick action of course.
I guess my code is a mixture of yours and mine but I think it should give you a start. Also, this is sitting inside a function to process mouse events:
void
RenderWindow::mouseEvent( void *, SoEventCallback * eventCallback )
{
const SoEvent *event = eventCallback->getEvent();
if ( ! event )
{
qDebug() << " ** Error in mousePressCallback: Event not found.";
return;
}
//SoType eventType = event->getTypeId();
//SbName eventTypeName = eventType.getName();
//const char * eventTypeString = eventTypeName.getString();
SoHandleEventAction * action = eventCallback->getAction();
const SbViewportRegion & viewportRegion = action->getViewportRegion();
SoRayPickAction pickAction( viewportRegion );
Up in main or a setup routine I register the mouse event (for both click action and location (moving the mouse over the viewport):
// Add a mouse event callback to catch mouse button presses.
SoEventCallback * mouseEventCallback = new SoEventCallback();
mouseEventCallback->setName( "MOUSE_EVENT_CALLBACK" );
mouseEventCallback->addEventCallback( SoMouseButtonEvent::getClassTypeId(), &::mouseEvent, static_cast<void *>( this ) );
// Add a mouse event callback to catch mouse motion.
mouseEventCallback->addEventCallback( SoLocation2Event::getClassTypeId(), &::mouseEvent, static_cast<void *>( this ) );
rootSeparator->addChild( mouseEventCallback );
Now that I look at it I wrote the chunks in reverse order ;-). Sorry.
Good Luck
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With