diff --git a/include/sdf/Mesh.hh b/include/sdf/Mesh.hh
index f19d98818..7cc48c955 100644
--- a/include/sdf/Mesh.hh
+++ b/include/sdf/Mesh.hh
@@ -37,6 +37,47 @@ namespace sdf
   // Forward declarations.
   class ParserConfig;
 
+  /// \brief Mesh optimization method
+  enum class MeshOptimization
+  {
+    /// \brief No mesh optimization
+    NONE,
+    /// \brief Convex hull
+    CONVEX_HULL,
+    /// \brief Convex decomposition
+    CONVEX_DECOMPOSITION
+  };
+
+  /// \brief Convex decomposition
+  class SDFORMAT_VISIBLE ConvexDecomposition
+  {
+    /// \brief Default constructor
+    public: ConvexDecomposition();
+
+    /// \brief Load the contact based on a element pointer. This is *not* the
+    /// usual entry point. Typical usage of the SDF DOM is through the Root
+    /// object.
+    /// \param[in] _sdf The SDF Element pointer
+    /// \return Errors, which is a vector of Error objects. Each Error includes
+    /// an error code and message. An empty vector indicates no error.
+    public: Errors Load(ElementPtr _sdf);
+
+    /// \brief Get a pointer to the SDF element that was used during
+    /// load.
+    /// \return SDF element pointer. The value will be nullptr if Load has
+    /// not been called.
+    public: sdf::ElementPtr Element() const;
+
+    /// \brief Get the maximum number of convex hulls that can be generated.
+    public: unsigned int MaxConvexHulls() const;
+
+    /// \brief Set the maximum number of convex hulls that can be generated.
+    public: void SetMaxConvexHulls(unsigned int _maxConvexHulls);
+
+    /// \brief Private data pointer.
+    GZ_UTILS_IMPL_PTR(dataPtr)
+  };
+
   /// \brief Mesh represents a mesh shape, and is usually accessed through a
   /// Geometry.
   class SDFORMAT_VISIBLE Mesh
@@ -61,6 +102,37 @@ namespace sdf
     /// an error code and message. An empty vector indicates no error.
     public: Errors Load(sdf::ElementPtr _sdf, const ParserConfig &_config);
 
+    /// \brief Get the mesh's optimization method
+    /// \return The mesh optimization method.
+    /// MeshOptimization::NONE if no mesh simplificaton is done.
+    public: MeshOptimization Optimization() const;
+
+    /// \brief Get the mesh's optimization method
+    /// \return The mesh optimization method.
+    /// Empty string if no mesh simplificaton is done.
+    public: std::string OptimizationStr() const;
+
+    /// \brief Set the mesh optimization method.
+    /// \param[in] _optimization The mesh optimization method.
+    public: void SetOptimization(MeshOptimization _optimization);
+
+    /// \brief Set the mesh optimization method.
+    /// \param[in] _optimization The mesh optimization method.
+    /// \return True if the _optimizationStr parameter matched a known
+    /// mesh optimization method. False if the mesh optimization method
+    /// could not be set.
+    public: bool SetOptimization(const std::string &_optimizationStr);
+
+    /// \brief Get the associated ConvexDecomposition object
+    /// \returns Pointer to the associated ConvexDecomposition object,
+    /// nullptr if the Mesh doesn't contain a ConvexDecomposition element.
+    public: const sdf::ConvexDecomposition *ConvexDecomposition() const;
+
+    /// \brief Set the associated ConvexDecomposition object.
+    /// \param[in] _convexDecomposition The ConvexDecomposition object.
+    public: void SetConvexDecomposition(
+        const sdf::ConvexDecomposition &_convexDecomposition);
+
     /// \brief Get the mesh's URI.
     /// \return The URI of the mesh data.
     public: std::string Uri() const;
diff --git a/sdf/1.11/mesh_shape.sdf b/sdf/1.11/mesh_shape.sdf
index 61bce76dd..a59300d46 100644
--- a/sdf/1.11/mesh_shape.sdf
+++ b/sdf/1.11/mesh_shape.sdf
@@ -1,5 +1,19 @@
 <element name="mesh" required="0">
   <description>Mesh shape</description>
