粒子系统的读取与保存
在前面的章节中,已经讲到了所有的粒子系统的基本使用方法和自定义粒子系统的方法。有时需要把一个好的粒子系统保存起来,方便以后使用。保存粒子系统可以通过简单地调用 osgDB::writeNodeFile()来完成,如果直接读取并加到根节点就可能会出现一系列的问题。当根节点进行各种矩阵变换时,读者将发现粒子系统会出现各种莫名其妙的现象,如倒转方向、消失等。造成这种现象的原因很简单,粒子系统是作为Drawable加入到叶节点Geode的,因此,对叶节点作各种矩阵变换实际上是对 Drawable进行矩阵变换,Drawable一旦进行矩阵变换,粒子系统就随之改变。因此,读取粒了系统时需要作一些处理。处理的方法有很多,例如,读取文件时,获取 Drawable 对象的句柄,然后将这个Drawable对象从读入节点的子节点中去除,并重新添加到根节点上。这种方法虽然能够达到我们所需要的目的,但是在很大程度上增加了程序的繁琐度,需要不停地删除、不停地增加。还有一种方法就是使粒子系统节点处于绝对变换下,即不受任何节点的任何矩阵变换。
绝对变换的具体实现方法为:写一个承自osg::MatrixTransform类的新类,反转所有矩阵变换,以达到粒子系统处于绝对变换中的目的。看一下下面的示例,读者就明白该怎么做了。
代码如程序清单11-7 所示:
1. /* 粒子系统的读写 */
2. // 创建一个新的变换类
3. class ParticleTransform :public osg::MatrixTransform
4. {
5. public:
6. class ParticleTransformCallback :public osg::NodeCallback
7. {
8. virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
9. {
10. // 得到节点
11. if (ParticleTransform *ps = dynamic_cast<ParticleTransform*>(node))
12. {
13. osg::NodePath &fullNodePath = nv->getNodePath();
14. if (fullNodePath.size() > 0)
15. {
16. //fullNodePath.pop_back();
17. // 反转各种矩阵变换
18. osg::Matrix localCoordMat = osg::computeLocalToWorld(fullNodePath);
19. osg::Matrix inverseOfAccum = osg::Matrix::inverse(localCoordMat);
20.
21. // 设置矩阵
22. ps->setMatrix(inverseOfAccum);
23. }
24.
25.
26. }
27. traverse(node, nv);
28. }
29. };
30.
31. ParticleTransform()
32. {
33. // 设置更新回调
34. setUpdateCallback(new ParticleTransformCallback());
35. }
36.
37. };
38.
39. // 更新回调
40. class orbit :public osg::NodeCallback
41. {
42. public:
43. // 构造函数
44. orbit() :_angle(0.0){}
45.
46. // 返回局部矩阵
47. osg::Matrix getWCMatrix()
48. {
49. return m;
50. }
51.
52. virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
53. {
54. osg::ref_ptr<osg::MatrixTransform> tx = dynamic_cast<osg::MatrixTransform*>(node);
55. if (tx != NULL)
56. {
57. _angle += 0.01;
58.
59. // 设置矩阵旋转
60. tx->setMatrix(osg::Matrix::rotate(_angle, 0.0, 0.0, 1.0));
61.
62. // 计算由世界坐标到局部坐标
63. m = osg::computeWorldToLocal(nv->getNodePath());
64. }
65.
66. traverse(node, nv);
67. }
68. private:
69. osg::Matrix m;// 矩阵
70. float _angle; // 角度
71.
72. };
73.
74. /* 粒子系统的读写 */
75. void readAndWriteParticleSystem_11_7(const string &strDataFolder)
76. {
77. osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
78. osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
79. traits->x = 40;
80. traits->y = 40;
81. traits->width = 600;
82. traits->height = 480;
83. traits->windowDecoration = true;
84. traits->doubleBuffer = true;
85. traits->sharedContext = 0;
86.
87. osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
88.
89. osg::ref_ptr<osg::Camera> camera = viewer->getCamera();
90. camera->setGraphicsContext(gc.get());
91. camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
92. GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
93. camera->setDrawBuffer(buffer);
94. camera->setReadBuffer(buffer);
95.
96. osg::ref_ptr<osg::Group> root = new osg::Group();
97.
98. // 读取奶牛模型
99. string strDataPath = strDataFolder + "cow.osg";
100. osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile(strDataPath);
101.
102. // 读取粒子系统模型
103. strDataPath = strDataFolder + "myvr.osg";
104. osg::ref_ptr<osg::Node> particleNode = osgDB::readNodeFile(strDataPath);
105.
106. // 添加矩阵变换节点
107. osg::ref_ptr<osg::MatrixTransform> cowTransform = new osg::MatrixTransform();
108.
109. // 设置更新回调
110. cowTransform->setUpdateCallback(new orbit());
111.
112. // 添加子节点
113. root->addChild(cowTransform.get());
114. cowTransform->addChild(cowNode.get());
115.
116. // 创建粒子系统变换节点
117. ParticleTransform *my = new ParticleTransform();
118.
119. // 添加子节点
120. my->addChild(particleNode.get());
121.
122. cowTransform->addChild(my);
123.
124. // 优化场景数据
125. osgUtil::Optimizer optimize;
126. optimize.optimize(root.get());
127.
128. viewer->setSceneData(root.get());
129.
130. viewer->realize();
131. viewer->run();
132. }
运行程序,截图如图11-9所示。
图11-9粒子系统的读取与保存截图