模型简单控制

来源:互联网 发布:清华北大抢人 知乎 编辑:程序博客网 时间:2024/05/16 12:55

1.读取模型

1.1 基本操作

添加模型

在 OSG 当中模型是使用 osg::Group 和 osg::Node 来装载在一起的,比如同时需要加入两个模型,模型 A 和模型 B, AB 各自是一个 NODE, 那么可以使用以下语句来做到, 首先使用一个 Group,然后 Group ->addChild(A),同样,之后要 Group->addChild(B)。然后再把 Group 添加到 viewer 当中就可以了。如图 3.1 所示 AB 之间的关系。在这里要申明的是 NODE 是 Group 的父类,在类中都有相应的方法可以转到对方,故 Node 与 Group是通用的,Node 也可以被当作 Group 来用
这里写图片描述

osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;osg::ref_ptr<osg::Group> root = new osg::Group;root ->addChild(osgDB::readNodeFile("glider.osg")) ;root ->addChild(osgDB::readNodeFile("osgcool.osg")) ;viewer->setSceneData(root);viewer->realize();viewer->run();

如果想要添加别的模型,还可以 root ->addChild,但是,如果想在飞机上面添加一些什么,就需要把飞机当成组结点,然后再飞机结点上再添加一些东西。可以这样。

osg::Group* root = new osg::Group() ;osg::Node *glider = osgDB::ReadNodeFile(“glider.osg”) ;glider ->asGroup() ->addChild(osgDB::ReadNodeFile(“xxx.osg””)) ;root ->addChild(glider) ;root ->addChild(osgDB::readNodeFile(“osgcool.osg”)) ;

删除结点

如果我们不需要某个结点了,我们想把它从场景中删除掉。不知道出于某种目的,反正现在要删除掉,可能是开始想看见它现在不想看见它了。可以通过 removeChild 方法,删除多个孩子也可以通过 removeChildren 方法,里面的参数有些需要索引值,有些需要结点本身的指针,读者可以自己尝试。
这里要提醒大家的是,如果要删除一个结点,那么该结点下的所有结点都会被删除。如果一个结点被加入到一个组中两次,那么这两次是分别存在的,删除一次还有另一次

隐藏模型

隐藏模型其实模型仍在渲染当中,因此损耗并未减少,node ->setNodeMask 可以设置隐藏与显示。osgcool ->setNodeMask(0x0) ;代表隐藏。 osgcool ->setNodeMask(1)代表显示。

osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;osg::ref_ptr<osg::Group> root = new osg::Group;osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");root ->addChild(osgDB::readNodeFile("glider.osg")) ;root ->addChild(node) ;node->setNodeMask(0x0);viewer->setSceneData(root);viewer->realize();viewer->run();

结点开关

开关能够隐掉一个结点,它还在内存当中消失,而且想要的时候它才能出来
在 OSG 当中,专门有一个类来负责打开与关闭结点,该类名为 osg::Switch,里面有相应的方法来控制它所管理的结点的打开与关闭。

#include <osgDB/ReadFile>#include <osgViewer/Viewer>#include <osg/Node>#include <osg/Switch>void main(){    osgViewer::Viewer viewer;    osg::Group * root = new osg::Group() ;    osg::Switch *sw = new osg::Switch() ;    osg::Node* cow = osgDB::readNodeFile("cow.osg") ;    //往开关中添加 cow 但是关掉它,第二个参数为 false    sw ->addChild(cow, false) ;    sw ->addChild(osgDB::readNodeFile("glider.osg")) ;    root ->addChild(sw) ;    viewer.setSceneData(root);    viewer.realize();    viewer.run();}

将父节点下的子节点替换

group->replaceChild(oldChild, newChild);

1.2 超级指针

超级指针,其实就是引用一个计数器,这个计数器会计算这个箱子被引用的次数,被
别人引用一次这个计数器增加一,别人不用一次,即:释放一次,则计数器减一。当减至 0 时,内存放掉不用。

使用一个 Node 的三种方法,对比一下:

方法一,最好的方法,十分安全,也是OSG中最常用的方法,多少版本它都没变
osg::ref_ptr aNode (new osg::Node());
group->addChild (aNode.get());

方法一:在 new::Node()时申请了一个 Node 的资源,这时在堆内引用该 Node 的计算器会被置 1。在 group->addChild(aNode.get())时又引用了一次,会再加 1。在这两次引用都结束时,Node 的资源就会被释放。

