From 6214fbfbbe6b421088860a6a503fb5dbed6fbe17 Mon Sep 17 00:00:00 2001 From: Vitaly Ovchinnikov Date: Sun, 13 Dec 2015 22:54:50 +1300 Subject: [PATCH 1/3] this patch fixes multiple objects generation in OBJ reader if faces are prepended with 'usemtl' line --- code/ObjFileParser.cpp | 54 ++++++++++++++++++--------------- test/models/OBJ/cube_usemtl.mtl | 11 +++++++ test/models/OBJ/cube_usemtl.obj | 44 +++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 24 deletions(-) create mode 100644 test/models/OBJ/cube_usemtl.mtl create mode 100644 test/models/OBJ/cube_usemtl.obj diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 83262b5d4..4d8b20c46 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -457,15 +457,6 @@ void ObjFileParser::getFace(aiPrimitiveType type) // Get values for a new material description void ObjFileParser::getMaterialDesc() { - // Each material request a new object. - // Sometimes the object is already created (see 'o' tag by example), but it is not initialized ! - // So, we create a new object only if the current on is already initialized ! - if (m_pModel->m_pCurrent != NULL && - ( m_pModel->m_pCurrent->m_Meshes.size() > 1 || - (m_pModel->m_pCurrent->m_Meshes.size() == 1 && m_pModel->m_Meshes[m_pModel->m_pCurrent->m_Meshes[0]]->m_Faces.size() != 0) ) - ) - m_pModel->m_pCurrent = NULL; - // Get next data for material data m_DataIt = getNextToken(m_DataIt, m_DataItEnd); if (m_DataIt == m_DataItEnd) { @@ -477,25 +468,40 @@ void ObjFileParser::getMaterialDesc() ++m_DataIt; } + // In some cases we should ignore this 'usemtl' command, this variable helps us to do so + bool skip = false; + // Get name std::string strName(pStart, &(*m_DataIt)); - if ( strName.empty()) - return; + if (strName.empty()) + skip = true; - // Search for material - std::map::iterator it = m_pModel->m_MaterialMap.find( strName ); - if ( it == m_pModel->m_MaterialMap.end() ) { - // Not found, use default material - m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; - DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); - } else { - // Found, using detected material - m_pModel->m_pCurrentMaterial = (*it).second; - if ( needsNewMesh( strName )) + // If the current mesh has the same material, we simply ignore that 'usemtl' command + // There is no need to create another object or even mesh here + if (m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString(strName)) + skip = true; + + if (!skip) + { + // Search for material + std::map::iterator it = m_pModel->m_MaterialMap.find(strName); + if (it == m_pModel->m_MaterialMap.end()) { - createMesh( strName ); + // Not found, use default material + m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; + DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); + strName = m_pModel->m_pDefaultMaterial->MaterialName.C_Str(); } - m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName ); + else + { + // Found, using detected material + m_pModel->m_pCurrentMaterial = (*it).second; + } + + if (needsNewMesh(strName)) + createMesh(); + + m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName); } // Skip rest of line @@ -759,7 +765,7 @@ bool ObjFileParser::needsNewMesh( const std::string &rMaterialName ) bool newMat = false; int matIdx = getMaterialIndex( rMaterialName ); int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex; - if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) || curMatIdx != matIdx ) + if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx ) { // New material -> only one material per mesh, so we need to create a new // material diff --git a/test/models/OBJ/cube_usemtl.mtl b/test/models/OBJ/cube_usemtl.mtl new file mode 100644 index 000000000..040e0adad --- /dev/null +++ b/test/models/OBJ/cube_usemtl.mtl @@ -0,0 +1,11 @@ +newmtl mtl +Ka 1.000 1.000 1.000 +Kd 1.000 1.000 1.000 +Ns 200.000 +Ks 0.050 0.050 0.050 + +newmtl mtl2 +Ka 1.000 1.000 1.000 +Kd 1.000 1.000 1.000 +Ns 16.000 +Ks 0.375 0.375 0.375 diff --git a/test/models/OBJ/cube_usemtl.obj b/test/models/OBJ/cube_usemtl.obj new file mode 100644 index 000000000..d840a28fc --- /dev/null +++ b/test/models/OBJ/cube_usemtl.obj @@ -0,0 +1,44 @@ +mtllib cube_usemtl.mtl + +g cube + +v 0.0 0.0 0.0 +v 0.0 0.0 1.0 +v 0.0 1.0 0.0 +v 0.0 1.0 1.0 +v 1.0 0.0 0.0 +v 1.0 0.0 1.0 +v 1.0 1.0 0.0 +v 1.0 1.0 1.0 + +vn 0.0 0.0 1.0 +vn 0.0 0.0 -1.0 +vn 0.0 1.0 0.0 +vn 0.0 -1.0 0.0 +vn 1.0 0.0 0.0 +vn -1.0 0.0 0.0 + +usemtl mtl3 +f 1//2 7//2 5//2 +usemtl mtl3 +f 1//2 3//2 7//2 +usemtl mtl +f 1//6 4//6 3//6 +usemtl mtl +f 1//6 2//6 4//6 +usemtl mtl +f 3//3 8//3 7//3 +usemtl mtl2 +f 3//3 4//3 8//3 +usemtl mtl2 +f 5//5 7//5 8//5 +usemtl mtl2 +f 5//5 8//5 6//5 +usemtl mtl2 +f 1//4 5//4 6//4 +usemtl mtl +f 1//4 6//4 2//4 +usemtl mtl +f 2//1 6//1 8//1 +usemtl mtl +f 2//1 8//1 4//1 From c9ef6132a89fa00bb9123391be61e577baeb7691 Mon Sep 17 00:00:00 2001 From: Vitaly Ovchinnikov Date: Sun, 13 Dec 2015 23:10:31 +1300 Subject: [PATCH 2/3] a small fix --- code/ObjFileParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 4d8b20c46..cc898f2a0 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -499,7 +499,7 @@ void ObjFileParser::getMaterialDesc() } if (needsNewMesh(strName)) - createMesh(); + createMesh(strName); m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName); } From af40c99a6a58c950a025ec9f421831a69cda2660 Mon Sep 17 00:00:00 2001 From: Vitaly Ovchinnikov Date: Mon, 14 Dec 2015 08:32:09 +1300 Subject: [PATCH 3/3] trimming spaces around material names --- code/ObjFileMtlImporter.cpp | 2 ++ code/ObjFileParser.cpp | 1 + code/ObjTools.h | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/code/ObjFileMtlImporter.cpp b/code/ObjFileMtlImporter.cpp index 5b5160a44..6653b30ce 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/ObjFileMtlImporter.cpp @@ -284,6 +284,8 @@ void ObjFileMtlImporter::createMaterial() } } + name = trim_whitespaces(name); + std::map::iterator it = m_pModel->m_MaterialMap.find( name ); if ( m_pModel->m_MaterialMap.end() == it) { // New Material created diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index cc898f2a0..5428bdad2 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -473,6 +473,7 @@ void ObjFileParser::getMaterialDesc() // Get name std::string strName(pStart, &(*m_DataIt)); + strName = trim_whitespaces(strName); if (strName.empty()) skip = true; diff --git a/code/ObjTools.h b/code/ObjTools.h index b5ed12192..04e2b042d 100644 --- a/code/ObjTools.h +++ b/code/ObjTools.h @@ -238,6 +238,14 @@ unsigned int tokenize( const string_type& str, std::vector& tokens, return static_cast( tokens.size() ); } +template +string_type trim_whitespaces(string_type str) +{ + while (!str.empty() && IsSpace(str[0])) str.erase(0); + while (!str.empty() && IsSpace(str[str.length() - 1])) str.erase(str.length() - 1); + return str; +} + } // Namespace Assimp #endif // OBJ_TOOLS_H_INC