Version 1 (modified by osg, 7 years ago)

Initial copy of NPS tutorial

Node masks

Node masks allow you to selectively traverse sub-graphs within your scene. For example if you wanted to toggle the visibility of a model on/off you could adjust the node mask used for the cull traversal. Node masks would also be useful for showing different representations of scene objects for different camera views or for changing how a node is rendered.

Cameras and nodes (including osg::Group instances - thus subtrees in the scene graph) each have a mask assigned to them. During the pre-render traversal of the scene graph a logical OR comparison of the current node mask and camera's node mask is made. If the comparison is non-zero, the traversal will continue and if there is geometry associated with the node it will be sent to the render graph for rendering. If the logical OR is zero, traversal will not continue further down the scene. Any associated geometry will not be rendered.

The code

For a quick demo, the following code sets up two cameras and a scene with a terrain skin and a tank model. The node mask for the terrain skin is 0x1; the node mask for the tank is 0x2. There are two cameras viewing the world. The topmost camera's mask is set to 0x3. The bottom camera has a node mask of 0x2.

The first section of code loads and sets up the scene. The setupCameras methods adds two cameras we care about and two others to make things look reasonable.

(The cameras we don't care about take care of clearing the background and rendering some text.)

       osg::ref_ptr<osg::Group> root = new osg::Group();
       osg::ref_ptr<osg::Node> tankNode = NULL;
       osg::ref_ptr<osg::Node> terrainNode = NULL;

       osg::ref_ptr<osg::PositionAttitudeTransform> 
          tankXform = new osg::PositionAttitudeTransform;

       Producer::CameraConfig* myCameraConfig = setupCameras();
       osgProducer::Viewer viewer(myCameraConfig);

       osgDB::setDataFilePathList(buildFilePathList());

       tankNode = osgDB::readNodeFile("t72-tank_des.flt");
       terrainNode = osgDB::readNodeFile("JoeDirt.flt");

       tankXform->setPosition( osg::Vec3(5,5,8) );

       root->addChild(terrainNode.get());
       root->addChild(tankXform.get());

Setting masks on nodes is straight-forward. This is what it looks like:

       terrainNode->setNodeMask(0x1);
       tankXform->setNodeMask(0x2);

Setting masks on the cameras is a bit more involved. The scene view associated with each camera needs an inheritance mask to set up culling based on masks we will set. The next section of code sets up this inheritance mask. Then it sets these masks using the setCullMask method.

(Code for setting the masks for the two cameras we don't care about is left out for clarity.)

       int inheritanceMask = 
          (osgUtil::SceneView::VariablesMask::ALL_VARIABLES &
          ~osgUtil::SceneView::VariablesMask::CULL_MASK);

       // set mask for upper camera
       viewer.getSceneHandlerList().at(1)->getSceneView()->setInheritanceMask(inheritanceMask);
       viewer.getSceneHandlerList().at(1)->getSceneView()->setCullMask(0x3);

       // set mask for lower camera
       viewer.getSceneHandlerList().at(2)->getSceneView()->setInheritanceMask(inheritanceMask);
       viewer.getSceneHandlerList().at(2)->getSceneView()->setCullMask(0x2);

The only thing left is to enter the simulation loop...

       while( !viewer.done() )
       {
          viewer.sync();
          viewer.update();
          viewer.frame();
       }