The "SplitLargeMeshes"-Process handles bones correctly now. Added Unittest for it and fixed some minor details.
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@73 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
0209fba554
commit
76ebdecd7a
|
@ -234,6 +234,56 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pMesh->HasBones())
|
||||||
|
{
|
||||||
|
// assume the number of bones won't change in most cases
|
||||||
|
pcMesh->mBones = new aiBone*[pMesh->mNumBones];
|
||||||
|
|
||||||
|
// iterate through all bones of the mesh and find those which
|
||||||
|
// need to be copied to the splitted mesh
|
||||||
|
std::vector<aiVertexWeight> avTempWeights;
|
||||||
|
for (unsigned int p = 0; p < pcMesh->mNumBones;++p)
|
||||||
|
{
|
||||||
|
aiBone* const bone = pcMesh->mBones[p];
|
||||||
|
avTempWeights.clear();
|
||||||
|
avTempWeights.reserve(bone->mNumWeights / iSubMeshes);
|
||||||
|
|
||||||
|
for (unsigned int q = 0; q < bone->mNumWeights;++q)
|
||||||
|
{
|
||||||
|
aiVertexWeight& weight = bone->mWeights[q];
|
||||||
|
if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum)
|
||||||
|
{
|
||||||
|
avTempWeights.push_back(weight);
|
||||||
|
weight = avTempWeights.back();
|
||||||
|
weight.mVertexId -= iBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!avTempWeights.empty())
|
||||||
|
{
|
||||||
|
// we'll need this bone. Copy it ...
|
||||||
|
aiBone* pc = new aiBone();
|
||||||
|
pcMesh->mBones[pcMesh->mNumBones++] = pc;
|
||||||
|
pc->mName = aiString(bone->mName);
|
||||||
|
pc->mNumWeights = avTempWeights.size();
|
||||||
|
pc->mOffsetMatrix = bone->mOffsetMatrix;
|
||||||
|
|
||||||
|
// no need to reallocate the array for the last submesh.
|
||||||
|
// Here we can reuse the (large) source array, although
|
||||||
|
// we'll waste some memory
|
||||||
|
if (iSubMeshes-1 == i)
|
||||||
|
{
|
||||||
|
pc->mWeights = bone->mWeights;
|
||||||
|
bone->mWeights = NULL;
|
||||||
|
}
|
||||||
|
else pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
||||||
|
|
||||||
|
// copy the weights
|
||||||
|
::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// (we will also need to copy the array of indices)
|
// (we will also need to copy the array of indices)
|
||||||
unsigned int iCurrent = 0;
|
unsigned int iCurrent = 0;
|
||||||
for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
|
for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
|
||||||
|
@ -356,6 +406,25 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
||||||
{
|
{
|
||||||
if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT)
|
if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT)
|
||||||
{
|
{
|
||||||
|
typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable;
|
||||||
|
VertexWeightTable* avPerVertexWeights = NULL;
|
||||||
|
|
||||||
|
// build a per-vertex weight list if necessary
|
||||||
|
if (pMesh->HasBones())
|
||||||
|
{
|
||||||
|
avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
|
||||||
|
for (unsigned int i = 0; i < pMesh->mNumBones;++i)
|
||||||
|
{
|
||||||
|
aiBone* bone = pMesh->mBones[i];
|
||||||
|
for (unsigned int a = 0; a < bone->mNumWeights;++a)
|
||||||
|
{
|
||||||
|
aiVertexWeight& weight = bone->mWeights[a];
|
||||||
|
avPerVertexWeights[weight.mVertexId].push_back(
|
||||||
|
std::pair<unsigned int,float>(a,weight.mWeight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we need to split this mesh into sub meshes
|
// we need to split this mesh into sub meshes
|
||||||
// determine the estimated size of a submesh
|
// determine the estimated size of a submesh
|
||||||
// (this could be too large. Max waste is a single digit percentage)
|
// (this could be too large. Max waste is a single digit percentage)
|
||||||
|
@ -382,6 +451,13 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
||||||
pcMesh->mNumVertices = 0;
|
pcMesh->mNumVertices = 0;
|
||||||
pcMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
pcMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
||||||
|
|
||||||
|
typedef std::vector<aiVertexWeight> BoneWeightList;
|
||||||
|
if (pMesh->HasBones())
|
||||||
|
{
|
||||||
|
pcMesh->mBones = new aiBone*[pMesh->mNumBones];
|
||||||
|
::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones);
|
||||||
|
}
|
||||||
|
|
||||||
// clear the temporary helper array
|
// clear the temporary helper array
|
||||||
if (0 != iBase)
|
if (0 != iBase)
|
||||||
{
|
{
|
||||||
|
@ -491,7 +567,28 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
||||||
pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
|
pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// check whether we have bone weights assigned to this vertex
|
||||||
rFace.mIndices[v] = pcMesh->mNumVertices;
|
rFace.mIndices[v] = pcMesh->mNumVertices;
|
||||||
|
if (avPerVertexWeights)
|
||||||
|
{
|
||||||
|
VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ];
|
||||||
|
if( !table.empty() )
|
||||||
|
{
|
||||||
|
for (VertexWeightTable::const_iterator
|
||||||
|
iter = table.begin();
|
||||||
|
iter != table.end();++iter)
|
||||||
|
{
|
||||||
|
// allocate the bone weight array if necessary
|
||||||
|
BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first];
|
||||||
|
if (!pcWeightList)
|
||||||
|
{
|
||||||
|
pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList());
|
||||||
|
}
|
||||||
|
pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
avWasCopied[iIndex] = pcMesh->mNumVertices;
|
avWasCopied[iIndex] = pcMesh->mNumVertices;
|
||||||
pcMesh->mNumVertices++;
|
pcMesh->mNumVertices++;
|
||||||
}
|
}
|
||||||
|
@ -502,6 +599,36 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check which bones we'll need to create for this submesh
|
||||||
|
if (pMesh->HasBones())
|
||||||
|
{
|
||||||
|
aiBone** ppCurrent = pcMesh->mBones;
|
||||||
|
for (unsigned int k = 0; k < pMesh->mNumBones;++k)
|
||||||
|
{
|
||||||
|
// check whether the bone is existing
|
||||||
|
BoneWeightList* pcWeightList;
|
||||||
|
if (pcWeightList = (BoneWeightList*)pcMesh->mBones[k])
|
||||||
|
{
|
||||||
|
aiBone* pcOldBone = pMesh->mBones[k];
|
||||||
|
aiBone* pcOut;
|
||||||
|
*ppCurrent++ = pcOut = new aiBone();
|
||||||
|
pcOut->mName = aiString(pcOldBone->mName);
|
||||||
|
pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
|
||||||
|
pcOut->mNumWeights = pcWeightList->size();
|
||||||
|
pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
|
||||||
|
|
||||||
|
// copy the vertex weights
|
||||||
|
::memcpy(pcOut->mWeights,&pcWeightList->operator[](0),
|
||||||
|
pcOut->mNumWeights * sizeof(aiVertexWeight));
|
||||||
|
|
||||||
|
// delete the temporary bone weight list
|
||||||
|
delete pcWeightList;
|
||||||
|
pcMesh->mNumBones++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// copy the face list to the mesh
|
// copy the face list to the mesh
|
||||||
pcMesh->mFaces = new aiFace[vFaces.size()];
|
pcMesh->mFaces = new aiFace[vFaces.size()];
|
||||||
pcMesh->mNumFaces = (unsigned int)vFaces.size();
|
pcMesh->mNumFaces = (unsigned int)vFaces.size();
|
||||||
|
@ -519,6 +646,9 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete the per-vertex weight list again
|
||||||
|
delete[] avPerVertexWeights;
|
||||||
|
|
||||||
// now delete the old mesh data
|
// now delete the old mesh data
|
||||||
delete pMesh;
|
delete pMesh;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "../include/aiMesh.h"
|
#include "../include/aiMesh.h"
|
||||||
#include "../include/aiScene.h"
|
#include "../include/aiScene.h"
|
||||||
|
|
||||||
|
class SplitLargeMeshesTest;
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess
|
||||||
{
|
{
|
||||||
friend class Importer;
|
friend class Importer;
|
||||||
friend class SplitLargeMeshesProcess_Vertex;
|
friend class SplitLargeMeshesProcess_Vertex;
|
||||||
|
friend class ::SplitLargeMeshesTest;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Constructor to be privately used by Importer */
|
/** Constructor to be privately used by Importer */
|
||||||
|
@ -134,6 +136,7 @@ public:
|
||||||
class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess
|
class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess
|
||||||
{
|
{
|
||||||
friend class Importer;
|
friend class Importer;
|
||||||
|
friend class ::SplitLargeMeshesTest;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Constructor to be privately used by Importer */
|
/** Constructor to be privately used by Importer */
|
||||||
|
|
|
@ -7,9 +7,15 @@
|
||||||
#include <cppunit/TestRunner.h>
|
#include <cppunit/TestRunner.h>
|
||||||
#include <cppunit/BriefTestProgressListener.h>
|
#include <cppunit/BriefTestProgressListener.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
int main (int argc, char* argv[])
|
int main (int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
// seed the randomizer with the current system time
|
||||||
|
time_t t;time(&t);
|
||||||
|
srand((unsigned int)t);
|
||||||
|
|
||||||
// Informiert Test-Listener ueber Testresultate
|
// Informiert Test-Listener ueber Testresultate
|
||||||
CPPUNIT_NS :: TestResult testresult;
|
CPPUNIT_NS :: TestResult testresult;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
#include "utSplitLargeMeshes.h"
|
||||||
|
#include "aiPostProcess.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION (SplitLargeMeshesTest);
|
||||||
|
|
||||||
|
void SplitLargeMeshesTest :: setUp (void)
|
||||||
|
{
|
||||||
|
aiSetVertexSplitLimit(1000);
|
||||||
|
aiSetTriangleSplitLimit(1000);
|
||||||
|
|
||||||
|
// construct the processes
|
||||||
|
this->piProcessTriangle = new SplitLargeMeshesProcess_Triangle();
|
||||||
|
this->piProcessVertex = new SplitLargeMeshesProcess_Vertex();
|
||||||
|
|
||||||
|
this->pcMesh1 = new aiMesh();
|
||||||
|
pcMesh1->mNumVertices = 2100; // quersumme: 3
|
||||||
|
pcMesh1->mVertices = new aiVector3D[pcMesh1->mNumVertices];
|
||||||
|
pcMesh1->mNormals = new aiVector3D[pcMesh1->mNumVertices];
|
||||||
|
|
||||||
|
pcMesh1->mNumFaces = pcMesh1->mNumVertices / 3;
|
||||||
|
pcMesh1->mFaces = new aiFace[pcMesh1->mNumFaces];
|
||||||
|
|
||||||
|
unsigned int qq = 0;
|
||||||
|
for (unsigned int i = 0; i < pcMesh1->mNumFaces;++i)
|
||||||
|
{
|
||||||
|
aiFace& face = pcMesh1->mFaces[i];
|
||||||
|
face.mNumIndices = 3;
|
||||||
|
face.mIndices = new unsigned int[3];
|
||||||
|
face.mIndices[0] = qq++;
|
||||||
|
face.mIndices[1] = qq++;
|
||||||
|
face.mIndices[2] = qq++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate many, many faces with randomized indices for
|
||||||
|
// the second mesh
|
||||||
|
this->pcMesh2 = new aiMesh();
|
||||||
|
pcMesh2->mNumVertices = 3000;
|
||||||
|
pcMesh2->mVertices = new aiVector3D[pcMesh2->mNumVertices];
|
||||||
|
pcMesh2->mNormals = new aiVector3D[pcMesh2->mNumVertices];
|
||||||
|
|
||||||
|
pcMesh2->mNumFaces = 10000;
|
||||||
|
pcMesh2->mFaces = new aiFace[pcMesh2->mNumFaces];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < pcMesh2->mNumFaces;++i)
|
||||||
|
{
|
||||||
|
aiFace& face = pcMesh2->mFaces[i];
|
||||||
|
face.mNumIndices = 3;
|
||||||
|
face.mIndices = new unsigned int[3];
|
||||||
|
face.mIndices[0] = unsigned int((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices);
|
||||||
|
face.mIndices[1] = unsigned int((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices);
|
||||||
|
face.mIndices[2] = unsigned int((rand() / (float)RAND_MAX) * pcMesh2->mNumVertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitLargeMeshesTest :: tearDown (void)
|
||||||
|
{
|
||||||
|
delete this->piProcessTriangle;
|
||||||
|
delete this->piProcessVertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitLargeMeshesTest :: testVertexSplit()
|
||||||
|
{
|
||||||
|
std::vector< std::pair<aiMesh*, unsigned int> > avOut;
|
||||||
|
|
||||||
|
int iOldFaceNum = (int)pcMesh1->mNumFaces;
|
||||||
|
piProcessVertex->SplitMesh(0,pcMesh1,avOut);
|
||||||
|
|
||||||
|
for (std::vector< std::pair<aiMesh*, unsigned int> >::const_iterator
|
||||||
|
iter = avOut.begin(), end = avOut.end();
|
||||||
|
iter != end; ++iter)
|
||||||
|
{
|
||||||
|
aiMesh* mesh = (*iter).first;
|
||||||
|
CPPUNIT_ASSERT(mesh->mNumVertices < 1000);
|
||||||
|
CPPUNIT_ASSERT(0 != mesh->mNormals && 0 != mesh->mVertices);
|
||||||
|
|
||||||
|
iOldFaceNum -= mesh->mNumFaces;
|
||||||
|
delete mesh;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(0 == iOldFaceNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitLargeMeshesTest :: testTriangleSplit()
|
||||||
|
{
|
||||||
|
std::vector< std::pair<aiMesh*, unsigned int> > avOut;
|
||||||
|
|
||||||
|
// the number of faces shouldn't change
|
||||||
|
int iOldFaceNum = (int)pcMesh2->mNumFaces;
|
||||||
|
piProcessTriangle->SplitMesh(0,pcMesh2,avOut);
|
||||||
|
|
||||||
|
for (std::vector< std::pair<aiMesh*, unsigned int> >::const_iterator
|
||||||
|
iter = avOut.begin(), end = avOut.end();
|
||||||
|
iter != end; ++iter)
|
||||||
|
{
|
||||||
|
aiMesh* mesh = (*iter).first;
|
||||||
|
CPPUNIT_ASSERT(mesh->mNumFaces < 1000);
|
||||||
|
CPPUNIT_ASSERT(0 != mesh->mNormals && 0 != mesh->mVertices);
|
||||||
|
|
||||||
|
iOldFaceNum -= mesh->mNumFaces;
|
||||||
|
delete mesh;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(0 == iOldFaceNum);
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef TESTLM_H
|
||||||
|
#define TESTLM_H
|
||||||
|
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
#include <aiTypes.h>
|
||||||
|
#include <aiMesh.h>
|
||||||
|
#include <aiScene.h>
|
||||||
|
#include <SplitLargeMeshes.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
class SplitLargeMeshesTest : public CPPUNIT_NS :: TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE (SplitLargeMeshesTest);
|
||||||
|
CPPUNIT_TEST (testVertexSplit);
|
||||||
|
CPPUNIT_TEST (testTriangleSplit);
|
||||||
|
CPPUNIT_TEST_SUITE_END ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setUp (void);
|
||||||
|
void tearDown (void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void testVertexSplit (void);
|
||||||
|
void testTriangleSplit (void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SplitLargeMeshesProcess_Triangle* piProcessTriangle;
|
||||||
|
SplitLargeMeshesProcess_Vertex* piProcessVertex;
|
||||||
|
aiMesh* pcMesh1;
|
||||||
|
aiMesh* pcMesh2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,17 +2,12 @@
|
||||||
|
|
||||||
|
|
||||||
#include "utVertexTriangleAdjacency.h"
|
#include "utVertexTriangleAdjacency.h"
|
||||||
#include <math.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION (VTAdjacency);
|
CPPUNIT_TEST_SUITE_REGISTRATION (VTAdjacency);
|
||||||
|
|
||||||
void VTAdjacency :: setUp (void)
|
void VTAdjacency :: setUp (void)
|
||||||
{
|
{
|
||||||
// seed the randomizer
|
|
||||||
time_t t;time(&t);
|
|
||||||
srand((unsigned int)t);
|
|
||||||
|
|
||||||
// build a test mesh with randomized input data
|
// build a test mesh with randomized input data
|
||||||
// *******************************************************************************
|
// *******************************************************************************
|
||||||
pMesh = new aiMesh();
|
pMesh = new aiMesh();
|
||||||
|
|
|
@ -753,6 +753,10 @@
|
||||||
RelativePath="..\..\test\unit\utRemoveComments.h"
|
RelativePath="..\..\test\unit\utRemoveComments.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\test\unit\utSplitLargeMeshes.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\test\unit\utVertexTriangleAdjacency.h"
|
RelativePath="..\..\test\unit\utVertexTriangleAdjacency.h"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue