diff --git a/modules/ovis/include/opencv2/ovis.hpp b/modules/ovis/include/opencv2/ovis.hpp
index 0c605999634..d2a5437838b 100644
--- a/modules/ovis/include/opencv2/ovis.hpp
+++ b/modules/ovis/include/opencv2/ovis.hpp
@@ -414,6 +414,23 @@ CV_EXPORTS_W void createGridMesh(const String& name, const Size2f& size, const S
  */
 CV_EXPORTS_W void createTriangleMesh(const String& name, InputArray vertices, InputArray normals = noArray(), InputArray indices = noArray());
 
+/**
+ * Loads a mesh from a known resource location.
+ *
+ * The file format is determined by the file extension. Supported formats are Ogre @c .mesh and everything that Assimp can load.
+ * @param meshname Name of the mesh file
+ * @param vertices vertex coordinates, each value contains 3 floats
+ * @param indices per-face list of vertices, each value contains 3 ints
+ * @param normals per-vertex normals, each value contains 3 floats
+ * @param colors per-vertex colors, each value contains 4 uchars
+ * @param texCoords per-vertex texture coordinates, each value contains 2 floats
+ *
+ * @see addResourceLocation()
+ */
+CV_EXPORTS_W void loadMesh(const String& meshname, OutputArray vertices, OutputArray indices,
+                           OutputArray normals = noArray(), OutputArray colors = noArray(),
+                           OutputArray texCoords = noArray());
+
 /// @deprecated use setMaterialProperty
 CV_EXPORTS_W void updateTexture(const String& name, InputArray image);
 //! @}
diff --git a/modules/ovis/src/ovis.cpp b/modules/ovis/src/ovis.cpp
index 38dfcbc2ee0..a0286aca524 100644
--- a/modules/ovis/src/ovis.cpp
+++ b/modules/ovis/src/ovis.cpp
@@ -31,7 +31,7 @@ static Vector2 toOGRE_SS = Vector2(1, -1);
 
 WindowScene::~WindowScene() {}
 
-void _createTexture(const String& name, Mat image)
+void _createTexture(const String& name, Mat image, int mipmaps)
 {
     PixelFormat format;
     switch(image.type())
@@ -62,7 +62,7 @@ void _createTexture(const String& name, Mat image)
     if(!tex)
     {
         tex = texMgr.createManual(name, RESOURCEGROUP_NAME, TEX_TYPE_2D, image.cols, image.rows,
-                                  MIP_DEFAULT, format);
+                                  mipmaps, format);
     }
 
     PixelBox box(image.cols, image.rows, 1, format, image.ptr());
@@ -441,7 +441,7 @@ class WindowSceneImpl : public WindowScene
 
         String name = sceneMgr->getName() + "_Background";
 
-        _createTexture(name, image.getMat());
+        _createTexture(name, image.getMat(), 0);
 
         // ensure bgplane is visible
         bgplane->setVisible(true);
@@ -808,7 +808,7 @@ class WindowSceneImpl : public WindowScene
         String name = "_" + sceneMgr->getName() + "_DefaultBackground";
 
         Mat_<Vec3b> img = (Mat_<Vec3b>(2, 1) << Vec3b(2, 1, 1), Vec3b(240, 120, 120));
-        _createTexture(name, img);
+        _createTexture(name, img, 0);
 
         MaterialPtr mat = MaterialManager::getSingleton().create(name, RESOURCEGROUP_NAME);
         Pass* rpass = mat->getTechniques()[0]->getPasses()[0];
@@ -1155,5 +1155,77 @@ void updateTexture(const String& name, InputArray image)
     CV_Assert(tex);
     _createTexture(name, image.getMat());
 }
