If anyone uses the CSceneNodeAnimatorFollowSpline, its implementation is a hermite spline, which moving last control point affect the first point.
Catmull-Rom tend to fix this issue. Anyway here is the modification to the CSceneNodeAnimatorFollowSpline animate function. You can create another spline animator call CSceneNodeAnimatorFollowCatmullSpline.
Code: Select all
//! animates a scene node
void CSceneNodeAnimatorFollowCatmullSpline::animateNode(ISceneNode* node, u32 timeMs)
{
if(!node)
return;
const u32 pSize = Points.size();
if (pSize==0)
{
if ( !Loop )
HasFinished = true;
return;
}
if (pSize==1)
{
if ( timeMs > StartTime )
{
node->setPosition(Points[0]);
if ( !Loop )
HasFinished = true;
}
return;
}
const f32 dt = ( (timeMs-StartTime) * Speed * 0.001f );
const s32 unwrappedIdx = core::floor32( dt );
if ( !Loop && unwrappedIdx >= (s32)pSize-1 )
{
node->setPosition(Points[pSize-1]);
HasFinished = true;
return;
}
const bool pong = PingPong && (unwrappedIdx/(pSize-1))%2;
const f32 u = pong ? 1.f-core::fract ( dt ) : core::fract ( dt );
const s32 idx = pong ? (pSize-2) - (unwrappedIdx % (pSize-1))
: (PingPong ? unwrappedIdx % (pSize-1)
: unwrappedIdx % pSize);
const core::vector3df& p0 = Points[clamp(idx, pSize)];
const core::vector3df& p1 = Points[clamp(idx + 1, pSize)];
core::vector3df t1;
core::vector3df t2;
if (idx > 0)
{
t1 = 0.5f*(Points[clamp(idx + 1, pSize)] - Points[clamp(idx - 1, pSize)]);
}
else
{
t1 = Points[clamp(idx + 1, pSize)] - Points[clamp(idx, pSize)];
}
if (idx < Points.size() - 2)
{
t2 = 0.5f * (Points[clamp(idx + 2, pSize)] - Points[clamp(idx, pSize)]);
}
else
{
t2 = Points[clamp(idx + 1, pSize)] - Points[clamp(idx, pSize)];
}
// hermite polynomials
const f32 h1 = 2.0f * u * u * u - 3.0f * u * u + 1.0f;
const f32 h2 = -2.0f * u * u * u + 3.0f * u * u;
const f32 h3 = u * u * u - 2.0f * u * u + u;
const f32 h4 = u * u * u - u * u;
core::vector3df f = p0 * h1 + p1 * h2 + t1 * h3 + t2 * h4;
node->setPosition(f);
}
const bool pong = PingPong && (unwrappedIdx / (pSize - 1)) % 2;
const f32 u = pong ? 1.f - core::fract(dt) : core::fract(dt);
if we set u as below. It seems to also works.
const f32 u = core::fract(dt);