Version 1 (modified by osg, 7 years ago)

Initial copy of NPS Version

Where in the world am I?

One way to get the world coordinates (position relative to world origin) of a node is to create a callback that updates a matrix. An example of doing this is buried somewhere in here. The penalty for this is that the update callback will always be called. This callback will be invoked and the matrix will be calculated once per frame whether you need it to be or not. If you're not happy with this you can use a visitor.

Using a nodeVisitor to calculate position relative to world origin

Say you're an osg node; you're in a scene graph. Between you and the root node there are a few transforms. How do you know where you are in world coordinates? Technically, you don't. Each transform above you has its own matrix - only. Most often these matrices contain relative data. To calculate world coordinates you need to multiply all of the matrices between the root node and you. Visitors make this easy. Visitors keep track of the path they have followed while traversing the scene graph. OSG provides a method that takes a nodePath and calculates the world coordinates based on the matrices along this path.

  • Create a visitor that goes from leaf to root.
  • For the node you're interested in, start the visitor.
  • This visitor transits up the scene graph...
  • The first time it gets to the root node:
  • Use the visitor's nodePath to calculate world coordinates of node.

NOTES:

  • A few caveats related to cameraNodes here.
  • And some info on rotated models here.

In C++ it looks like this:

    // Visitor to return the world coordinates of a node.
    // It traverses from the starting node to the parent.
    // The first time it reaches a root node, it stores the world coordinates of 
    // the node it started from.  The world coordinates are found by concatenating all 
    // the matrix transforms found on the path from the start node to the root node.

    class getWorldCoordOfNodeVisitor : public osg::NodeVisitor 
    {
    public:
       getWorldCoordOfNodeVisitor():
          osg::NodeVisitor(NodeVisitor::TRAVERSE_PARENTS), done(false)
          {
             wcMatrix= new osg::Matrixd();
          }
          virtual void apply(osg::Node &node)
          {
             if (!done)
             {
                if ( 0 == node.getNumParents() ) // no parents
                {
                   wcMatrix->set( osg::computeLocalToWorld(this->getNodePath()) );
                   done = true;
                }
                traverse(node);
             }
          }
          osg::Matrixd* giveUpDaMat() 
          {
             return wcMatrix;
          }
    private:
       bool done;
       osg::Matrix* wcMatrix;
    };

    // Given a valid node placed in a scene under a transform, return the
    // world coordinates in an osg::Matrix.
    // Creates a visitor that will update a matrix representing world coordinates
    // of the node, return this matrix.
    // (This could be a class member for something derived from node also.

    osg::Matrixd* getWorldCoords( osg::Node* node) 
    {
       getWorldCoordOfNodeVisitor* ncv = new getWorldCoordOfNodeVisitor();
       if (node && ncv)
       {
          node->accept(*ncv);
          return ncv->giveUpDaMat();
       }
       else
       {
          return NULL;
       }
    }