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座標軸有所不同。

(全文完)

發佈了98 篇原創文章 · 獲贊 12 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章