Kimkulling/fix bahavior of remove redundat mats issue 5438 (#5451)

* Fix crash in viewer

* Fix bevavior when material was not referenced
pull/5372/head^2
Kim Kulling 2024-02-01 21:27:04 +01:00 committed by GitHub
parent 3476c79801
commit 3990ec80a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 100 additions and 95 deletions

View File

@ -75,124 +75,129 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin"); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
unsigned int redundantRemoved = 0, unreferencedRemoved = 0; unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
if (pScene->mNumMaterials) { if (pScene->mNumMaterials == 0) {
// Find out which materials are referenced by meshes return;
std::vector<bool> abReferenced(pScene->mNumMaterials,false); }
for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; // Find out which materials are referenced by meshes
std::vector<bool> abReferenced(pScene->mNumMaterials,false);
for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
// If a list of materials to be excluded was given, match the list with // If a list of materials to be excluded was given, match the list with
// our imported materials and 'salt' all positive matches to ensure that // our imported materials and 'salt' all positive matches to ensure that
// we get unique hashes later. // we get unique hashes later.
if (mConfigFixedMaterials.length()) { if (mConfigFixedMaterials.length()) {
std::list<std::string> strings; std::list<std::string> strings;
ConvertListToStrings(mConfigFixedMaterials,strings); ConvertListToStrings(mConfigFixedMaterials,strings);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
aiMaterial* mat = pScene->mMaterials[i]; aiMaterial* mat = pScene->mMaterials[i];
aiString name; aiString name;
mat->Get(AI_MATKEY_NAME,name); mat->Get(AI_MATKEY_NAME,name);
if (name.length) { if (name.length) {
std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data); std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
if (it != strings.end()) { if (it != strings.end()) {
// Our brilliant 'salt': A single material property with ~ as first // Our brilliant 'salt': A single material property with ~ as first
// character to mark it as internal and temporary. // character to mark it as internal and temporary.
const int dummy = 1; const int dummy = 1;
((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
// Keep this material even if no mesh references it // Keep this material even if no mesh references it
abReferenced[i] = true; abReferenced[i] = true;
ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'"); ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
}
} }
} }
} }
}
// TODO: re-implement this algorithm to work in-place // TODO: re-implement this algorithm to work in-place
unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) { for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
aiMappingTable[ i ] = 0; aiMappingTable[ i ] = 0;
}
unsigned int iNewNum = 0;
// Iterate through all materials and calculate a hash for them
// store all hashes in a list and so a quick search whether
// we do already have a specific hash. This allows us to
// determine which materials are identical.
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];;
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
// No mesh is referencing this material, remove it.
if (!abReferenced[i]) {
++unreferencedRemoved;
delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr;
continue;
} }
unsigned int iNewNum = 0;
// Iterate through all materials and calculate a hash for them // Check all previously mapped materials for a matching hash.
// store all hashes in a list and so a quick search whether // On a match we can delete this material and just make it ref to the same index.
// we do already have a specific hash. This allows us to uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
// determine which materials are identical. for (unsigned int a = 0; a < i;++a) {
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; if (abReferenced[a] && me == aiHashes[a]) {
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { ++redundantRemoved;
// No mesh is referencing this material, remove it. me = 0;
if (!abReferenced[i]) { aiMappingTable[i] = aiMappingTable[a];
++unreferencedRemoved;
delete pScene->mMaterials[i]; delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr; pScene->mMaterials[i] = nullptr;
break;
}
}
// This is a new material that is referenced, add to the map.
if (me) {
aiMappingTable[i] = iNewNum++;
}
}
// If the new material count differs from the original,
// we need to rebuild the material list and remap mesh material indexes.
if (iNewNum < 1) {
//throw DeadlyImportError("No materials remaining");
return;
}
if (iNewNum != pScene->mNumMaterials) {
ai_assert(iNewNum > 0);
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
{
// if the material is not referenced ... remove it
if (!abReferenced[p]) {
continue; continue;
} }
// Check all previously mapped materials for a matching hash. // generate new names for modified materials that had no names
// On a match we can delete this material and just make it ref to the same index. const unsigned int idx = aiMappingTable[p];
uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); if (ppcMaterials[idx]) {
for (unsigned int a = 0; a < i;++a) { aiString sz;
if (abReferenced[a] && me == aiHashes[a]) { if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
++redundantRemoved; sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
me = 0; ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
aiMappingTable[i] = aiMappingTable[a];
delete pScene->mMaterials[i];
pScene->mMaterials[i] = nullptr;
break;
} }
} } else {
// This is a new material that is referenced, add to the map. ppcMaterials[idx] = pScene->mMaterials[p];
if (me) {
aiMappingTable[i] = iNewNum++;
} }
} }
// If the new material count differs from the original, // update all material indices
// we need to rebuild the material list and remap mesh material indexes. for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
if(iNewNum < 1) aiMesh* mesh = pScene->mMeshes[p];
throw DeadlyImportError("No materials remaining"); ai_assert(nullptr != mesh);
if (iNewNum != pScene->mNumMaterials) { mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
ai_assert(iNewNum > 0);
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
{
// if the material is not referenced ... remove it
if (!abReferenced[p]) {
continue;
}
// generate new names for modified materials that had no names
const unsigned int idx = aiMappingTable[p];
if (ppcMaterials[idx]) {
aiString sz;
if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
}
} else {
ppcMaterials[idx] = pScene->mMaterials[p];
}
}
// update all material indices
for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
aiMesh* mesh = pScene->mMeshes[p];
ai_assert(nullptr != mesh);
mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
}
// delete the old material list
delete[] pScene->mMaterials;
pScene->mMaterials = ppcMaterials;
pScene->mNumMaterials = iNewNum;
} }
// delete temporary storage // delete the old material list
delete[] aiHashes; delete[] pScene->mMaterials;
delete[] aiMappingTable; pScene->mMaterials = ppcMaterials;
pScene->mNumMaterials = iNewNum;
} }
// delete temporary storage
delete[] aiHashes;
delete[] aiMappingTable;
if (redundantRemoved == 0 && unreferencedRemoved == 0) { if (redundantRemoved == 0 && unreferencedRemoved == 0) {
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
} else { } else {