osg视点跟随

来源:互联网 发布:美洲文明落后知乎 编辑:程序博客网 时间:2024/06/06 11:02

主要是获取节点的当前矩阵,然后用矩阵来变换相机的位置。

步骤如下:

1. 定义struct updateAccumlatedMatrix : public osg::NodeCallback。这个类的核心是使用更新回调来获取某个给定节点之前所有节点的矩阵和。使用函数osg::computeWorldToLocal( osg::NodePath)来获取得到模型的世界坐标系矩阵。参数NodePath是当前模型节点到场景根节点的路径,可以使用访问器NodeVisitor的getNodePath()方法设法取得。

struct updateAccumlatedMatrix : public osg::NodeCallback

{

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)

{ matrix = osg::computeWorldToLocal(nv->getNodePath() );

traverse(node,nv);

 }

osg::Matrix matrix;

};

2.创建一个类transformAccumulator。

其中包括一个osg::Node实例作为数据成员。此节点数据成员的更新回调是上述updateAccumulatedMatrix类的实例,同时此节点也将设置为场景的一部分。

为了读取用于描绘节点世界坐标的矩阵(该矩 阵与节点实例相关联),我们需要为矩阵提供一个“get”方法。

还需要提供添加节点到场景图形的方法。

为了保证这个类的实例只有一个相关联的节点,我们还需要记录这个类的父节点。

osg::Matrix transformAccumulator::getMatrix()

{ return mpcb->matrix; }

bool transformAccumulator::attachToGroup(osg::Group* g)
{ bool success = false; if (parent != NULL)

 { int n = parent->getNumChildren();

  for (int i = 0; i < n; i++)

   { if (node == parent->getChild(i) )

     { parent->removeChild(i,1); success = true; }

   }

    if (! success)

    { return success; }

  }

  g->addChild(node);

return true; }

 

以上这两个类就可以获得节点的当前矩阵。

osgGA::MatrixManipulator类即可提供一种更新相机位置矩阵的方法。

我们可以从MatrixManipulator继承一个新的类,以实现利用场景中某个节点的世界坐标矩阵来改变相机的位置。为了实现这一目的,这个类需要提供一个数据成员,作为上述的 accumulateTransform实例的句柄。新建类同时还需要保存相机位置矩阵的相应数据。

MatrixManipulator类的核心是“handle”方法。这个方法用于检查选中的GUI事件并作出响应。对我们的类而言,唯一需要响应的 GUI事件就是“FRAME”事件。在每一个“帧事件”中,我们都需要设置相机位置矩阵与transformAccumulator矩阵的数值相等。我们 可以在类的成员中创建一个简单的updateMatrix方法来实现这一操作。

class followNodeMatrixManipulator : public osgGA::MatrixManipulator

{ public:

followNodeMatrixManipulator( transformAccumulator* ta);

bool handle (const osgGA::GUIEventAdapter&ea, osgGA::GUIActionAdapter&aa);

void updateTheMatrix();

virtual void setByMatrix(const osg::Matrixd& mat) {theMatrix = mat;}

virtual void setByInverseMatrix(const osg::Matrixd&mat) {}

virtual osg::Matrixd getInverseMatrix() const;

virtual osg::Matrixd getMatrix() const;

protected:

 ~followNodeMatrixManipulator() {}

transformAccumulator* worldCoordinatesOfNode;

osg::Matrixd theMatrix; };

 

followNodeMatrixManipulator::followNodeMatrixManipulator( transformAccumulator* ta)

{ worldCoordinatesOfNode = ta; theMatrix = osg::Matrixd::identity(); }

void followNodeMatrixManipulator::updateTheMatrix()

{ theMatrix = worldCoordinatesOfNode->getMatrix(); }

osg::Matrixd followNodeMatrixManipulator::getInverseMatrix() const

{

osg::Matrixd m;

m = theMatrix * osg::Matrixd::rotate(-M_PI/2.0, osg::Vec3(1,0,0) );

return m;

 }

bool followNodeMatrixManipulator::handle (const osgGA::GUIEventAdapter&ea, osgGA::GUIActionAdapter&aa)

switch(ea.getEventType())

  { case (osgGA::GUIEventAdapter::FRAME):

     { updateTheMatrix(); return false; }

   }

return false;

 }

上述的所有类都定义完毕之后,即可直接对其进行使用。我们需要声明一个transformAccumulator类的实例。该实例应当与场景图形中的某个节点相关联。然后,我们需要声明nodeFollowerMatrixManipulator类的实例。此操纵器类的构造函数将获取 transformAccumulator实例的指针。最后,将新的矩阵操纵器添加到视口操控器列表中。

osg::PositionAttitudeTransform *followerPAT = new osg::PositionAttitudeTransform();
followerPAT->setPosition( osg::Vec3(0,-20,4) );

//设置跟随节点位置

cowpos->addChild(followerPAT);//跟随矩阵为节点矩阵的子节点
transformAccumulator* tankWorldCoords = new transformAccumulator();

tankWorldCoords->attachToGroup(followerPAT);//获得路径,
followNodeMatrixManipulator* followTank = new followNodeMatrixManipulator(tankWorldCoords);

while( !viewer.done() )
{
   viewer.setCameraManipulator(followTank);//这句就是执行语句
   viewer.frame();
}

原创粉丝点击