: Documentation : Interaction Tutorials
Introduction
In this tutorial we extend the concept of proximity based interaction to multiple markers, using the spatial relationships between markers rather than to the camera.
Proximity Based Interaction - Marker to Marker
Because we know the 3D positions of all tracked markers, it is trivial to compute the distances between markers. When the distance decreases below a certain threshold, or exceeds a certain threshold, we can invoke an action to update the application.
Setup
In this tutorial we will use two markers.
osg::MatrixTransform* mtA = scene->addTrackedTransform("single;data/patt.hiro;80;0;0");
osg::MatrixTransform* mtB = scene->addTrackedTransform("single;data/patt.kanji;80;0;0");
Each marker will have two different models associated with it. Whenever the distance between the markers is above a particular threshold, we will display one set of models, and whenever the distance drops below the threshold, we will swap the models for the other set.
Switch
To flip backwards and forwards between different models, we will use an
osg::ref_ptr<osg::Switch> switchA = new osg::Switch();
switchA->addChild(osgDB::readNodeFile("data/voltmeter_low.osg"), true);
switchA->addChild(osgDB::readNodeFile("data/voltmeter_high.osg"), false);
mtA->addChild(switchA.get());
osg::ref_ptr<osg::Switch> switchB = new osg::Switch();
switchB->addChild(osgDB::readNodeFile("data/battery.osg"), true);
switchB->addChild(osgDB::readNodeFile("data/battery_spark.osg"), false);
mtB->addChild(switchB.get());
MarkerProximityUpdateCallback
All that is left to do is define how to continuously calculate the distances between the two markers, compare that distance with a particular threshold, and use each marker’s switch node to load the appropriate model.
To do this we define a new update callback, which holds information about both the the markers’ parent transform nodes, and the switch nodes. We will attach the update callback to our scene graph, so that the information is updated every traversal. Within this new callback we can then perform the necessary calculations.
Recall from the Animation
tutorial that to create an update callback, we must subclass
class MarkerProximityUpdateCallback : public osg::NodeCallback {
private:
osg::MatrixTransform* mtA;
osg::MatrixTransform* mtB;
osg::Switch* mSwitchA;
osg::Switch* mSwitchB;
float mThreshold;
public:
MarkerProximityUpdateCallback(
osg::MatrixTransform* mA, osg::MatrixTransform* mB,
osg::Switch* switchA, osg::Switch* switchB,
float threshold) :
osg::NodeCallback(),
mtA(mA), mtB(mB),
mSwitchA(switchA), mSwitchB(switchB),
mThreshold(threshold) { }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
/** CALCULATE INTER-MARKER PROXIMITY:
Here we obtain the current position of each marker, and the
distance between them by examining
the translation components of their parent transformation
matrices **/
osg::Vec3 posA = mtA->getMatrix().getTrans();
osg::Vec3 posB = mtB->getMatrix().getTrans();
osg::Vec3 offset = posA - posB;
float distance = offset.length();
scene->setUpdateCallback(new MarkerProximityUpdateCallback(mtA, mtB,
switchA.get(),
switchB.get(),
200.0f));
/** LOAD APPROPRIATE MODELS:
Here we use each marker's OSG Switch node to swap between
models, depending on the inter-marker distance we have just
calculated. **/
if (distance <= mThreshold) {
if (mSwitchA->getNumChildren() > 1) mSwitchA->setSingleChildOn(1);
if (mSwitchB->getNumChildren() > 1) mSwitchB->setSingleChildOn(1);
} else {
if (mSwitchA->getNumChildren() > 0) mSwitchA->setSingleChildOn(0);
if (mSwitchB->getNumChildren() > 0) mSwitchB->setSingleChildOn(0);
}
traverse(node,nv);
}
};
Finally …
Here we add the callback to the scene graph, by adding it to the Scene node’s list of update callbacks.
scene->setUpdateCallback(new MarkerProximityUpdateCallback(mtA, mtB,
switchA.get(), switchB.get(),
200.0f));
We then add the scene data to the viewer, and set up the viewer loop, as before.