+
+void loadMesh(const String& meshname, OutputArray vertices, OutputArray indices, OutputArray normals, OutputArray colors, OutputArray texCoords)
+{
+    CV_Assert(_app);
+
+    auto mesh = MeshManager::getSingleton().load(meshname, RESOURCEGROUP_NAME);
+    auto smeshes = mesh->getSubMeshes();
+    CV_Assert(smeshes.size() == 1);
+
+    auto smesh = smeshes.front();
+
+    CV_Assert(smesh->operationType == RenderOperation::OT_TRIANGLE_LIST);
+
+    if (auto ibuf = smesh->indexData->indexBuffer)
+    {
+        auto idtype = ibuf->getType() == HardwareIndexBuffer::IT_16BIT ? CV_16S : CV_32S;
+        auto imat = Mat(smesh->indexData->indexCount, 3, idtype);
+        ibuf->readData(0, ibuf->getSizeInBytes(), imat.ptr());
+        imat.copyTo(indices);
+    }
+
+    auto vertexData = smesh->useSharedVertices ? mesh->sharedVertexData : smesh->vertexData;
+    DefaultHardwareBufferManagerBase swhbm;
+
+    // download all buffers to CPU for reorganization
+    auto tmpVertexData = vertexData->clone(true, &swhbm);
+    auto tgtDecl = swhbm.createVertexDeclaration();
+    tgtDecl->addElement(0, 0, VET_FLOAT3, VES_POSITION); // separate position buffer
+
+    bool has_normals = vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
+    bool has_texcoords = vertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES);
+    bool has_colors = vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE);
+    if (has_normals)
+        tgtDecl->addElement(1, 0, VET_FLOAT3, VES_NORMAL); // separate normal buffer
+    if (has_texcoords)
+        tgtDecl->addElement(2, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); // separate texcoord buffer
+    if (has_colors)
+        tgtDecl->addElement(3, 0, VET_UBYTE4_NORM, VES_DIFFUSE); // separate color buffer
+
+    tmpVertexData->reorganiseBuffers(tgtDecl);
+
+    // copy data
+    auto vertmat = Mat(vertexData->vertexCount, 3, CV_32F);
+    auto posbuf = tmpVertexData->vertexBufferBinding->getBuffer(0);
+    posbuf->readData(0, posbuf->getSizeInBytes(), vertmat.ptr());
+    vertmat.copyTo(vertices);
+
+    if(has_normals && normals.needed())
+    {
+        auto normmat = Mat(vertexData->vertexCount, 3, CV_32F);
+        auto nbuf = tmpVertexData->vertexBufferBinding->getBuffer(1);
+        nbuf->readData(0, nbuf->getSizeInBytes(), normmat.ptr());
+        normmat.copyTo(normals);
+    }
+
+    if(has_texcoords && texCoords.needed())
+    {
+        auto texmat = Mat(vertexData->vertexCount, 2, CV_32F);
+        auto tbuf = tmpVertexData->vertexBufferBinding->getBuffer(2);
+        tbuf->readData(0, tbuf->getSizeInBytes(), texmat.ptr());
+        texmat.copyTo(texCoords);
+    }
+
+    if(has_colors && colors.needed())
+    {
+        auto colmat = Mat(vertexData->vertexCount, 4, CV_8U);
+        auto cbuf = tmpVertexData->vertexBufferBinding->getBuffer(3);
+        cbuf->readData(0, cbuf->getSizeInBytes(), colmat.ptr());
+        colmat.copyTo(colors);
+    }
+}
+
 }
 }
diff --git a/modules/ovis/src/precomp.hpp b/modules/ovis/src/precomp.hpp
index 3111ee60dab..ff4be085b4e 100644
--- a/modules/ovis/src/precomp.hpp
+++ b/modules/ovis/src/precomp.hpp
@@ -18,7 +18,7 @@ struct Application;
 extern Ptr<Application> _app;
 
 extern const char* RESOURCEGROUP_NAME;
-void _createTexture(const String& name, Mat image);
+void _createTexture(const String& name, Mat image, int mipmaps = Ogre::MIP_DEFAULT);
 }
 }