diff --git a/examples/particles_demo/Main.cc b/examples/particles_demo/Main.cc index a53535e7b..57ccdcb0e 100644 --- a/examples/particles_demo/Main.cc +++ b/examples/particles_demo/Main.cc @@ -113,7 +113,7 @@ void buildScene(ScenePtr _scene) emitter->SetLifetime(2); emitter->SetVelocityRange(10, 20); emitter->SetMaterial(particleMaterial); - emitter->SetColorImage(RESOURCE_PATH + "/smokecolors.png"); + emitter->SetColorRangeImage(RESOURCE_PATH + "/smokecolors.png"); emitter->SetScaleRate(10); emitter->SetEmitting(true); root->AddChild(emitter); diff --git a/include/ignition/rendering/ParticleEmitter.hh b/include/ignition/rendering/ParticleEmitter.hh index 178a3546f..4ea2437b5 100644 --- a/include/ignition/rendering/ParticleEmitter.hh +++ b/include/ignition/rendering/ParticleEmitter.hh @@ -46,6 +46,9 @@ namespace ignition /// \brief Ellipsoid emitter. EM_ELLIPSOID = 3, + + /// \brief Total number of emitters (keep always at the end). + EM_NUM_EMITTERS = 4, }; /// \class ParticleEmitter ParticleEmitter.hh @@ -199,9 +202,12 @@ namespace ignition /// \sa SetColorRange public: virtual ignition::math::Color ColorEnd() const = 0; - /// \brief Sets a colour for all particle emitted. - /// The actual colour will be interpolated between these two colors. - /// Default values are Color::White and Color::White respectively. + /// \brief Sets a color for all particle emitted. + /// The actual color will be interpolated between these two colors + /// Color::White is the default color for the particles unless a specific + /// function is used. + /// Note that this function overrides the particle colors set with + /// SetColorRangeImage(). /// \param[in] _colorStart Start color. /// \param[in] _colorEnd End color. /// \sa ColorStart @@ -225,18 +231,20 @@ namespace ignition /// \brief Get the path to the color image used as an affector. /// \return The color image name or empty string if the image is not set. - /// \sa SetColorImage - public: virtual std::string ColorImage() const = 0; + /// \sa SetColorRangeImage + public: virtual std::string ColorRangeImage() const = 0; /// \brief Set the path to the color image used as an affector. This - /// affector modifies the colour of particles in flight. The colors are - /// taken from a specified image file. The range of colour values begins + /// affector modifies the color of particles in flight. The colors are + /// taken from a specified image file. The range of color values begins /// from the left side of the image and move to the right over the /// lifetime of the particle, therefore only the horizontal dimension of /// the image is used. + /// Note that this function overrides the particle colors set with + /// SetColorRange(). /// \param[in] _image The color image name. - /// \sa ColorImage - public: virtual void SetColorImage(const std::string &_image) = 0; + /// \sa ColorRangeImage + public: virtual void SetColorRangeImage(const std::string &_image) = 0; }; } } diff --git a/include/ignition/rendering/base/BaseParticleEmitter.hh b/include/ignition/rendering/base/BaseParticleEmitter.hh index f6ca7e1bc..1c0459a2a 100644 --- a/include/ignition/rendering/base/BaseParticleEmitter.hh +++ b/include/ignition/rendering/base/BaseParticleEmitter.hh @@ -131,10 +131,11 @@ namespace ignition public: virtual void SetScaleRate(double _scaleRate) override; // Documentation inherited. - public: virtual std::string ColorImage() const override; + public: virtual std::string ColorRangeImage() const override; // Documentation inherited. - public: virtual void SetColorImage(const std::string &_image) override; + public: virtual void SetColorRangeImage( + const std::string &_image) override; /// \brief Emitter type. protected: EmitterType type = EM_POINT; @@ -179,7 +180,7 @@ namespace ignition protected: double scaleRate = 1; /// \brief The color image. - protected: std::string colorImage = ""; + protected: std::string colorRangeImage = ""; /// \brief Only the scene can create a particle emitter private: friend class BaseScene; @@ -393,16 +394,16 @@ namespace ignition ///////////////////////////////////////////////// template - std::string BaseParticleEmitter::ColorImage() const + std::string BaseParticleEmitter::ColorRangeImage() const { - return this->colorImage; + return this->colorRangeImage; } ///////////////////////////////////////////////// template - void BaseParticleEmitter::SetColorImage(const std::string &_image) + void BaseParticleEmitter::SetColorRangeImage(const std::string &_image) { - this->colorImage = _image; + this->colorRangeImage = _image; } } } diff --git a/ogre2/include/ignition/rendering/ogre2/Ogre2ParticleEmitter.hh b/ogre2/include/ignition/rendering/ogre2/Ogre2ParticleEmitter.hh index 2407af1ae..07bb893fe 100644 --- a/ogre2/include/ignition/rendering/ogre2/Ogre2ParticleEmitter.hh +++ b/ogre2/include/ignition/rendering/ogre2/Ogre2ParticleEmitter.hh @@ -79,7 +79,7 @@ namespace ignition public: virtual void SetScaleRate(double _scaleRate); // Documentation inherited. - public: virtual void SetColorImage(const std::string &_image); + public: virtual void SetColorRangeImage(const std::string &_image); // Documentation inherited. protected: virtual void Init() override; diff --git a/ogre2/src/Ogre2ParticleEmitter.cc b/ogre2/src/Ogre2ParticleEmitter.cc index d56679885..b0eddcae5 100644 --- a/ogre2/src/Ogre2ParticleEmitter.cc +++ b/ogre2/src/Ogre2ParticleEmitter.cc @@ -39,13 +39,14 @@ class ignition::rendering::Ogre2ParticleEmitterPrivate public: Ogre::ParticleSystem *ps = nullptr; /// \brief Ogre particle emitter. - public: Ogre::ParticleEmitter *emitter = nullptr; + public: std::array emitters; - // \brief Ogre colour image affector. - public: Ogre::ParticleAffector *colourImageAffector = nullptr; + // \brief Ogre color image affector. + public: Ogre::ParticleAffector *colorImageAffector = nullptr; - // \brief Ogre colour interpolator affector. - public: Ogre::ParticleAffector *colourInterpolatorAffector = nullptr; + // \brief Ogre color interpolator affector. + public: Ogre::ParticleAffector *colorInterpolatorAffector = nullptr; /// \brief Ogre scaler affector. public: Ogre::ParticleAffector *scalerAffector = nullptr; @@ -54,6 +55,16 @@ class ignition::rendering::Ogre2ParticleEmitterPrivate public: Ogre::HlmsUnlitDatablock *ogreDatablock = nullptr; }; +// Names used in Ogre for the supported emitters. +static const std::array + kOgreEmitterTypes = + { + "Point", + "Box", + "Cylinder", + "Ellipsoid", + }; + ////////////////////////////////////////////////// Ogre2ParticleEmitter::Ogre2ParticleEmitter() : dataPtr(new Ogre2ParticleEmitterPrivate) @@ -69,40 +80,18 @@ Ogre2ParticleEmitter::~Ogre2ParticleEmitter() void Ogre2ParticleEmitter::Ogre2ParticleEmitter::SetType( const EmitterType _type) { - switch (_type) + // Sanity check: Make sure that the emitter type is valid. + if (_type == EmitterType::EM_NUM_EMITTERS) { - case EmitterType::EM_POINT: - { - this->dataPtr->ps->removeAllEmitters(); - this->dataPtr->emitter = this->dataPtr->ps->addEmitter("Point"); - break; - } - case EmitterType::EM_BOX: - { - this->dataPtr->ps->removeAllEmitters(); - this->dataPtr->emitter = this->dataPtr->ps->addEmitter("Box"); - break; - } - case EmitterType::EM_CYLINDER: - { - this->dataPtr->ps->removeAllEmitters(); - this->dataPtr->emitter = this->dataPtr->ps->addEmitter("Cylinder"); - break; - } - case EmitterType::EM_ELLIPSOID: - { - this->dataPtr->ps->removeAllEmitters(); - this->dataPtr->emitter = this->dataPtr->ps->addEmitter("Ellipsoid"); - break; - } - default: - { - ignerr << "Unsupported particle emitter type [" << _type << "]" - << std::endl; - return; - } + ignerr << "SetType() error: You shouldn't use EM_NUM_EMITTERS as a type." + << std::endl; + return; } + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) + this->dataPtr->emitters[i]->setEnabled(false); + + this->dataPtr->emitters[_type]->setEnabled(true); this->type = _type; } @@ -141,11 +130,15 @@ void Ogre2ParticleEmitter::SetEmitterSize(const ignition::math::Vector3d &_size) // Set all parameters. for (auto[param, value] : allParamsToSet) { - if (!this->dataPtr->emitter->setParameter(param, value)) + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) { - ignerr << "Ignoring SetEmitterSize() because SetParameter(" - << param << " " << value << ") failed." << std::endl; - return; + if (!this->dataPtr->emitters[i]->setParameter(param, value)) + { + ignerr << "SetEmitterSize() error for " << kOgreEmitterTypes[i] + << " emitter because SetParameter(" << param << " " << value + << ") failed." << std::endl; + return; + } } } break; @@ -172,21 +165,25 @@ void Ogre2ParticleEmitter::SetRate(double _rate) return; } - this->dataPtr->emitter->setEmissionRate(_rate); + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) + this->dataPtr->emitters[i]->setEmissionRate(_rate); + this->rate = _rate; } ////////////////////////////////////////////////// void Ogre2ParticleEmitter::SetDuration(double _duration) { - this->dataPtr->emitter->setDuration(_duration); + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) + this->dataPtr->emitters[i]->setDuration(_duration); + this->duration = _duration; } ////////////////////////////////////////////////// void Ogre2ParticleEmitter::SetEmitting(bool _enable) { - this->dataPtr->emitter->setEnabled(_enable); + this->dataPtr->emitters[this->type]->setEnabled(_enable); this->dataPtr->ps->setEmitting(_enable); this->emitting = _enable; } @@ -217,7 +214,9 @@ void Ogre2ParticleEmitter::SetLifetime(double _lifetime) return; } - this->dataPtr->emitter->setTimeToLive(_lifetime); + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) + this->dataPtr->emitters[i]->setTimeToLive(_lifetime); + this->lifetime = _lifetime; } @@ -240,7 +239,9 @@ void Ogre2ParticleEmitter::SetMaterial(const MaterialPtr &_material) void Ogre2ParticleEmitter::SetVelocityRange(double _minVelocity, double _maxVelocity) { - this->dataPtr->emitter->setParticleVelocity(_minVelocity, _maxVelocity); + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) + this->dataPtr->emitters[i]->setParticleVelocity(_minVelocity, _maxVelocity); + this->minVelocity = _minVelocity; this->maxVelocity = _maxVelocity; } @@ -250,10 +251,10 @@ void Ogre2ParticleEmitter::SetColorRange( const ignition::math::Color &_colorStart, const ignition::math::Color &_colorEnd) { - // Colour interpolator affector. - if (!this->dataPtr->colourInterpolatorAffector) + // Color interpolator affector. + if (!this->dataPtr->colorInterpolatorAffector) { - this->dataPtr->colourInterpolatorAffector = + this->dataPtr->colorInterpolatorAffector = this->dataPtr->ps->addAffector("ColourInterpolator"); } @@ -278,7 +279,7 @@ void Ogre2ParticleEmitter::SetColorRange( // Set all parameters. for (auto[param, value] : allParamsToSet) { - if (!this->dataPtr->colourInterpolatorAffector->setParameter(param, value)) + if (!this->dataPtr->colorInterpolatorAffector->setParameter(param, value)) { ignerr << "Ignoring SetColorRange() because SetParameter(" << param << " " << value << ") failed." << std::endl; @@ -327,20 +328,20 @@ void Ogre2ParticleEmitter::SetScaleRate(double _scaleRate) } ////////////////////////////////////////////////// -void Ogre2ParticleEmitter::SetColorImage(const std::string &_image) +void Ogre2ParticleEmitter::SetColorRangeImage(const std::string &_image) { // Sanity check: Make sure that the texture can be found. if (!common::exists(_image) || !common::isFile(_image)) { - ignerr << "SetColorImage() error: Texture [" << _image << "] not found" + ignerr << "SetColorRangeImage() error: Texture [" << _image << "] not found" << std::endl; return; } - // Colour image affector. - if (!this->dataPtr->colourImageAffector) + // Color image affector. + if (!this->dataPtr->colorImageAffector) { - this->dataPtr->colourImageAffector = + this->dataPtr->colorImageAffector = this->dataPtr->ps->addAffector("ColourImage"); } @@ -352,15 +353,15 @@ void Ogre2ParticleEmitter::SetColorImage(const std::string &_image) // Set all parameters. for (auto[param, value] : allParamsToSet) { - if (!this->dataPtr->colourImageAffector->setParameter(param, value)) + if (!this->dataPtr->colorImageAffector->setParameter(param, value)) { - ignerr << "Ignoring SetColorImage() because SetParameter(" + ignerr << "Ignoring SetColorRangeImage() because SetParameter(" << param << " " << value << ") failed." << std::endl; return; } } - this->colorImage = _image; + this->colorRangeImage = _image; } ////////////////////////////////////////////////// @@ -374,9 +375,20 @@ void Ogre2ParticleEmitter::Init() this->dataPtr->ps->setParticleQuota(500); this->dataPtr->ps->setSortingEnabled(true); - // Instantiate the particle emitter and default parameters. - this->dataPtr->emitter = this->dataPtr->ps->addEmitter("Point"); - this->dataPtr->emitter->setDirection(Ogre::Vector3::UNIT_X); + IGN_ASSERT(kOgreEmitterTypes.size() == EmitterType::EM_NUM_EMITTERS, + "The nummer of supported emitters does not match the number of " + "Ogre emitter types."); + + // Instantiate all particle emitters and their default parameters. + // Note that we enable the point emitter by default. + for (auto i = 0; i < EmitterType::EM_NUM_EMITTERS; ++i) + { + this->dataPtr->emitters[i] = + this->dataPtr->ps->addEmitter(kOgreEmitterTypes[i]); + this->dataPtr->emitters[i]->setEnabled(false); + this->dataPtr->emitters[i]->setDirection(Ogre::Vector3::UNIT_X); + } + this->dataPtr->emitters[EmitterType::EM_POINT]->setEnabled(true); // Instantiate the default material. auto mat = this->scene->CreateMaterial(); diff --git a/src/ParticleEmitter_TEST.cc b/src/ParticleEmitter_TEST.cc index 475f073e3..ed6c3743f 100644 --- a/src/ParticleEmitter_TEST.cc +++ b/src/ParticleEmitter_TEST.cc @@ -72,20 +72,20 @@ void ParticleEmitterTest::CheckBasicAPI() ParticleEmitterPtr particleEmitter = this->scene->CreateParticleEmitter(); // Default values. - EmitterType expectedEmitterType = EmitterType::EM_POINT; - ignition::math::Vector3d expectedEmitterSize = ignition::math::Vector3d::One; - double expectedRate = 10.0; - double expectedDuration = 0; - bool expectedEmitting = false; - ignition::math::Vector3d expectedParticleSize = {1, 1, 1}; - double expectedLifetime = 5; - MaterialPtr expectedMaterial = nullptr; - double expectedMinVel = 1; - double expectedMaxVel = 1; - ignition::math::Color expectedColorStart = ignition::math::Color::White; - ignition::math::Color expectedColorEnd = ignition::math::Color::White; - double expectedScaleRate = 1; - std::string expectedColorImage = ""; + EmitterType expectedEmitterType = EmitterType::EM_POINT; + math::Vector3d expectedEmitterSize = ignition::math::Vector3d::One; + double expectedRate = 10.0; + double expectedDuration = 0; + bool expectedEmitting = false; + math::Vector3d expectedParticleSize = {1, 1, 1}; + double expectedLifetime = 5; + MaterialPtr expectedMaterial = nullptr; + double expectedMinVel = 1; + double expectedMaxVel = 1; + math::Color expectedColorStart = ignition::math::Color::White; + math::Color expectedColorEnd = ignition::math::Color::White; + double expectedScaleRate = 1; + std::string expectedColorRangeImage = ""; // Check default expectations. EXPECT_EQ(expectedEmitterType, particleEmitter->Type()); @@ -101,23 +101,23 @@ void ParticleEmitterTest::CheckBasicAPI() EXPECT_EQ(expectedColorStart, particleEmitter->ColorStart()); EXPECT_EQ(expectedColorEnd, particleEmitter->ColorEnd()); EXPECT_DOUBLE_EQ(expectedScaleRate, particleEmitter->ScaleRate()); - EXPECT_EQ(expectedColorImage, particleEmitter->ColorImage()); + EXPECT_EQ(expectedColorRangeImage, particleEmitter->ColorRangeImage()); // Modify values. - expectedEmitterType = EmitterType::EM_BOX; - expectedEmitterSize = {0.2, 0.2, 0.2}; - expectedRate = 5.0; - expectedDuration = 30; - expectedEmitting = true; - expectedParticleSize = {200, 300, 400}; - expectedLifetime = 10; - expectedMaterial = nullptr; - expectedMinVel = 2; - expectedMaxVel = 3; - expectedColorStart = ignition::math::Color::Red; - expectedColorEnd = ignition::math::Color::Blue; - expectedScaleRate = 10; - expectedColorImage = "anImage"; + expectedEmitterType = EmitterType::EM_BOX; + expectedEmitterSize = {0.2, 0.2, 0.2}; + expectedRate = 5.0; + expectedDuration = 30; + expectedEmitting = true; + expectedParticleSize = {200, 300, 400}; + expectedLifetime = 10; + expectedMaterial = nullptr; + expectedMinVel = 2; + expectedMaxVel = 3; + expectedColorStart = ignition::math::Color::Red; + expectedColorEnd = ignition::math::Color::Blue; + expectedScaleRate = 10; + expectedColorRangeImage = "anImage"; // Modify attributes. particleEmitter->SetType(expectedEmitterType); @@ -131,23 +131,23 @@ void ParticleEmitterTest::CheckBasicAPI() particleEmitter->SetVelocityRange(expectedMinVel, expectedMaxVel); particleEmitter->SetColorRange(expectedColorStart, expectedColorEnd); particleEmitter->SetScaleRate(expectedScaleRate); - particleEmitter->SetColorImage(expectedColorImage); + particleEmitter->SetColorRangeImage(expectedColorRangeImage); // Check getters. - EXPECT_EQ(expectedEmitterType, particleEmitter->Type()); - EXPECT_EQ(expectedEmitterSize, particleEmitter->EmitterSize()); - EXPECT_DOUBLE_EQ(expectedRate, particleEmitter->Rate()); - EXPECT_DOUBLE_EQ(expectedDuration, particleEmitter->Duration()); - EXPECT_EQ(expectedEmitting, particleEmitter->Emitting()); - EXPECT_EQ(expectedParticleSize, particleEmitter->ParticleSize()); - EXPECT_DOUBLE_EQ(expectedLifetime, particleEmitter->Lifetime()); - EXPECT_EQ(expectedMaterial, particleEmitter->Material()); - EXPECT_DOUBLE_EQ(expectedMinVel, particleEmitter->MinVelocity()); - EXPECT_DOUBLE_EQ(expectedMaxVel, particleEmitter->MaxVelocity()); - EXPECT_EQ(expectedColorStart, particleEmitter->ColorStart()); - EXPECT_EQ(expectedColorEnd, particleEmitter->ColorEnd()); + EXPECT_EQ(expectedEmitterType, particleEmitter->Type()); + EXPECT_EQ(expectedEmitterSize, particleEmitter->EmitterSize()); + EXPECT_DOUBLE_EQ(expectedRate, particleEmitter->Rate()); + EXPECT_DOUBLE_EQ(expectedDuration, particleEmitter->Duration()); + EXPECT_EQ(expectedEmitting, particleEmitter->Emitting()); + EXPECT_EQ(expectedParticleSize, particleEmitter->ParticleSize()); + EXPECT_DOUBLE_EQ(expectedLifetime, particleEmitter->Lifetime()); + EXPECT_EQ(expectedMaterial, particleEmitter->Material()); + EXPECT_DOUBLE_EQ(expectedMinVel, particleEmitter->MinVelocity()); + EXPECT_DOUBLE_EQ(expectedMaxVel, particleEmitter->MaxVelocity()); + EXPECT_EQ(expectedColorStart, particleEmitter->ColorStart()); + EXPECT_EQ(expectedColorEnd, particleEmitter->ColorEnd()); EXPECT_DOUBLE_EQ(expectedScaleRate, particleEmitter->ScaleRate()); - EXPECT_EQ(expectedColorImage, particleEmitter->ColorImage()); + EXPECT_EQ(expectedColorRangeImage, particleEmitter->ColorRangeImage()); } /////////////////////////////////////////////////