//------------------------------------------------------------------------------ //! Blends between 2 animations at a specific frame. //! This is done by interpolating 2 frames of animA, then 2 frames of animB, //! then blending the 2 resulting frames together according to the factor. //! @param animA: The first animation. //! @param timeA: A time hint for the first animation. //! @param animB: The second animation. //! @param timeB: A time hint for the second animation. //! @param factor: A blend factor to merge animA with animB. //! @param dstPose: A pre-allocated pose into which to store the result. void Puppeteer::blendFrame( SkeletalAnimation* animA, float timeA, SkeletalAnimation* animB, float timeB, float factor, SkeletalPose& dstPose ) { DBG_BLOCK( os_pup, "Puppeteer::blendFrame(" << animA << ", " << timeA << ", " << animB << ", " << timeB << ", " << factor << ")" ); animA->makeRelative(); animB->makeRelative(); // Compute poses. SkeletalPose* pA0; SkeletalPose* pA1; float tA; SkeletalPose* pB0; SkeletalPose* pB1; float tB; animA->getPoses( timeA, pA0, pA1, tA ); animB->getPoses( timeB, pB0, pB1, tB ); DBG_MSG( os_pup, "A: " << timeA << " --> " << tA ); DBG_MSG( os_pup, "B: " << timeB << " --> " << tB ); const SkeletalPose::BoneContainer& bA0 = pA0->bones(); const SkeletalPose::BoneContainer& bA1 = pA1->bones(); const SkeletalPose::BoneContainer& bB0 = pB0->bones(); const SkeletalPose::BoneContainer& bB1 = pB1->bones(); //Reff refA = pA0->referential().slerp( pA1->referential(), tA ); //Reff refB = pB0->referential().slerp( pB1->referential(), tB ); //Reff ref = refA.slerp( refB, factor ); Reff refA = pA0->referential().nlerp( pA1->referential(), tA ); Reff refB = pB0->referential().nlerp( pB1->referential(), tB ); Reff ref = refA.nlerp( refB, factor ); dstPose.referential( ref ); SkeletalPose::BoneContainer& dstBones = dstPose.bones(); CHECK( bA0.size() == bB0.size() ); CHECK( bA0.size() == dstBones.size() ); const uint nBones = uint(dstBones.size()); for( uint i = 0; i < nBones; ++i ) { //Quatf sorient = bA0[i].slerp( bA1[i], tA ); //Quatf eorient = bB0[i].slerp( bB1[i], tB ); //Quatf orient = sorient.slerp( eorient, factor ); Quatf sorient = bA0[i].nlerp( bA1[i], tA ); Quatf eorient = bB0[i].nlerp( bB1[i], tB ); Quatf orient = sorient.nlerp( eorient, factor ); dstBones[i] = orient; } }
//------------------------------------------------------------------------------ //! RCP<SkeletalAnimation> Puppeteer::blend( SkeletalAnimation* startAnim, SkeletalAnimation* endAnim ) { DBG_BLOCK( os_pup, "Puppeteer::blend(" << startAnim << ", " << endAnim << ")" ); RCP<SkeletalAnimation> anim = new SkeletalAnimation(); anim->skeleton( startAnim->skeleton() ); startAnim->makeRelative(); endAnim->makeRelative(); // Compute duration, rate and number of poses. float duration = (startAnim->duration() + endAnim->duration()) * 0.5f; float rate = CGM::max( startAnim->rate(), endAnim->rate() ); uint numPoses = uint(rate*duration) + 1; anim->reservePoses( numPoses ); anim->rate( rate ); anim->velocity( (startAnim->velocity() + endAnim->velocity())*0.5f ); anim->offset( (startAnim->offset() + endAnim->offset())*0.5f ); // Compute poses. SkeletalPose* sp0; SkeletalPose* sp1; SkeletalPose* ep0; SkeletalPose* ep1; for( uint p = 0; p < numPoses; ++p ) { float t = float(p) / float(numPoses-1); float st; float et; startAnim->getPosesClamped( startAnim->duration() * t, sp0, sp1, st ); endAnim->getPosesClamped( endAnim->duration() * t, ep0, ep1, et ); const SkeletalPose::BoneContainer& sb0 = sp0->bones(); const SkeletalPose::BoneContainer& sb1 = sp1->bones(); const SkeletalPose::BoneContainer& eb0 = ep0->bones(); const SkeletalPose::BoneContainer& eb1 = ep1->bones(); //Reff sref = sp0->referential().slerp( sp1->referential(), st ); //Reff eref = ep0->referential().slerp( ep1->referential(), et ); //Reff ref = sref.slerp( eref, t ); Reff sref = sp0->referential().nlerp( sp1->referential(), st ); Reff eref = ep0->referential().nlerp( ep1->referential(), et ); Reff ref = sref.nlerp( eref, t ); SkeletalPose* pose = anim->addPose( ref ); pose->reserveBones( uint(sb0.size()) ); for( uint i = 0; i < sb0.size(); ++i ) { //Quatf sorient = sb0[i].slerp( sb1[i], st ); //Quatf eorient = eb0[i].slerp( eb1[i], et ); //Quatf orient = sorient.slerp( eorient, t ); Quatf sorient = sb0[i].nlerp( sb1[i], st ); Quatf eorient = eb0[i].nlerp( eb1[i], et ); Quatf orient = sorient.nlerp( eorient, t ); pose->addBone( orient ); } } return anim; }