osgART tutorial 1: First simple osgART scene
From ARToolworks support library
Main Page > osgART > osgART Tutorials > osgART tutorial 1: First simple osgART scene
Contents |
Introduction
In this tutorial, we will present the code necessary to perform the simplest possible task for a video see-through AR application: displaying a cube on top of a marker.
The code to perform this task is very close to the smallest amount of code necessary for any functional AR application that uses osgART. Thus, while there may seem to be a number of lines of code which you may not understand yet, you can consider some of this code "boilerplate" code, which is reused again and again, relatively unchanged, in almost every osgART-based application.
The actual code for this task appears right in the osgART package, as an example named "osgARTTest". You should open the file osgARTTest.cpp in your code editor and follow along with the snippets from it which are presented below.
Setup
- Headers
#include <osg/ShapeDrawable> #include <osgART/Foundation> #include <osgART/ARTTransform> #include <osgART/VideoLayer> #include <osgART/ARSceneNode> #include <osgART/PluginManager> #include <osgART/TransformFilterCallback> #include <osgART/Viewer>
- Preloading plugins
- A viewer
// preload the tracker osgART::PluginManager::getInstance()->load("osgart_tracker_artoolkit"); // preload the video osgART::PluginManager::getInstance()->load("osgart_video_artoolkit"); // Set up the osgART viewer (a wrapper around osgProducer or osgViewer). osgART::Viewer viewer; osg::ref_ptr<osgART::ARSceneNode> root = new osgART::ARSceneNode; viewer.setSceneData(root.get());
Video Plugin
A Video Plugin is required to get an image into osgART.
// Load a video plugin. osg::ref_ptr<osgART::GenericVideo> video = dynamic_cast<osgART::GenericVideo*>(osgART::PluginManager::getInstance()->get("video_artoolkit")); // check if an instance of the video stream could be started if (!video.valid()) { // Without video an AR application can not work. Quit if none found. osg::notify(osg::FATAL) << "Could not initialize video plugin!" << std::endl; exit(-1); } // found video - configure now osgART::VideoConfiguration* _config = video->getVideoConfiguration(); // if the configuration is existing if (_config) { // it is possible to configure the plugin before opening it //_config->deviceconfig = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // "<dsvl_input><avi_file use_reference_clock=\"true\" file_name=\"Data\\MyVideo.avi\" loop_avi=\"true\" render_secondary=\"true\">" // "<pixel_format><RGB32/></pixel_format></avi_file></dsvl_input>"; }
Tracker Plugin
- Required to track markers
// Load a tracker plugin. osg::ref_ptr<osgART::GenericTracker> tracker = dynamic_cast<osgART::GenericTracker*>(osgART::PluginManager::getInstance()->get("tracker_artoolkit")); // check if the tracker plugin could be loaded if (!tracker.valid()) { // this example needs a tracker. Quit if none found. osg::notify(osg::FATAL) << "Could not initialize tracker plugin!" << std::endl; exit(-1); } // flipping the video can be done on the fly or in advance video->setFlip(false,true); // Open the video. This will not yet start the video stream but will // get information about the format of the video which is essential // for the connected tracker video->open(); // Tracker parameters are read and written via a field mechanism. // Init access to a field within the tracker, in this case, the binarization threshhold. osg::ref_ptr< osgART::TypedField<int> > _threshold = reinterpret_cast< osgART::TypedField<int>* >(tracker->get("threshold")); // Values are be accessed through a get()/set() mechanism on the field pointer. if (_threshold.valid()) { // Set the threshold, and read back. _threshold->set(100); osg::notify(osg::WARN) << "Field 'threshold' = " << _threshold->get() << std::endl; } else { osg::notify(osg::WARN) << "Field 'threshold' not supported for this tracker" << std::endl; } // Connect the video to a tracker. This will also init the tracker. if (!root->connect(tracker.get(),video.get())) { osg::notify(osg::FATAL) << "Error connecting video with tracker!" << std::endl; exit(-1); }
Scenegraph
// Creating a video background osg::Group* foregroundGroup = new osg::Group(); // Creating a video background osg::ref_ptr<osgART::VideoLayer> videoBackground = new osgART::VideoLayer(video.get() , 1); //initialize the video background videoBackground->init(); //adding it to the scene graph foregroundGroup->addChild(videoBackground.get()); foregroundGroup->getOrCreateStateSet()->setRenderBinDetails(2, "RenderBin"); //use the projection matrix from the tracker (i.e. intrinsic camera parameters) //for the projection matrix. osg::Projection* projectionMatrix = new osg::Projection(osg::Matrix(tracker->getProjectionMatrix()));
Markers and Filtering
The transformation matrix for a marker can be smoothed to reduce jitter, using Filtering.
// create marker with id number '0' osg::ref_ptr<osgART::Marker> marker = tracker->getMarker(0); // check before accessing the linked marker if (!marker.valid()) { osg::notify(osg::FATAL) << "No Marker defined!" << std::endl; exit(-1); } // optionally add transitional smoothing //osgART::TransformFilterCallback* tfc = new osgART::TransformFilterCallback(); //marker->setFilterCallback(tfc); //tfc->enableTranslationalSmoothing(true); //tfc->enableRotationalSmoothing(true); // activate the marker marker->setActive(true); // create a matrix transform related to the marker osg::ref_ptr<osg::MatrixTransform> markerTrans = new osgART::ARTTransform(marker.get());
Graphical Content
- What we want to draw on the marker
//and simply create a blue cube object float boxSize = 40.0f; osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, boxSize / 2.0f), boxSize)); sd->setColor(osg::Vec4(0, 0, 1, 1)); osg::Geode* geode = new osg::Geode(); geode->addDrawable(sd); markerTrans->addChild(geode);
Assembling the Scenegraph
//assemble all things together osg::Group* sceneGroup = new osg::Group(); sceneGroup->getOrCreateStateSet()->setRenderBinDetails(5, "RenderBin"); sceneGroup->addChild(markerTrans.get()); foregroundGroup->addChild(sceneGroup); osg::MatrixTransform* modelViewMatrix = new osg::MatrixTransform(); modelViewMatrix->addChild(foregroundGroup); projectionMatrix->addChild(modelViewMatrix); root->addChild(projectionMatrix);
Main Loop
video->start(); viewer.realize(); while (!viewer.done()) { viewer.frame(); }
Cleanup
viewer.sync(); viewer.cleanup_frame(); viewer.sync(); //stop the video video->stop(); //close the video video->close();