Improve speed for finalizing skinned meshes (removal of unnecessary frames after loading) (thx @ichtyander for the testmodel)

Down from ~20 seconds to ~0,5 seconds :-)


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4622 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2014-01-03 18:25:53 +00:00
parent 29faf510ac
commit cc2b3716b7
3 changed files with 102 additions and 63 deletions

View File

@ -1,6 +1,7 @@
--------------------------
Changes in 1.9 (not yet released)
- Improve speed for finalizing skinned meshes (removal of unnecessary frames after loading) (thx @ichtyander for the testmodel)
- Collada loader now instantiates camera nodes which had been ignore so far (thx @NemoStein for the test .dae)
- line2d::intersectWith has a new parameter to allow ignoring intersections with coincident lines
- vector2d::equals now has an tolerance parameter for passing the epsilon (like vector3d had). Note that this changes the default

View File

@ -24,7 +24,7 @@ namespace gui
//! Validate when enter was pressed
EGUI_SBV_ENTER = 2,
//! Validate when the editbox loses the focus
EGUI_SBV_LOSE_FOCUS = 4,
EGUI_SBV_LOSE_FOCUS = 4
};

View File

@ -10,6 +10,80 @@
#include "IAnimatedMeshSceneNode.h"
#include "os.h"
namespace
{
// Frames must always be increasing, so we remove objects where this isn't the case
// return number of kicked keys
template <class T> // T = objects containing a "frame" variable
irr::u32 dropBadKeys(irr::core::array<T>& array)
{
if (array.size()<2)
return 0;
irr::u32 n=1; // new index
for(irr::u32 j=1;j<array.size();++j)
{
if (array[j].frame < array[j-1].frame)
continue; //bad frame, unneeded and may cause problems
if ( n != j )
array[n] = array[j];
++n;
}
irr::u32 d = array.size()-n; // remove already copied keys
if ( d > 0 )
{
array.erase(n, d);
}
return d;
}
// drop identical middle keys - we only need the first and last
// return number of kicked keys
template <class T, typename Cmp> // Cmp = comparison for keys of type T
irr::u32 dropMiddleKeys(irr::core::array<T>& array, Cmp & cmp)
{
if ( array.size() < 3 )
return 0;
irr::u32 s = 0; // old index for current key
irr::u32 n = 1; // new index for next key
for(irr::u32 j=1;j<array.size();++j)
{
if ( cmp(array[j], array[s]) )
continue; // same key, handle later
if ( j > s+1 ) // had there been identical keys?
array[n++] = array[j-1]; // keep the last
array[n++] = array[j]; // keep the new one
s = j;
}
if ( array.size() > s+1 ) // identical keys at the array end?
array[n++] = array[array.size()-1]; // keep the last
irr::u32 d = array.size()-n; // remove already copied keys
if ( d > 0 )
{
array.erase(n, d);
}
return d;
}
bool identicalPos(const irr::scene::ISkinnedMesh::SPositionKey& a, const irr::scene::ISkinnedMesh::SPositionKey& b)
{
return a.position == b.position;
}
bool identicalScale(const irr::scene::ISkinnedMesh::SScaleKey& a, const irr::scene::ISkinnedMesh::SScaleKey& b)
{
return a.scale == b.scale;
}
bool identicalRotation(const irr::scene::ISkinnedMesh::SRotationKey& a, const irr::scene::ISkinnedMesh::SRotationKey& b)
{
return a.rotation == b.rotation;
}
};
namespace irr
{
namespace scene
@ -881,10 +955,10 @@ void CSkinnedMesh::checkForAnimation()
SkinnedLastFrame=false;
}
//! called by loader after populating with mesh and bone data
void CSkinnedMesh::finalize()
{
os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG);
u32 i;
// Make sure we recalc the next frame
@ -939,8 +1013,6 @@ void CSkinnedMesh::finalize()
Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount());
}
//Todo: optimise keys here...
checkForAnimation();
if (HasAnimation)
@ -952,76 +1024,42 @@ void CSkinnedMesh::finalize()
core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys;
core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys;
if (PositionKeys.size()>2)
// drop identical middle keys - we only need the first and last frame
irr::u32 dropped = dropMiddleKeys<SPositionKey>(PositionKeys, identicalPos);
if ( dropped > 0 )
{
for(u32 j=0;j<PositionKeys.size()-2;++j)
{
if (PositionKeys[j].position == PositionKeys[j+1].position && PositionKeys[j+1].position == PositionKeys[j+2].position)
{
PositionKeys.erase(j+1); //the middle key is unneeded
--j;
}
}
os::Printer::log("Skinned Mesh - unneeded position frames kicked:", core::stringc(dropped).c_str(), ELL_DEBUG);
}
if (PositionKeys.size()>1)
// drop frames with bad keys (frames out of order)
dropped = dropBadKeys<SPositionKey>(PositionKeys);
if ( dropped > 0 )
{
for(u32 j=0;j<PositionKeys.size()-1;++j)
{
if (PositionKeys[j].frame >= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems
{
PositionKeys.erase(j+1);
--j;
}
}
irr::os::Printer::log("Skinned Mesh - bad position frames kicked:", irr::core::stringc(dropped).c_str(), irr::ELL_DEBUG);
}
if (ScaleKeys.size()>2)
dropped = dropMiddleKeys<SScaleKey>(ScaleKeys, identicalScale);
if ( dropped > 0 )
{
for(u32 j=0;j<ScaleKeys.size()-2;++j)
{
if (ScaleKeys[j].scale == ScaleKeys[j+1].scale && ScaleKeys[j+1].scale == ScaleKeys[j+2].scale)
{
ScaleKeys.erase(j+1); //the middle key is unneeded
--j;
}
}
os::Printer::log("Skinned Mesh - unneeded scale frames kicked:", core::stringc(dropped).c_str(), ELL_DEBUG);
}
if (ScaleKeys.size()>1)
dropped = dropBadKeys<SScaleKey>(ScaleKeys);
if ( dropped > 0 )
{
for(u32 j=0;j<ScaleKeys.size()-1;++j)
{
if (ScaleKeys[j].frame >= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems
{
ScaleKeys.erase(j+1);
--j;
}
}
irr::os::Printer::log("Skinned Mesh - bad scale frames kicked:", irr::core::stringc(dropped).c_str(), irr::ELL_DEBUG);
}
if (RotationKeys.size()>2)
dropped = dropMiddleKeys<SRotationKey>(RotationKeys, identicalRotation);
if ( dropped > 0 )
{
for(u32 j=0;j<RotationKeys.size()-2;++j)
{
if (RotationKeys[j].rotation == RotationKeys[j+1].rotation && RotationKeys[j+1].rotation == RotationKeys[j+2].rotation)
{
RotationKeys.erase(j+1); //the middle key is unneeded
--j;
}
}
os::Printer::log("Skinned Mesh - unneeded rotation frames kicked:", core::stringc(dropped).c_str(), ELL_DEBUG);
}
if (RotationKeys.size()>1)
dropped = dropBadKeys<SRotationKey>(RotationKeys);
if ( dropped > 0 )
{
for(u32 j=0;j<RotationKeys.size()-1;++j)
{
if (RotationKeys[j].frame >= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems
{
RotationKeys.erase(j+1);
--j;
}
}
irr::os::Printer::log("Skinned Mesh - bad rotation frames kicked:", irr::core::stringc(dropped).c_str(), irr::ELL_DEBUG);
}