Fix skinned meshes not playing their last frame.

Also clarified animation documentation to describe current behavior more exactly.
CSkinnedMesh had returned the last key instead of the number of keys.
Thx to whoever mentioned to me once that our example dwarf is not playing his full animation in the meshviewer.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5118 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2015-08-13 21:29:09 +00:00
parent 44e73315e9
commit 125e73ef55
6 changed files with 37 additions and 31 deletions

View File

@ -1,6 +1,7 @@
--------------------------
Changes in 1.9 (not yet released)
- Fix skinned meshes not playing their last frame. Also clarified animation documentation to describe current behavior more exactly.
- Add IWriteFile::flush interface (thx @ JLouisB for the patch).
- CLightSceneNode::updateAbsolutePosition does now light recalculations. This is to fix using animators with lights.
- Fix collada export for objects with rotations around more than 1 axis.

View File

@ -22,8 +22,9 @@ namespace scene
public:
//! Gets the frame count of the animated mesh.
/** \return The amount of frames. If the amount is 1,
it is a static, non animated mesh. */
/** Note that the play-time is usually getFrameCount()-1 as it stops as soon as the last frame-key is reached.
\return The amount of frames. If the amount is 1,
it is a static, non animated mesh. */
virtual u32 getFrameCount() const = 0;
//! Gets the animation speed of the animated mesh.

View File

@ -72,7 +72,11 @@ namespace scene
virtual void setCurrentFrame(f32 frame) = 0;
//! Sets the frame numbers between the animation is looped.
/** The default is 0 - MaximalFrameCount of the mesh.
/** The default is 0 to getFrameCount()-1 of the mesh.
Number of played frames is end-start.
It interpolates toward the last frame but stops when it is reached.
It does not interpolate back to start even when looping.
Looping animations should ensure last and first frame-key are identical.
\param begin: Start frame number of the loop.
\param end: End frame number of the loop.
\return True if successful, false if not. */

View File

@ -850,7 +850,7 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh)
// get start and begin time
setAnimationSpeed(Mesh->getAnimationSpeed()); // NOTE: This had been commented out (but not removed!) in r3526. Which caused meshloader-values for speed to be ignored unless users specified explicitly. Missing a test-case where this could go wrong so I put the code back in.
setFrameLoop(0, Mesh->getFrameCount());
setFrameLoop(0, Mesh->getFrameCount()-1);
}

View File

@ -23,7 +23,7 @@ namespace
irr::u32 n=1; // new index
for(irr::u32 j=1;j<array.size();++j)
{
if (array[j].frame < array[n-1].frame)
if (array[j].frame < array[n-1].frame)
continue; //bad frame, unneeded and may cause problems
if ( n != j )
array[n] = array[j];
@ -36,7 +36,7 @@ namespace
}
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
@ -55,7 +55,7 @@ namespace
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;
s = j;
}
if ( array.size() > s+1 ) // identical keys at the array end?
array[n++] = array[array.size()-1]; // keep the last
@ -67,21 +67,21 @@ namespace
}
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
@ -92,7 +92,7 @@ namespace scene
//! constructor
CSkinnedMesh::CSkinnedMesh()
: SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f),
: SkinningBuffers(0), EndFrame(0.f), FramesPerSecond(25.f),
LastAnimatedFrame(-1), SkinnedLastFrame(false),
InterpolationMode(EIM_LINEAR),
HasAnimation(false), PreparedForSkinning(false),
@ -124,7 +124,7 @@ CSkinnedMesh::~CSkinnedMesh()
//! If the amount is 1, it is a static (=non animated) mesh.
u32 CSkinnedMesh::getFrameCount() const
{
return core::floor32(AnimationFrames);
return core::floor32(EndFrame+1.f);
}
@ -878,22 +878,22 @@ void CSkinnedMesh::checkForAnimation()
if (HasAnimation)
{
//--- Find the length of the animation ---
AnimationFrames=0;
EndFrame=0;
for(i=0;i<AllJoints.size();++i)
{
if (AllJoints[i]->UseAnimationFrom)
{
if (AllJoints[i]->UseAnimationFrom->PositionKeys.size())
if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames)
AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > EndFrame)
EndFrame=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size())
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames)
AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > EndFrame)
EndFrame=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->RotationKeys.size())
if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames)
AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame;
if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > EndFrame)
EndFrame=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame;
}
}
}
@ -958,7 +958,7 @@ void CSkinnedMesh::checkForAnimation()
//! called by loader after populating with mesh and bone data
void CSkinnedMesh::finalize()
{
os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG);
os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG);
u32 i;
// Make sure we recalc the next frame
@ -1023,7 +1023,7 @@ void CSkinnedMesh::finalize()
irr::u32 unorderedScaleKeys = 0;
irr::u32 redundantRotationKeys = 0;
irr::u32 unorderedRotationKeys = 0;
//--- optimize and check keyframes ---
for(i=0;i<AllJoints.size();++i)
{
@ -1053,11 +1053,11 @@ void CSkinnedMesh::finalize()
}
Key=&PositionKeys.getLast();
if (Key->frame!=AnimationFrames)
if (Key->frame!=EndFrame)
{
PositionKeys.push_back(*Key);
Key=&PositionKeys.getLast();
Key->frame=AnimationFrames;
Key->frame=EndFrame;
}
}
@ -1073,11 +1073,11 @@ void CSkinnedMesh::finalize()
}
Key=&ScaleKeys.getLast();
if (Key->frame!=AnimationFrames)
if (Key->frame!=EndFrame)
{
ScaleKeys.push_back(*Key);
Key=&ScaleKeys.getLast();
Key->frame=AnimationFrames;
Key->frame=EndFrame;
}
}
@ -1093,11 +1093,11 @@ void CSkinnedMesh::finalize()
}
Key=&RotationKeys.getLast();
if (Key->frame!=AnimationFrames)
if (Key->frame!=EndFrame)
{
RotationKeys.push_back(*Key);
Key=&RotationKeys.getLast();
Key->frame=AnimationFrames;
Key->frame=EndFrame;
}
}
}
@ -1108,7 +1108,7 @@ void CSkinnedMesh::finalize()
}
if ( unorderedPosKeys > 0 )
{
irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked:", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG);
irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked:", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG);
}
if ( redundantScaleKeys > 0 )
{

View File

@ -194,7 +194,7 @@ private:
core::aabbox3d<f32> BoundingBox;
f32 AnimationFrames;
f32 EndFrame;
f32 FramesPerSecond;
f32 LastAnimatedFrame;