+
+  <attribute name="optimization" type="string" default="" required="0">
+    <description>
+      Set whether to optimize the mesh using one of the specified methods. Values include: "convex_hull" - a single convex hull that encapsulates the mesh, "convex_decomposition" - decompose the mesh into multiple convex hull meshes. Default value is an empty string which means no mesh optimization.
+    </description>
+  </attribute>
+
+  <element name="convex_decomposition" required="0">
+    <description>Convex decomposition parameters. Applicable if the mesh optimization attribute is set to convex_decomposition</description>
+    <element name="max_convex_hulls" type="unsigned int" default="16" required="0">
+      <description>Maximum number of convex hulls to decompose into. If the input mesh has multiple submeshes, this limit is applied when decomposing each submesh</description>
+    </element>
+  </element>
+
   <element name="uri" type="string" default="__default__" required="1">
     <description>Mesh uri</description>
   </element>
diff --git a/sdf/1.12/mesh_shape.sdf b/sdf/1.12/mesh_shape.sdf
index 61bce76dd..a59300d46 100644
--- a/sdf/1.12/mesh_shape.sdf
+++ b/sdf/1.12/mesh_shape.sdf
@@ -1,5 +1,19 @@
 <element name="mesh" required="0">
   <description>Mesh shape</description>
+
+  <attribute name="optimization" type="string" default="" required="0">
+    <description>
+      Set whether to optimize the mesh using one of the specified methods. Values include: "convex_hull" - a single convex hull that encapsulates the mesh, "convex_decomposition" - decompose the mesh into multiple convex hull meshes. Default value is an empty string which means no mesh optimization.
+    </description>
+  </attribute>
+
+  <element name="convex_decomposition" required="0">
+    <description>Convex decomposition parameters. Applicable if the mesh optimization attribute is set to convex_decomposition</description>
+    <element name="max_convex_hulls" type="unsigned int" default="16" required="0">
+      <description>Maximum number of convex hulls to decompose into. If the input mesh has multiple submeshes, this limit is applied when decomposing each submesh</description>
+    </element>
+  </element>
+
   <element name="uri" type="string" default="__default__" required="1">
     <description>Mesh uri</description>
   </element>
diff --git a/src/Mesh.cc b/src/Mesh.cc
index 9dfddcf2b..f026e2d63 100644
--- a/src/Mesh.cc
+++ b/src/Mesh.cc
@@ -14,8 +14,10 @@
  * limitations under the License.
  *
 */
+#include <array>
 #include <filesystem>
 #include <optional>
+#include <string_view>
 
 #include <gz/math/Inertial.hh>
 #include "sdf/CustomInertiaCalcProperties.hh"
@@ -27,9 +29,35 @@
 
 using namespace sdf;
 
-// Private data class
+/// Mesh Optimization method strings. These should match the data in
+/// `enum class MeshOptimization` located in Mesh.hh, and the size
+/// template parameter should match the number of elements as well.
+constexpr std::array<const std::string_view, 3> kMeshOptimizationStrs =
+{
+  "",
+  "convex_hull",
+  "convex_decomposition"
+};
+
+// Private data class for ConvexDecomposition
+class sdf::ConvexDecomposition::Implementation
+{
+  /// \brief Maximum number of convex hulls to generate.
+  public: unsigned int maxConvexHulls{16u};
+
+  /// \brief The SDF element pointer used during load.
+  public: sdf::ElementPtr sdf = nullptr;
+};
+
+// Private data class for Mesh
 class sdf::Mesh::Implementation
 {
+  /// \brief Mesh optimization method
+  public: MeshOptimization optimization = MeshOptimization::NONE;
+
+  /// \brief Optional convex decomposition.
+  public: std::optional<sdf::ConvexDecomposition> convexDecomposition;
+
   /// \brief The mesh's URI.
   public: std::string uri = "";
 
@@ -49,6 +77,62 @@ class sdf::Mesh::Implementation
   public: sdf::ElementPtr sdf = nullptr;
 };
 
