2
0
Эх сурвалжийг харах

- added materials to Collada Export

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1165 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
ulfjorensen 13 жил өмнө
parent
commit
82f027b01f

+ 160 - 2
code/ColladaExporter.cpp

@@ -94,6 +94,7 @@ void ColladaExporter::WriteFile()
 
 	WriteHeader();
 
+  WriteMaterials();
 	WriteGeometryLibrary();
 
 	WriteSceneLibrary();
@@ -127,6 +128,155 @@ void ColladaExporter::WriteHeader()
 	mOutput << startstr << "</asset>" << endstr;
 }
 
+// ------------------------------------------------------------------------------------------------
+// Reads a single surface entry from the given material keys
+void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
+{
+  if( pSrcMat->GetTextureCount( pTexture) > 0 )
+  {
+    aiString texfile;
+    unsigned int uvChannel = 0;
+    pSrcMat->GetTexture( pTexture, 0, &texfile, nullptr, &uvChannel);
+    poSurface.texture = texfile.C_Str();
+    poSurface.channel = uvChannel;
+  } else
+  {
+    if( pKey )
+      pSrcMat->Get( pKey, pType, pIndex, poSurface.color);
+  }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes an image entry for the given surface
+void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd)
+{
+  if( !pSurface.texture.empty() )
+  {
+    mOutput << startstr << "<image id=\"" << pNameAdd << "\" name=\"" << pNameAdd << "\">" << endstr;
+    PushTag(); 
+    mOutput << startstr << "<init_from>" << pSurface.texture << "</init_from>" << endstr;
+    PopTag();
+    mOutput << startstr << "</image>" << endstr;
+  }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes a color-or-texture entry into an effect definition
+void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
+{
+  mOutput << startstr << "<" << pTypeName << ">" << endstr;
+  PushTag();
+  if( pSurface.texture.empty() )
+  {
+    mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
+  } else
+  {
+    mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+  }
+  PopTag();
+  mOutput << startstr << "</" << pTypeName << ">" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the material setup
+void ColladaExporter::WriteMaterials()
+{
+  materials.resize( mScene->mNumMaterials);
+
+  /// collect all materials from the scene
+  for( size_t a = 0; a < mScene->mNumMaterials; ++a )
+  {
+    const aiMaterial* mat = mScene->mMaterials[a];
+
+    aiString name;
+    if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
+      name = "mat";
+    materials[a].name = boost::lexical_cast<std::string> (a) + name.C_Str();
+
+    ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
+    ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
+    ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
+    ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
+    ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
+    ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, nullptr, 0, 0);
+
+    mat->Get( AI_MATKEY_SHININESS, materials[a].shininess);
+  }
+
+  // output textures if present
+  mOutput << startstr << "<library_images>" << endstr; 
+  PushTag();
+  for( auto it = materials.cbegin(); it != materials.cend(); ++it )
+  { 
+    const Material& mat = *it;
+    WriteImageEntry( mat.ambient, mat.name + "_ambient_image");
+    WriteImageEntry( mat.diffuse, mat.name + "_diffuse_image");
+    WriteImageEntry( mat.specular, mat.name + "_specular_image");
+    WriteImageEntry( mat.emissive, mat.name + "_emissive_image");
+    WriteImageEntry( mat.reflective, mat.name + "_reflective_image");
+    WriteImageEntry( mat.normal, mat.name + "_normal_image");
+  }
+  PopTag();
+  mOutput << startstr << "</library_images>" << endstr;
+
+  // output effects - those are the actual carriers of information
+  mOutput << startstr << "<library_effects>" << endstr;
+  PushTag();
+  for( auto it = materials.cbegin(); it != materials.cend(); ++it )
+  {
+    const Material& mat = *it;
+    // this is so ridiculous it must be right
+    mOutput << startstr << "<effect id=\"" << mat.name << "-fx\" name=\"" << mat.name << "\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<profile_COMMON>" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique sid=\"standard\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<phong>" << endstr;
+    PushTag();
+
+    WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "_ambient_image");
+    WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "_diffuse_image");
+    WriteTextureColorEntry( mat.specular, "specular", mat.name + "_specular_image");
+    WriteTextureColorEntry( mat.emissive, "emission", mat.name + "_emissive_image");
+    WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "_reflective_image");
+    if( !mat.normal.texture.empty() )
+      WriteTextureColorEntry( mat.normal, "bump", mat.name + "_normal_image");
+
+    mOutput << startstr << "<shininess>" << endstr;
+    PushTag();
+    mOutput << startstr << "<float sid=\"shininess\">" << mat.shininess << "</float>" << endstr;
+    PopTag();
+    mOutput << startstr << "</shininess>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</phong>" << endstr;
+    PopTag();
+    mOutput << startstr << "</technique>" << endstr;
+    PopTag();
+    mOutput << startstr << "</profile_COMMON>" << endstr;
+    PopTag();
+    mOutput << startstr << "</effect>" << endstr;
+  }
+  PopTag();
+  mOutput << startstr << "</library_effects>" << endstr;
+
+  // write materials - they're just effect references
+  mOutput << startstr << "<library_materials>" << endstr;
+  PushTag();
+  for( auto it = materials.cbegin(); it != materials.cend(); ++it )
+  {
+    const Material& mat = *it;
+    mOutput << startstr << "<material id=\"" << mat.name << "\" name=\"" << mat.name << "\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<instance_effect url=\"#" << mat.name << "-fx\"/>" << endstr;
+    PopTag();
+    mOutput << startstr << "</material>" << endstr;
+  }
+  PopTag();
+  mOutput << startstr << "</library_materials>" << endstr;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Writes the geometry library
 void ColladaExporter::WriteGeometryLibrary()
