浏览代码

BUGFIX : Fix handling of multiple materials per object definition in Obj-Loader.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@745 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
kimmi 15 年之前
父节点
当前提交
f3310b0f36
共有 4 个文件被更改,包括 120 次插入60 次删除
  1. 11 4
      code/ObjFileData.h
  2. 42 33
      code/ObjFileImporter.cpp
  3. 63 23
      code/ObjFileParser.cpp
  4. 4 0
      code/ObjFileParser.h

+ 11 - 4
code/ObjFileData.h

@@ -107,14 +107,20 @@ struct Face
 //!	\brief	Stores all objects of an objfile object definition
 struct Object
 {
+	enum ObjectType
+	{
+		ObjType,
+		GroupType
+	};
+
 	//!	Object name
 	std::string m_strObjName;
-	//!	Assigend face instances
-	std::vector<Face*> m_Faces;
 	//!	Transformation matrix, stored in OpenGL format
 	aiMatrix4x4 m_Transformation;
 	//!	All sub-objects referenced by this object
 	std::vector<Object*> m_SubObjects;
+	///	Assigned meshes
+	std::vector<unsigned int> m_Meshes;
 
 	//!	\brief	Default constructor
 	Object() :
@@ -189,6 +195,8 @@ struct Material
 //!	\brief	Data structure to store a mesh
 struct Mesh
 {
+	static const unsigned int NoMaterial = 999999999;
+
 	///	Array with pointer to all stored faces
 	std::vector<Face*> m_Faces;
 	///	Assigned material
@@ -205,7 +213,7 @@ struct Mesh
 	Mesh() :
 		m_pMaterial(NULL),
 		m_uiNumIndices(0),
-		m_uiMaterialIndex(0),
+		m_uiMaterialIndex( NoMaterial ),
 		m_hasNormals(false)
 	{
 		memset(m_uiUVCoordinates, 0, sizeof( unsigned int ) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
@@ -305,7 +313,6 @@ struct Model
 		}
 		
 		m_Groups.clear();
-		
 	}
 };
 

+ 42 - 33
code/ObjFileImporter.cpp

@@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
 
 #include "DefaultIOSystem.h"
-
 #include "ObjFileImporter.h"
 #include "ObjFileParser.h"
 #include "ObjFileData.h"
@@ -140,8 +139,8 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
 		return;
 		
 	// Create the root node of the scene
-	pScene->mRootNode = new aiNode();
-	if (!pModel->m_ModelName.empty())
+	pScene->mRootNode = new aiNode;
+	if ( !pModel->m_ModelName.empty() )
 	{
 		// Set the name of the scene
 		pScene->mRootNode->mName.Set(pModel->m_ModelName);
@@ -175,40 +174,46 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
 
 // ------------------------------------------------------------------------------------------------
 //	Creates all nodes of the model
-aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pData, 
+aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject, 
 									 unsigned int uiMeshIndex,
 									 aiNode *pParent, aiScene* pScene, 
-									 std::vector<aiMesh*> &MeshArray)
+									 std::vector<aiMesh*> &MeshArray )
 {
 	ai_assert( NULL != pModel );
-	if (NULL == pData)
+	if ( NULL == pObject )
 		return NULL;
 	
 	// Store older mesh size to be able to computate mesh offsets for new mesh instances
 	const size_t oldMeshSize = MeshArray.size();
-	aiNode *pNode = new aiNode();
+	aiNode *pNode = new aiNode;
 	
 	if (pParent != NULL)
-		this->appendChildToParentNode(pParent, pNode);
+		appendChildToParentNode(pParent, pNode);
 
-	aiMesh *pMesh = new aiMesh;
-	createTopology( pModel, pData, uiMeshIndex, pMesh );	
-	if ( pMesh->mNumVertices > 0 ) 
-	{
-		MeshArray.push_back( pMesh );
-	}
-	else
+	
+	for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
 	{
-		delete pMesh;
+		unsigned int meshId = pObject->m_Meshes[ i ];
+		aiMesh *pMesh = new aiMesh;
+		createTopology( pModel, pObject, meshId, pMesh );	
+		if ( pMesh->mNumVertices > 0 ) 
+		{
+			MeshArray.push_back( pMesh );
+		}
+		else
+		{
+			delete pMesh;
+		}
 	}
 
-	// Create all nodes from the subobjects stored in the current object
-	if ( !pData->m_SubObjects.empty() )
+	// Create all nodes from the sub-objects stored in the current object
+	if ( !pObject->m_SubObjects.empty() )
 	{
-		pNode->mNumChildren = (unsigned int)pData->m_SubObjects.size();
-		pNode->mChildren = new aiNode*[pData->m_SubObjects.size()];
+		size_t numChilds = pObject->m_SubObjects.size();
+		pNode->mNumChildren = static_cast<unsigned int>( numChilds );
+		pNode->mChildren = new aiNode*[ numChilds ];
 		pNode->mNumMeshes = 1;
-		pNode->mMeshes = new unsigned int[1];
+		pNode->mMeshes = new unsigned int[ 1 ];
 	}
 
 	// Set mesh instances into scene- and node-instances
@@ -216,7 +221,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 	if ( meshSizeDiff > 0 )
 	{
 		pNode->mMeshes = new unsigned int[ meshSizeDiff ];
-		pNode->mNumMeshes = (unsigned int)meshSizeDiff;
+		pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
 		size_t index = 0;
 		for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
 		{
@@ -248,7 +253,10 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
 	if ( pMesh->mNumFaces > 0 )
 	{
 		pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
-		pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
+		if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial )
+		{
+			pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
+		}
 
 		// Copy all data from all stored meshes
 		for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
@@ -278,7 +286,7 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
 }
 
 // ------------------------------------------------------------------------------------------------
-//	Creates a vretex array
+//	Creates a vertex array
 void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, 
 										const ObjFile::Object* pCurrentObject, 
 										unsigned int uiMeshIndex,
@@ -288,7 +296,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
 	ai_assert( NULL != pCurrentObject );
 	
 	// Break, if no faces are stored in object
-	if (pCurrentObject->m_Faces.empty())
+	if ( pCurrentObject->m_Meshes.empty() )
 		return;
 
 	// Get current mesh
@@ -366,10 +374,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
 void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes)
 {
 	iNumMeshes = 0;
-	if (rObjects.empty())	
+	if ( rObjects.empty() )	
 		return;
 
-	iNumMeshes += (unsigned int)rObjects.size();
+	iNumMeshes += static_cast<unsigned int>( rObjects.size() );
 	for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
 		it != rObjects.end(); 
 		++it)
@@ -400,17 +408,18 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
 		Assimp::MaterialHelper* mat = new Assimp::MaterialHelper();
 		
 		// Store material name
-		std::map<std::string, ObjFile::Material*>::const_iterator it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
+		std::map<std::string, ObjFile::Material*>::const_iterator it;
+		it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
 		
 		// No material found, use the default material
-		if ( pModel->m_MaterialMap.end() == it)
+		if ( pModel->m_MaterialMap.end() == it )
 			continue;
 
 		ObjFile::Material *pCurrentMaterial = (*it).second;
 		mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
 
 		// convert illumination model
-		int sm;
+		int sm = 0;
 		switch (pCurrentMaterial->illumination_model) 
 		{
 		case 0:
@@ -474,8 +483,8 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
 void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
 {
 	// Checking preconditions
-	ai_assert (NULL != pParent);
-	ai_assert (NULL != pChild);
+	ai_assert( NULL != pParent );
+	ai_assert( NULL != pChild );
 
 	// Assign parent to child
 	pChild->mParent = pParent;
@@ -486,7 +495,7 @@ void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
 	if (pParent->mChildren != NULL)
 	{
 		sNumChildren = pParent->mNumChildren;
-		ai_assert (0 != sNumChildren);
+		ai_assert( 0 != sNumChildren );
 		for (size_t index = 0; index < pParent->mNumChildren; index++)
 		{
 			temp.push_back(pParent->mChildren [ index ] );

+ 63 - 23
code/ObjFileParser.cpp

@@ -50,7 +50,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/aiTypes.h"
 #include "DefaultIOSystem.h"
 
-namespace Assimp	{
+namespace Assimp	
+{
+
 // -------------------------------------------------------------------
 const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME; 
 // fix: changed that to our standard default name
@@ -78,6 +80,7 @@ ObjFileParser::ObjFileParser(std::vector<char> &Data,const std::string &strModel
 }
 
 // -------------------------------------------------------------------
+//	Destrcutor.
 ObjFileParser::~ObjFileParser()
 {
 	delete m_pModel->m_pDefaultMaterial;
@@ -88,12 +91,14 @@ ObjFileParser::~ObjFileParser()
 }
 
 // -------------------------------------------------------------------
+//	Returns a pointer to the model instance.
 ObjFile::Model *ObjFileParser::GetModel() const
 {
 	return m_pModel;
 }
 
 // -------------------------------------------------------------------
+//	File parsing method.
 void ObjFileParser::parseFile()
 {
 	if (m_DataIt == m_DataItEnd)
@@ -201,7 +206,6 @@ void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
 	size_t index = 0;
 	while (m_DataIt != m_DataItEnd)
 	{
-		// (Aramis) removed assertion (index<length-1) in favour of an explicit check
 		if (*m_DataIt == '\n' || *m_DataIt == '\r' || index == length-1)
 			break;
 
@@ -265,7 +269,6 @@ void ObjFileParser::getFace()
 	std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
 	std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
 	bool hasNormal = false;
-	
 
 	bool vt = (!m_pModel->m_TextureCoord.empty());
 	bool vn = (!m_pModel->m_Normals.empty());
@@ -329,7 +332,7 @@ void ObjFileParser::getFace()
 			++pPtr;
 	}
 
-	ObjFile::Face *face = new ObjFile::Face(pIndices, pNormalID, pTexID);
+	ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID );
 	
 	// Set active material, if one set
 	if (NULL != m_pModel->m_pCurrentMaterial) 
@@ -339,23 +342,20 @@ void ObjFileParser::getFace()
 
 	// Create a default object, if nothing there
 	if ( NULL == m_pModel->m_pCurrent )
-		createObject("defaultobject");
-
-	// Store the new instance
-	m_pModel->m_pCurrent->m_Faces.push_back(face);
+		createObject( "defaultobject" );
 	
 	// Assign face to mesh
 	if ( NULL == m_pModel->m_pCurrentMesh )
 	{
-		m_pModel->m_pCurrentMesh = new ObjFile::Mesh();
-		m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
+		createMesh();
 	}
 	
 	// Store the face
 	m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
 	m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
 	m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size(); 
-	if(!m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal) {
+	if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) 
+	{
 		m_pModel->m_pCurrentMesh->m_hasNormals = true;
 	}
 	// Skip the rest of the line
@@ -391,6 +391,10 @@ void ObjFileParser::getMaterialDesc()
 	{
 		// Found, using detected material
 		m_pModel->m_pCurrentMaterial = (*it).second;
+		if ( needsNewMesh( strName ))
+		{
+			createMesh();	
+		}
 		m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName );
 	}
 
@@ -460,11 +464,11 @@ void ObjFileParser::getNewMaterial()
 		return;
 
 	char *pStart = &(*m_DataIt);
-	std::string strMat(pStart, *m_DataIt);
+	std::string strMat( pStart, *m_DataIt );
 	while ( isSeparator( *m_DataIt ) )
 		m_DataIt++;
 	std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
-	if (it == m_pModel->m_MaterialMap.end())
+	if ( it == m_pModel->m_MaterialMap.end() )
 	{
 		// Show a warning, if material was not found
 		DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat);
@@ -473,7 +477,10 @@ void ObjFileParser::getNewMaterial()
 	else
 	{
 		// Set new material
-		m_pModel->m_pCurrentMaterial = (*it).second;
+		if ( needsNewMesh( strMat ) )
+		{
+			createMesh();	
+		}
 		m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
 	}
 
@@ -514,13 +521,12 @@ void ObjFileParser::getGroupName()
 	std::string strGroupName(pStart, &(*m_DataIt));
 
 	// Change active group, if necessary
-	if (m_pModel->m_strActiveGroup != strGroupName)
+	if ( m_pModel->m_strActiveGroup != strGroupName )
 	{
 		// Search for already existing entry
 		ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(&strGroupName);
 		
 		// We are mapping groups into the object structure
-		/// TODO: Is this the right way to do it????
 		createObject( strGroupName );
 		
 		// New group name, creating a new entry
@@ -557,8 +563,8 @@ void ObjFileParser::getObjectName()
 	if (m_DataIt == m_DataItEnd)
 		return;
 	char *pStart = &(*m_DataIt);
-	while (!isSeparator(*m_DataIt))
-		m_DataIt++;
+	while ( !isSeparator( *m_DataIt ) )
+		++m_DataIt;
 
 	std::string strObjectName(pStart, &(*m_DataIt));
 	if (!strObjectName.empty()) 
@@ -588,15 +594,15 @@ void ObjFileParser::getObjectName()
 //	Creates a new object instance
 void ObjFileParser::createObject(const std::string &strObjectName)
 {
-	ai_assert (NULL != m_pModel);
-	ai_assert (!strObjectName.empty());
+	ai_assert( NULL != m_pModel );
+	ai_assert( !strObjectName.empty() );
 
-	m_pModel->m_pCurrent = new ObjFile::Object();
+	m_pModel->m_pCurrent = new ObjFile::Object;
 	m_pModel->m_pCurrent->m_strObjName = strObjectName;
 	m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
 	
-	m_pModel->m_pCurrentMesh = new ObjFile::Mesh();
-	m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
+
+	createMesh();
 
 	if( m_pModel->m_pCurrentMaterial )
 	{
@@ -605,6 +611,39 @@ void ObjFileParser::createObject(const std::string &strObjectName)
 		m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
 	}		
 }
+// -------------------------------------------------------------------
+//	Creates a new mesh
+void ObjFileParser::createMesh()
+{
+	ai_assert( NULL != m_pModel );
+	m_pModel->m_pCurrentMesh = new ObjFile::Mesh;
+	m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
+	unsigned int meshId = m_pModel->m_Meshes.size()-1;
+	if ( NULL != m_pModel->m_pCurrent )
+	{
+		m_pModel->m_pCurrent->m_Meshes.push_back( meshId );
+	}
+	else
+	{
+		DefaultLogger::get()->error("OBJ: No object detected to attach a new mesh instance.");
+	}
+}
+
+// -------------------------------------------------------------------
+//	Returns true, if a new mesh must be created.
+bool ObjFileParser::needsNewMesh( const std::string &rMaterialName )
+{
+	bool newMat = false;
+	int matIdx = getMaterialIndex( rMaterialName );
+	int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
+	if ( curMatIdx != ObjFile::Mesh::NoMaterial || curMatIdx != matIdx )
+	{
+		// New material -> only one material per mesh, so we need to create a new 
+		// material
+		newMat = true;
+	}
+	return newMat;
+}
 
 // -------------------------------------------------------------------
 //	Shows an error in parsing process.
@@ -613,6 +652,7 @@ void ObjFileParser::reportErrorTokenInFace()
 	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 	DefaultLogger::get()->error("OBJ: Not supported token in face description detected");
 }
+
 // -------------------------------------------------------------------
 
 }	// Namespace Assimp

+ 4 - 0
code/ObjFileParser.h

@@ -108,6 +108,10 @@ private:
 	void getObjectName();
 	/// Creates a new object.
 	void createObject(const std::string &strObjectName);
+	///	Creates a new mesh.
+	void createMesh(); 
+	///	Returns true, if a new mesh instance must be created.
+	bool needsNewMesh( const std::string &rMaterialName );
 	///	Error report in token
 	void reportErrorTokenInFace();