Learning OSG programing---osgClip
OSG Clip例程剖析
首先是创建剪切节点的函数代码:
1 osg::ref_ptr<osg::Node> decorate_with_clip_node(const osg::ref_ptr<osg::Node>& subgraph) 2 { 3 osg::ref_ptr<osg::Group> rootnode = new osg::Group; 4 5 // create wireframe view of the model so the user can see 6 // what parts are being culled away. 7 osg::StateSet* stateset = new osg::StateSet; 8 //osg::Material* material = new osg::Material; 9 osg::PolygonMode* polymode = new osg::PolygonMode; 10 polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE); 11 stateset->setAttributeAndModes(polymode,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); 12 13 osg::Group* wireframe_subgraph = new osg::Group; 14 wireframe_subgraph->setStateSet(stateset); 15 wireframe_subgraph->addChild(subgraph); 16 rootnode->addChild(wireframe_subgraph); 17 18 // more complex approach to managing ClipNode, allowing 19 // ClipNode node to be transformed independently from the subgraph 20 // that it is clipping. 21 22 osg::MatrixTransform* transform= new osg::MatrixTransform; 23 24 osg::NodeCallback* nc = new osg::AnimationPathCallback(subgraph->getBound().center(),osg::Vec3(0.0f,1.0f,1.0f),osg::inDegrees(45.0f)); 25 transform->setUpdateCallback(nc); 26 27 osg::ClipNode* clipnode = new osg::ClipNode; 28 osg::BoundingSphere bs = subgraph->getBound(); 29 bs.radius()*= 0.4f; 30 31 osg::BoundingBox bb; 32 bb.expandBy(bs); 33 34 clipnode->createClipBox(bb); 35 clipnode->setCullingActive(false); 36 37 transform->addChild(clipnode); 38 rootnode->addChild(transform); 39 40 41 // create clipped part. 42 osg::Group* clipped_subgraph = new osg::Group; 43 44 clipped_subgraph->setStateSet(clipnode->getStateSet()); 45 clipped_subgraph->addChild(subgraph); 46 rootnode->addChild(clipped_subgraph); 47 48 return rootnode; 49 }
经过梳理发现这段代码主要有两大部分组成:根节点下包含线框子图wireframe_subgraph和裁剪子图clipped_subgraph两部分。他们分别负责绘制线框模型和裁剪模型。
通过将线框子图的状态集设置为osg::PolygonMode::LINE,并将函数的参数osg::Node& subgraph加入到其下作为子节点。
声明转换矩阵transform,并设置其模拟路径回调函数。声明裁剪节点clipnode,并创建其边界盒(边界正方体),设置边界盒的边长为函数的参数osg::Node& subgraph的边界球半径的0.4倍。将裁剪节点clipnode作为转换矩阵transform的字节点,以使其按照模拟回调函数不断地进行旋转裁剪,显示动态裁剪效果。
最后将已裁剪的节点clipped_subgraph的状态集设置为裁剪节点clipnode的状态集。并将其加入到根节点。
利用绘图工具对以上函数的对象关系进行梳理分析如下:
注意在上图中,裁剪节点并没有包含函数参数subgraph作为其子节点。它仅仅是一个旋转的裁剪盒子。
下一个函数是简单裁剪函数,与以上函数不同的是,它没有显示模型的线框模式,而是对模型直接进行裁剪。其函数代码如下:
1 osg::ref_ptr<osg::Node> simple_decorate_with_clip_node(const osg::ref_ptr<osg::Node>& subgraph) 2 { 3 osg::ref_ptr<osg::Group> rootnode = new osg::Group; 4 5 6 // more complex approach to managing ClipNode, allowing 7 // ClipNode node to be transformed independently from the subgraph 8 // that it is clipping. 9 10 osg::MatrixTransform* transform= new osg::MatrixTransform; 11 12 osg::NodeCallback* nc = new osg::AnimationPathCallback(subgraph->getBound().center(),osg::Vec3(0.0f,0.0f,1.0f),osg::inDegrees(45.0f)); 13 transform->setUpdateCallback(nc); 14 15 osg::ClipNode* clipnode = new osg::ClipNode; 16 osg::BoundingSphere bs = subgraph->getBound(); 17 bs.radius()*= 0.4f; 18 19 osg::BoundingBox bb; 20 bb.expandBy(bs); 21 22 clipnode->createClipBox(bb); 23 clipnode->setCullingActive(false); 24 25 transform->addChild(clipnode); 26 rootnode->addChild(transform); 27 28 29 // create clipped part. 30 osg::Group* clipped_subgraph = new osg::Group; 31 32 clipped_subgraph->setStateSet(clipnode->getStateSet()); 33 clipped_subgraph->addChild(subgraph); 34 rootnode->addChild(clipped_subgraph); 35 36 return rootnode; 37 }
可以看到,简单裁剪函数去掉了第一个函数中5~16行创建线框模型的代码。分别用正常和简单模式运行程序,结果如下:
普通模式
简单模式
总结:
程序通过函数参数subgraph获得其边界球,并取其边界球半径的0.4倍建立边界盒。将上述边界盒设为裁剪节点clipnode的裁剪盒。建立转换矩阵transform,设置其模拟路径(动态旋转效果),并将clipnode作为其子节点。将裁剪节点clipnode的状态集设置为裁剪后的子图clipped_subgraph的状态集,以完成对子图参数subgrpah的动态裁剪。最后将转换矩阵transform,裁剪后的子图clipped_subgraph,线框模型添加到根节点中,实现最终的裁剪效果。通过设置转换矩阵transform的模拟回调路径,或修改裁剪节点clipnode的大小和形状,可修改动态裁剪的效果。