zoukankan      html  css  js  c++  java
  • OSG模型简单控制

    欢迎访问我的新博客:http://www.milkcu.com/blog/

    原文地址:http://www.milkcu.com/blog/archives/1392673560.html

    结点基本操作

    添加结点

    OSG中使用osg::Nodeosg::Group装载模型,Node是Group的父类。

    可以通过下面代码再场景中显示多个模型:

    #include <osgDB/ReadFile>
    #include <osgViewer/Viewer>
    #include <osg/Node>
    int main(void)
    {
        osgViewer::Viewer viewer;
        osg::Group * root = new osg::Group();
        root->addChild(osgDB::readNodeFile("glider.osg"));
        root->addChild(osgDB::readNodeFile("osgcool.osgt"));
        viewer.setSceneData(root);
        viewer.realize();
        viewer.run();
        return 0;
    }
    

    默认时两节点是加在场景的中间。
    那为什么飞机会在左边呢?
    为什么牛会把其他模型覆盖掉呢?

    组结点

    如果想在原结点中添加点什么,就需要把原结点作为组结点。

    可以使用下面代码再飞机结点中再添加一些东西。

    删除结点

    可以通过removeChild和removeChildren方法删除结点,需要的参数为索引值或结点本身的指针。

    可以通过下面代码实现指定结点的删除:

    #include <osgDB/ReadFile>
    #include <osgViewer/Viewer>
    #include <osg/Node>
    int main(void)
    {
        osgViewer::Viewer viewer;
        osg::Group * root = new osg::Group();
        root->addChild(osgDB::readNodeFile("osgcool.osgt"));
        osg::Node * glider = osgDB::readNodeFile("glider.osg");
        root->addChild(glider);
        root->addChild(glider);
        root->removeChild(glider);
        root->removeChild(glider);
        viewer.setSceneData(root);
        viewer.realize();
        viewer.run();
        return 0;
    }
    

    如果删除一个结点,那么该结点下的所有结点都会被删除。

    如果一个极点被加入到一组中多次,那么这两次是分别存在的,删除一次还有一次。

    隐藏结点

    隐藏的模型仍在渲染,不会从内存中消失,损耗并未减少,只不过隐藏了而已。

    node->setNodeMask()可以设置隐藏与显示,node->setNodeMask(0x0)表示隐藏,node->setNodeMask(1)表示显示。

    可以通过下面代码实现隐藏指定模型:

    # include <osgDB/ReadFile>
    # include <osgViewer/Viewer>
    # include <osg/Node>
    int main(void)
    {
        osgViewer::Viewer viewer;
        osg::Group * root = new osg::Group();
        osg::Node * osgcool = osgDB::readNodeFile("osgcool.osgt");
        root->addChild(osgcool);
        root->addChild(osgDB::readNodeFile("glider.osg"));
        osgcool->setNodeMask(0x0);
        viewer.setSceneData(root);
        viewer.realize();
        viewer.run();
        return 0;
    }
    

    在运行程序时按空格键时会回到中心点,该中心点是面向包围球的圆心,如果不存在osgcool,那么按空格会把飞机置于场景中映,而有了osgcool飞机会被放置在左边。

    结点开关

    可以使用结点开关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 * osgcool = osgDB::readNodeFile("osgcool.osgt");
        sw->addChild(osgcool, false);
        sw->addChild(osgDB::readNodeFile("glider.osg"));
        root->addChild(sw);
        viewer.setSceneData(root);
        viewer.realize();
        viewer.run();
    }
    

    由于osgcool模型根本不存在,所以glider模型置于场景中间。

    超级指针

    超级指针机制,其实就是引用一个计数器。引用一次加一,释放一次减一。当减至0时,内存释放。

    使用结点的三种方法:

    方法一(超级指针):

    osg::ref_ptr<osg::Node> node = new osg::Node();
    group->addChild(node.get());
    

    这是最好的方法,十分安全,也是OSG中最常用的方法。在new osg::Node()时申请了一个Node的资源,这时在堆内引用该Node的计数器会被置1。在group->addChild(aNode.get())时又引用了一次,会再加1。在这两次引用都结束时,Node的资源就会被释放。

    方法二:

    group->addChild(new osg::Node());
    

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

    方法三:

    osg::Node * node = new osg::Node();
    group->addChile(node);
    

    这个应该是最常用,但是最烂的方法了,原因在于如果在osg::Node*node = new osg::Node()之后发生了错误,抛出了异常,Node所占用的资源没有释放。

    在有大量交互以及场景变换时,建议使用超级指针。

    模型矩阵变换

    模型的移动、旋转、缩放其实都是对矩阵进行操作,矩阵可以当作一个特殊的结点加入到组结点中。

    通过osg::MatrixTransform定义变换矩阵,
    通过setMatrix(osg::Matrix::translate(x, y, z))实现模型移动,
    通过setMatrix(osg::Matrix::scale(x, y, z))实现模型缩放,
    通过setMatrix(osg::Matrix::rotate(x, y, z))实现模型旋转。

    可以通过下面的代码实现模型的移动、旋转、缩放:

    # include <osgDB/ReadFile>
    # include <osgViewer/Viewer>
    # include <osg/Node>
    # include <osg/MatrixTransform>
    
    int main(void)
    {
        osgViewer::Viewer viewer;
        osg::ref_ptr<osg::Group> root = new osg::Group;
        osg::ref_ptr<osg::Node> osgcool = osgDB::readNodeFile("osgcool.osgt");
    
        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);
    
        viewer.setSceneData(root.get());
        viewer.realize();
        viewer.run();
        return 0;
    }
    

    在OSG中,坐标轴是可以设置的,默认向右的是X轴,向里的是Y轴,向上的是Z轴,与传统OPENGL坐标轴有所不同。

    (全文完)

  • 相关阅读:
    mysql子查询
    hibernate lazy属性true false extra 抓取策略
    unittest下,生成的测试报告
    python创建excel文件,并进行读与存操作
    configparser模块简介
    PyCharm里面的c、m、F、f、v、p分别代表什么含义?
    Python之路(第十七篇)logging模块
    configparser模块简介
    python中os.sep的作用以及sys._getframe().f_back.f_code.co_xxx的含义
    os.getcwd()和os.path.realpath(__file__)的区别
  • 原文地址:https://www.cnblogs.com/milkcu/p/3808871.html
Copyright © 2011-2022 走看看