+/////////////////////////////////////////////////
+ConvexDecomposition::ConvexDecomposition()
+  : dataPtr(gz::utils::MakeImpl<Implementation>())
+{
+}
+
+/////////////////////////////////////////////////
+Errors ConvexDecomposition::Load(ElementPtr _sdf)
+{
+  Errors errors;
+
+  this->dataPtr->sdf = _sdf;
+
+  // Check that sdf is a valid pointer
+  if (!_sdf)
+  {
+    errors.push_back({ErrorCode::ELEMENT_MISSING,
+        "Attempting to load convex decomposition, "
+        "but the provided SDF element is null."});
+    return errors;
+  }
+
+  // We need a convex_decomposition element
+  if (_sdf->GetName() != "convex_decomposition")
+  {
+    errors.push_back({ErrorCode::ELEMENT_INCORRECT_TYPE,
+        "Attempting to load convex decomposition, but the provided SDF "
+        "element is not <convex_decomposition>."});
+    return errors;
+  }
+
+  this->dataPtr->maxConvexHulls = _sdf->Get<unsigned int>(
+      errors, "max_convex_hulls",
+      this->dataPtr->maxConvexHulls).first;
+
+  return errors;
+}
+
+/////////////////////////////////////////////////
+sdf::ElementPtr ConvexDecomposition::Element() const
+{
+  return this->dataPtr->sdf;
+}
+
+/////////////////////////////////////////////////
+unsigned int ConvexDecomposition::MaxConvexHulls() const
+{
+  return this->dataPtr->maxConvexHulls;
+}
+
+/////////////////////////////////////////////////
+void ConvexDecomposition::SetMaxConvexHulls(unsigned int _maxConvexHulls)
+{
+  this->dataPtr->maxConvexHulls = _maxConvexHulls;
+}
+
 /////////////////////////////////////////////////
 Mesh::Mesh()
   : dataPtr(gz::utils::MakeImpl<Implementation>())
@@ -61,6 +145,7 @@ Errors Mesh::Load(ElementPtr _sdf)
   return this->Load(_sdf, ParserConfig::GlobalConfig());
 }
 
+
 /////////////////////////////////////////////////
 Errors Mesh::Load(ElementPtr _sdf, const ParserConfig &_config)
 {
@@ -87,6 +172,20 @@ Errors Mesh::Load(ElementPtr _sdf, const ParserConfig &_config)
     return errors;
   }
 
+  // Optimization
+  if (_sdf->HasAttribute("optimization"))
+  {
+    this->SetOptimization(_sdf->Get<std::string>("optimization", "").first);
+  }
+
+  if (_sdf->HasElement("convex_decomposition"))
+  {
+    this->dataPtr->convexDecomposition.emplace();
+    Errors err = this->dataPtr->convexDecomposition->Load(
+        _sdf->GetElement("convex_decomposition", errors));
+    errors.insert(errors.end(), err.begin(), err.end());
+  }
+
   if (_sdf->HasElement("uri"))
   {
     std::unordered_set<std::string> paths;
@@ -140,6 +239,56 @@ sdf::ElementPtr Mesh::Element() const
   return this->dataPtr->sdf;
 }
 
