查看: 3402|回复: 9

共享Node节点,DOF变换问题

[复制链接]

该用户从未签到

发表于 2008-9-11 17:47:11 | 显示全部楼层 |阅读模式
模型Node节点同时是几个PositionAttitudeTransform变换的子节点,模型Node下包含一个DOF节点,当几个PositionAttitudeTransform变换时,模型Node随之发生不同的变换,当其下的DOF节点则随着最后一次PositionAttitudeTransform的变换而全部变换,有没有解决该问题的办法啊?附上相关代码,希望高手们帮忙分析解决下,谢谢:
osg::Group* root = new osg::Group();
   osg::Group* tankOneGroup = NULL;
   osg::Group* tankTwoGroup = NULL;
   osg::Group* tankThreeGroup = NULL;

   osgViewer::Viewer viewer;

   // Load the models from the same file
   tankOneGroup = dynamic_cast<osg::Group*>
      (osgDB::readNodeFile("../NPS_Data/Models/t72-tank/t72-tank_des.flt"));
   tankTwoGroup = tankOneGroup;
   tankThreeGroup = tankOneGroup;
   
   // findNodeVisitor will turn osgSim:OFTransform nodes
   // animation field to false
   tankOneGroup->accept( *(new findNodeVisitor("")) );

   // add the first tank as a child of the root node
   root->addChild(tankOneGroup);

   // declare a transform for positioning the second tank
   osg:ositionAttitudeTransform* tankTwoPAT =
      new osg::PositionAttitudeTransform();
   // move the second tank five units right, five units forward
   tankTwoPAT->setPosition( osg::Vec3(5,5,0) );
   // add the tank as a child of its transform to the scene
   tankTwoPAT->addChild(tankTwoGroup);
   root->addChild(tankTwoPAT);

   // declare a transform for positioning the third tank
   osg::PositionAttitudeTransform* tankThreePAT =
      new osg::PositionAttitudeTransform();
   // move the third tank ten units right
   tankThreePAT->setPosition( osg::Vec3(10,0,0) );
   // rotate the tank model 22.5 degrees to the left
   //  (to demonstrate that rotation of the turret will be
   //   relative to the tank's heading)
   tankThreePAT->setAttitude( osg:uat(3.14159/8.0, osg::Vec3(0,0,1) ));
   // add the tank as a child of its transform to the scene
   tankThreePAT->addChild(tankThreeGroup);
   root->addChild(tankThreePAT);

   // Declare an instance of 'findNodeVisitor' class and set its
   findNodeVisitor findNode("gun");

   // Initiate traversal of this findNodeVisitor instance starting
   // from tankTwoGroup, searching all its children.  Build a list
   // of nodes whose names matched the searchForName string above.
   tankTwoGroup->accept(findNode);

   // Declare a switch type and assign it to the first node
   // in our list of matching nodes.
   osgSim::DOFTransform * tankDOF =
           dynamic_cast<osgSim::DOFTransform *> (findNode.getFirst()) ;

   if (tankDOF)
   {
           tankDOF->setCurrentHPR( osg::Vec3(-3.14159/2.0,0.0,0.0) );
   }

   // Declare an instance of 'findNodeVisitor'; set the name to search
   // for to "turret"
   findNodeVisitor findTurretNode("turret");
   // Initiate a traversal starting from the subtree that represents
   // the third tank model we loaded.
   tankThreeGroup->accept(findTurretNode);

   // Make sure we found a node and it's the correct type
   osgSim::DOFTransform * turretDOF =
      dynamic_cast<osgSim::DOFTransform *> (findTurretNode.getFirst()) ;

   // if it's a valid DOF node, set the heading of the turret
   // to 22.5 degrees right relative to the tank's heading.
   if (turretDOF)
   {
      turretDOF->setCurrentHPR( osg::Vec3(-3.14159/4.0,0.0,0.0) );
   }

   // Declare an instance of 'findNodeVisitor'; set the name to search
   // for to "gun"
   findNodeVisitor findGunNode("gun");
   // Initiate a traversal from the subtree that represents the third
   // tank model we loaded.
   tankThreeGroup->accept(findGunNode);

   // Make sure we found a node and it's the correct type
   osgSim::DOFTransform * gunDOF =
      dynamic_cast<osgSim::DOFTransform *> (findGunNode.getFirst()) ;

   // If the node we found is a valid  DOF transform, set the pitch
   // to 22.5 degrees up relative to the turret's pitch.
   if (gunDOF)
   {
      gunDOF->setCurrentHPR( osg::Vec3(0.0,3.14159/8.0,0.0) );
   }

   viewer.addEventHandler(new osgViewer::StatsHandler);
   viewer.setCameraManipulator(new osgGA::TrackballManipulator());
   viewer.setSceneData( root );
   viewer.realize();

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

   以上显示结果是坦克模型的大炮姿态一样。

