Bladeren bron

Prefix MTL textures with the MTL directory path (#5928)

* Prefix MTL textures with the MTL directory path.

Path to textures defined in MTL files are relative to the MTL
file rather than to the OBJ, so we need to prefix them with the
MTL file directory path.

* Adding test issue 2355

* Trying to fix for Windows when file has Linux path

---------

Co-authored-by: Kim Kulling <[email protected]>
David Campos Rodríguez 6 maanden geleden
bovenliggende
commit
1e44036c36

+ 18 - 2
code/AssetLib/Obj/ObjFileMtlImporter.cpp

@@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjFileMtlImporter.h"
 #include "ObjFileData.h"
 #include "ObjTools.h"
+#include <assimp/DefaultIOSystem.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/fast_atof.h>
 #include <assimp/material.h>
@@ -89,8 +90,9 @@ static constexpr char TypeOption[] = "-type";
 // -------------------------------------------------------------------
 //  Constructor
 ObjFileMtlImporter::ObjFileMtlImporter(std::vector<char> &buffer,
-        const std::string &,
+        const std::string &strAbsPath,
         ObjFile::Model *pModel) :
+        m_strAbsPath(strAbsPath),
         m_DataIt(buffer.begin()),
         m_DataItEnd(buffer.end()),
         m_pModel(pModel),
@@ -103,6 +105,20 @@ ObjFileMtlImporter::ObjFileMtlImporter(std::vector<char> &buffer,
         m_pModel->mDefaultMaterial = new ObjFile::Material;
         m_pModel->mDefaultMaterial->MaterialName.Set("default");
     }
+    
+    // Try with OS folder separator first
+    char folderSeparator = DefaultIOSystem().getOsSeparator();
+    std::size_t found = m_strAbsPath.find_last_of(folderSeparator);
+    if (found == std::string::npos) {
+        // Not found, try alternative folder separator
+        folderSeparator = (folderSeparator == '/' ? '\\' : '/');
+        found = m_strAbsPath.find_last_of(folderSeparator);
+    }
+    if (found != std::string::npos) {
+        m_strAbsPath = m_strAbsPath.substr(0, found + 1);
+    } else {
+        m_strAbsPath = "";
+    }
     load();
 }
 
@@ -442,7 +458,7 @@ void ObjFileMtlImporter::getTexture() {
     std::string texture;
     m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, texture);
     if (nullptr != out) {
-        out->Set(texture);
+        out->Set(m_strAbsPath + texture);
     }
 }
 

+ 13 - 0
test/models/OBJ/folder/mtl_different_folder.mtl

@@ -0,0 +1,13 @@
+
+# Example for github issue #2355: {OBJ} mtllib with a path == can't find texture file
+
+newmtl Whatever
+Ka 0 0 0
+Kd 0.141176 0.184314 0.411765
+Ks 0 0 0
+Ni 1
+Ns 400
+Tf 1 1 1
+d 1
+map_Kd image.jpg
+

+ 31 - 0
test/models/OBJ/mtl_different_folder.obj

@@ -0,0 +1,31 @@
+#	                Vertices: 8
+#	                  Points: 0
+#	                   Lines: 0
+#	                   Faces: 6
+#	               Materials: 1
+
+o 1
+mtllib folder/mtl_different_folder.mtl
+
+# Vertex list
+
+v -0.5 -0.5 0.5
+v -0.5 -0.5 -0.5
+v -0.5 0.5 -0.5
+v -0.5 0.5 0.5
+v 0.5 -0.5 0.5
+v 0.5 -0.5 -0.5
+v 0.5 0.5 -0.5
+v 0.5 0.5 0.5
+
+# Point/Line/Face list
+
+usemtl Whatever
+f 4 3 2 1
+f 2 6 5 1
+f 3 7 6 2
+f 8 7 3 4
+f 5 8 4 1
+f 6 7 8 5
+
+# End of file

+ 14 - 0
test/unit/utObjImportExport.cpp

@@ -525,3 +525,17 @@ TEST_F(utObjImportExport, import_with_line_continuations) {
     EXPECT_NEAR(vertices[2].y, 0.5f, threshold);
     EXPECT_NEAR(vertices[2].z, -0.5f, threshold);
 }
+
+TEST_F(utObjImportExport, issue2355_mtl_texture_prefix) {
+    ::Assimp::Importer importer;
+    const aiScene *const scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/mtl_different_folder.obj", aiProcess_ValidateDataStructure);
+    EXPECT_NE(nullptr, scene);
+
+    EXPECT_EQ(scene->mNumMaterials, 2U);
+    const aiMaterial *const material = scene->mMaterials[1];
+
+    aiString texturePath;
+    material->GetTexture(aiTextureType_DIFFUSE, 0, &texturePath);
+    // The MTL file is in `folder`, the image path should have been prefixed with the folder
+    EXPECT_STREQ("folder/image.jpg", texturePath.C_Str());
+}