方法二,也是非常好的方法,有时候不适用,但也十分安全
group->addChild (new osg:: Node ());

方法二:这个方法也是很实用的,但是无法引出 Node 的指针,也许在别处可以用到,事实上会经常用到。如果已经这样做了,得到 Node 指针也不是不可以的,可以使用 NodeVisitor 来得到 Node 的指针,也可以使用 findChild 方法来做这件事。

方法三,非常危险,但是令许多人无故铤而走险的方法
osg:: Node* anotherNode = new osg:: Node ();
group->addChild (anotherNode);

方法三:这个应该是最常用,但是最烂的方法了,原因在于如果在 osg::Node*antherode = new osg::Node()之后发生了错误,抛出了异常,谁来释放 Node 所占用的资源呢。而这个异常在后面被捕获,程序正常的走下去,而内存却没有被正常的放掉。

2. 移动/旋转/缩放模型

移动/旋转/缩放其实都是对矩阵进行操作,在 OSG 当中,矩阵可以当作一个特殊的结点加入到 root 当中,而矩阵下也可以另入结点,而加入的结点就会被这个矩阵处理过,比如移动过/旋转过/缩放过。在 OSG 中控制矩阵的类可以为 osg::MatrixTransform

2.1 直接使用osg::MatrixTransform

功能:移动/旋转/缩放模型,这里加入了四个 glider,一个是默认加入在最中间,一个向上移 2 单位,一个是向下移 2 单位且缩放 0.5 倍,另一个是向右 4 单位,缩放 0.5 且平躺 45 度。

#ifdef _DEBUG#pragma comment(lib,"osgd.lib")#pragma comment(lib,"osgDBd.lib")#pragma comment(lib,"osgViewerd.lib")#pragma comment(lib,"OpenThreadsd.lib")#pragma comment(lib,"osgGAd.lib")#else#pragma comment(lib,"osg.lib")#pragma comment(lib,"osgDB.lib")#pragma comment(lib,"osgViewer.lib")#pragma comment(lib,"OpenThreads.lib")#pragma comment(lib,"osgGA.lib")#endif#include <osgDB/ReadFile>#include <osgViewer/Viewer>#include <osg/Node>#include <osg/MatrixTransform>void main(){    osgViewer::Viewer viewer;    osg::ref_ptr < osg::Group> root = new osg::Group() ;    osg::ref_ptr < osg::Node> osgcool = osgDB::readNodeFile("glider.osg") ;    osg::ref_ptr < osg::MatrixTransform> trans = new osg::MatrixTransform ;    trans ->setMatrix(osg::Matrix::translate(0, 0, 2)) ;    trans ->addChild(osgcool.get()) ;    osg::ref_ptr < osg::MatrixTransform> scale = new osg::MatrixTransform ;    scale ->setMatrix(osg::Matrix::scale(0.5, 0.5, 0.5)*osg::Matrix::translate(0, 0, -2)) ;    scale ->addChild(osgcool.get()) ;    osg::ref_ptr < osg::MatrixTransform > rot = new osg::MatrixTransform ;    rot ->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(45.0), 1, 0, 0)*osg::Matrix::scale(0.5, 0.5,        0.5)*osg::Matrix::translate(4, 0, -2)) ;    rot ->addChild(osgcool.get()) ;    root ->addChild(osgcool.get()) ;    root ->addChild(trans.get()) ;    root ->addChild(scale.get()) ;    root ->addChild(rot.get()) ;    viewer.setSceneData(root.get());    viewer.realize();    viewer.run();}

2.2 模型控制类实现模型的平移、旋转、缩放等操作

创建NodeMatrix.h文件