该用户从未签到

发表于 2008-9-11 19:55:44 | 显示全部楼层
这是指针引用造成的。。。

最简单的解决方法就是深拷贝指针

该用户从未签到

发表于 2008-9-11 20:13:10 | 显示全部楼层
楼上说的应该没错~~
tankOneGroup,tankTwoGroup,tankThreeGroup事实上指向同一个节点,所以对它们的一切操作都等同于对同一个节点的操作。

这个节点结构相当于这样的:
root
  |
---------------------------------
|                        |               |
|               tankTwoPAT    tankThreePAT
|                        |               |
---------------------------------
|
tankOneGroup

因此对tankOneGroup,tankTwoGroup和tankThreeGroup的DOF子节点的操作都等同与对tankOneGroup子节点的操作。

使用深拷贝是不错的解决方案
tankTwoGroup= dynamic_cast<osg:: PositionAttitudeTransform*>( tankOneGroup->clone(osg::CopyOp:: DEEP_COPY_ALL) );
tankThreeGroup= dynamic_cast<osg:: PositionAttitudeTransform*>( tankOneGroup->clone(osg::CopyOp:: DEEP_COPY_ALL) );

这样生成如下的结构图:
root
  |
---------------------------------------------------
|                                 |                      |
|               tankTwoPAT    tankThreePAT
|                                 |                      |
tankOneGroup    tankTwoGroup  tankThreeGroup


在论坛上贴出代码比在QQ上聊还是明白得多嘛~~不然我都没明白您都做什么

[ 本帖最后由 array 于 2008-9-11 20:16 编辑 ]

该用户从未签到

 楼主| 发表于 2008-9-11 20:23:04 | 显示全部楼层
上面代码好像有点问题,不过我的想法是这样的:
对于共享的Node节点,经过不同的positionAttitudeTransform变换后,实现了同一节点不同位置及角度的变换,这个是没问题的,但在紧跟其后的DOF节点访问时,我想实现在每次不同的PAT变换之后,再变换一下相关DOF节点,但不改变之前或之后的紧随PAT变换的DOF节点变换,不知道该如何去实现,数据结构是:
Node  ---- PAT  变换--- DOF变换
Node  ---- PAT2 变换 --- DOF2变换
Node  ---- PAT3变换 --- DOF3变换
其中DOF节点是Node节点的子节点,Node是实体模型,DOF是实体模型中的局部,模型是基于Creator建立的openflight格式。希望有同仁可以帮忙解决下,不甚感激!

该用户从未签到

 楼主| 发表于 2008-9-11 20:35:41 | 显示全部楼层
呵呵,感谢array和二楼的兄弟,我把代码贴上去后回过头来,想了下,就是刚才你说的那个指针引用的地方有问题,我的本意不是这样的,我也知道你们说的clone方式,我的最终目的是想尽量少耗内存或CPU去读写同一个模型,所以才采用了共享节点的办法,如果使用你们所说的clone方式,我测试比较了,这个与直接读取三次一样的模型,所消耗内存CPU一样,帧数也差不多,所以差别不是很大,我就是想避开这个,看能不能只用作简单矩阵变换就能实现,同一节点的DOF,不同的变换。

该用户从未签到

发表于 2008-9-11 20:52:39 | 显示全部楼层
原帖由 white_water125 于 2008-9-11 20:35 发表
呵呵,感谢array和二楼的兄弟,我把代码贴上去后回过头来,想了下,就是刚才你说的那个指针引用的地方有问题,我的本意不是这样的,我也知道你们说的clone方式,我的最终目的是想尽量少耗内存或CPU去读写同一个模型, ...


那最好自己重载PAT一个新的类,例如名为TankActionModifier(简称TAM),这个类除了可以控制坦克运动之外,还可以直接控制坦克子节点中的炮塔/机枪
然后用多个TAM节点,同一个坦克子节点。

我没有仔细想过,不过也许这样可以

该用户从未签到

 楼主| 发表于 2008-9-11 21:05:28 | 显示全部楼层
好的,明白了,感谢array老大,我下去试试,非常感激!呵呵

该用户从未签到

 楼主| 发表于 2008-9-12 09:38:21 | 显示全部楼层
原帖由 array 于 2008-9-11 20:52 发表


那最好自己重载PAT一个新的类,例如名为TankActionModifier(简称TAM),这个类除了可以控制坦克运动之外,还可以直接控制坦克子节点中的炮塔/机枪
然后用多个TAM节点,同一个坦克子节点。

我没有仔细想过, ...

