From 0860254a2bf343f81442b7ac309c93804b7b50d8 Mon Sep 17 00:00:00 2001 From: gongwei Date: Fri, 29 Nov 2013 10:47:30 +0800 Subject: [PATCH] Fix Obj texture parsing error: where obj texture map statement contains texture option, it will fail to parse the correct image url, as a result, the texture won't be shown. Besides, we also add clamp texture mode for obj --- code/ObjFileData.h | 17 +++++++ code/ObjFileImporter.cpp | 66 ++++++++++++++++++++++++++- code/ObjFileMtlImporter.cpp | 91 +++++++++++++++++++++++++++++++++++++ code/ObjFileMtlImporter.h | 2 + 4 files changed, 175 insertions(+), 1 deletion(-) diff --git a/code/ObjFileData.h b/code/ObjFileData.h index 7b30efe2e..7b2b6cf12 100755 --- a/code/ObjFileData.h +++ b/code/ObjFileData.h @@ -161,6 +161,19 @@ struct Material aiString textureSpecularity; aiString textureOpacity; aiString textureDisp; + enum TextureType + { + TextureDiffuseType = 0, + TextureSpecularType, + TextureAmbientType, + TextureBumpType, + TextureNormalType, + TextureSpecularityType, + TextureOpacityType, + TextureDispType, + TextureTypeCount + }; + bool clamp[TextureTypeCount]; //! Ambient color aiColor3D ambient; @@ -186,6 +199,10 @@ struct Material , ior (1.f) { // empty + for (size_t i = 0; i < TextureTypeCount; ++i) + { + clamp[i] = false; + } } // Destructor diff --git a/code/ObjFileImporter.cpp b/code/ObjFileImporter.cpp index 14c8e8aff..2e07cf1ec 100644 --- a/code/ObjFileImporter.cpp +++ b/code/ObjFileImporter.cpp @@ -548,29 +548,93 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI ); // Adding textures - if ( 0 != pCurrentMaterial->texture.length ) + if ( 0 != pCurrentMaterial->texture.length ) + { mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); + mat->AddProperty(&bClamp, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); + } + } if ( 0 != pCurrentMaterial->textureAmbient.length ) + { mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_AMBIENT(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_AMBIENT(0)); + } + } if ( 0 != pCurrentMaterial->textureSpecular.length ) + { mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_SPECULAR(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_SPECULAR(0)); + } + } if ( 0 != pCurrentMaterial->textureBump.length ) + { mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_HEIGHT(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_HEIGHT(0)); + } + } if ( 0 != pCurrentMaterial->textureNormal.length ) + { mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0)); + } + } if ( 0 != pCurrentMaterial->textureDisp.length ) + { mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) ); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_DISPLACEMENT(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_DISPLACEMENT(0)); + } + } if ( 0 != pCurrentMaterial->textureOpacity.length ) + { mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_OPACITY(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_OPACITY(0)); + } + } if ( 0 != pCurrentMaterial->textureSpecularity.length ) + { mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0)); + if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType]) + { + int bClamp = 1; + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_U_SHININESS(0)); + mat->AddProperty(&bClamp,1, AI_MATKEY_MAPPINGMODE_V_SHININESS(0)); + } + } // Store material property info in material array in scene pScene->mMaterials[ pScene->mNumMaterials ] = mat; diff --git a/code/ObjFileMtlImporter.cpp b/code/ObjFileMtlImporter.cpp index c6816577d..c9969f451 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/ObjFileMtlImporter.cpp @@ -263,47 +263,138 @@ void ObjFileMtlImporter::createMaterial() // Gets a texture name from data. void ObjFileMtlImporter::getTexture() { aiString *out( NULL ); + int clampIndex = -1; const char *pPtr( &(*m_DataIt) ); if ( !ASSIMP_strincmp( pPtr, DiffuseTexture.c_str(), DiffuseTexture.size() ) ) { // Diffuse texture out = & m_pModel->m_pCurrentMaterial->texture; + clampIndex = ObjFile::Material::TextureDiffuseType; } else if ( !ASSIMP_strincmp( pPtr,AmbientTexture.c_str(),AmbientTexture.size() ) ) { // Ambient texture out = & m_pModel->m_pCurrentMaterial->textureAmbient; + clampIndex = ObjFile::Material::TextureAmbientType; } else if (!ASSIMP_strincmp( pPtr, SpecularTexture.c_str(), SpecularTexture.size())) { // Specular texture out = & m_pModel->m_pCurrentMaterial->textureSpecular; + clampIndex = ObjFile::Material::TextureSpecularType; } else if ( !ASSIMP_strincmp( pPtr, OpacityTexture.c_str(), OpacityTexture.size() ) ) { // Opacity texture out = & m_pModel->m_pCurrentMaterial->textureOpacity; + clampIndex = ObjFile::Material::TextureOpacityType; } else if (!ASSIMP_strincmp( pPtr,"map_ka",6)) { // Ambient texture out = & m_pModel->m_pCurrentMaterial->textureAmbient; + clampIndex = ObjFile::Material::TextureAmbientType; } else if ( !ASSIMP_strincmp( pPtr, BumpTexture1.c_str(), BumpTexture1.size() ) || !ASSIMP_strincmp( pPtr, BumpTexture2.c_str(), BumpTexture2.size() ) || !ASSIMP_strincmp( pPtr, BumpTexture3.c_str(), BumpTexture3.size() ) ) { // Bump texture out = & m_pModel->m_pCurrentMaterial->textureBump; + clampIndex = ObjFile::Material::TextureBumpType; } else if (!ASSIMP_strincmp( pPtr,NormalTexture.c_str(), NormalTexture.size())) { // Normal map out = & m_pModel->m_pCurrentMaterial->textureNormal; + clampIndex = ObjFile::Material::TextureNormalType; } else if (!ASSIMP_strincmp( pPtr, DisplacementTexture.c_str(), DisplacementTexture.size() ) ) { // Displacement texture out = &m_pModel->m_pCurrentMaterial->textureDisp; + clampIndex = ObjFile::Material::TextureDispType; } else if (!ASSIMP_strincmp( pPtr, SpecularityTexture.c_str(),SpecularityTexture.size() ) ) { // Specularity scaling (glossiness) out = & m_pModel->m_pCurrentMaterial->textureSpecularity; + clampIndex = ObjFile::Material::TextureSpecularityType; } else { DefaultLogger::get()->error("OBJ/MTL: Encountered unknown texture type"); return; } + m_pModel->m_pCurrentMaterial->clamp[clampIndex] = getClamp(); + skipTextureOption(); + std::string strTexture; m_DataIt = getName( m_DataIt, m_DataItEnd, strTexture ); out->Set( strTexture ); } +// ------------------------------------------------------------------- +// Try to find if there is a "-clamp on" texture option. It doesn't +// skip part of stream here, that is, it won't modify m_DataIt here +bool ObjFileMtlImporter::getClamp() +{ + unsigned int uiLine; + DataArrayIt itEnd = skipLine(m_DataIt, m_DataItEnd, uiLine); + if (itEnd != m_DataItEnd) + --itEnd; + + std::string line(m_DataIt, itEnd); + + std::vector token; + const unsigned int numToken = tokenize( line, token, " " ); + for (unsigned int i = 0; i < numToken; ++i) + { + if (!ASSIMP_stricmp(token[i], "-clamp") && i + 1 < numToken) + { + if (token[i+1] == "on") + return true; + } + } + + return false; +} + +/* ///////////////////////////////////////////////////////////////////////////// + * Texture Option + * ///////////////////////////////////////////////////////////////////////////// + * According to http://en.wikipedia.org/wiki/Wavefront_.obj_file#Texture_options + * Texture map statement can contains various texture option, for example: + * + * map_Ka -o 1 1 1 some.png + * map_Kd -clamp on some.png + * + * So we need to skip this option, just keep the last part which is the url of + * image, otherwise we will get a wrong url like "-clamp on some.png". + * Here we also take a special case into account where url contains space: + * + * map_Kd -clamp on "url contains space.png" + * + * ///////////////////////////////////////////////////////////////////////////// + */ +void ObjFileMtlImporter::skipTextureOption() +{ + unsigned int uiLine; + DataArrayIt itEnd = skipLine(m_DataIt, m_DataItEnd, uiLine); + if (itEnd != m_DataItEnd) { + --itEnd; + --itEnd; + } + + char token = ' '; + if (*itEnd == '\"') + { + token = '\"'; + --itEnd; + } + + while (itEnd != m_DataIt) + { + if (token == '\"' ) + { + if (*itEnd == token) + break; + } + else if (isSeparator(*itEnd)) + { + break; + } + + --itEnd; + } + + m_DataIt = itEnd; + +} + // ------------------------------------------------------------------- } // Namespace Assimp diff --git a/code/ObjFileMtlImporter.h b/code/ObjFileMtlImporter.h index a2111194d..32e9a5c67 100644 --- a/code/ObjFileMtlImporter.h +++ b/code/ObjFileMtlImporter.h @@ -92,6 +92,8 @@ private: void createMaterial(); /// Get texture name from loaded data. void getTexture(); + bool getClamp(); + void skipTextureOption(); private: //! Absolute pathname