- added a new post processing step to split up meshes into submeshes with a limited number of bones.
- fixed some wording details git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@864 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
b12d8be8ca
commit
a9e96e2f9b
|
@ -257,6 +257,9 @@ using namespace Assimp::Formatter;
|
|||
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
|
||||
# include "OptimizeGraph.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS
|
||||
# include "SplitByBoneCountProcess.h"
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Intern;
|
||||
|
@ -478,6 +481,9 @@ Importer::Importer()
|
|||
#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
|
||||
pimpl->mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS)
|
||||
pimpl->mPostProcessingSteps.push_back( new SplitByBoneCountProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
|
||||
pimpl->mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle());
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2010, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/// @file SplitByBoneCountProcess.cpp
|
||||
/// Implementation of the SplitByBoneCount postprocessing step
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
// internal headers of the post-processing framework
|
||||
#include "SplitByBoneCountProcess.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
SplitByBoneCountProcess::SplitByBoneCountProcess()
|
||||
{
|
||||
// set default, might be overriden by importer config
|
||||
mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SplitByBoneCountProcess::~SplitByBoneCountProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag.
|
||||
bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return !!(pFlags & aiProcess_SplitByBoneCount);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Updates internal properties
|
||||
void SplitByBoneCountProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// ein andermal.
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void SplitByBoneCountProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
DefaultLogger::get()->debug("SplitByBoneCountProcess begin");
|
||||
|
||||
// early out
|
||||
bool isNecessary = false;
|
||||
for( size_t a = 0; a < pScene->mNumMeshes; ++a)
|
||||
if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
|
||||
isNecessary = true;
|
||||
|
||||
if( !isNecessary )
|
||||
{
|
||||
DefaultLogger::get()->debug( boost::str( boost::format( "SplitByBoneCountProcess early-out: no meshes with more than %d bones.") % mMaxBoneCount));
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to do something. Let's go.
|
||||
mSubMeshIndices.clear();
|
||||
mSubMeshIndices.resize( pScene->mNumMeshes);
|
||||
|
||||
// build a new array of meshes for the scene
|
||||
std::vector<aiMesh*> meshes;
|
||||
|
||||
for( size_t a = 0; a < pScene->mNumMeshes; ++a)
|
||||
{
|
||||
aiMesh* srcMesh = pScene->mMeshes[a];
|
||||
|
||||
std::vector<aiMesh*> newMeshes;
|
||||
SplitMesh( pScene->mMeshes[a], newMeshes);
|
||||
|
||||
// mesh was split
|
||||
if( !newMeshes.empty() )
|
||||
{
|
||||
// store new meshes and indices of the new meshes
|
||||
for( size_t b = 0; b < newMeshes.size(); ++b)
|
||||
{
|
||||
mSubMeshIndices[a].push_back( meshes.size());
|
||||
meshes.push_back( newMeshes[b]);
|
||||
}
|
||||
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
delete srcMesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||
mSubMeshIndices[a].push_back( meshes.size());
|
||||
meshes.push_back( srcMesh);
|
||||
}
|
||||
}
|
||||
|
||||
// rebuild the scene's mesh array
|
||||
pScene->mNumMeshes = meshes.size();
|
||||
delete [] pScene->mMeshes;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
|
||||
|
||||
// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
|
||||
UpdateNode( pScene->mRootNode);
|
||||
|
||||
DefaultLogger::get()->debug( boost::str( boost::format( "SplitByBoneCountProcess end: split %d meshes into %d submeshes.") % mSubMeshIndices.size() % meshes.size()));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Splits the given mesh by bone count.
|
||||
void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const
|
||||
{
|
||||
// skip if not necessary
|
||||
if( pMesh->mNumBones <= mMaxBoneCount )
|
||||
return;
|
||||
|
||||
// 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
|
||||
typedef std::pair<size_t, float> BoneWeight;
|
||||
std::vector< std::vector<BoneWeight> > vertexBones( pMesh->mNumVertices);
|
||||
for( size_t a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
for( size_t b = 0; b < bone->mNumWeights; ++b)
|
||||
vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
|
||||
}
|
||||
|
||||
size_t numFacesHandled = 0;
|
||||
std::vector<bool> isFaceHandled( pMesh->mNumFaces, false);
|
||||
while( numFacesHandled < pMesh->mNumFaces )
|
||||
{
|
||||
// which bones are used in the current submesh
|
||||
size_t numBones = 0;
|
||||
std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
|
||||
// indices of the faces which are going to go into this submesh
|
||||
std::vector<size_t> subMeshFaces;
|
||||
subMeshFaces.reserve( pMesh->mNumFaces);
|
||||
// accumulated vertex count of all the faces in this submesh
|
||||
size_t numSubMeshVertices = 0;
|
||||
|
||||
// add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit
|
||||
for( size_t a = 0; a < pMesh->mNumFaces; ++a)
|
||||
{
|
||||
// skip if the face is already stored in a submesh
|
||||
if( isFaceHandled[a] )
|
||||
continue;
|
||||
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
// check every vertex if its bones would still fit into the current submesh
|
||||
bool fitsInCurrentSubmesh = true;
|
||||
for( size_t b = 0; b < face.mNumIndices; ++b )
|
||||
{
|
||||
const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]];
|
||||
for( size_t c = 0; c < vb.size(); ++c)
|
||||
{
|
||||
// if the bone is already used in this submesh, it's ok
|
||||
if( isBoneUsed[ vb[c].first ] )
|
||||
continue;
|
||||
|
||||
// if it's not used, yet, we would need to add it. That only works
|
||||
// if we're still under the bone count limit
|
||||
if( numBones >= mMaxBoneCount )
|
||||
{
|
||||
fitsInCurrentSubmesh = false;
|
||||
break;
|
||||
} else
|
||||
{
|
||||
numBones++;
|
||||
isBoneUsed[ vb[c].first ] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !fitsInCurrentSubmesh )
|
||||
continue;
|
||||
|
||||
// store the face index and the vertex count
|
||||
subMeshFaces.push_back( a);
|
||||
numSubMeshVertices += face.mNumIndices;
|
||||
|
||||
// remember that this face is handled
|
||||
isFaceHandled[a] = true;
|
||||
numFacesHandled++;
|
||||
}
|
||||
|
||||
// create a new mesh to hold this subset of the source mesh
|
||||
aiMesh* newMesh = new aiMesh;
|
||||
if( pMesh->mName.length > 0 )
|
||||
newMesh->mName.Set( boost::str( boost::format( "%s_sub%d") % pMesh->mName.data % poNewMeshes.size()));
|
||||
newMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
||||
newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
|
||||
poNewMeshes.push_back( newMesh);
|
||||
|
||||
// create all the arrays for this mesh if the old mesh contained them
|
||||
newMesh->mNumVertices = numSubMeshVertices;
|
||||
newMesh->mNumFaces = subMeshFaces.size();
|
||||
newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
|
||||
if( pMesh->HasNormals() )
|
||||
newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
|
||||
if( pMesh->HasTangentsAndBitangents() )
|
||||
{
|
||||
newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
|
||||
newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices];
|
||||
}
|
||||
for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
|
||||
{
|
||||
if( pMesh->HasTextureCoords( a) )
|
||||
newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
|
||||
newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
|
||||
}
|
||||
for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
|
||||
{
|
||||
if( pMesh->HasVertexColors( a) )
|
||||
newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
|
||||
}
|
||||
|
||||
// and copy over the data, generating faces with linear indices along the way
|
||||
newMesh->mFaces = new aiFace[subMeshFaces.size()];
|
||||
size_t nvi = 0; // next vertex index
|
||||
std::vector<size_t> previousVertexIndices( numSubMeshVertices, SIZE_MAX); // per new vertex: its index in the source mesh
|
||||
for( size_t a = 0; a < subMeshFaces.size(); ++a )
|
||||
{
|
||||
const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
|
||||
aiFace& dstFace = newMesh->mFaces[a];
|
||||
dstFace.mNumIndices = srcFace.mNumIndices;
|
||||
dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
|
||||
|
||||
// accumulate linearly all the vertices of the source face
|
||||
for( size_t b = 0; b < dstFace.mNumIndices; ++b )
|
||||
{
|
||||
size_t srcIndex = srcFace.mIndices[b];
|
||||
dstFace.mIndices[b] = nvi;
|
||||
previousVertexIndices[nvi] = srcIndex;
|
||||
|
||||
newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
|
||||
if( pMesh->HasNormals() )
|
||||
newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
|
||||
if( pMesh->HasTangentsAndBitangents() )
|
||||
{
|
||||
newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
|
||||
newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
|
||||
}
|
||||
for( size_t c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
|
||||
{
|
||||
if( pMesh->HasTextureCoords( c) )
|
||||
newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
|
||||
}
|
||||
for( size_t c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
|
||||
{
|
||||
if( pMesh->HasVertexColors( c) )
|
||||
newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
|
||||
}
|
||||
|
||||
nvi++;
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert( nvi == numSubMeshVertices );
|
||||
|
||||
// Create the bones for the new submesh: first create the bone array
|
||||
newMesh->mNumBones = 0;
|
||||
newMesh->mBones = new aiBone*[numBones];
|
||||
|
||||
std::vector<size_t> mappedBoneIndex( pMesh->mNumBones, SIZE_MAX);
|
||||
for( size_t a = 0; a < pMesh->mNumBones; ++a )
|
||||
{
|
||||
if( !isBoneUsed[a] )
|
||||
continue;
|
||||
|
||||
// create the new bone
|
||||
const aiBone* srcBone = pMesh->mBones[a];
|
||||
aiBone* dstBone = new aiBone;
|
||||
mappedBoneIndex[a] = newMesh->mNumBones;
|
||||
newMesh->mBones[newMesh->mNumBones++] = dstBone;
|
||||
dstBone->mName = srcBone->mName;
|
||||
dstBone->mOffsetMatrix = srcBone->mOffsetMatrix;
|
||||
dstBone->mNumWeights = 0;
|
||||
}
|
||||
|
||||
ai_assert( newMesh->mNumBones == numBones );
|
||||
|
||||
// iterate over all new vertices and count which bones affected its old vertex in the source mesh
|
||||
for( size_t a = 0; a < numSubMeshVertices; ++a )
|
||||
{
|
||||
size_t oldIndex = previousVertexIndices[a];
|
||||
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex];
|
||||
|
||||
for( size_t b = 0; b < bonesOnThisVertex.size(); ++b )
|
||||
{
|
||||
size_t newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
|
||||
if( newBoneIndex != SIZE_MAX )
|
||||
newMesh->mBones[newBoneIndex]->mNumWeights++;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate all bone weight arrays accordingly
|
||||
for( size_t a = 0; a < newMesh->mNumBones; ++a )
|
||||
{
|
||||
aiBone* bone = newMesh->mBones[a];
|
||||
ai_assert( bone->mNumWeights > 0 );
|
||||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
bone->mNumWeights = 0; // for counting up in the next step
|
||||
}
|
||||
|
||||
// now copy all the bone vertex weights for all the vertices which made it into the new submesh
|
||||
for( size_t a = 0; a < numSubMeshVertices; ++a)
|
||||
{
|
||||
// find the source vertex for it in the source mesh
|
||||
size_t previousIndex = previousVertexIndices[a];
|
||||
// these bones were affecting it
|
||||
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex];
|
||||
// all of the bones affecting it should be present in the new submesh, or else
|
||||
// the face it comprises shouldn't be present
|
||||
for( size_t b = 0; b < bonesOnThisVertex.size(); ++b)
|
||||
{
|
||||
size_t newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
|
||||
ai_assert( newBoneIndex != SIZE_MAX );
|
||||
aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights;
|
||||
newMesh->mBones[newBoneIndex]->mNumWeights++;
|
||||
|
||||
dstWeight->mVertexId = a;
|
||||
dstWeight->mWeight = bonesOnThisVertex[b].second;
|
||||
}
|
||||
}
|
||||
|
||||
// I have the strange feeling that this will break apart at some point in time...
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const
|
||||
{
|
||||
// rebuild the node's mesh index list
|
||||
if( pNode->mNumMeshes > 0 )
|
||||
{
|
||||
std::vector<size_t> newMeshList;
|
||||
for( size_t a = 0; a < pNode->mNumMeshes; ++a)
|
||||
{
|
||||
size_t srcIndex = pNode->mMeshes[a];
|
||||
const std::vector<size_t>& replaceMeshes = mSubMeshIndices[srcIndex];
|
||||
newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
|
||||
}
|
||||
|
||||
delete pNode->mMeshes;
|
||||
pNode->mNumMeshes = newMeshList.size();
|
||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||
std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
|
||||
}
|
||||
|
||||
// do that also recursively for all children
|
||||
for( size_t a = 0; a < pNode->mNumChildren; ++a )
|
||||
{
|
||||
UpdateNode( pNode->mChildren[a]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2010, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/// @file SplitByBoneCountProcess.h
|
||||
/// Defines a post processing step to split meshes with many bones into submeshes
|
||||
#ifndef AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
#define AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
|
||||
#include <vector>
|
||||
#include "BaseProcess.h"
|
||||
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// NOTE: If you change these limits, don't forget to change the
|
||||
// corresponding values in all Assimp ports
|
||||
|
||||
// **********************************************************
|
||||
// Java: ConfigProperty.java,
|
||||
// ConfigProperty.DEFAULT_VERTEX_SPLIT_LIMIT
|
||||
// ConfigProperty.DEFAULT_TRIANGLE_SPLIT_LIMIT
|
||||
// **********************************************************
|
||||
|
||||
// default limit for bone count
|
||||
#if (!defined AI_SBBC_DEFAULT_MAX_BONES)
|
||||
# define AI_SBBC_DEFAULT_MAX_BONES 60
|
||||
#endif
|
||||
|
||||
/** Postprocessing filter to split meshes with many bones into submeshes
|
||||
* so that each submesh has a certain max bone count.
|
||||
*
|
||||
* Applied BEFORE the JoinVertices-Step occurs.
|
||||
* Returns NON-UNIQUE vertices, splits by bone count.
|
||||
*/
|
||||
class ASSIMP_API SplitByBoneCountProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
|
||||
protected:
|
||||
/** Constructor to be privately used by Importer */
|
||||
SplitByBoneCountProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~SplitByBoneCountProcess();
|
||||
|
||||
public:
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @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;
|
||||
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
|
||||
protected:
|
||||
/** 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);
|
||||
|
||||
/// Splits the given mesh by bone count.
|
||||
/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
|
||||
/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
|
||||
void SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const;
|
||||
|
||||
/// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void UpdateNode( aiNode* pNode) const;
|
||||
|
||||
public:
|
||||
/// Max bone count. Splitting occurs if a mesh has more than that number of bones.
|
||||
size_t mMaxBoneCount;
|
||||
|
||||
/// Per mesh index: Array of indices of the new submeshes.
|
||||
std::vector< std::vector<size_t> > mSubMeshIndices;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC
|
|
@ -516,8 +516,7 @@ struct aiMesh
|
|||
* point or line primitives are undefined and set to qNaN. See
|
||||
* the #mNormals member for a detailled discussion of qNaNs.
|
||||
* @note If the mesh contains tangents, it automatically also
|
||||
* contains bitangents (the bitangent is just the cross product of
|
||||
* tangent and normal vectors).
|
||||
* contains bitangents.
|
||||
*/
|
||||
C_STRUCT aiVector3D* mTangents;
|
||||
|
||||
|
@ -626,6 +625,8 @@ struct aiMesh
|
|||
mColors[a] = NULL;
|
||||
mNumBones = 0; mBones = NULL;
|
||||
mMaterialIndex = 0;
|
||||
mNumAnimMeshes = 0;
|
||||
mAnimMeshes = NULL;
|
||||
}
|
||||
|
||||
//! Deletes all storage allocated for the mesh
|
||||
|
|
|
@ -494,7 +494,13 @@ enum aiPostProcessSteps
|
|||
* x1
|
||||
* @endcode
|
||||
*/
|
||||
aiProcess_FlipWindingOrder = 0x1000000
|
||||
aiProcess_FlipWindingOrder = 0x1000000,
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
/** <hr>This step splits meshes with many bones into submeshes so that each
|
||||
* submesh has fewer or as many bones as a given limit.
|
||||
*/
|
||||
aiProcess_SplitByBoneCount = 0x2000000
|
||||
|
||||
// aiProcess_GenEntityMeshes = 0x100000,
|
||||
// aiProcess_OptimizeAnimations = 0x200000
|
||||
|
|
|
@ -261,7 +261,7 @@ struct aiString
|
|||
}
|
||||
|
||||
/** Constructor from std::string */
|
||||
aiString(const std::string& pString) :
|
||||
explicit aiString(const std::string& pString) :
|
||||
length(pString.length())
|
||||
{
|
||||
length = length>=MAXLEN?MAXLEN-1:length;
|
||||
|
|
|
@ -89,6 +89,7 @@ unsigned int ppsteps = aiProcess_CalcTangentSpace | // calculate tangents and bi
|
|||
aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master
|
||||
aiProcess_LimitBoneWeights | // limit bone weights to 4 per vertex
|
||||
aiProcess_OptimizeMeshes | // join small meshes, if possible;
|
||||
aiProcess_SplitByBoneCount | // split meshes with too many bones. Necessary for our (limited) hardware skinning shader
|
||||
0;
|
||||
|
||||
unsigned int ppstepsdefault = ppsteps;
|
||||
|
|
|
@ -2090,6 +2090,14 @@
|
|||
RelativePath="..\..\code\SortByPTypeProcess.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SplitByBoneCountProcess.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SplitByBoneCountProcess.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SplitLargeMeshes.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue