diff --git a/include/gz/sim/rendering/Events.hh b/include/gz/sim/rendering/Events.hh index 18ea194118..132f9baa92 100644 --- a/include/gz/sim/rendering/Events.hh +++ b/include/gz/sim/rendering/Events.hh @@ -44,9 +44,9 @@ namespace gz using SceneUpdate = gz::common::EventT; - /// \brief The render event is emitted before rendering updates. + /// \brief The pre render event is emitted before rendering updates. /// The event is emitted in the rendering thread so rendering - /// calls can ben make in this event callback + /// calls can be made in this event callback /// /// For example: /// \code @@ -55,9 +55,20 @@ namespace gz using PreRender = gz::common::EventT; - /// \brief The render event is emitted after rendering updates. + /// \brief The render event is emitted during rendering updates. /// The event is emitted in the rendering thread so rendering - /// calls can ben make in this event callback + /// calls can be made in this event callback + /// + /// For example: + /// \code + /// eventManager.Emit(); + /// \endcode + using Render = gz::common::EventT; + + /// \brief The post render event is emitted after rendering updates. + /// The event is emitted in the rendering thread so rendering + /// calls can be made in this event callback /// /// For example: /// \code @@ -65,6 +76,20 @@ namespace gz /// \endcode using PostRender = gz::common::EventT; + + /// \brief The force render event may be emitted outside the + /// rendering thread to force rendering calls ie. to ensure + /// rendering occurs even if it wasn't seemingly necessary. + /// + /// Useful for custom, out-of-tree rendering sensors that + /// need the rendering thread to perform an update. + /// + /// For example: + /// \code + /// eventManager.Emit(); + /// \endcode + using ForceRender = gz::common::EventT; } } // namespace events } // namespace sim diff --git a/src/systems/sensors/Sensors.cc b/src/systems/sensors/Sensors.cc index 948e27a2a9..6bc5fe0afa 100644 --- a/src/systems/sensors/Sensors.cc +++ b/src/systems/sensors/Sensors.cc @@ -113,6 +113,9 @@ class gz::sim::systems::SensorsPrivate /// \brief Flag to signal if rendering update is needed public: bool updateAvailable { false }; + /// \brief Flag to signal if a rendering update must be done + public: std::atomic forceUpdate { false }; + /// \brief Thread that rendering will occur in public: std::thread renderThread; @@ -129,6 +132,9 @@ class gz::sim::systems::SensorsPrivate /// \brief Connection to events::Stop event, used to stop thread public: gz::common::ConnectionPtr stopConn; + /// \brief Connection to events::ForceRender event, used to force rendering + public: gz::common::ConnectionPtr forceRenderConn; + /// \brief Update time for the next rendering iteration public: std::chrono::steady_clock::duration updateTime; @@ -185,6 +191,9 @@ class gz::sim::systems::SensorsPrivate /// \brief Stop the rendering thread public: void Stop(); + /// \brief Force rendering thread to render + public: void ForceRender(); + /// \brief Update battery state of sensors in model /// \param[in] _ecm Entity component manager public: void UpdateBatteryState(const EntityComponentManager &_ecm); @@ -275,7 +284,7 @@ void SensorsPrivate::RunOnce() this->renderUtil.Update(); } - if (!this->activeSensors.empty()) + if (!this->activeSensors.empty() || this->forceUpdate) { // disable sensors that are out of battery or re-enable sensors that are // being charged @@ -344,6 +353,7 @@ void SensorsPrivate::RunOnce() // publish data IGN_PROFILE("RunOnce"); this->sensorManager.RunOnce(this->updateTime); + this->eventManager->Emit(); } // re-enble sensors @@ -366,6 +376,7 @@ void SensorsPrivate::RunOnce() } this->updateAvailable = false; + this->forceUpdate = false; lock.unlock(); this->renderCv.notify_one(); } @@ -422,6 +433,12 @@ void SensorsPrivate::Stop() } } +////////////////////////////////////////////////// +void SensorsPrivate::ForceRender() +{ + this->forceUpdate = true; +} + ////////////////////////////////////////////////// void Sensors::RemoveSensor(const Entity &_entity) { @@ -540,6 +557,9 @@ void Sensors::Configure(const Entity &/*_id*/, this->dataPtr->stopConn = _eventMgr.Connect( std::bind(&SensorsPrivate::Stop, this->dataPtr.get())); + this->dataPtr->forceRenderConn = _eventMgr.Connect( + std::bind(&SensorsPrivate::ForceRender, this->dataPtr.get())); + // Kick off worker thread this->dataPtr->Run(); } @@ -573,7 +593,8 @@ void Sensors::PostUpdate(const UpdateInfo &_info, { std::unique_lock lock(this->dataPtr->renderMutex); if (!this->dataPtr->initialized && - (_ecm.HasComponentType(components::Camera::typeId) || + (this->dataPtr->forceUpdate || + _ecm.HasComponentType(components::Camera::typeId) || _ecm.HasComponentType(components::DepthCamera::typeId) || _ecm.HasComponentType(components::GpuLidar::typeId) || _ecm.HasComponentType(components::RgbdCamera::typeId) || @@ -623,7 +644,8 @@ void Sensors::PostUpdate(const UpdateInfo &_info, this->dataPtr->sensorMaskMutex.unlock(); if (!activeSensors.empty() || - this->dataPtr->renderUtil.PendingSensors() > 0) + this->dataPtr->renderUtil.PendingSensors() > 0 || + this->dataPtr->forceUpdate) { if (this->dataPtr->disableOnDrainedBattery) this->dataPtr->UpdateBatteryState(_ecm); diff --git a/tutorials/rendering_plugins.md b/tutorials/rendering_plugins.md index b50a761abe..e62160544f 100644 --- a/tutorials/rendering_plugins.md +++ b/tutorials/rendering_plugins.md @@ -100,7 +100,7 @@ events. Here's how to do it: ### Render events on the server -The server plugin will need to listen to `gz::sim::events::PreRender` or +The server plugin will need to listen `gz::sim::events::PreRender`, `gz::sim::events::Render` or `gz::sim::events::PostRender` events. Here's how to do it: