Merge branch 'master' into gltf2_broken_bones_count

pull/3039/head
Kim Kulling 2020-03-03 11:33:56 +01:00 committed by GitHub
commit 0b227219b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 40 additions and 0 deletions

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits> #include <limits>
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/Exceptional.h>
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
@ -94,7 +95,10 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
bool isNecessary = false; bool isNecessary = false;
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
{
isNecessary = true; isNecessary = true;
break;
}
if( !isNecessary ) if( !isNecessary )
{ {
@ -155,7 +159,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
{ {
// skip if not necessary // skip if not necessary
if( pMesh->mNumBones <= mMaxBoneCount ) if( pMesh->mNumBones <= mMaxBoneCount )
{
return; return;
}
// necessary optimisation: build a list of all affecting bones for each vertex // necessary optimisation: build a list of all affecting bones for each vertex
// TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
@ -165,8 +171,10 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
{ {
const aiBone* bone = pMesh->mBones[a]; const aiBone* bone = pMesh->mBones[a];
for( unsigned int b = 0; b < bone->mNumWeights; ++b) for( unsigned int b = 0; b < bone->mNumWeights; ++b)
{
vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight)); vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
} }
}
unsigned int numFacesHandled = 0; unsigned int numFacesHandled = 0;
std::vector<bool> isFaceHandled( pMesh->mNumFaces, false); std::vector<bool> isFaceHandled( pMesh->mNumFaces, false);
@ -189,7 +197,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
{ {
// skip if the face is already stored in a submesh // skip if the face is already stored in a submesh
if( isFaceHandled[a] ) if( isFaceHandled[a] )
{
continue; continue;
}
const aiFace& face = pMesh->mFaces[a]; const aiFace& face = pMesh->mFaces[a];
// check every vertex if its bones would still fit into the current submesh // check every vertex if its bones would still fit into the current submesh
@ -201,17 +211,27 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
unsigned int boneIndex = vb[c].first; unsigned int boneIndex = vb[c].first;
// if the bone is already used in this submesh, it's ok // if the bone is already used in this submesh, it's ok
if( isBoneUsed[boneIndex] ) if( isBoneUsed[boneIndex] )
{
continue; continue;
}
// if it's not used, yet, we would need to add it. Store its bone index // if it's not used, yet, we would need to add it. Store its bone index
if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() ) if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() )
{
newBonesAtCurrentFace.push_back( boneIndex); newBonesAtCurrentFace.push_back( boneIndex);
} }
} }
}
if (newBonesAtCurrentFace.size() > mMaxBoneCount)
{
throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
}
// leave out the face if the new bones required for this face don't fit the bone count limit anymore // leave out the face if the new bones required for this face don't fit the bone count limit anymore
if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
{
continue; continue;
}
// mark all new bones as necessary // mark all new bones as necessary
while( !newBonesAtCurrentFace.empty() ) while( !newBonesAtCurrentFace.empty() )
@ -219,7 +239,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
unsigned int newIndex = newBonesAtCurrentFace.back(); unsigned int newIndex = newBonesAtCurrentFace.back();
newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear() newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear()
if( isBoneUsed[newIndex] ) if( isBoneUsed[newIndex] )
{
continue; continue;
}
isBoneUsed[newIndex] = true; isBoneUsed[newIndex] = true;
numBones++; numBones++;
@ -237,7 +259,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
// create a new mesh to hold this subset of the source mesh // create a new mesh to hold this subset of the source mesh
aiMesh* newMesh = new aiMesh; aiMesh* newMesh = new aiMesh;
if( pMesh->mName.length > 0 ) if( pMesh->mName.length > 0 )
{
newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size()); newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
}
newMesh->mMaterialIndex = pMesh->mMaterialIndex; newMesh->mMaterialIndex = pMesh->mMaterialIndex;
newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
poNewMeshes.push_back( newMesh); poNewMeshes.push_back( newMesh);
@ -247,7 +271,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size()); newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
newMesh->mVertices = new aiVector3D[newMesh->mNumVertices]; newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
if( pMesh->HasNormals() ) if( pMesh->HasNormals() )
{
newMesh->mNormals = new aiVector3D[newMesh->mNumVertices]; newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
}
if( pMesh->HasTangentsAndBitangents() ) if( pMesh->HasTangentsAndBitangents() )
{ {
newMesh->mTangents = new aiVector3D[newMesh->mNumVertices]; newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
@ -256,14 +282,18 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
{ {
if( pMesh->HasTextureCoords( a) ) if( pMesh->HasTextureCoords( a) )
{
newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices]; newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
}
newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
} }
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
{ {
if( pMesh->HasVertexColors( a) ) if( pMesh->HasVertexColors( a) )
{
newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices]; newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
} }
}
// and copy over the data, generating faces with linear indices along the way // and copy over the data, generating faces with linear indices along the way
newMesh->mFaces = new aiFace[subMeshFaces.size()]; newMesh->mFaces = new aiFace[subMeshFaces.size()];
@ -285,7 +315,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
if( pMesh->HasNormals() ) if( pMesh->HasNormals() )
{
newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
}
if( pMesh->HasTangentsAndBitangents() ) if( pMesh->HasTangentsAndBitangents() )
{ {
newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
@ -294,13 +326,17 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
{ {
if( pMesh->HasTextureCoords( c) ) if( pMesh->HasTextureCoords( c) )
{
newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
} }
}
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
{ {
if( pMesh->HasVertexColors( c) ) if( pMesh->HasVertexColors( c) )
{
newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
} }
}
nvi++; nvi++;
} }
@ -316,7 +352,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
{ {
if( !isBoneUsed[a] ) if( !isBoneUsed[a] )
{
continue; continue;
}
// create the new bone // create the new bone
const aiBone* srcBone = pMesh->mBones[a]; const aiBone* srcBone = pMesh->mBones[a];
@ -340,9 +378,11 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
{ {
unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
if( newBoneIndex != std::numeric_limits<unsigned int>::max() ) if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
{
newMesh->mBones[newBoneIndex]->mNumWeights++; newMesh->mBones[newBoneIndex]->mNumWeights++;
} }
} }
}
// allocate all bone weight arrays accordingly // allocate all bone weight arrays accordingly
for( unsigned int a = 0; a < newMesh->mNumBones; ++a ) for( unsigned int a = 0; a < newMesh->mNumBones; ++a )