2.4 场景中节点的拷贝-osg::CopyOp类
osg::CopyOp类是一个拷贝类,主要负责场景中节点的拷贝,根据不同的需要,控制使用深拷贝或者浅拷贝来拷贝场景中的节点。
深拷贝是指源对象与拷贝对象互相对独立,其中任何一个对象的改动都不会对另一个对象造成影响,例如,一头牛的节点被拷贝了,对原来牛的节点做矩阵变换并不会影响拷贝对象。浅拷贝是指源对象与拷贝对象共用一个实体,仅仅是引用的变量不同(名称不同),对其中任何一个对象的牛也会随之做相应的矩阵变换。深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆或者其它系统资源),这个类的对象发生复制的过程就可以称之为深拷贝;反之,对象存在资源但复制过程并未复制资源的情况视为浅拷贝。
浅拷贝资源后,在释放资源时会产生资源归属不清的情况,这种情况会导致程序运行出错,所以一定要注意,当在场景中共享一个节点时,确定使用深拷贝或浅拷贝时,尤其要注意。
还有一个问题是,当场景中多父节点共享一个子节点时,进行深拷贝时也会出现问题,即默认情况下会改变原来树的结构,这时需要自定义控制子节点的拷贝,以避免多次重复拷贝而改变场景中的树结构。
2.4.1 自定义场景拷贝示例(一)
自定义场景拷贝示例主要演示如何拷贝场景中的一个或多个节点,了解深拷贝与浅拷贝的区别。通过自定义拷贝类,深入了解节点拷贝的过程,也将明显看到深拷贝与浅拷贝之间的区别。
#include<osgViewer/Viewer>
#include<osg/Node>
#include<osg/Geometry>
#include<osg/Image>
#include<osg/Geode>
#include<osg/Group>
#include<osg/Notify>
#include<osg/Texture>
#include<osg/StateSet>
#include<osg/StateAttribute>
#include<osgDB/Registry>
#include<osgDB/ReadFile>
#include<osgDB/WriteFile>
#include<osgUtil/Optimizer>
#include<iostream>
// 自定义Copy类,用于输出拷贝信息
class MyCopyOp:public osg::CopyOp
{
public:
inline MyCopyOp(CopyFlags flags = SHALLOW_COPY);
osg::CopyOp(flags),_blank(2),_number(5)
{
;
}
// 内联函数用于控制输出信息格式,实现下三角规则输出
inline void moveIn()const
{
_blank += _number;
}
inline void moveOut()const
{
_blank -= _number;
}
inline void writeIndent()const
{
for(int i=0; i<_blank;++i)
{
std::cout<<" ";
}
}
// 引用计数器copy
virtual osg::Referenced* operator()(const osg::Referenced* ref)const
{
writeIndent();
std::cout<<"copying Referenced"<<ref<<std::endl;
moveIn();
osg::Referenced* ret_ref = CopyOp::operator()(ref);
moveOut();
return ret_ref;
}
// 对象copy
virtual osg::Object* operator()(const osg::Object*obj)const
{
writeIndent();
std::cout<<"copying Object"<<obj;
if(obj)
{
std::cout<<" "<<obj->className();
}
std::cout<<std::endl;
moveIn();
osg::Object* ret_obj = CopyOp::operator()(obj);
moveOut();
return ret_obj;
}
// 节点copy
virtual osg::Node* operator()(const osg::Node*node)const
{
writeIndent();
std::cout<<"copying Node"<<node;
if(node);
{
std::cout<<" "<<node->className()<<" "<<node->getName()<<"";
}
std::cout<<std::endl;
moveIn();
osg::Node* ret_node = CopyOp::operator()(node);
moveOut();
return ret_node;
}
// Drawable copy
virtual osg::Drawable* operator()(const osg::Drawable*drawable)const
{
writeIndent();
std::cout<<"copying Drawable"<<drawable;
if(drawable)
{
std::cout<<" "<<drawable->className();
}
std::cout<<std::endl;
moveIn();
osg::Drawable* ret_drawable = CopyOp::operator()(drawable);
moveOut();
return ret_drawable;
}
// 状态集copy
virtual osg::StateSet* operator()(const osg::StateSet* stateset)const
{
writeIndent();
std::cout<<"copying StateSet"<<stateset;
if(stateset)
{
std::cout<<" "<<stateset->className();
}
std::cout<<std::endl;
moveIn();
osg::StateSet* ret_stateset = CopyOp::operator()(stateset);
moveOut();
return ret_stateset;
}
// 状态属性copy
virtual osg::StateSet* operator()(const osg::StateSet*stateset)const
{
writeIndent();
std::cout<<"copying StateSet"<<stateset;
if(stateset)
{
std::cout<<" "<<stateset->className();
}
std::cout<<std::endl;
moveIn();
osg::StateSet* ret_stateset = CopyOp::operator()(stateset);
moveOut();
return ret_stateset;
}
// 状态属性copy
virtual osg::StateAttribute* operator()(const osg::StateAttribute* attr)const
{
writeIndent();
std::cout<<"copying StateAttribute"<<attr;
if(attr)
{
std::cout<<" "<<attr->className();
}
std::cout<<std::endl;
moveIn();
osg::StateAttribute* ret_attr = CopyOp::operator()(attr);
moveOut();
return ret_attr;
}
// 纹理信息 copy
virtual osg::Texture* operatot()(const osg::Texture* text)const
{
writeIndent();
std::cout<<"copying Texture"<<text;
if(text)
{
std::cout<<" "<<text->className();
}
std::cout<<std::endl;
moveIn();
osg::Texture* ret_text = CopyOp::operator()(text);
moveOut();
return ret_text;
}
// 贴图copy
virtual osg::Image* operator()(const osg::Image*image)const
{
writeIndent();
std::cout<<"copying Image"<<image;
if(image)
{
std::cout<<" "<<image->className();
}
std::cout<<std::endl;
moveIn();
osg::Image* ret_image = CopyOp::operator()(image);
moveOut();
return ret_image;
}
private:
// 此处的两个变量必须是可变型变量,因为在const函数中使用,需要突破const的限制
// 空格增减变量
mutable int _number;
// 空格总数
mutable int _blank;
};
int main()
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Node> rootnode = osgDB::readNodeFile("glider.osg");
// 优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(rootnode.get());
// 浅拷贝一个场景
osg::ref_ptr<osg::Node> shallowCopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::SHALLOW_COPY));
std::cout<<std::endl<<" 完成浅拷贝一个场景"<<std::endl<<std::endl;
// 深拷贝一个场景
osg::ref_ptr<osg::Node> deepCopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::DEEP_COPY_ALL));
std::cout<<std::endl<<"完成深拷贝一个场景"<<std::endl<<std::endl;
// 自定义输出信息浅拷贝场景
osg::ref_ptr<osg::Node>myShallowCopy = dynamic_cast<osg::Node*>(rootnode->clone(MyCopyOp(osg::CopyOp::SHALLOW_COPY)));
std::cout<<std::endl<<"完成一个自定义输出信息浅拷贝场景"<<std::endl<<std::endl;
// 自定义输出信息深拷贝场景
osg::ref_ptr<osg::Node>myDeepCopy = dynamic_cast<osg::Node*>(rootnode->clone(MyCopyOp(osg::CopyOp::DEEP_COPY_ALL)));
std::cout<<std::endl<<"完成一个自定义输出信息深拷贝场景"<<std::endl<<std::endl;
viewer->setSceneData(rootnode.get());
viewer->realize();
viewer->run();
return 0;
}
2.4.2 自定义场景拷贝示例(二)
本节的示例将更进一步向读者展示如何拷贝场景中多父节点的场景树,这是在场景中拷贝节点树时非常值得注意的。
#include<osgViewer/Viewer>
#include<osg/Geometry>
#include<osg/Image>
#include<osg/Geode>
#include<osg/Group>
#include<osg/Notify>
#include<osg/Texture>
#include<osg/StateSet>
#include<osg/StateAttribute>
#include<osg/MatrixTransform>
#include<osg/PositionAttitudeTransform>
#include<osgDB/Registry>
#include<osgDB/ReadFile>
#include<osgDB/WriteFile>
#include<osgUtil/Optimizer>
#include<iostream>
//---------------------------------------------------------------------------------------
// 自定义Copy类,用于输出拷贝信息
class GraphCopyOp:public osg::CopyOp
{
public:
inline GraphCopyOp(CopyFlags flags = SHALLOW_COPY):osg::CopyOp(flags)
{
_nodeCopyMap.clear();
}
// 节点的copy
virtual osg::Node* operator()(const osg::Node*node)const
{
// 判断是否为深拷贝
if(node && _flags&DEEP_COPY_NODES)
{
// 判断节点的父节点是否有多个,如果只有一个,则直接深拷贝
if(node->getNumParents()>1)
{
// 判断是否已经拷贝
if(_nodeCopyMap.find(node)!=_nodeCopyMap.end())
{
std::cout<<"Copy of node"<<node<<" "<<node->getName()<<","<<_nodeCopyMap[node]<<", will be reused"<<end::endl;
// 直接返回拷贝对象的地址
return (osg::Node*)(_nodeCopyMap[node]);
}
else
{
// 进行拷贝并在映射表中保存拷贝对象
osg::Node* newNode = dynamic_cast<osg::Node*>(node->clone(*this));
_nodeCopyMap[node] = newNode;
return newNode;
}
}
else
{
// 直接拷贝
return dynamic_cast<osg::Node*>(node->clone(*this));
}
}
else
{
// 直接返回地址
return const_cast<osg::Node*>(node);
}
}
protected:
// 节点映射表,用来保存child的拷贝,分别作为原象和像
mutable std::map<const osg::Node*,osg::Node*>_nodeCopyMap;
};
//-------------------------------------------------------------------------------------------
int main()
{
osg::ref_ptr<osgViewer::Viewer>viewer = new osgViewer::Viewer();
// 创建一个多父节点共享一个子节点的场景
osg::ref_ptr<osg::Group>rootnode = new osg::Group();
osg::ref_ptr<osg::Node>node = osgDB::readNodeFile("glider.osg");
// 子节点par,共享node
osg::ref_ptr<osg::PositionAttitudeTransform>par = new osg::PositionAttitudeTransform();
par->setPosition(osg::Vec3(5.0f, 0.0f, 0.0f));
par->addChild(node.get());
// 子节点吗,共享node
osg::ref_ptr<osg::MatrixTransform>mt = new osg::MatrixTransform();
osg::Matrix m;
m.makeScale(2.0f,2.0f,2.0f);
mt->setMatrix(m);
mt->addChild(node.get());
// 添加子节点
rootnode->addChild(par.get());
rootnode->addChild(mt.get());
// 优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(rootnode.get());
// 一个多父节点和一个子节点场景的默认深拷贝
osg::ref_ptr<osg::Node>deepCopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::DEEP_COPY_ALL));
std::cout<<std::endl<<"完成一个多父节点一个子节点的场景的默认深拷贝"<<std::endl<<std::endl;
osgDB::writeNodeFile(*(deepCopy.get()),"deepCopy.osg");
// 完成一个多父节点和一个子节点场景的浅拷贝
osg::ref_ptr<osg::Node> myShallowCopy = dynamic_cast<osg::Node*>(rootnode->clone(GrapCopyOp(osg::CopyOp::SHALLOW_COPY)));
std::cout<<std::endl<<"完成一个多父节点一个子节点的场景的浅拷贝"<<std::endl<<std::endl;
osgDB::writeNodeFile(*(myShallowCopy.get()),"myShallowCopy.osg");
viewer->setSceneData(rootnode.get());
viewer->realize();
viewer->run();
return 0;
}