本章我们将学习实现包含火焰、烟雾、雨雪三种特效的示例代码及详细说明。
粒子系统(osgParticle)
OpenSceneGraph(OSG)的粒子系统(osgParticle)是一个强大的工具包,用于创建各种自然现象和视觉特效,如火焰、烟雾、雨雪、爆炸等。它基于物理模拟原理,通过管理大量微小的"粒子"对象来生成复杂的动态效果。
核心组件
osgParticle系统由以下几个核心组件构成:
-
ParticleSystem(粒子系统)
- 管理所有粒子的容器
- 负责粒子的生命周期、渲染和属性设置
- 可以关联纹理图像以增强视觉效果
-
Particle(粒子)
- 粒子系统的基本单元
- 定义了粒子的属性:大小、颜色、生命周期、速度等
- 每个粒子系统都有一个"粒子模板",新生成的粒子会继承这些属性
-
Emitter(发射器)
- 负责生成新粒子
- 控制粒子的初始位置、方向和速度
- 常见类型:点发射器、线发射器、面发射器和体发射器
-
Program(程序)
- 控制粒子的行为和运动
- 通过添加各种Operator(操作器)来实现物理效果
-
Operator(操作器)
- 对粒子施加各种力和效果
- 常见类型:
- AccelOperator:添加加速度(如重力)
- AgeOperator:管理粒子的老化过程
- FluidFrictionOperator:模拟流体阻力
- ForceOperator:添加自定义力
- IntersectorOperator:处理粒子碰撞
-
Counter(计数器)
- 控制粒子的生成速率
- 常见类型:
- RandomRateCounter:随机速率生成
- ConstantRateCounter:恒定速率生成
工作流程
使用osgParticle创建特效的基本步骤:
- 创建ParticleSystem并设置粒子属性
- 创建Emitter并配置粒子生成方式
- 创建Program并添加所需的Operator
- 将ParticleSystem添加到场景图中
- 使用ParticleSystemUpdater确保粒子系统随时间更新
高级特性
- 纹理和渲染:支持点精灵(Point Sprite)渲染,使粒子始终面向相机
- 粒子行为:可以通过自定义Operator实现复杂的物理模拟
- 粒子交互:支持粒子间的碰撞检测和响应
- 性能优化:通过批处理和剔除技术提高大量粒子的渲染效率
应用场景
osgParticle广泛应用于:
- 游戏开发中的特效(爆炸、魔法效果等)
- 虚拟仿真中的自然现象模拟
- 影视动画中的视觉特效
- 科学可视化中的流体和气体模拟
通过调整粒子系统的各种参数,可以创建出几乎任何你能想象到的动态效果。前面提供的代码示例展示了如何实现几种常见的特效,你可以基于这些基础进一步定制和扩展,创建更复杂的视觉效果。
实战效果
particle.cpp
···cpp
#include <osgViewer/Viewer>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/ModularEmitter>
#include <osgParticle/ModularProgram>
#include <osgParticle/AccelOperator>
#include <osgParticle/FluidFrictionOperator>
#include <osgParticle/SectorPlacer>
#include <osgParticle/RadialShooter>
#include <osgParticle/RandomRateCounter>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/Point>
#include <osg/PointSprite>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgGA/StateSetManipulator>
#include <osgGA/GUIEventHandler>
#include <osgText/Text>
#include <osg/PositionAttitudeTransform>
#include
// 粒子效果类型枚举
enum ParticleEffect {
FIRE,
SMOKE,
RAIN,
SNOW
};
// 粒子系统创建器类
class ParticleSystemCreator {
public:
static osgParticle::ParticleSystem* createFireEffect() {
osgParticle::ParticleSystem* ps = createBaseParticleSystem(“images/fire.png”);
osgParticle::Particle& ptemplate = ps->getDefaultParticleTemplate();
// 设置粒子属性
ptemplate.setLifeTime(1.5f);
ptemplate.setSizeRange(osgParticle::rangef(0.1f, 0.8f));
ptemplate.setAlphaRange(osgParticle::rangef(1.0f, 0.0f));
ptemplate.setColorRange(osgParticle::rangev4(
osg::Vec4(1.0f, 0.5f, 0.1f, 1.0f), // 开始颜色 (橙色)
osg::Vec4(1.0f, 1.0f, 0.0f, 0.0f) // 结束颜色 (黄色到透明)
));
ptemplate.setMass(0.1f);
ptemplate.setRadius(0.05f);
return ps;
}
static osgParticle::ParticleSystem* createSmokeEffect() {
osgParticle::ParticleSystem* ps = createBaseParticleSystem("images/smoke.png");
osgParticle::Particle& ptemplate = ps->getDefaultParticleTemplate();
// 设置粒子属性
ptemplate.setLifeTime(4.0f);
ptemplate.setSizeRange(osgParticle::rangef(0.2f, 1.5f));
ptemplate.setAlphaRange(osgParticle::rangef(0.1f, 0.0f));
ptemplate.setColorRange(osgParticle::rangev4(
osg::Vec4(0.3f, 0.3f, 0.3f, 0.5f), // 开始颜色 (深灰色)
osg::Vec4(0.8f, 0.8f, 0.8f, 0.0f) // 结束颜色 (浅灰色到透明)
));
ptemplate.setMass(0.05f);
ptemplate.setRadius(0.1f);
return ps;
}
static osgParticle::ParticleSystem* createRainEffect() {
osgParticle::ParticleSystem* ps = createBaseParticleSystem("images/raindrop.png");
osgParticle::Particle& ptemplate = ps->getDefaultParticleTemplate();
// 设置粒子属性
ptemplate.setLifeTime(5.0f);
ptemplate.setSizeRange(osgParticle::rangef(0.05f, 0.1f));
ptemplate.setAlphaRange(osgParticle::rangef(0.8f, 0.8f));
ptemplate.setColorRange(osgParticle::rangev4(
osg::Vec4(0.7f, 0.7f, 1.0f, 0.8f), // 开始颜色 (淡蓝色)
osg::Vec4(0.5f, 0.5f, 1.0f, 0.8f) // 结束颜色 (深蓝色)
));
ptemplate.setMass(0.3f);
ptemplate.setRadius(0.01f);
return ps;
}
static osgParticle::ParticleSystem* createSnowEffect() {
osgParticle::ParticleSystem* ps = createBaseParticleSystem("images/snowflake.png");
osgParticle::Particle& ptemplate = ps->getDefaultParticleTemplate();
// 设置粒子属性
ptemplate.setLifeTime(10.0f);
ptemplate.setSizeRange(osgParticle::rangef(0.1f, 0.3f));
ptemplate.setAlphaRange(osgParticle::rangef(0.9f, 0.9f));
ptemplate.setColorRange(osgParticle::rangev4(
osg::Vec4(1.0f, 1.0f, 1.0f, 0.9f), // 开始颜色 (白色)
osg::Vec4(1.0f, 1.0f, 1.0f, 0.9f) // 结束颜色 (白色)
));
ptemplate.setMass(0.01f);
ptemplate.setRadius(0.05f);
return ps;
}
private:
static osgParticle::ParticleSystem* createBaseParticleSystem(const std::string& texturePath) {
osgParticle::ParticleSystem* ps = new osgParticle::ParticleSystem();
// 基本粒子系统设置
ps->setDefaultAttributes(texturePath, true, false);
ps->getDefaultParticleTemplate().setShape(osgParticle::Particle::QUAD);
// 删除不兼容的API调用
// ps->setParticleScaleByDistance(1.0f, 50.0f, 100.0f); // 不兼容API
ps->setDoublePassRendering(true);
// 启用点精灵
osg::StateSet* ss = ps->getOrCreateStateSet();
ss->setAttribute(new osg::Point(20.0f), osg::StateAttribute::ON);
ss->setTextureAttributeAndModes(0, new osg::PointSprite, osg::StateAttribute::ON);
// 设置混合模式
osg::BlendFunc* blendFunc = new osg::BlendFunc();
blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
ss->setAttributeAndModes(blendFunc);
ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
return ps;
}
};
// 粒子发射器创建器类
class ParticleEmitterCreator {
public:
static osgParticle::ModularEmitter* createFireEmitter(osgParticle::ParticleSystem* ps) {
osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter();
emitter->setParticleSystem(ps);
// 设置计数器 (粒子生成率)
osgParticle::RandomRateCounter* counter = new osgParticle::RandomRateCounter();
counter->setRateRange(50, 100); // 50-100 粒子/秒
// 设置放置器 (粒子生成位置)
osgParticle::SectorPlacer* placer = new osgParticle::SectorPlacer();
placer->setCenter(osg::Vec3(0.0f, 0.0f, 0.0f));
placer->setRadiusRange(0.1f, 0.3f);
// 设置发射器 (粒子初始速度)
osgParticle::RadialShooter* shooter = new osgParticle::RadialShooter();
shooter->setInitialSpeedRange(0.5f, 1.5f);
shooter->setPhiRange(0.0f, osg::PI * 0.1f);
shooter->setThetaRange(0.0f, osg::PI * 0.1f);
emitter->setCounter(counter);
emitter->setPlacer(placer);
emitter->setShooter(shooter);
return emitter;
}
static osgParticle::ModularEmitter* createSmokeEmitter(osgParticle::ParticleSystem* ps) {
osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter();
emitter->setParticleSystem(ps);
osgParticle::RandomRateCounter* counter = new osgParticle::RandomRateCounter();
counter->setRateRange(20, 30); // 20-30 粒子/秒
osgParticle::SectorPlacer* placer = new osgParticle::SectorPlacer();
placer->setCenter(osg::Vec3(0.0f, 0.0f, 0.5f)); // 在火焰上方生成
placer->setRadiusRange(0.2f, 0.5f);
osgParticle::RadialShooter* shooter = new osgParticle::RadialShooter();
shooter->setInitialSpeedRange(0.1f, 0.3f);
shooter->setPhiRange(0.0f, osg::PI * 0.2f);
emitter->setCounter(counter);
emitter->setPlacer(placer);
emitter->setShooter(shooter);
return emitter;
}
static osgParticle::ModularEmitter* createRainEmitter(osgParticle::ParticleSystem* ps) {
osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter();
emitter->setParticleSystem(ps);
osgParticle::RandomRateCounter* counter = new osgParticle::RandomRateCounter();
counter->setRateRange(500, 800); // 500-800 粒子/秒
osgParticle::SectorPlacer* placer = new osgParticle::SectorPlacer();
placer->setCenter(osg::Vec3(0.0f, 0.0f, 10.0f)); // 在顶部生成
placer->setRadiusRange(8.0f, 10.0f);
osgParticle::RadialShooter* shooter = new osgParticle::RadialShooter();
shooter->setInitialSpeedRange(2.0f, 5.0f);
shooter->setThetaRange(0.0f, osg::PI_2); // 向下发射
emitter->setCounter(counter);
emitter->setPlacer(placer);
emitter->setShooter(shooter);
return emitter;
}
static osgParticle::ModularEmitter* createSnowEmitter(osgParticle::ParticleSystem* ps) {
osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter();
emitter->setParticleSystem(ps);
osgParticle::RandomRateCounter* counter = new osgParticle::RandomRateCounter();
counter->setRateRange(200, 300); // 200-300 粒子/秒
osgParticle::SectorPlacer* placer = new osgParticle::SectorPlacer();
placer->setCenter(osg::Vec3(0.0f, 0.0f, 10.0f)); // 在顶部生成
placer->setRadiusRange(10.0f, 15.0f);
osgParticle::RadialShooter* shooter = new osgParticle::RadialShooter();
shooter->setInitialSpeedRange(0.5f, 1.5f);
shooter->setThetaRange(0.0f, osg::PI_2); // 向下发射
emitter->setCounter(counter);
emitter->setPlacer(placer);
emitter->setShooter(shooter);
return emitter;
}
};
// 粒子程序创建器类 (控制粒子行为)
class ParticleProgramCreator {
public:
static osgParticle::ModularProgram* createFireProgram() {
osgParticle::ModularProgram* program = new osgParticle::ModularProgram();
// 添加重力
osgParticle::AccelOperator* gravity = new osgParticle::AccelOperator();
gravity->setToGravity();
// 添加流体阻力
osgParticle::FluidFrictionOperator* fluidFriction = new osgParticle::FluidFrictionOperator();
fluidFriction->setFluidToAir();
program->addOperator(gravity);
program->addOperator(fluidFriction);
return program;
}
static osgParticle::ModularProgram* createSmokeProgram() {
osgParticle::ModularProgram* program = new osgParticle::ModularProgram();
// 添加重力 (较小的值)
osgParticle::AccelOperator* gravity = new osgParticle::AccelOperator();
gravity->setAcceleration(osg::Vec3(0.0f, 0.0f, 0.2f));
// 添加流体阻力
osgParticle::FluidFrictionOperator* fluidFriction = new osgParticle::FluidFrictionOperator();
fluidFriction->setFluidToAir();
program->addOperator(gravity);
program->addOperator(fluidFriction);
return program;
}
static osgParticle::ModularProgram* createRainProgram() {
osgParticle::ModularProgram* program = new osgParticle::ModularProgram();
// 添加重力
osgParticle::AccelOperator* gravity = new osgParticle::AccelOperator();
gravity->setToGravity();
// 添加风阻力
osgParticle::FluidFrictionOperator* wind = new osgParticle::FluidFrictionOperator();
wind->setFluidToAir();
wind->setWind(osg::Vec3(1.0f, 0.0f, 0.0f)); // 添加风
program->addOperator(gravity);
program->addOperator(wind);
return program;
}
static osgParticle::ModularProgram* createSnowProgram() {
osgParticle::ModularProgram* program = new osgParticle::ModularProgram();
// 添加重力 (较小的值)
osgParticle::AccelOperator* gravity = new osgParticle::AccelOperator();
gravity->setAcceleration(osg::Vec3(0.0f, 0.0f, -1.0f));
// 添加风阻力
osgParticle::FluidFrictionOperator* wind = new osgParticle::FluidFrictionOperator();
wind->setFluidToAir();
wind->setWind(osg::Vec3(1.5f, 0.0f, 0.0f)); // 更强的风
// 移除了不存在的RandomForceOperator
program->addOperator(gravity);
program->addOperator(wind);
return program;
}
};
// 事件处理器:切换粒子效果
class ParticleSwitcher : public osgGA::GUIEventHandler {
public:
ParticleSwitcher(osg::Group* particleGroup)
: _particleGroup(particleGroup), _currentEffect(FIRE) {
createAllEffects();
showEffect(FIRE);
}
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
switch (ea.getKey()) {
case '1':
showEffect(FIRE);
return true;
case '2':
showEffect(SMOKE);
return true;
case '3':
showEffect(RAIN);
return true;
case '4':
showEffect(SNOW);
return true;
case 'r':
toggleRainSnow();
return true;
}
}
return false;
}
void showEffect(ParticleEffect effect) {
// 隐藏所有效果
for (int i = 0; i < 4; ++i) {
_particleGroup->getChild(i)->setNodeMask(0);
}
// 显示当前效果
_particleGroup->getChild(effect)->setNodeMask(0xFFFFFFFF);
_currentEffect = effect;
}
void toggleRainSnow() {
if (_currentEffect == RAIN) {
showEffect(SNOW);
} else if (_currentEffect == SNOW) {
showEffect(RAIN);
}
}
private:
void createAllEffects() {
// 创建火焰效果
osg::Group* fireGroup = new osg::Group();
osgParticle::ParticleSystem* firePS = ParticleSystemCreator::createFireEffect();
osgParticle::ModularEmitter* fireEmitter = ParticleEmitterCreator::createFireEmitter(firePS);
osgParticle::ModularProgram* fireProgram = ParticleProgramCreator::createFireProgram();
fireProgram->setParticleSystem(firePS);
osg::Geode* fireGeode = new osg::Geode();
fireGeode->addDrawable(firePS);
fireGroup->addChild(fireEmitter);
fireGroup->addChild(fireProgram);
fireGroup->addChild(fireGeode);
// 创建烟雾效果
osg::Group* smokeGroup = new osg::Group();
osgParticle::ParticleSystem* smokePS = ParticleSystemCreator::createSmokeEffect();
osgParticle::ModularEmitter* smokeEmitter = ParticleEmitterCreator::createSmokeEmitter(smokePS);
osgParticle::ModularProgram* smokeProgram = ParticleProgramCreator::createSmokeProgram();
smokeProgram->setParticleSystem(smokePS);
osg::Geode* smokeGeode = new osg::Geode();
smokeGeode->addDrawable(smokePS);
smokeGroup->addChild(smokeEmitter);
smokeGroup->addChild(smokeProgram);
smokeGroup->addChild(smokeGeode);
// 创建雨效果
osg::Group* rainGroup = new osg::Group();
osgParticle::ParticleSystem* rainPS = ParticleSystemCreator::createRainEffect();
osgParticle::ModularEmitter* rainEmitter = ParticleEmitterCreator::createRainEmitter(rainPS);
osgParticle::ModularProgram* rainProgram = ParticleProgramCreator::createRainProgram();
rainProgram->setParticleSystem(rainPS);
osg::Geode* rainGeode = new osg::Geode();
rainGeode->addDrawable(rainPS);
rainGroup->addChild(rainEmitter);
rainGroup->addChild(rainProgram);
rainGroup->addChild(rainGeode);
// 创建雪效果
osg::Group* snowGroup = new osg::Group();
osgParticle::ParticleSystem* snowPS = ParticleSystemCreator::createSnowEffect();
osgParticle::ModularEmitter* snowEmitter = ParticleEmitterCreator::createSnowEmitter(snowPS);
osgParticle::ModularProgram* snowProgram = ParticleProgramCreator::createSnowProgram();
snowProgram->setParticleSystem(snowPS);
osg::Geode* snowGeode = new osg::Geode();
snowGeode->addDrawable(snowPS);
snowGroup->addChild(snowEmitter);
snowGroup->addChild(snowProgram);
snowGroup->addChild(snowGeode);
// 添加到粒子组
_particleGroup->addChild(fireGroup);
_particleGroup->addChild(smokeGroup);
_particleGroup->addChild(rainGroup);
_particleGroup->addChild(snowGroup);
// 添加粒子系统更新器
osgParticle::ParticleSystemUpdater* updater = new osgParticle::ParticleSystemUpdater();
updater->addParticleSystem(firePS);
updater->addParticleSystem(smokePS);
updater->addParticleSystem(rainPS);
updater->addParticleSystem(snowPS);
_particleGroup->addChild(updater);
}
osg::ref_ptr<osg::Group> _particleGroup;
ParticleEffect _currentEffect;
};
// 创建信息显示
osgText::Text* createInfoText(const std::string& message, float yPos) {
osgText::Text* text = new osgText::Text();
text->setFont(“fonts/arial.ttf”);
text->setCharacterSize(20.0f);
text->setPosition(osg::Vec3(10.0f, yPos, 0.0f));
text->setColor(osg::Vec4(1.0f, 1.0f, 0.5f, 1.0f));
text->setText(message);
text->setBackdropType(osgText::Text::OUTLINE);
return text;
}
int main() {
// 创建查看器
osgViewer::Viewer viewer;
// 创建根节点
osg::Group* root = new osg::Group();
// 添加地面
osg::Geode* groundGeode = new osg::Geode();
osg::Geometry* groundGeometry = osg::createTexturedQuadGeometry(
osg::Vec3(-15.0f, -15.0f, 0.0f),
osg::Vec3(30.0f, 0.0f, 0.0f),
osg::Vec3(0.0f, 30.0f, 0.0f)
);
osg::Texture2D* groundTexture = new osg::Texture2D(osgDB::readImageFile("images/ground.jpg"));
if (groundTexture) {
groundTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
groundTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
groundGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, groundTexture);
}
groundGeode->addDrawable(groundGeometry);
root->addChild(groundGeode);
// 创建粒子组
osg::Group* particleGroup = new osg::Group();
root->addChild(particleGroup);
// 添加事件处理器
viewer.addEventHandler(new ParticleSwitcher(particleGroup));
// 添加状态设置处理器(允许调整渲染状态)
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
// 添加信息显示
osg::Geode* textGeode = new osg::Geode();
textGeode->addDrawable(createInfoText("OSG Particle System Demo", 550.0f));
textGeode->addDrawable(createInfoText("Press 1: Fire Effect", 520.0f));
textGeode->addDrawable(createInfoText("Press 2: Smoke Effect", 490.0f));
textGeode->addDrawable(createInfoText("Press 3: Rain Effect", 460.0f));
textGeode->addDrawable(createInfoText("Press 4: Snow Effect", 430.0f));
textGeode->addDrawable(createInfoText("Press R: Toggle Rain/Snow", 400.0f));
root->addChild(textGeode);
// 设置场景数据
viewer.setSceneData(root);
// 设置相机位置
viewer.getCamera()->setViewMatrixAsLookAt(
osg::Vec3(0.0f, -10.0f, 8.0f), // 眼睛位置
osg::Vec3(0.0f, 0.0f, 2.0f), // 观察点
osg::Vec3(0.0f, 0.0f, 1.0f) // 上方向
);
// 启动查看器
return viewer.run();
}
### 运行效果


