|
@@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
|
#include "LimitBoneWeightsProcess.h"
|
|
|
+#include <assimp/SmallVector.h>
|
|
|
#include <assimp/StringUtils.h>
|
|
|
#include <assimp/postprocess.h>
|
|
|
#include <assimp/DefaultLogger.hpp>
|
|
@@ -52,7 +53,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
using namespace Assimp;
|
|
|
|
|
|
-
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
// Constructor to be privately used by Importer
|
|
|
LimitBoneWeightsProcess::LimitBoneWeightsProcess()
|
|
@@ -76,10 +76,12 @@ bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
// Executes the post processing step on the given imported data.
|
|
|
-void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
|
|
|
+void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
|
|
+{
|
|
|
ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
|
|
|
- for (unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
|
|
|
- ProcessMesh(pScene->mMeshes[a]);
|
|
|
+
|
|
|
+ for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
|
|
|
+ ProcessMesh(pScene->mMeshes[m]);
|
|
|
}
|
|
|
|
|
|
ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
|
|
@@ -95,107 +97,96 @@ void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
// Unites identical vertices in the given mesh
|
|
|
-void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
|
|
|
+void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh)
|
|
|
{
|
|
|
- if( !pMesh->HasBones())
|
|
|
+ if (!pMesh->HasBones())
|
|
|
return;
|
|
|
|
|
|
// collect all bone weights per vertex
|
|
|
- typedef std::vector< std::vector< Weight > > WeightsPerVertex;
|
|
|
- WeightsPerVertex vertexWeights( pMesh->mNumVertices);
|
|
|
+ typedef SmallVector<Weight,8> VertexWeightArray;
|
|
|
+ typedef std::vector<VertexWeightArray> WeightsPerVertex;
|
|
|
+ WeightsPerVertex vertexWeights(pMesh->mNumVertices);
|
|
|
+ size_t maxVertexWeights = 0;
|
|
|
|
|
|
- // collect all weights per vertex
|
|
|
- for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
|
|
+ for (unsigned int b = 0; b < pMesh->mNumBones; ++b)
|
|
|
{
|
|
|
- const aiBone* bone = pMesh->mBones[a];
|
|
|
- for( unsigned int b = 0; b < bone->mNumWeights; b++)
|
|
|
+ const aiBone* bone = pMesh->mBones[b];
|
|
|
+ for (unsigned int w = 0; w < bone->mNumWeights; ++w)
|
|
|
{
|
|
|
- const aiVertexWeight& w = bone->mWeights[b];
|
|
|
- vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight));
|
|
|
+ const aiVertexWeight& vw = bone->mWeights[w];
|
|
|
+ vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight));
|
|
|
+ maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (maxVertexWeights <= mMaxWeights)
|
|
|
+ return;
|
|
|
+
|
|
|
unsigned int removed = 0, old_bones = pMesh->mNumBones;
|
|
|
|
|
|
// now cut the weight count if it exceeds the maximum
|
|
|
- bool bChanged = false;
|
|
|
- for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
|
|
|
+ for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
|
|
|
{
|
|
|
- if( vit->size() <= mMaxWeights)
|
|
|
+ if (vit->size() <= mMaxWeights)
|
|
|
continue;
|
|
|
|
|
|
- bChanged = true;
|
|
|
-
|
|
|
// more than the defined maximum -> first sort by weight in descending order. That's
|
|
|
// why we defined the < operator in such a weird way.
|
|
|
- std::sort( vit->begin(), vit->end());
|
|
|
+ std::sort(vit->begin(), vit->end());
|
|
|
|
|
|
// now kill everything beyond the maximum count
|
|
|
unsigned int m = static_cast<unsigned int>(vit->size());
|
|
|
- vit->erase( vit->begin() + mMaxWeights, vit->end());
|
|
|
- removed += static_cast<unsigned int>(m-vit->size());
|
|
|
+ vit->resize(mMaxWeights);
|
|
|
+ removed += static_cast<unsigned int>(m - vit->size());
|
|
|
|
|
|
// and renormalize the weights
|
|
|
float sum = 0.0f;
|
|
|
- for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it ) {
|
|
|
+ for(const Weight* it = vit->begin(); it != vit->end(); ++it) {
|
|
|
sum += it->mWeight;
|
|
|
}
|
|
|
- if( 0.0f != sum ) {
|
|
|
+ if (0.0f != sum) {
|
|
|
const float invSum = 1.0f / sum;
|
|
|
- for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it ) {
|
|
|
+ for(Weight* it = vit->begin(); it != vit->end(); ++it) {
|
|
|
it->mWeight *= invSum;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (bChanged) {
|
|
|
- // rebuild the vertex weight array for all bones
|
|
|
- typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone;
|
|
|
- WeightsPerBone boneWeights( pMesh->mNumBones);
|
|
|
- for( unsigned int a = 0; a < vertexWeights.size(); a++)
|
|
|
+ // clear weight count for all bone
|
|
|
+ for (unsigned int a = 0; a < pMesh->mNumBones; ++a)
|
|
|
+ {
|
|
|
+ pMesh->mBones[a]->mNumWeights = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // rebuild the vertex weight array for all bones
|
|
|
+ for (unsigned int a = 0; a < vertexWeights.size(); ++a)
|
|
|
+ {
|
|
|
+ const VertexWeightArray& vw = vertexWeights[a];
|
|
|
+ for (const Weight* it = vw.begin(); it != vw.end(); ++it)
|
|
|
{
|
|
|
- const std::vector<Weight>& vw = vertexWeights[a];
|
|
|
- for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it)
|
|
|
- boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight));
|
|
|
+ aiBone* bone = pMesh->mBones[it->mBone];
|
|
|
+ bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // and finally copy the vertex weight list over to the mesh's bones
|
|
|
- std::vector<bool> abNoNeed(pMesh->mNumBones,false);
|
|
|
- bChanged = false;
|
|
|
+ // remove empty bones
|
|
|
+ unsigned int writeBone = 0;
|
|
|
|
|
|
- for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
|
|
+ for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone)
|
|
|
+ {
|
|
|
+ aiBone* bone = pMesh->mBones[readBone];
|
|
|
+ if (bone->mNumWeights > 0)
|
|
|
{
|
|
|
- const std::vector<aiVertexWeight>& bw = boneWeights[a];
|
|
|
- aiBone* bone = pMesh->mBones[a];
|
|
|
-
|
|
|
- if ( bw.empty() )
|
|
|
- {
|
|
|
- abNoNeed[a] = bChanged = true;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // copy the weight list. should always be less weights than before, so we don't need a new allocation
|
|
|
- ai_assert( bw.size() <= bone->mNumWeights);
|
|
|
- bone->mNumWeights = static_cast<unsigned int>( bw.size() );
|
|
|
- ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
|
|
|
+ pMesh->mBones[writeBone++] = bone;
|
|
|
}
|
|
|
-
|
|
|
- if (bChanged) {
|
|
|
- // the number of new bones is smaller than before, so we can reuse the old array
|
|
|
- aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur;
|
|
|
-
|
|
|
- for (std::vector<bool>::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) {
|
|
|
- if (*iter) {
|
|
|
- delete *ppcSrc;
|
|
|
- --pMesh->mNumBones;
|
|
|
- }
|
|
|
- else *ppcCur++ = *ppcSrc;
|
|
|
- ++ppcSrc;
|
|
|
- }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ delete bone;
|
|
|
}
|
|
|
+ }
|
|
|
+ pMesh->mNumBones = writeBone;
|
|
|
|
|
|
- if (!DefaultLogger::isNullLogger()) {
|
|
|
- ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones );
|
|
|
- }
|
|
|
+ if (!DefaultLogger::isNullLogger()) {
|
|
|
+ ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);
|
|
|
}
|
|
|
}
|