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 <kimkulling@users.noreply.github.com>
This commit is contained in:
David Campos Rodríguez
2025-01-15 02:03:32 -07:00
committed by GitHub
parent 2f6dcdfd72
commit 1e44036c36
4 changed files with 76 additions and 2 deletions

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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());
}