自定义粒子系统示例(二)

        目前自定义粒子的方法有很多,在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();

		// 关联image
		texture->setImage(image.get());

		// 关联Texture2D纹理对象,第三个参数默认为ON
		stateset->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对象1
	osg::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 所示

OSG粒子系统与阴影-自定义粒子系统示例<2>(5)-LMLPHP

图11-8自定义粒子系统示例(二)截图

11-26 05:28