当前位置: 首页 > news >正文

Day 17: 粒子系统(osgParticle)实战

在这里插入图片描述

本章我们将学习实现包含火焰、烟雾、雨雪三种特效的示例代码及详细说明。

粒子系统(osgParticle)

OpenSceneGraph(OSG)的粒子系统(osgParticle)是一个强大的工具包,用于创建各种自然现象和视觉特效,如火焰、烟雾、雨雪、爆炸等。它基于物理模拟原理,通过管理大量微小的"粒子"对象来生成复杂的动态效果。

核心组件

osgParticle系统由以下几个核心组件构成:

  1. ParticleSystem(粒子系统)

    • 管理所有粒子的容器
    • 负责粒子的生命周期、渲染和属性设置
    • 可以关联纹理图像以增强视觉效果
  2. Particle(粒子)

    • 粒子系统的基本单元
    • 定义了粒子的属性:大小、颜色、生命周期、速度等
    • 每个粒子系统都有一个"粒子模板",新生成的粒子会继承这些属性
  3. Emitter(发射器)

    • 负责生成新粒子
    • 控制粒子的初始位置、方向和速度
    • 常见类型:点发射器、线发射器、面发射器和体发射器
  4. Program(程序)

    • 控制粒子的行为和运动
    • 通过添加各种Operator(操作器)来实现物理效果
  5. Operator(操作器)

    • 对粒子施加各种力和效果
    • 常见类型:
      • AccelOperator:添加加速度(如重力)
      • AgeOperator:管理粒子的老化过程
      • FluidFrictionOperator:模拟流体阻力
      • ForceOperator:添加自定义力
      • IntersectorOperator:处理粒子碰撞
  6. Counter(计数器)

    • 控制粒子的生成速率
    • 常见类型:
      • RandomRateCounter:随机速率生成
      • ConstantRateCounter:恒定速率生成

工作流程

使用osgParticle创建特效的基本步骤:

  1. 创建ParticleSystem并设置粒子属性
  2. 创建Emitter并配置粒子生成方式
  3. 创建Program并添加所需的Operator
  4. 将ParticleSystem添加到场景图中
  5. 使用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); // 不兼容APIps->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)); // 更强的风// 移除了不存在的RandomForceOperatorprogram->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();

}

### 运行效果
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e84611fdb4994b7e81b3cf50df0542ec.png)![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/775de421d0954e97ae979032b4658137.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/032ef0887b804b65b204cab7cf818dd6.png)

相关文章:

  • 解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
  • 【网络安全】开源系统getshell漏洞挖掘
  • XCTF-web-easyupload
  • 每日算法刷题Day27 6.9:leetcode二分答案2道题,用时1h20min
  • 【STM32】G030单片机开启超过8个ADC通道的方法
  • FOPLP vs CoWoS
  • SublimeText 4.4200
  • Xen Server服务器释放磁盘空间
  • 在Ubuntu上利用loongarch64交叉编译工具编译opencv4.4.0
  • 接口 RESTful 中的超媒体:REST 架构的灵魂驱动
  • AI人工智能与LLM语言大模型
  • AIGC 基础篇 Python基础 03 列表与条件判断
  • OpenCV CUDA模块光流计算-----实现Farneback光流算法的类cv::cuda::FarnebackOpticalFlow
  • FreeRTOS队列
  • c语言——字符函数
  • 查询宝塔的数据库信息
  • 多轮对话实现
  • 【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
  • 格恩朗超声波水表 绿色助农 精准领航​
  • 02.运算符
  • 最新的网站建设架构/南宁网络推广培训机构
  • cms开发是什么意思/江苏seo外包
  • 网站建设合同书保密条款/sem代运营托管公司
  • 营销网站的建设流程/沈阳seo关键词排名
  • 平顶山哪里做网站/怎样做百度推广
  • 公司flash网站模板/汕尾网站seo