Parcourir la source

- finalized Collada mesh part - can read static models now, using dummy materials

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@246 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
ulfjorensen il y a 17 ans
Parent
commit
78969d0a95
4 fichiers modifiés avec 166 ajouts et 2 suppressions
  1. 127 1
      code/ColladaLoader.cpp
  2. 12 0
      code/ColladaLoader.h
  3. 22 1
      code/ColladaParser.cpp
  4. 5 0
      code/ColladaParser.h

+ 127 - 1
code/ColladaLoader.cpp

@@ -90,7 +90,25 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
 	// build the node hierarchy from it
 	pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode);
 
-	pScene->mFlags = AI_SCENE_FLAGS_INCOMPLETE;
+	// store all meshes
+	StoreSceneMeshes( pScene);
+
+	// create dummy material
+	Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
+	aiString name( std::string( "dummy"));
+	mat->AddProperty( &name, AI_MATKEY_NAME);
+
+	int shadeMode = aiShadingMode_Phong;
+	mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
+	aiColor4D colAmbient( 0.2f, 0.2f, 0.2f, 1.0f), colDiffuse( 0.8f, 0.8f, 0.8f, 1.0f), colSpecular( 0.5f, 0.5f, 0.5f, 0.5f);
+	mat->AddProperty( &colAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
+	mat->AddProperty( &colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+	mat->AddProperty( &colSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
+	float specExp = 5.0f;
+	mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS);
+	pScene->mNumMaterials = 1;
+	pScene->mMaterials = new aiMaterial*[1];
+	pScene->mMaterials[0] = mat;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -112,5 +130,113 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla
 		node->mChildren[a]->mParent = node;
 	}
 
+	// construct meshes
+	BuildMeshesForNode( pParser, pNode, node);
+
 	return node;
 }
+
+// ------------------------------------------------------------------------------------------------
+// Builds meshes for the given node and references them
+void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const ColladaParser::Node* pNode, aiNode* pTarget)
+{
+	// accumulated mesh references by this node
+	std::vector<size_t> newMeshRefs;
+
+	// for the moment we simply ignore all material tags and transfer the meshes one by one
+	BOOST_FOREACH( const std::string& mid, pNode->mMeshes)
+	{
+		// find the referred mesh
+		ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find( mid);
+		if( srcMeshIt == pParser.mMeshLibrary.end())
+		{
+			DefaultLogger::get()->warn( boost::str( boost::format( "Unable to find geometry for ID \"%s\". Skipping.") % mid));
+			continue;
+		}
+
+		// if we already have the mesh at the library, just add its index to the node's array
+		std::map<std::string, size_t>::const_iterator dstMeshIt = mMeshIndexbyID.find( mid);
+		if( dstMeshIt != mMeshIndexbyID.end())
+		{
+			newMeshRefs.push_back( dstMeshIt->second);
+		} else
+		{
+			// else we have to add the mesh to the collection and store its newly assigned index at the node
+			aiMesh* dstMesh = new aiMesh;
+			const ColladaParser::Mesh* srcMesh = srcMeshIt->second;
+
+			// copy positions
+			dstMesh->mNumVertices = srcMesh->mPositions.size();
+			dstMesh->mVertices = new aiVector3D[dstMesh->mNumVertices];
+			std::copy( srcMesh->mPositions.begin(), srcMesh->mPositions.end(), dstMesh->mVertices);
+
+			// normals, if given. HACK: (thom) Due to the fucking Collada spec we never know if we have the same
+			// number of normals as there are positions. So we also ignore any vertex attribute if it has a different count
+			if( srcMesh->mNormals.size() == dstMesh->mNumVertices)
+			{
+				dstMesh->mNormals = new aiVector3D[dstMesh->mNumVertices];
+				std::copy( srcMesh->mNormals.begin(), srcMesh->mNormals.end(), dstMesh->mNormals);
+			}
+
+			// same for texturecoords, as many as we have
+			for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
+			{
+				if( srcMesh->mTexCoords[a].size() == dstMesh->mNumVertices)
+				{
+					dstMesh->mTextureCoords[a] = new aiVector3D[dstMesh->mNumVertices];
+					for( size_t b = 0; b < dstMesh->mNumVertices; ++b)
+						dstMesh->mTextureCoords[a][b].Set( srcMesh->mTexCoords[a][b].x, srcMesh->mTexCoords[a][b].y, 0.0f);
+					dstMesh->mNumUVComponents[a] = 2;
+				}
+			}
+
+			// same for vertex colors, as many as we have
+			for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
+			{
+				if( srcMesh->mColors[a].size() == dstMesh->mNumVertices)
+				{
+					dstMesh->mColors[a] = new aiColor4D[dstMesh->mNumVertices];
+					std::copy( srcMesh->mColors[a].begin(), srcMesh->mColors[a].end(), dstMesh->mColors[a]);
+				}
+			}
+
+			// create faces. Due to the fact that each face uses unique vertices, we can simply count up on each vertex
+			size_t vertex = 0;
+			dstMesh->mNumFaces = srcMesh->mFaceSize.size();
+			dstMesh->mFaces = new aiFace[dstMesh->mNumFaces];
+			for( size_t a = 0; a < dstMesh->mNumFaces; ++a)
+			{
+				size_t s = srcMesh->mFaceSize[a];
+				aiFace& face = dstMesh->mFaces[a];
+				face.mNumIndices = s;
+				face.mIndices = new unsigned int[s];
+				for( size_t b = 0; b < s; ++b)
+					face.mIndices[b] = vertex++;
+			}
+
+			// store the mesh, and store its new index in the node
+			newMeshRefs.push_back( mMeshes.size());
+			mMeshes.push_back( dstMesh);
+		}
+	}
+
+	// now place all mesh references we gathered in the target node
+	pTarget->mNumMeshes = newMeshRefs.size();
+	if( newMeshRefs.size())
+	{
+		pTarget->mMeshes = new size_t[pTarget->mNumMeshes];
+		std::copy( newMeshRefs.begin(), newMeshRefs.end(), pTarget->mMeshes);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Stores all meshes in the given scene
+void ColladaLoader::StoreSceneMeshes( aiScene* pScene)
+{
+	pScene->mNumMeshes = mMeshes.size();
+	if( mMeshes.size() > 0)
+	{
+		pScene->mMeshes = new aiMesh*[mMeshes.size()];
+		std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
+	}
+}

+ 12 - 0
code/ColladaLoader.h

@@ -85,9 +85,21 @@ protected:
 	/** Recursively constructs a scene node for the given parser node and returns it. */
 	aiNode* BuildHierarchy( const ColladaParser& pParser, const ColladaParser::Node* pNode);
 
+	/** Builds meshes for the given node and references them */
+	void BuildMeshesForNode( const ColladaParser& pParser, const ColladaParser::Node* pNode, aiNode* pTarget);
+
+	/** Stores all meshes in the given scene */
+	void StoreSceneMeshes( aiScene* pScene);
+
 protected:
 	/** Filename, for a verbose error message */
 	std::string mFileName;
+
+	/** Which mesh-material compound was stored under which mesh ID */
+	std::map<std::string, size_t> mMeshIndexbyID;
+
+	/** Accumulated meshes for the target scene */
+	std::vector<aiMesh*> mMeshes;
 };
 
 } // end of namespace Assimp

+ 22 - 1
code/ColladaParser.cpp

@@ -747,7 +747,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
 					child->mName = mReader->getAttributeValue( attrName);
 
 				// TODO: (thom) support SIDs
-				assert( TestAttribute( "sid") == -1);
+//				assert( TestAttribute( "sid") == -1);
 
 				pNode->mChildren.push_back( child);
 				child->mParent = pNode;
@@ -759,6 +759,10 @@ void ColladaParser::ReadSceneNode( Node* pNode)
 				// test for it, in case we need to implement it
 				assert( false);
 				SkipElement();
+			} else if( IsElement( "instance_geometry"))
+			{
+				// Reference to a mesh, we possible material associations
+				ReadNodeGeometry( pNode);
 			} else
 			{
 				// skip everything else for the moment
@@ -800,6 +804,23 @@ void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType)
 	TestClosing( tagName.c_str());
 }
 
+// ------------------------------------------------------------------------------------------------
+// Reads a mesh reference in a node and adds it to the node's mesh list
+void ColladaParser::ReadNodeGeometry( Node* pNode)
+{
+	// referred mesh is given as an attribute of the <instance_geometry> element
+	int attrUrl = GetAttribute( "url");
+	const char* url = mReader->getAttributeValue( attrUrl);
+	if( url[0] != '#')
+		ThrowException( "Unknown reference format");
+	
+	// store the mesh ID
+	pNode->mMeshes.push_back( std::string( url+1));
+	
+	// for the moment, skip the rest
+	SkipElement();
+}
+
 // ------------------------------------------------------------------------------------------------
 // Reads the collada scene
 void ColladaParser::ReadScene()

+ 5 - 0
code/ColladaParser.h

@@ -84,6 +84,8 @@ public:
 		/** Operations in order to calculate the resulting transformation to parent. */
 		std::vector<Transform> mTransforms;
 
+		std::vector<std::string> mMeshes; ///< Meshes at this node
+
 		Node() { mParent = NULL; }
 		~Node() { for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; }
 	};
@@ -213,6 +215,9 @@ protected:
 	/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
 	void ReadNodeTransformation( Node* pNode, TransformType pType);
 
+	/** Reads a mesh reference in a node and adds it to the node's mesh list */
+	void ReadNodeGeometry( Node* pNode);
+
 	/** Reads the collada scene */
 	void ReadScene();