- further Collada work: materials are now loaded from profile_COMMON, meshes are properly split up at material borders

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@260 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
This commit is contained in:
ulfjorensen
2008-12-04 17:06:26 +00:00
parent d320a4bc64
commit 917db45b3c
9 changed files with 526 additions and 161 deletions

View File

@@ -87,6 +87,12 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// parse the input file
ColladaParser parser( pFile);
if( !parser.mRootNode)
throw new ImportErrorException( "File came out empty. Somethings wrong here.");
// create the materials first, for the meshes to find
BuildMaterials( parser, pScene);
// build the node hierarchy from it
pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode);
@@ -107,23 +113,6 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// 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;
}
// ------------------------------------------------------------------------------------------------
@@ -168,70 +157,100 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
DefaultLogger::get()->warn( boost::str( boost::format( "Unable to find geometry for ID \"%s\". Skipping.") % mid.mMesh));
continue;
}
const Collada::Mesh* srcMesh = srcMeshIt->second;
// 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.mMesh);
if( dstMeshIt != mMeshIndexbyID.end())
// build a mesh for each of its subgroups
size_t vertexStart = 0, faceStart = 0;
for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm)
{
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 Collada::Mesh* srcMesh = srcMeshIt->second;
const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm];
// find material assigned to this submesh
std::map<std::string, std::string>::const_iterator meshMatIt = mid.mMaterials.find( submesh.mMaterial);
std::string meshMaterial;
if( meshMatIt != mid.mMaterials.end())
meshMaterial = meshMatIt->second;
else
DefaultLogger::get()->warn( boost::str( boost::format( "No material specified for subgroup \"%s\" in geometry \"%s\".") % submesh.mMaterial % mid.mMesh));
// copy positions
dstMesh->mNumVertices = srcMesh->mPositions.size();
dstMesh->mVertices = new aiVector3D[dstMesh->mNumVertices];
std::copy( srcMesh->mPositions.begin(), srcMesh->mPositions.end(), dstMesh->mVertices);
// built lookup index of the Mesh-Submesh-Material combination
ColladaMeshIndex index( mid.mMesh, sm, meshMaterial);
// 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)
// if we already have the mesh at the library, just add its index to the node's array
std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find( index);
if( dstMeshIt != mMeshIndexByID.end())
{
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++)
newMeshRefs.push_back( dstMeshIt->second);
} else
{
if( srcMesh->mTexCoords[a].size() == dstMesh->mNumVertices)
// else we have to add the mesh to the collection and store its newly assigned index at the node
aiMesh* dstMesh = new aiMesh;
// count the vertices addressed by its faces
size_t numVertices =
std::accumulate( srcMesh->mFaceSize.begin() + faceStart, srcMesh->mFaceSize.begin() + faceStart + submesh.mNumFaces, 0);
// copy positions
dstMesh->mNumVertices = numVertices;
dstMesh->mVertices = new aiVector3D[numVertices];
std::copy( srcMesh->mPositions.begin() + vertexStart, srcMesh->mPositions.begin() + vertexStart + numVertices, 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() == srcMesh->mPositions.size())
{
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;
dstMesh->mNormals = new aiVector3D[numVertices];
std::copy( srcMesh->mNormals.begin() + vertexStart, srcMesh->mNormals.begin() + vertexStart + numVertices, dstMesh->mNormals);
}
}
// 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)
// same for texturecoords, as many as we have
for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
{
dstMesh->mColors[a] = new aiColor4D[dstMesh->mNumVertices];
std::copy( srcMesh->mColors[a].begin(), srcMesh->mColors[a].end(), dstMesh->mColors[a]);
if( srcMesh->mTexCoords[a].size() == srcMesh->mPositions.size())
{
dstMesh->mTextureCoords[a] = new aiVector3D[numVertices];
for( size_t b = vertexStart; b < vertexStart + numVertices; ++b)
dstMesh->mTextureCoords[a][b].Set( srcMesh->mTexCoords[a][b].x, srcMesh->mTexCoords[a][b].y, 0.0f);
dstMesh->mNumUVComponents[a] = 2;
}
}
}
// 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++;
}
// 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() == srcMesh->mPositions.size())
{
dstMesh->mColors[a] = new aiColor4D[numVertices];
std::copy( srcMesh->mColors[a].begin() + vertexStart, srcMesh->mColors[a].begin() + vertexStart + numVertices, dstMesh->mColors[a]);
}
}
// store the mesh, and store its new index in the node
newMeshRefs.push_back( mMeshes.size());
mMeshes.push_back( dstMesh);
// 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 = submesh.mNumFaces;
dstMesh->mFaces = new aiFace[dstMesh->mNumFaces];
for( size_t a = 0; a < dstMesh->mNumFaces; ++a)
{
size_t s = srcMesh->mFaceSize[ faceStart + 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());
mMeshIndexByID[index] = mMeshes.size();
mMeshes.push_back( dstMesh);
vertexStart += numVertices; faceStart += submesh.mNumFaces;
// assign the material index
std::map<std::string, size_t>::const_iterator matIt = mMaterialIndexByName.find( meshMaterial);
if( matIt != mMaterialIndexByName.end())
dstMesh->mMaterialIndex = matIt->second;
else
dstMesh->mMaterialIndex = 0;
}
}
}
@@ -255,3 +274,106 @@ void ColladaLoader::StoreSceneMeshes( aiScene* pScene)
std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
}
}
// ------------------------------------------------------------------------------------------------
// Constructs materials from the collada material definitions
void ColladaLoader::BuildMaterials( const ColladaParser& pParser, aiScene* pScene)
{
std::vector<aiMaterial*> newMats;
for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); matIt != pParser.mMaterialLibrary.end(); ++matIt)
{
const Collada::Material& material = matIt->second;
// a material is only a reference to an effect
ColladaParser::EffectLibrary::const_iterator effIt = pParser.mEffectLibrary.find( material.mEffect);
if( effIt == pParser.mEffectLibrary.end())
continue;
const Collada::Effect& effect = effIt->second;
// create material
Assimp::MaterialHelper* mat = new Assimp::MaterialHelper;
aiString name( matIt->first);
mat->AddProperty( &name, AI_MATKEY_NAME);
int shadeMode;
switch( effect.mShadeType)
{
case Collada::Shade_Constant: shadeMode = aiShadingMode_NoShading; break;
case Collada::Shade_Lambert: shadeMode = aiShadingMode_Gouraud; break;
case Collada::Shade_Blinn: shadeMode = aiShadingMode_Blinn; break;
default: shadeMode = aiShadingMode_Phong; break;
}
mat->AddProperty<int>( &shadeMode, 1, AI_MATKEY_SHADING_MODEL);
mat->AddProperty( &effect.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
mat->AddProperty( &effect.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
mat->AddProperty( &effect.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
mat->AddProperty( &effect.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
mat->AddProperty( &effect.mShininess, 1, AI_MATKEY_SHININESS);
mat->AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
// add textures, if given
if( !effect.mTexAmbient.empty())
mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexAmbient), AI_MATKEY_TEXTURE_AMBIENT( 0));
if( !effect.mTexDiffuse.empty())
mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexDiffuse), AI_MATKEY_TEXTURE_DIFFUSE( 0));
if( !effect.mTexEmissive.empty())
mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexEmissive), AI_MATKEY_TEXTURE_EMISSIVE( 0));
if( !effect.mTexSpecular.empty())
mat->AddProperty( &FindFilenameForEffectTexture( pParser, effect, effect.mTexSpecular), AI_MATKEY_TEXTURE_SPECULAR( 0));
// store the material
mMaterialIndexByName[matIt->first] = newMats.size();
newMats.push_back( mat);
}
// store a dummy material if none were given
if( newMats.size() == 0)
{
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);
}
// store the materials in the scene
pScene->mNumMaterials = newMats.size();
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
std::copy( newMats.begin(), newMats.end(), pScene->mMaterials);
}
// ------------------------------------------------------------------------------------------------
// Resolves the texture name for the given effect texture entry
const aiString& ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser, const Collada::Effect& pEffect, const std::string& pName)
{
// recurse through the param references until we end up at an image
std::string name = pName;
while( 1)
{
// the given string is a param entry. Find it
Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find( name);
// if not found, we're at the end of the recursion. The resulting string should be the image ID
if( it == pEffect.mParams.end())
break;
// else recurse on
name = it->second.mReference;
}
// find the image referred by this name in the image library of the scene
ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name);
if( imIt == pParser.mImageLibrary.end())
throw new ImportErrorException( boost::str( boost::format( "Unable to resolve effect texture entry \"%s\", ended up at ID \"%s\".") % pName % name));
static aiString result;
result.Set( imIt->second.mFileName);
return result;
}