+//////////////////////////////////////////////////
+MeshOptimization Mesh::Optimization() const
+{
+  return this->dataPtr->optimization;
+}
+
+//////////////////////////////////////////////////
+std::string Mesh::OptimizationStr() const
+{
+  size_t index = static_cast<int>(this->dataPtr->optimization);
+  if (index < kMeshOptimizationStrs.size())
+    return std::string(kMeshOptimizationStrs[index]);
+  return "";
+}
+
+//////////////////////////////////////////////////
+bool Mesh::SetOptimization(const std::string &_optimizationStr)
+{
+  for (size_t i = 0; i < kMeshOptimizationStrs.size(); ++i)
+  {
+    if (_optimizationStr == kMeshOptimizationStrs[i])
+    {
+      this->dataPtr->optimization = static_cast<MeshOptimization>(i);
+      return true;
+    }
+  }
+  return false;
+}
+
+//////////////////////////////////////////////////
+void Mesh::SetOptimization(MeshOptimization _optimization)
+{
+  this->dataPtr->optimization = _optimization;
+}
+
+//////////////////////////////////////////////////
+const sdf::ConvexDecomposition *Mesh::ConvexDecomposition() const
+{
+  if (this->dataPtr->convexDecomposition.has_value())
+    return &this->dataPtr->convexDecomposition.value();
+  return nullptr;
+}
+
+//////////////////////////////////////////////////
+ void Mesh::SetConvexDecomposition(
+    const sdf::ConvexDecomposition &_convexDecomposition)
+{
+  this->dataPtr->convexDecomposition = _convexDecomposition;
+}
+
 //////////////////////////////////////////////////
 std::string Mesh::Uri() const
 {
@@ -244,6 +393,18 @@ sdf::ElementPtr Mesh::ToElement(sdf::Errors &_errors) const
   sdf::ElementPtr elem(new sdf::Element);
   sdf::initFile("mesh_shape.sdf", elem);
 
+  // Optimization
+  elem->GetAttribute("optimization")->Set<std::string>(
+      this->OptimizationStr());
+
+  if (this->dataPtr->convexDecomposition.has_value())
+  {
+    sdf::ElementPtr convexDecomp = elem->GetElement("convex_decomposition",
+        _errors);
+    convexDecomp->GetElement("max_convex_hulls")->Set(
+        this->dataPtr->convexDecomposition->MaxConvexHulls());
+  }
+
   // Uri
   sdf::ElementPtr uriElem = elem->GetElement("uri", _errors);
   uriElem->Set(_errors, this->Uri());
diff --git a/src/Mesh_TEST.cc b/src/Mesh_TEST.cc
index 51c1751f4..29ef70d85 100644
--- a/src/Mesh_TEST.cc
+++ b/src/Mesh_TEST.cc
@@ -34,6 +34,9 @@ TEST(DOMMesh, Construction)
   sdf::Mesh mesh;
   EXPECT_EQ(nullptr, mesh.Element());
 
+  EXPECT_EQ(std::string(), mesh.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::NONE, mesh.Optimization());
+  EXPECT_EQ(nullptr, mesh.ConvexDecomposition());
   EXPECT_EQ(std::string(), mesh.FilePath());
   EXPECT_EQ(std::string(), mesh.Uri());
   EXPECT_EQ(std::string(), mesh.Submesh());
@@ -45,24 +48,37 @@ TEST(DOMMesh, Construction)
 TEST(DOMMesh, MoveConstructor)
 {
   sdf::Mesh mesh;
+  EXPECT_TRUE(mesh.SetOptimization("convex_decomposition"));
   mesh.SetUri("banana");
   mesh.SetSubmesh("watermelon");
   mesh.SetCenterSubmesh(true);
   mesh.SetScale({0.5, 0.6, 0.7});
   mesh.SetFilePath("/pear");
 
+  sdf::ConvexDecomposition convexDecomp;
+  EXPECT_EQ(nullptr, convexDecomp.Element());
+  convexDecomp.SetMaxConvexHulls(10u);
+  mesh.SetConvexDecomposition(convexDecomp);
+
   sdf::Mesh mesh2(std::move(mesh));
+  EXPECT_EQ("convex_decomposition", mesh2.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_DECOMPOSITION, mesh2.Optimization());
   EXPECT_EQ("banana", mesh2.Uri());
   EXPECT_EQ("watermelon", mesh2.Submesh());
   EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale());
   EXPECT_TRUE(mesh2.CenterSubmesh());
   EXPECT_EQ("/pear", mesh2.FilePath());
+
+  auto convexDecomp2 = mesh2.ConvexDecomposition();
+  ASSERT_NE(nullptr, convexDecomp2);
+  EXPECT_EQ(10u, convexDecomp2->MaxConvexHulls());
 }
 
 /////////////////////////////////////////////////
 TEST(DOMMesh, CopyConstructor)
 {
   sdf::Mesh mesh;
+  EXPECT_TRUE(mesh.SetOptimization("convex_hull"));
   mesh.SetUri("banana");
   mesh.SetSubmesh("watermelon");
   mesh.SetCenterSubmesh(true);
@@ -70,6 +86,9 @@ TEST(DOMMesh, CopyConstructor)
   mesh.SetFilePath("/pear");
 
   sdf::Mesh mesh2(mesh);
+  EXPECT_EQ("convex_hull", mesh2.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_HULL, mesh2.Optimization());
+  EXPECT_EQ(nullptr, mesh2.ConvexDecomposition());
   EXPECT_EQ("banana", mesh2.Uri());
   EXPECT_EQ("watermelon", mesh2.Submesh());
   EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale());
@@ -81,6 +100,7 @@ TEST(DOMMesh, CopyConstructor)
 TEST(DOMMesh, CopyAssignmentOperator)
 {
   sdf::Mesh mesh;
+  EXPECT_TRUE(mesh.SetOptimization("convex_hull"));
   mesh.SetUri("banana");
   mesh.SetSubmesh("watermelon");
   mesh.SetCenterSubmesh(true);
@@ -89,6 +109,9 @@ TEST(DOMMesh, CopyAssignmentOperator)
 
   sdf::Mesh mesh2;
   mesh2 = mesh;
+  EXPECT_EQ("convex_hull", mesh2.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_HULL, mesh2.Optimization());
+  EXPECT_EQ(nullptr, mesh2.ConvexDecomposition());
   EXPECT_EQ("banana", mesh2.Uri());
   EXPECT_EQ("watermelon", mesh2.Submesh());
   EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale());
