How to use SetMaterial in a Visual plugin

asked 2020-07-15 04:56:36 -0600

srmainwaring gravatar image

I would like to change the material on a visual using a visual plugin. The plugin works as expected when the model has no material assigned in the sdf, but does not work when the material is set. I have tried setting the material using the Gazebo Visual::SetMaterial method and also setting the material on the Ogre::Entity (and Ogre::SubEntity) directly with the same results. I suspect it may be linked to the use of the Ogre RTSS but do not know enough about the full rendering system as it is used in Gazebo to verify this. Any help would be welcome.

Here is a minimal example to illustrate the approach.

Plugin code:

#include <gazebo/common/Plugin.hh>
#include <gazebo/rendering/Visual.hh>
#include <thread>

namespace gazebo
{
  class GZ_RENDERING_VISIBLE SetMaterialVisualPlugin : public gazebo::VisualPlugin
 {
   public: virtual ~SetMaterialVisualPlugin() {}

   public: SetMaterialVisualPlugin() {}

   public: void Load(
     gazebo::rendering::VisualPtr _visual,
     sdf::ElementPtr _sdf) override
  {
     std::lock_guard<std::mutex> lock(this->mutex);
     this->visual = _visual; 
     this->sdf = _sdf; 
   }

   public: void Init() override
   {
      std::lock_guard<std::mutex> lock(this->mutex);

     if (!this->isInitialised)
     {
       // Attempt to change the material.
       std::string materialName = "Gazebo/Purple";
       this->visual->SetMaterial(materialName);
       this->isInitialised = true;

        gzmsg << "SetMaterial(\"" << materialName << "\")" << std::endl;
        gzmsg << "Name:     " << this->visual->Name() << std::endl;
        gzmsg << "Material: " << this->visual->GetMaterialName() << std::endl;
      }
   }

   public: void Reset() override {}

   private:
      std::mutex mutex;
      bool isInitialised = false;
      gazebo::rendering::VisualPtr visual;
      sdf::ElementPtr sdf;
  };

  GZ_REGISTER_VISUAL_PLUGIN(SetMaterialVisualPlugin)

} // namespace gazebo

World file:

<?xml version="1.0" ?>
<sdf version="1.6">
  <world name="set_material_world">

    <!-- Lights -->
    <include>
      <uri>model://sun</uri>
    </include>

    <!-- Ground  -->
    <include>
      <uri>model://ground_plane</uri>
    </include>

    <!-- Red box - the plugin should change the material to Gazebo/Purple -->
    <model name="red_box">
      <pose>0 0 5 0 0 0</pose>
      <link name="link">
        <collision name="collision">
          <geometry>
            <box><size>1 1 1</size></box>
          </geometry>
        </collision>
        <visual name="visual">
          <plugin name="set_material_visual_plugin" filename="libSetMaterialVisualPlugin.so" />
          <geometry>
            <box><size>1 1 1</size></box>
          </geometry>
         <!-- If the following material is commented out the plugin sets
              the material to Gazebo/Purple, if left the plugin has no effect.
          -->
          <material>
            <script>
              <uri>__default__</uri>
              <name>Gazebo/Red</name>
            </script>
          </material>
        </visual>
      </link>
    </model>    

  </world>
</sdf>

The example is run using:

$ gazebo --world set_material.world --verbose
...
[Msg] SetMaterial("Gazebo/Purple")
[Msg] Name:     red_box::link::visual
[Msg] Material: red_box::link::visual_MATERIAL_Gazebo/Purple

In both cases the console log indicates the material has changed, but the colour on the screen is only updated when the model has no initial material assigned.

System: Gazebo 11 compiled from source on macOS 10.15.4

edit retag flag offensive close merge delete