- added a post processing step to limit the bone count per vertex
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@56 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
a40ac4eace
commit
492aa8358b
|
@ -89,6 +89,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "KillNormalsProcess.h"
|
||||
#include "SplitLargeMeshes.h"
|
||||
#include "PretransformVertices.h"
|
||||
#include "LimitBoneWeightsProcess.h"
|
||||
#include "../include/DefaultLogger.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -143,6 +144,7 @@ Importer::Importer() :
|
|||
mPostProcessingSteps.push_back( new JoinVerticesProcess());
|
||||
mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex());
|
||||
mPostProcessingSteps.push_back( new ConvertToLHProcess());
|
||||
mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/** Implementation of the LimitBoneWeightsProcess post processing step */
|
||||
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include "LimitBoneWeightsProcess.h"
|
||||
#include "../include/aiPostProcess.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
LimitBoneWeightsProcess::LimitBoneWeightsProcess()
|
||||
{
|
||||
// TODO: (thom) make this configurable from somewhere?
|
||||
mMaxWeights = 4;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
LimitBoneWeightsProcess::~LimitBoneWeightsProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_LimitBoneWeights) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
ProcessMesh( pScene->mMeshes[a]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Unites identical vertices in the given mesh
|
||||
void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
if( !pMesh->HasBones())
|
||||
return;
|
||||
|
||||
// collect all bone weights per vertex
|
||||
typedef std::vector< std::vector< Weight > > WeightsPerVertex;
|
||||
WeightsPerVertex vertexWeights( pMesh->mNumVertices);
|
||||
|
||||
// collect all weights per vertex
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
||||
{
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
for( unsigned int b = 0; b < bone->mNumWeights; b++)
|
||||
{
|
||||
const aiVertexWeight& w = bone->mWeights[b];
|
||||
vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight));
|
||||
}
|
||||
}
|
||||
|
||||
// now cut the weight count if it exceeds the maximum
|
||||
for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
|
||||
{
|
||||
if( vit->size() <= mMaxWeights)
|
||||
continue;
|
||||
|
||||
// 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());
|
||||
|
||||
// now kill everything beyond the maximum count
|
||||
vit->erase( vit->begin() + mMaxWeights, vit->end());
|
||||
|
||||
// and renormalize the weights
|
||||
float sum = 0.0f;
|
||||
for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it)
|
||||
sum += it->mWeight;
|
||||
for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it)
|
||||
it->mWeight /= sum;
|
||||
}
|
||||
|
||||
// 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++)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
// and finally copy the vertex weight list over to the mesh's bones
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
||||
{
|
||||
const std::vector<aiVertexWeight>& bw = boneWeights[a];
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
// ignore the bone if no vertex weights were removed there
|
||||
if( bw.size() == bone->mNumWeights)
|
||||
continue;
|
||||
|
||||
// copy the weight list. should always be less weights than before, so we don't need a new allocation
|
||||
assert( bw.size() < bone->mNumWeights);
|
||||
bone->mNumWeights = (unsigned int) bw.size();
|
||||
memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/** Defines a post processing step to limit the number of bones affecting a single vertex. */
|
||||
#ifndef AI_LIMITBONEWEIGHTSPROCESS_H_INC
|
||||
#define AI_LIMITBONEWEIGHTSPROCESS_H_INC
|
||||
|
||||
#include "BaseProcess.h"
|
||||
|
||||
struct aiMesh;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** This post processing step limits the number of bones affecting a vertex
|
||||
* to a certain maximum value. If a vertex is affected by more than that number
|
||||
* of bones, the bone weight with the least influence on this vertex are removed.
|
||||
* The other weights on this bone are then renormalized to assure the sum weight
|
||||
* to be 1.
|
||||
*/
|
||||
class LimitBoneWeightsProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
|
||||
protected:
|
||||
/** Constructor to be privately used by Importer */
|
||||
LimitBoneWeightsProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~LimitBoneWeightsProcess();
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
* @param pFlags The processing flags the importer was called with. A bitwise
|
||||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
// -------------------------------------------------------------------
|
||||
/** Limits the bone weight count for all vertices in the given mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
*/
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
|
||||
protected:
|
||||
/** Describes a bone weight on a vertex */
|
||||
struct Weight
|
||||
{
|
||||
unsigned int mBone; ///< Index of the bone
|
||||
float mWeight; ///< Weight of that bone on this vertex
|
||||
Weight() { }
|
||||
Weight( unsigned int pBone, float pWeight) { mBone = pBone; mWeight = pWeight; }
|
||||
/** Comparision operator to sort bone weights by descending weight */
|
||||
bool operator < (const Weight& pWeight) const { return mWeight > pWeight.mWeight; }
|
||||
};
|
||||
|
||||
/** Maximum number of bones influencing any single vertex. */
|
||||
unsigned int mMaxWeights;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_LIMITBONEWEIGHTSPROCESS_H_INC
|
|
@ -79,7 +79,7 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
|||
else if( strncmp( P + 8, "bin ", 4) == 0)
|
||||
mIsBinaryFormat = true;
|
||||
else
|
||||
ThrowException( "Unsupported xfile format");
|
||||
ThrowException( boost::str( boost::format( "Unsupported xfile format '%c%c%c%c'") % P[8] % P[9] % P[10] % P[11]));
|
||||
|
||||
// float size
|
||||
mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000
|
||||
|
|
|
@ -125,6 +125,17 @@ enum aiPostProcessSteps
|
|||
* the normal list will be zeroed.
|
||||
*/
|
||||
aiProcess_PreTransformVertices = 0x100,
|
||||
|
||||
/** Limits the number of bones simultaneously affecting a single vertex
|
||||
* to a maximum value. If any vertex is affected by more than that number
|
||||
* of bones, the least important vertex weights are removed and the remaining
|
||||
* vertex weights are renormalized so that the weights still sum up to 1.
|
||||
* At the moment the maximum bone count is hardcoded to 4.
|
||||
*
|
||||
* If you intend to perform the skinning in hardware, this post processing step
|
||||
* might be of interest for you.
|
||||
*/
|
||||
aiProcess_LimitBoneWeights = 0x200
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
RuntimeLibrary="1"
|
||||
EnableFunctionLevelLinking="true"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
|
@ -1012,6 +1013,10 @@
|
|||
RelativePath="..\..\code\KillNormalsProcess.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\LimitBoneWeightsProcess.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\MaterialSystem.h"
|
||||
>
|
||||
|
@ -1300,6 +1305,10 @@
|
|||
RelativePath="..\..\code\KillNormalsProcess.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\LimitBoneWeightsProcess.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\MaterialSystem.cpp"
|
||||
>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
|
|
Loading…
Reference in New Issue