@@ -100,6 +123,7 @@ TEST(DOMMesh, CopyAssignmentOperator)
 TEST(DOMMesh, MoveAssignmentOperator)
 {
   sdf::Mesh mesh;
+  EXPECT_TRUE(mesh.SetOptimization("convex_hull"));
   mesh.SetUri("banana");
   mesh.SetSubmesh("watermelon");
   mesh.SetCenterSubmesh(true);
@@ -108,6 +132,9 @@ TEST(DOMMesh, MoveAssignmentOperator)
 
   sdf::Mesh mesh2;
   mesh2 = std::move(mesh);
+  EXPECT_EQ("convex_hull", mesh2.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_HULL, mesh2.Optimization());
+  EXPECT_EQ(nullptr, mesh2.ConvexDecomposition());
   EXPECT_EQ("banana", mesh2.Uri());
   EXPECT_EQ("watermelon", mesh2.Submesh());
   EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale());
@@ -140,6 +167,29 @@ TEST(DOMMesh, Set)
   sdf::Mesh mesh;
   EXPECT_EQ(nullptr, mesh.Element());
 
+  EXPECT_EQ(std::string(), mesh.OptimizationStr());
+  EXPECT_TRUE(mesh.SetOptimization("convex_hull"));
+  EXPECT_EQ("convex_hull", mesh.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_HULL, mesh.Optimization());
+  mesh.SetOptimization(sdf::MeshOptimization::CONVEX_DECOMPOSITION);
+  EXPECT_EQ("convex_decomposition", mesh.OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_DECOMPOSITION,
+            mesh.Optimization());
+  // check invalid inputs
+  EXPECT_FALSE(mesh.SetOptimization("invalid"));
+  {
+    auto invalidMeshOpt = static_cast<sdf::MeshOptimization>(99);
+    mesh.SetOptimization(invalidMeshOpt);
+    EXPECT_EQ(invalidMeshOpt, mesh.Optimization());
+    EXPECT_EQ("", mesh.OptimizationStr());
+  }
+
+  sdf::ConvexDecomposition convexDecomp;
+  convexDecomp.SetMaxConvexHulls(10u);
+  mesh.SetConvexDecomposition(convexDecomp);
+  ASSERT_NE(nullptr, mesh.ConvexDecomposition());
+  EXPECT_EQ(10u, mesh.ConvexDecomposition()->MaxConvexHulls());
+
   EXPECT_EQ(std::string(), mesh.Uri());
   mesh.SetUri("http://myuri.com");
   EXPECT_EQ("http://myuri.com", mesh.Uri());
