歡迎訪問我的新博客:http://www.milkcu.com/blog/
原文地址:http://www.milkcu.com/blog/archives/1392673560.html
結點基本操作
添加結點
OSG中使用osg::Node
和osg::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座標軸有所不同。
(全文完)