: Documentation : Interaction Tutorials
Introduction
In this tutorial we extend the concept of proximity based interaction to multiple targets, using the spatial relationships between targets rather than to the camera.
Proximity Based Interaction - Target to Target
Because we know the 3D positions of all tracked targets, it is trivial to compute the distances between targets. 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 targets.
osg::MatrixTransform* mtA = scene->addTrackedTransform("single;data/artoolkit2/patt.hiro;80;0;0");
osg::MatrixTransform* mtB = scene->addTrackedTransform("single;data/artoolkit2/patt.kanji;80;0;0");
Each target will have two different models associated with it. Whenever the distance between the targets 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("media/models/voltmeter_low.osg"), true);
switchA->addChild(osgDB::readNodeFile("media/models/voltmeter_high.osg"), false);
mtA->addChild(switchA.get());
osg::ref_ptr<osg::Switch> switchB = new osg::Switch();
switchB->addChild(osgDB::readNodeFile("media/models/battery.osg"), true);
switchB->addChild(osgDB::readNodeFile("media/models/battery_spark.osg"), false);
mtB->addChild(switchB.get());
TargetProximityUpdateCallback
All that is left to do is define how to continuously calculate the distances between the two targets, compare that distance with a particular threshold, and use each target’s switch node to load the appropriate model.
To do this we define a new update callback, which holds information about both the the targets’ 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 TargetProximityUpdateCallback : public osg::NodeCallback {
private:
osg::MatrixTransform* mtA;
osg::MatrixTransform* mtB;
osg::Switch* mSwitchA;
osg::Switch* mSwitchB;
float mThreshold;
osgART::Scene* mScene;
public:
TargetProximityUpdateCallback(
osg::MatrixTransform* mA, osg::MatrixTransform* mB,
osg::Switch* switchA, osg::Switch* switchB,
float threshold, osgART::Scene *scene) :
osg::NodeCallback(),
mtA(mA), mtB(mB),
mSwitchA(switchA), mSwitchB(switchB),
mThreshold(threshold),mScene(scene) { }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
/** CALCULATE INTER-TARGET PROXIMITY:
Here we obtain the current position of each target, 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();
mScene->setUpdateCallback(new TargetProximityUpdateCallback(mtA, mtB, mSwitchA,
mSwitchB, 200.0f,mScene));
/** LOAD APPROPRIATE MODELS:
Here we use each target's OSG Switch node to swap between
models, depending on the inter-target 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 TargetProximityUpdateCallback(mtA, mtB,
switchA.get(), switchB.get(), 200.0f,scene));
We then add the scene data to the viewer, and set up the viewer loop, as before.