这个方法我琢磨了下,还是不可取,因为我最终关心的还是DOF的变换,而DOF的变换是通过访问模型节点Node,来获取DOF子节点,进而作相对变换,由于模型节点Node是共用的同一个,所以,不论怎么变换,最终DOF变换都是针对同一节点,所以,变换都一样。这是我的想法,array老大,如果有空,就以上NPS教程里的那个例子,可否帮忙测试下,谢谢。
我的目的是在共用同一模型Node节点的情况,每次变换其下的DOF子节点,可实现不同的DOF变换,互不影响,最好不用clone方式。

该用户从未签到

发表于 2008-9-12 12:42:51 | 显示全部楼层
呵呵,我明白您的难处在哪里了,其实这个还是可以实现的,不过需要在场景筛选时才能更改DOF节点的HPR值,这样不同的HPR设定就被保存到渲染后台状态树的不同节点中了~~
注意要添加Navy教程第七课源代码中的findNodeVisitor的两个文件。还有注意traverse函数的实现,这个恐怕是实现各个坦克姿态不同的关键~~

抱歉剥夺了您自己尝试编写代码的乐趣~~还是希望能看到大家把自己写的小技巧和小例子传到论坛上来,丰富我们的资源
  1. class TankActionModifier : public osg::PositionAttitudeTransform
  2. {
  3. public:
  4.         TankActionModifier() : _dofNode(NULL) {};
  5.         void addChildWithDOF( osg::Node* node, const std::string& sectName )
  6.         {
  7.                 osg::Group* group = dynamic_cast<osg::Group*>( node );
  8.                 if ( group && !sectName.empty() )
  9.                 {
  10.                         findNodeVisitor locater( sectName );
  11.                         group->accept( locater );
  12.                         _dofNode = dynamic_cast<osgSim::DOFTransform*>( locater.getFirst() );
  13.                 }
  14.                 addChild( node );
  15.         }

  16.         void setCurrentHPR( const osg::Vec3& hpr )
  17.         { _hpr = hpr; }

  18.         void traverse( osg::NodeVisitor& nv )
  19.         {
  20.                 if ( nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR )
  21.                 {
  22.                         if ( _dofNode )
  23.                                 _dofNode->setCurrentHPR( _hpr );
  24.                 }
  25.                 Transform::traverse( nv );
  26.         }

  27. protected:
  28.         osgSim::DOFTransform* _dofNode;
  29.         osg::Vec3 _hpr;
  30. };

  31. int main(int argc, char** argv)
  32. {
  33.         osg::ref_ptr<osg::Node> objRoot = osgDB::readNodeFile( "t72-tank_des.flt" );

  34.         // Create 3 TAMs
  35.         osg::ref_ptr<TankActionModifier> tamNode1 = new TankActionModifier;
  36.         tamNode1->addChildWithDOF( objRoot.get(), "turret" );
  37.         tamNode1->setPosition( osg::Vec3(-10.0, 0.0, 0.0) );
  38.         tamNode1->setCurrentHPR( osg::Vec3(osg::inDegrees(90.0), 0.0, 0.0) );

  39.         osg::ref_ptr<TankActionModifier> tamNode2 = new TankActionModifier;
  40.         tamNode2->setPosition( osg::Vec3(0.0, 0.0, 0.0) );
  41.         tamNode2->addChildWithDOF( objRoot.get(), "turret" );
  42.         tamNode2->setCurrentHPR( osg::Vec3(osg::inDegrees(0.0), 0.0, 0.0) );

  43.         osg::ref_ptr<TankActionModifier> tamNode3 = new TankActionModifier;
  44.         tamNode3->setPosition( osg::Vec3(10.0, 0.0, 0.0) );
  45.         tamNode3->addChildWithDOF( objRoot.get(), "turret" );
  46.         tamNode3->setCurrentHPR( osg::Vec3(osg::inDegrees(-90.0), 0.0, 0.0) );

  47.         // Add to root
  48.         osg::ref_ptr<osg::Group> root = new osg::Group;
  49.         root->addChild( tamNode1.get() );
  50.         root->addChild( tamNode2.get() );
  51.         root->addChild( tamNode3.get() );
  52.        
  53.         osgViewer::Viewer viewer;
  54.         viewer.setSceneData( root.get() );
  55.         viewer.setCameraManipulator( new osgGA::TrackballManipulator );
  56.         while ( !viewer.done() )
  57.                 viewer.frame();
  58.         return 0;
  59. }
复制代码

该用户从未签到

 楼主| 发表于 2008-9-12 14:08:19 | 显示全部楼层
原帖由 array 于 2008-9-12 12:42 发表
呵呵,我明白您的难处在哪里了,其实这个还是可以实现的,不过需要在场景筛选时才能更改DOF节点的HPR值,这样不同的HPR设定就被保存到渲染后台状态树的不同节点中了~~
注意要添加Navy教程第七课源代码中的findNodeV ...

棒,棒,棒!,呵呵,非常感谢版主,我彻底明白了,这里确实是一个不错的学习环境,得常来
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表