查看: 2341|回复: 10

菜鸟请教如何改变一个节点的父节点

[复制链接]

该用户从未签到

发表于 2009-8-5 09:07:21 | 显示全部楼层 |阅读模式
原以为应该挺容易,但是却报错。是这样,场景中有两个节点A和B,A是根节点,B是A的子节点。现在new一个新的节点C。要求把C作为A的子节点,B作为C的子节点,同时B不在是A的子节点。我试了两种写法:
1、A->removeChild(B); C->addChild(B); A->addChild(C);
这样第一句执行完B就从内存中清除了,后两句就报错了。
2、C->addChild(B); B->getParent(0)->removeChild(B); A->addChild(C);
第一句执行完,B有两个父节点,第二句获取到的父节点0就是A,这样三句都能执行不报错。但是在整个函数执行完后却报了奇怪的错误。
错误信息:
File: D:\VC80\VC\include\vector
Line: 117
Expression: (*this->_Mycont != NULL:, 0)
中断在这里:
void __cdecl _CRT_DEBUGGER_HOOK(int _Reserved)
{
......
}
我不知道代码写的对不对,错误也看不懂,请各位高手提示我一下,谢谢了!

该用户从未签到

发表于 2009-8-5 09:36:38 | 显示全部楼层
本帖最后由 liangzheng2k 于 2009-8-5 09:40 编辑
  1. A->setDataVariance(osg::Object::DYNAMIC);
  2. B->setDataVariance(osg::Object::DYNAMIC);
  3. C->setDataVariance(osg::Object::DYNAMIC);
复制代码
试一下

该用户从未签到

 楼主| 发表于 2009-8-5 11:11:50 | 显示全部楼层
谢谢楼上,但是不管用。我试了好像跟NodeVisitor有关,因为我是通过在A上设置NodeVisitor找到B的,NodeVisitor里用一个vector保存找到的节点。如果不用NodeVisitor,直接用A->getChild(0)找到B,那么第二种写法就能通过。
可是场景中的节点可能会很多,不可能不用NodeVisitor吧,有什么办法呢?我的代码大致如下:
FindNode f("name");
A->accept(f);
FindNode::NodeList nl = f.getNodeList();
if (nl.size() > 0)
{
  Group* B = new Group;
  for (int i = 0; i < nl.size(); i++)
  {
    Node* C = nl[i];
    B->addChild(C);
    Group* parent = C->getParent()->asGroup();
    if (parent) parent->removeChild(C);
  }
  A->addChild(B);
}
是不是写的不对?请指教

该用户从未签到

发表于 2009-8-5 11:31:44 | 显示全部楼层
介意把FindNode的代码也发出来吗?

该用户从未签到

发表于 2009-8-5 13:18:12 | 显示全部楼层
你跟踪一下节点指针,,看看是否找到相应的节点~~~

该用户从未签到

发表于 2009-8-5 13:18:45 | 显示全部楼层
你跟踪一下节点指针,,看看是否找到相应的节点~~~

该用户从未签到

 楼主| 发表于 2009-8-5 15:26:23 | 显示全部楼层
FindNode.h

class FindNode : public osg::NodeVisitor
{
public:
        typedef std::vector<osg::Node*> NodeList;

public:
        FindNodeR1(const std::string &searchName);
        ~FindNodeR1(void);

        virtual void apply(osg::Node &searchNode);

        osg::Node* GetFirst();
        NodeList& GetNodeList() { return m_vFoundNodeList; }

protected:
        NodeList m_vFoundNodeList;
        std::string m_strSearchName;
};


FindNode.cpp

FindNode::FindNode(const std::string &searchName) :
osg::NodeVisitor(TRAVERSE_ALL_CHILDREN),
m_strSearchName(searchName)
{
}

FindNode::~FindNode(void)
{
}

osg::Node* FindNode::GetFirst()
{
        return *(m_vFoundNodeList.begin());
}

void FindNode::apply(osg::Node& searchNode)
{
        if (m_strSearchName == searchNode->getName())
                m_vFoundNodeList.push_back(geode);

        traverse(searchNode);
}

这代码还真没啥花头,好像没有更简单的了。我实在想不出原因,会不会不是osg的问题,而是其他内存释放之类的问题?

该用户从未签到

发表于 2009-8-5 16:14:18 | 显示全部楼层
  1. void FindNode::apply(osg::Node& searchNode)
  2. {
  3.         if (m_strSearchName == searchNode->getName())
  4.                 m_vFoundNodeList.push_back(geode);

  5.         traverse(searchNode);
  6. }
  7. searchNode->getName()是不是应该是searchNode.getName()
  8. m_vFoundNodeList.push_back(geode);是不是应该是m_vFoundNodeList.push_back(searchNode);
复制代码
另外,你有没有试过在SingleThread下运行正常否?

该用户从未签到

 楼主| 发表于 2009-8-6 16:09:22 | 显示全部楼层
不好意思,我现在发现这其实并不是更改父节点造成的错误。我做了个简单的实验,同样是ABC三个组节点,在不包含任何数据的前提下,进行如前所述的操作,不管是否多线程都不会报错。但问题是现在B节点下存在大量数据,根据错误提示,我查了不少地方。一说是不要在遍历vector时更改其内容,但我并没有使用vector。另一说是osg中动态更改节点需要使用setDataVariance(osg::Object:YNAMIC)或者使用NodeCallback。我试了把3个节点都设置为DYNAMIC,但是没用。NodeCallback还不会用,感觉它应该是每帧都会调用的吧?可更改父节点是个一次性的操作。到底该怎么办呢?再次谢谢各位!

该用户从未签到

发表于 2009-8-6 16:44:30 | 显示全部楼层
如果你是在仿真循环前进行这些操作,是不用考虑DYNAMIC的问题的。但是,如果是在循环中进行这种操作,一种情况是已经开始了仿真遍历,就需要加上DYNAMIC,需要注意的是,DYNAMIC属性要在仿真遍历前加上;一种情况是没有进行仿真遍历,这时也不用考虑DYNAMIC的问题。
针对错误,你可以用CallStack跟一下是否是在traverse函数时出的错。

该用户从未签到

发表于 2009-11-21 14:27:29 | 显示全部楼层
我也遇到了  我发现removeChild 好像是深度删除  用ref增加一数就可以了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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