: Documentation : Interaction Tutorials

This tutorial demonstrates an easy way to implement, within an osgART scene, the manipulation of 3D objects using mouse input. It makes use of the osgManipulator library. This manipulation includes translation, rotation, scaling, and combinations of these transformations.

Manipulation Introduction

The osgManipulator library provides support for interactive 3D manipulators. To manipulate an object, we need a Selection node and a Dragger node. In an ordinary (non-AR) OSG application, the Dragger node handles the mouse input, and generates motion commands. The Selection node (to which we add the object we want to manipulate as a child) listens to the motion commands, and transforms the object accordingly. This technique is much the same for an osgART application, except we must handle the mouse picking ourselves. There are various types of Dragger available, which either allow a single type of manipulation (such as 1D translation), or a combination of transformations. To pass the Dragger commands to the Selection listener, we use a CommandManager.

Our first requirements is to add from out previous examples the class header related to the osg::Manipulator:

#include <osgManipulator/Selection>
#include <osgManipulator/CommandManager>
#include <osgManipulator/Dragger>
#include <osgManipulator/TabBoxDragger>
#include <osgManipulator/TrackballDragger>

Don’t forget to also link the sample with the osgManipulator library.

In order for the manipulation to work correctly in our osgART scene, we need to set the Viewport of the osg::Camera within our scene. Camera is generally hidden in a scene, for simplifying programming, but you can query it by calling getCamera() from the scene as we will see in a minute.

As before we will track one marker whose transform node is mt (see previous examples). We first specifically state the size of the Viewer’s window, as we will use the same co-ordinates in the next section.


Set Camera’s Viewport and adding the Event Handler

Next, we set the Viewport of our scene’s osg::Camera object. It makes sense to set it to the same dimensions as that of Viewer’s window. If we do not set the Viewport, the osgManipulator library will not work correctly for us. Also you need to only get your camera after you call addTracker otherwise it will not work.

osg::ref_ptr<osg::Camera> camera=scene->getCamera(); //call after addTracker

camera->setViewport(0,0,1400,1400); //RESOLUTION same as VIEWER

Also note that, as mentioned, we will be handling the mouse events ourselves, and have therefore added the handler to the Viewer’s list of event handlers. Our handler will need access to the Camera which will be passed in argument.

viewer.addEventHandler(new MouseManipulationEventHandler(camera.get()));

Add Objects and Manipulators

In this tutorial we demonstrate just two sorts of Dragger - a TrackballDragger which performs 3D rotation and a TabBoxDragger which performs 3D scaling and translation. Of course, the choice of Dragger in an application will depend on the required functionality.

Add First Object and a Dragger

This one uses a Trackball Dragger.

  • First we create the geometry - here we load a model from file.
osg::ref_ptr<osg::MatrixTransform> geom1 =
        new osg::MatrixTransform(osg::Matrixd::scale(osg::Vec3f(8.0,4.0,8.0)));
  • Next we add a node into the scene graph whose subgraph will contain the object, along with the Selection and Dragger nodes.
osg::ref_ptr<osg::Group> group = new osg::Group();
  • The osgManipulator::Selection node
osg::ref_ptr<osgManipulator::Selection> selection =
        new osgManipulator::Selection();

* The <dox_osg>osgManipulator::Dragger</dox_osg> node - This one is a TrackballDragger for 3D rotation
<source lang="cpp">
 osg::ref_ptr<osgManipulator::Dragger> dragger =
        new osgManipulator::TrackballDragger();
  • Define the starting matrix for the Dragger
float scale = geom1->getBound().radius() * 1.5f;
osg::Matrix mat = osg::Matrix::scale(scale, scale, scale) * osg::Matrix::translate(geom1->getBound().center());
  • Now use the osgManipulator::CommandManager to pass the Dragger motion commands to the Selection listener
osg::ref_ptr<osgManipulator::CommandManager> commandManager =
        new osgManipulator::CommandManager();
commandManager->connect(*(dragger.get()), *(selection.get()));

That’s it, we can start the video and setup the Viewer loop now. All that is left is to define our mouse picking handler. For a scene with multiple manipulators, we can just repeat the above process. Here we’ll repeat that process for one more object and Dragger type. The final section of this tutorial describes the mouse picking handler.

Add Second Object and Dragger

This one uses a TabBox Dragger.

/** The Geometry for the TabBoxDragger  **/
osg::ref_ptr<osg::Geode> geom2 = new osg::Geode();
osg::ref_ptr<osg::ShapeDrawable> shape =
      new osg::ShapeDrawable(new osg::Cone(osg::Vec3(-100.0,0.0,30.0), 20.0f, 50.0f));
shape->setColor(osg::Vec4(0.2f, 0.6f, 0.2f, 1.0f));

/** osg::Group node **/
group = new osg::Group();

/** Selection Node **/
selection =  new osgManipulator::Selection();

/** Dragger Node:
  * This one is a TabBoxDragger for both scaling and translation **/
dragger = new osgManipulator::TabBoxDragger();

/** Starting matrix for the Dragger **/
scale = geom2->getBound().radius() * 1.5f;
mat = osg::Matrix::scale(scale, scale, scale) * osg::Matrix::translate(geom2->getBound().center());

/** Command Manager - connects Dragger objects with Selection objects **/
commandManager->connect(*(dragger.get()), *(selection.get()));

Mouse Picking Event Handler

Global definitions.

osgManipulator::PointerInfo pointerInfo;
osgManipulator::Dragger* activeDragger = NULL;

typedef osgUtil::LineSegmentIntersector::Intersections::iterator intersectIter;
typedef osg::NodePath::iterator npIter;

Our handler. Basically, we determine whether the mouse has “picked” a Dragger, and then whether the mouse is being “dragged”. If so, we provide the Dragger with the information it needs (ie. mouse position, camera info), using an osgManipulator::PointerInfo object.

class MouseManipulationEventHandler : public osgGA::GUIEventHandler {

    MouseManipulationEventHandler() : osgGA::GUIEventHandler() { }

    virtual bool handle(const osgGA::GUIEventAdapter& ea,
                                     osgGA::GUIActionAdapter& aa,
                                     osg::Object* obj,
                                     osg::NodeVisitor* nv) {

        bool somethingChanged = false;

        osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
        if (view) {

            switch (ea.getEventType()) {

                case osgGA::GUIEventAdapter::PUSH: {

                    osgUtil::LineSegmentIntersector::Intersections intersections;

                        if (view->computeIntersections(ea.getX(), ea.getY(), intersections)) {

                            pointerInfo.setMousePosition(ea.getX(), ea.getY());

                            for (intersectIter iter = intersections.begin();
                                iter != intersections.end();
                                ++iter) {
                                pointerInfo.addIntersection(iter->nodePath, iter->getLocalIntersectPoint());

                            for (npIter iter = pointerInfo._hitList.front().first.begin();
                                iter != pointerInfo._hitList.front().first.end();
                                ++iter) {

                                if (osgManipulator::Dragger* dragger =
                                    dynamic_cast<osgManipulator::Dragger*>(*iter)) {
                                    dragger->handle(pointerInfo, ea, aa);
                                    activeDragger = dragger;
                                    return false;

                case osgGA::GUIEventAdapter::RELEASE:
                case osgGA::GUIEventAdapter::DRAG:

                if (activeDragger) {
                    pointerInfo._hitIter = pointerInfo._hitList.begin();
                    pointerInfo.setMousePosition(ea.getX(), ea.getY());
                    activeDragger->handle(pointerInfo, ea, aa);
                    return false;

        return false;