@@ -199,7 +349,7 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
 	mOutput << startstr << "</vertices>" << endstr;
 
 	// write face setup
-	mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"tellme\">" << endstr;
+	mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"theresonlyone\">" << endstr;
 	PushTag();
 	mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
 	
@@ -356,8 +506,16 @@ void ColladaExporter::WriteNode( const aiNode* pNode)
 		// const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
 		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
 		PushTag();
-
+    mOutput << startstr << "<bind_material>" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"" << materials[mScene->mMeshes[pNode->mMeshes[a]]->mMaterialIndex].name << "\" />" << endstr;
 		PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+    PopTag();
+    mOutput << startstr << "</bind_material>" << endstr;
+    PopTag();
 		mOutput << startstr << "</instance_geometry>" << endstr;
 	}
 

+ 33 - 0
code/ColladaExporter.h

@@ -68,6 +68,9 @@ protected:
 	/// Writes the asset header
 	void WriteHeader();
 
+  /// Writes the material setup
+  void WriteMaterials();
+
 	/// Writes the geometry library
 	void WriteGeometryLibrary();
 
@@ -105,6 +108,36 @@ protected:
 	std::string startstr;
 	/// current line end string for simple stream insertion
 	std::string endstr;
+
+  // pair of color and texture - texture precedences color
+  struct Surface 
+  { 
+    aiColor4D color; 
+    std::string texture; 
+    size_t channel; 
+    Surface() { channel = 0; }
+  };
+
+  // summarize a material in an convinient way. 
+  struct Material
+  {
+    std::string name;
+    Surface ambient, diffuse, specular, emissive, reflective, normal;
+    float shininess; /// specular exponent
+
+    Material() { shininess = 16.0f; }
+  };
+
+  std::vector<Material> materials;
+
+protected:
+  /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
+  /// Reads a single surface entry from the given material keys
+  void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex);
+  /// Writes an image entry for the given surface
+  void WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd);
+  /// Writes a color-or-texture entry into an effect definition
+  void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName);
 };
 
 }