@@ -165,6 +215,7 @@ TEST(DOMMesh, Set)
 TEST(DOMMesh, Load)
 {
   sdf::Mesh mesh;
+  sdf::ConvexDecomposition convexDecomp;
   sdf::Errors errors;
 
   // Null element name
@@ -173,6 +224,11 @@ TEST(DOMMesh, Load)
   EXPECT_EQ(sdf::ErrorCode::ELEMENT_MISSING, errors[0].Code());
   EXPECT_EQ(nullptr, mesh.Element());
 
+  errors = convexDecomp.Load(nullptr);
+  ASSERT_EQ(1u, errors.size());
+  EXPECT_EQ(sdf::ErrorCode::ELEMENT_MISSING, errors[0].Code());
+  EXPECT_EQ(nullptr, convexDecomp.Element());
+
   // Bad element name
   sdf::ElementPtr sdf(new sdf::Element());
   sdf->SetName("bad");
@@ -181,6 +237,11 @@ TEST(DOMMesh, Load)
   EXPECT_EQ(sdf::ErrorCode::ELEMENT_INCORRECT_TYPE, errors[0].Code());
   EXPECT_NE(nullptr, mesh.Element());
 
+  errors = convexDecomp.Load(sdf);
+  ASSERT_EQ(1u, errors.size());
+  EXPECT_EQ(sdf::ErrorCode::ELEMENT_INCORRECT_TYPE, errors[0].Code());
+  EXPECT_NE(nullptr, convexDecomp.Element());
+
   // Missing <uri> element
   sdf->SetName("mesh");
   errors = mesh.Load(sdf);
@@ -296,21 +357,30 @@ TEST(DOMMesh, ToElement)
 {
   sdf::Mesh mesh;
 
+  EXPECT_TRUE(mesh.SetOptimization("convex_decomposition"));
   mesh.SetUri("mesh-uri");
   mesh.SetScale(gz::math::Vector3d(1, 2, 3));
   mesh.SetSubmesh("submesh");
   mesh.SetCenterSubmesh(false);
 
+  sdf::ConvexDecomposition convexDecomp;
+  convexDecomp.SetMaxConvexHulls(10u);
+  mesh.SetConvexDecomposition(convexDecomp);
+
   sdf::ElementPtr elem = mesh.ToElement();
   ASSERT_NE(nullptr, elem);
 
   sdf::Mesh mesh2;
   mesh2.Load(elem);
 
+  EXPECT_EQ(mesh.OptimizationStr(), mesh2.OptimizationStr());
+  EXPECT_EQ(mesh.Optimization(), mesh2.Optimization());
   EXPECT_EQ(mesh.Uri(), mesh2.Uri());
   EXPECT_EQ(mesh.Scale(), mesh2.Scale());
   EXPECT_EQ(mesh.Submesh(), mesh2.Submesh());
   EXPECT_EQ(mesh.CenterSubmesh(), mesh2.CenterSubmesh());
+  ASSERT_NE(nullptr, mesh2.ConvexDecomposition());
+  EXPECT_EQ(10u, mesh2.ConvexDecomposition()->MaxConvexHulls());
 }
 
 /////////////////////////////////////////////////
@@ -332,6 +402,7 @@ TEST(DOMMesh, ToElementErrorOutput)
   sdf::Mesh mesh;
   sdf::Errors errors;
 
+  EXPECT_TRUE(mesh.SetOptimization("convex_hull"));
   mesh.SetUri("mesh-uri");
   mesh.SetScale(gz::math::Vector3d(1, 2, 3));
   mesh.SetSubmesh("submesh");
@@ -345,6 +416,9 @@ TEST(DOMMesh, ToElementErrorOutput)
   errors = mesh2.Load(elem);
   EXPECT_TRUE(errors.empty());
 
+  EXPECT_EQ(mesh.OptimizationStr(), mesh2.OptimizationStr());
+  EXPECT_EQ(mesh.Optimization(), mesh2.Optimization());
+  EXPECT_EQ(nullptr, mesh2.ConvexDecomposition());
   EXPECT_EQ(mesh.Uri(), mesh2.Uri());
   EXPECT_EQ(mesh.Scale(), mesh2.Scale());
   EXPECT_EQ(mesh.Submesh(), mesh2.Submesh());
diff --git a/test/integration/geometry_dom.cc b/test/integration/geometry_dom.cc
index 07d50d570..297d1f0af 100644
--- a/test/integration/geometry_dom.cc
+++ b/test/integration/geometry_dom.cc
@@ -179,6 +179,12 @@ TEST(DOMGeometry, Shapes)
   EXPECT_EQ(sdf::GeometryType::MESH, meshCol->Geom()->Type());
   const sdf::Mesh *meshColGeom = meshCol->Geom()->MeshShape();
   ASSERT_NE(nullptr, meshColGeom);
+  EXPECT_EQ("convex_decomposition", meshColGeom->OptimizationStr());
+  EXPECT_EQ(sdf::MeshOptimization::CONVEX_DECOMPOSITION,
+            meshColGeom->Optimization());
+  ASSERT_NE(nullptr, meshColGeom->ConvexDecomposition());
+  EXPECT_EQ(4u, meshColGeom->ConvexDecomposition()->MaxConvexHulls());
+
   EXPECT_EQ("https://fuel.gazebosim.org/1.0/an_org/models/a_model/mesh/"
       "mesh.dae", meshColGeom->Uri());
   EXPECT_TRUE(gz::math::Vector3d(0.1, 0.2, 0.3) ==
diff --git a/test/sdf/shapes.sdf b/test/sdf/shapes.sdf
index 1f5f4fa27..f411afa37 100644
--- a/test/sdf/shapes.sdf
+++ b/test/sdf/shapes.sdf
@@ -120,7 +120,10 @@
 
       <collision name="mesh_col">
         <geometry>
-          <mesh>
+          <mesh optimization="convex_decomposition">
+            <convex_decomposition>
+              <max_convex_hulls>4</max_convex_hulls>
+            </convex_decomposition>
             <uri>https://fuel.gazebosim.org/1.0/an_org/models/a_model/mesh/mesh.dae</uri>
             <submesh>
               <name>my_submesh</name>