首页 > 代码库 > OpenSceneGraph几个重要功能节点练习

OpenSceneGraph几个重要功能节点练习

OpenSceneGraph几个重要功能节点练习

 一. 空间变换节点

 

空间变换中最重要的是坐标系和矩阵运算了。OSG坐标系中使用右手系,Z轴垂直向上,X轴水平向右,Y轴垂直屏幕向里,与OpenGL和DirectX都不同。
相关缩放、旋转和平移主要由osg::Matrix, osg::Vec3, osg::Quat几个类来完成。
局部坐标系向世界坐标系转换规则是:设在局部坐标系下顶点 V 转换成世界坐标系坐标 V‘:
    V‘ = V * Mn* Mn-1*……* M3* M2* M1* M0

其中M0到Mn一次为各个矩阵变换。从世界坐标系坐标下顶点 V‘ 转换成局部坐标系 V:
    V  = V‘ * M0-1 * M1-1 * M2-1 * M3-1 *……* Mn-1-1 * Mn-1

 

 

 

对于空间变换而言,无论是OpenGL,DirectX还是OSG,一般都会遵守SRT(Scale/Rotate/Translate)的运算顺序来完成符合矩阵的构建:
其公式为:

 

    M =Ms * Mr * Mt

osg::Matrix mt = osg::Matrix::scale( osg::Vex3(sx, sy, sz) ) *                       osg::Matrix::rotate( osg::Quat(angle, axis) ) *                       osg::Matrix::translate( osg::Vec3(tx, ty, tz) ) ;
osg::MatrixTransform, osg::PositionAttitudeTransform, osg::AutoTransform 示例:

 

代码#include <osg/Node>#include <osg/AutoTransform>#include <osg/MatrixTransform>#include <osg/PositionAttitudeTransform>#include <osgDB/ReadFile>#include <osgViewer/Viewer> //library for OSG #pragma comment(lib, "osgd.lib") #pragma comment(lib, "osgDBd.lib") #pragma comment(lib, "osgViewerd.lib")osg::Transform*  createAutoTransform(double posX, osg::Node* node){    osg::ref_ptr<osg::AutoTransform> at = new osg::AutoTransform();    at->setAutoRotateMode( osg::AutoTransform::ROTATE_TO_SCREEN );    at->setPosition( osg::Vec3(posX, 0, 0) );    at->addChild( node );    return at.release();}osg::Transform*  createMatrixTransform(double posX, double rotateZ, osg::Node* node){    osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform();    mt->setMatrix( osg::Matrix::rotate( rotateZ, osg::Z_AXIS) *                         osg::Matrix::translate( posX, 0, 0) );    mt->addChild( node );    return mt.release();}osg::Transform* createPositionAttitudeTransform(double posX, double rotateZ, osg::Node* node){    osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();    pat->setAttitude( osg::Quat(rotateZ, osg::Z_AXIS) );    pat->setPosition( osg::Vec3(posX, 0, 0) );    pat->addChild(node);    return pat.release();}int main(int argc, char** argv){    osg::ArgumentParser argument(&argc, argv);    osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles(argument);    if( !node.get() ) node = osgDB::readNodeFile( "cow.osg" );    osg::ref_ptr<osg::Group> root = new osg::Group();    root->addChild( createAutoTransform(0.0, node) );    root->addChild( createMatrixTransform(-15.0, osg::PI_4, node) );    root->addChild( createPositionAttitudeTransform(15.0, -osg::PI_4, node) );    osgViewer::Viewer  viewer;    viewer.setSceneData( root.get() );    return viewer.run();}

 

二. 开关节点(osg::Switch)
开关节点Switch的作用是,在场景中某时刻,它的某些子节点被隐藏和忽略,而列外一些节点正常显示并完成相应功能。示例中利用开关节点的更新回调实现子节点的切换: 

 

代码#include <osg/Switch>#include <osg/NodeCallback>#include <osgDB/ReadFile>#include <osgDB/WriteFile>#include <osgViewer/Viewer>#pragma comment(lib, "osgd.lib")#pragma comment(lib, "osgDBd.lib")#pragma comment(lib, "osgViewerd.lib")class CessnaCallback: public osg::NodeCallback{public:    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)    {        osg::Switch* sw = dynamic_cast<osg::Switch*>(node);        if(sw && nv)        {            const osg::FrameStamp* fs = nv->getFrameStamp();            if( fs )            {                if( _fireStartFrame < fs->getFrameNumber() )                {                    sw->setValue(0, false);                    sw->setValue(1, true);                }            }        }        traverse(node, nv);    }private:    static const int _fireStartFrame = 900;};int main(int argc, char** argv){        osg::ref_ptr<osg::Switch> root = new osg::Switch();    root->addChild( osgDB::readNodeFile("cessna.osg"), true );    root->addChild( osgDB::readNodeFile("cessnafire.osg"), false );    root->addUpdateCallback(new CessnaCallback() );    osgDB::writeNodeFile( *(root.get()), "Switch.osg" );    osgViewer::Viewer viewer;    viewer.setSceneData( root.get() );    return viewer.run();}

三. 细节层次节点(osg::LOD)

LOD节点,其基本实现功能是在不影响渲染效果的条件下 ,根据场景对象与观察者的距离,从多个预置方案中选择一种合适的来表达要渲染的物体,从而减轻系统的负担,模型越靠近观察者越精细,而远处只需要较少的多边形类表达。示例如下:

代码#include <osg/LOD>#include <osgDB/ReadFile>#include <osgViewer/Viewer>#include <osg/Notify>#pragma comment(lib, "osgd.lib")#pragma comment(lib, "osgDBd.lib")#pragma comment(lib, "osgViewerd.lib")int main(int argc, char** argv){    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile( "bunny-high.ive" );    if(!node)    {        osg::notify(osg::NotifySeverity::ALWAYS) << "Cannot open the model bunny!\n" ;        return 0;    }    float r = node->getBound().radius();    osg::ref_ptr<osg::LOD> lod = new osg::LOD();    lod->addChild(node.get(), 0.0f, r*3 );    lod->addChild( osgDB::readNodeFile("bunny-mid.ive"), r*3, r*7 );    lod->addChild( osgDB::readNodeFile("bunny-low.ive"), r*7, FLT_MAX );    osgViewer::Viewer viewer;    viewer.setSceneData( lod.get() );    viewer.run();}

 

四. 代理节点(ProxyNode)
ProxyNode代理节点是一种用于动态加载其他模型节点的节点类型。这些节点不会立即被解析和加入场景,而是在场景运行过程中逐步载入。示例:

代码#include <osg/ProxyNode>#include <osgDB/ReadFile>#include <osg/ArgumentParser>#include <osgViewer/Viewer>#include <osg/Notify>#include <iostream>#pragma comment(lib, "osgd.lib")#pragma comment(lib, "osgDBd.lib")#pragma comment(lib, "osgViewerd.lib")int main(int argc, char** argv){    osg::ArgumentParser argument(&argc, argv);    osg::ref_ptr<osg::ProxyNode> pn = new osg::ProxyNode();    unsigned int num = 0;    for(int i = 1; i < argument.argc(); i++)    {        if( argument.isString(i) )        {            std::cout << num << ":  " << argument[i] << "\n" ;            pn->setFileName( num++, argument[i] );        }    }    if( !pn->getNumFileNames() )        pn->setFileName(0, "cow.osg" );    osgViewer::Viewer viewer;    viewer.setSceneData( pn.get() );    return viewer.run();}

 

OpenSceneGraph几个重要功能节点练习