自定义粒子系统示例(二)
目前自定义粒子的方法有很多,在OSG 中使用的是 Billboard 技术与色彩融合技术。色彩融合是一种高级的渲染技术,如果读者有兴趣,可参看 OSG 粒子系统实现的源代码。这里采用简单的布告牌技术(osg::Billboard)与动画来实现。这种方法也可以生成比较好的粒子系统的效果。最好使用同名的贴图,示例中并没有对这些贴图进行处理,它只是向读者展示如何模拟一个自定义的粒子系统,读者可仔细体会。
自定义粒子系统示例(二)的代码如程序清单11-6所示。
/* 自定义粒子系统示例2 */
void particleSystem_11_6(const string &strDataFolder)
{osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;traits->x = 40;traits->y = 40;traits->width = 600;traits->height = 480;traits->windowDecoration = true;traits->doubleBuffer = true;traits->sharedContext = 0;osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());osg::ref_ptr<osg::Camera> camera = viewer->getCamera();camera->setGraphicsContext(gc.get());camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;camera->setDrawBuffer(buffer);camera->setReadBuffer(buffer);osg::ref_ptr<osg::Group> root = new osg::Group();// 向场景中添加帧动画osg::ref_ptr<osg::Sequence>sq = new osg::Sequence();sq = createSequence(strDataFolder);root->addChild(sq.get());// 优化场景数据osgUtil::Optimizer optimize;optimize.optimize(root.get());viewer->setSceneData(root.get());viewer->realize();viewer->run();
}osg::ref_ptr<osg::Node> createBillBoard(osg::ref_ptr<osg::Image> image)
{// 创建四边形osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();// 设置顶点osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();v->push_back(osg::Vec3(-0.5, 0.0, -0.5));v->push_back(osg::Vec3(0.5, 0.0, -0.5));v->push_back(osg::Vec3(0.5, 0.0, 0.5));v->push_back(osg::Vec3(-0.5, 0.0, 0.5));geometry->setVertexArray(v.get());// 设置法线osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array();normal->push_back(osg::Vec3(1.0, 0.0, 0.0) ^ osg::Vec3(0.0, 0.0, 1.0));geometry->setNormalArray(normal.get());geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);// 设置纹理坐标osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();vt->push_back(osg::Vec2(0.0, 0.0));vt->push_back(osg::Vec2(1.0, 0.0));vt->push_back(osg::Vec2(1.0, 1.0));vt->push_back(osg::Vec2(0.0, 1.0));geometry->setTexCoordArray(0, vt.get());// 绘制四边形geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));if (image.get()){// 属性对象osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();// 创建一个Texture2D属性对象osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();// 关联imagetexture->setImage(image.get());// 关联Texture2D纹理对象,第三个参数默认为ONstateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);// 启用混合stateset->setMode(GL_BLEND, osg::StateAttribute::ON);// 关闭光照stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);geometry->setStateSet(stateset.get());}// 创建BillBoard对象1osg::ref_ptr<osg::Billboard> billboard1 = new osg::Billboard();// 设置旋转模式为绕视点billboard1->setMode(osg::Billboard::POINT_ROT_EYE);// 添加Drawable,并设置其位置,默认位置为osg::Vec3(0,0,0)billboard1->addDrawable(geometry.get(), osg::Vec3(5.0, 0.0, 0.0));//osg::ref_ptr<osg::Billboard> billboard2 = new osg::Billboard();osg::ref_ptr<osg::Group> billboard = new osg::Group();billboard->addChild(billboard1.get());return billboard.get();
}// 创建帧动画
osg::ref_ptr<osg::Sequence> createSequence(const string &strDataFolder)
{// 创建帧动画对象osg::ref_ptr<osg::Sequence> seq = new osg::Sequence();// 文件名向量对象typedef std::vector<string> Filenames;Filenames filenames;char name_count[256];for (int i = 0; i < 60; ++i){sprintf_s(name_count, "%sosgVR\\bz%d.jpg", strDataFolder.c_str(),i);filenames.push_back(name_count);}for (Filenames::iterator itr = filenames.begin(); itr != filenames.end(); ++itr){// 加载模型osg::Image *image = osgDB::readImageFile(*itr);if (image){// 添加子节点seq->addChild(createBillBoard(image));// 设定节点的持续时间seq->setTime(seq->getNumChildren() - 1, 0.1);}}// 设置帧动画持续的时间seq->setInterval(osg::Sequence::LOOP, 0, -1);// 设置播放的速度及重复的次数seq->setDuration(1.0, -1);// 开始播放seq->setMode(osg::Sequence::START);return seq.get();
}
运行程序,截图如图 11-8 所示
图11-8自定义粒子系统示例(二)截图