#ifdef _DEBUG#pragma comment(lib, "osgd.lib")#pragma comment(lib, "osgDBd.lib")#pragma comment(lib, "osgGAd.lib")#pragma comment(lib, "osgViewerd.lib")#pragma comment(lib, "OpenThreadsd.lib")#pragma comment(lib, "osgUtild.lib")#pragma comment(lib, "osgTextd.lib")#else#pragma comment(lib, "osg.lib")#pragma comment(lib, "osgDB.lib")#pragma comment(lib, "osgGA.lib")#pragma comment(lib, "osgViewer.lib")#pragma comment(lib, "OpenThreads.lib")#pragma comment(lib, "osgUtil.lib")#pragma comment(lib, "osgText.lib")#endif#include <osgViewer/Viewer>#include <osgDB/ReadFile>#include <osgGA/GUIEventAdapter>#include <osgViewer/ViewerEventHandlers>#include <osg/AnimationPath>#include <iostream>#include <osg/MatrixTransform>#include <osg/PositionAttitudeTransform>#include <osg/Matrixd>class NodeMatrix : public osg::MatrixTransform{public:    NodeMatrix(void);    ~NodeMatrix(void);public:    /**设置当前模型转动方式,pivot绕哪个点旋转,axis绕着那个轴转动,angularVelocity旋转速度*/    void rotating(const osg::Vec3d &pivot, const osg::Vec3d &axis, float angularVelocity);    /**旋转模型*/    void toRotate(const osg::Matrix &mat);    /**旋转模型*/    void toRotate(float angle, const osg::Vec3f &axis);    /**缩放模型*/    void toScale(const osg::Matrix &mat);    /**缩放模型*/    void toScale(double lel);    /**addsChild方法*/    void addsChild(osg::Node *node);    /**将模型移到目的点*/    void toPosition(osg::Vec3d &pos);    /**得到模型当前的位置*/    osg::Vec3d getPosition();    /**限制模型大小*/    void adapt(osg::BoundingSphere &sps);    /**限制模型大小*/    void adapt(osg::Node *node);private:    osg::ref_ptr<osg::MatrixTransform> pat;    osg::BoundingSphere ps;    osg::Node * pnode;    float level;    osg::Vec3d position;};

创建NodeMatrix.cpp

#define NODE_MATRIX __declspec(dllexport)#include "NodeMatrix.h"NodeMatrix::NodeMatrix(void){    pat = new osg::MatrixTransform;    addChild(pat.get());    level = 1.0;    position = osg::Vec3d(0, 0, 0);}NodeMatrix::~NodeMatrix(void){}/**设置当前模型转动方式*/void NodeMatrix::rotating(const osg::Vec3d &pivot, const osg::Vec3d &axis, float angularVelocity){    setUpdateCallback(new osg::AnimationPathCallback(pivot, axis, angularVelocity));}/**旋转模型*/void NodeMatrix::toRotate(const osg::Matrix &mat){    pat->setMatrix(mat);}/**旋转模型*/void NodeMatrix::toRotate(float angle, const osg::Vec3f &axis){    pat->setMatrix(osg::Matrix::rotate(angle, axis));}/**缩放模型*/void NodeMatrix::toScale(const osg::Matrix &mat){    pat->setMatrix(mat);}/**缩放模型*/void NodeMatrix::toScale(double lel){    pat->setMatrix(osg::Matrix::scale(lel, lel, lel));}/**addsChild方法*/void NodeMatrix::addsChild(osg::Node *node){    pat->addChild(node);    pnode = node;    ps = node->getBound();    osg::notify(osg::NOTICE)<<ps.center().x() << "  " <<ps.center().y() << "  " <<ps.center().z() << std::endl;}/**将模型移到目的点*/void NodeMatrix::toPosition(osg::Vec3d &pos){    osg::Vec3d cps;    cps.set(-ps.center().x()*level, -ps.center().y()*level, -ps.center().z()*level);    pat->setMatrix(osg::Matrix::translate(cps)*osg::Matrix::translate(pos));    position = pos;}/**限制模型大小*/void NodeMatrix::adapt(osg::BoundingSphere &sps){    float level = sps.radius()/ps.radius();    pat->setMatrix(osg::Matrix::scale(level, level, level));}/**限制模型大小*/void NodeMatrix::adapt(osg::Node * node){    osg::BoundingSphere sps = node->getBound();    level = sps.radius()/ps.radius();    pat->setMatrix(osg::Matrix::scale(level, level, level));}/**得到当前的位置*/osg::Vec3d NodeMatrix::getPosition(){    return position;}

创建main.cpp文件

#include "NodeMatrix.h"int main(){    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;    osg::ref_ptr<NodeMatrix> nm = new NodeMatrix;    osg::ref_ptr<osg::Group> group = new osg::Group;    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("glider.osg");    nm->addsChild(osgDB::readNodeFile("Cow.osg"));    //nm->rotating(osg::Vec3d(10.0, 0.0, 0.0), osg::Z_AXIS, 1.0);    //nm->toRotate(1, osg::Y_AXIS);    nm->toPosition(osg::Vec3d(50.0, 0.0, 0.0));    //nm->adapt(node.get());    group->addChild(node.get());    group->addChild(nm.get());    viewer->setSceneData(group.get());    return viewer->run();}

参考书:FreeSouth的《QpenSceneGraph程序设计》