[原创]IrrLicht中MS3D模型骨骼动画支持bug的排除

试验过在IrrLicht中导入播放骨骼动画模型的朋友可能会发现,引擎存在下列问题:一, 当一次循环结束时会产生无效帧,在原模型不远的位置出现一片不规则的图片,严重影响显示效果。二,当模型包含旋转动作时发现模型在旋转过程中方向会突然反向,猜想也是计算错误。针对这两个问题,可以采用如下解决办法。
针对出现无效帧的问题,代码做如下修改:
在类SMS3DMeshBuffer的loadFile方法中(请对照原代码)
 // 获得旋转的关键帧
  //>>rxue add
  s32 j;
  SKeyframe k;
  MS3DKeyframe* eka = NULL; // this contains data of first keyframe
  f32 first = 0; // this is time of first keyframe
  //<<rxue add end

  for (j=0; j<pJoint->NumRotationKeyframes; ++j)
  {
   MS3DKeyframe* kf = (MS3DKeyframe*)pPtr;
   pPtr += sizeof(MS3DKeyframe);
   //>>rxue add
   if(j==0)
   {
    eka = kf;
    first = kf->Time;
   }
   k.timeindex = (kf->Time-first) * 1000.0f;
   //<<rxue add end
   k.data.X = kf->Parameter[0];
   k.data.Y = kf->Parameter[1];
   k.data.Z = kf->Parameter[2];
   jnt.RotationKeys.push_back(k);
  }
  //>>rxue add
  totalTime -= first;
  if(eka)
  {
   k.timeindex = totalTime;
   k.data.X = eka->Parameter[0];
   k.data.Y = eka->Parameter[1];
   k.data.Z = eka->Parameter[2];
   jnt.RotationKeys.push_back(k);
  }
  eka = NULL;
  //<<rxue add end


  // 获得变换的关键帧
  first = 0; //rxue add
  for (j=0; j<pJoint->NumTranslationKeyframes; ++j)
  {
   MS3DKeyframe* kf = (MS3DKeyframe*)pPtr;
   pPtr += sizeof(MS3DKeyframe);
   
   //>>rxue add
   if(j==0)
   {
    eka = kf;
    first = kf->Time;
   }
   
   k.timeindex = (kf->Time-first) * 1000.0f;
   //<<rxue add end   
   k.data.X = kf->Parameter[0];
   k.data.Y = kf->Parameter[1];
   k.data.Z = kf->Parameter[2];
   jnt.TranslationKeys.push_back(k);
  }
  //>> rxue add Let's add one keyframe to the end
  if(eka)
  {
   k.timeindex = totalTime;
   k.data.X = eka->Parameter[0];
   k.data.Y = eka->Parameter[1];
   k.data.Z = eka->Parameter[2];
   jnt.TranslationKeys.push_back(k);
  }
  //<<rxue add end
旋转反向的问题:
修改SMS3DMeshBuffer类的getKeyframeData方法如下:(注意:s32type为增加的参数,所以函数声明也要做相应修改
void CAnimatedMeshMS3D::getKeyframeData(core::array<SKeyframe>& keys, f32 time, core::vector3df& outdata,s32 type)
{
 if(type == 0)
 {
  for (s32 i=0; i<(s32)keys.size()-1; ++i)
  {
   if (keys[i].timeindex <= time && keys[i+1].timeindex >= time)
   {    
    f32 interpolate = (time - keys[i].timeindex)/(keys[i+1].timeindex - keys[i].timeindex);    
    outdata = keys[i].data + ((keys[i+1].data - keys[i].data) * interpolate);   
    return;
   }
  }
 }
 else
 {
  for (s32 i=0; i<(s32)keys.size()-1; ++i)
  {
   if (keys[i].timeindex <= time && keys[i+1].timeindex >= time)
   {
    irr::core::quaternion q1(keys[i].data.X,keys[i].data.Y,keys[i].data.Z);
    irr::core::quaternion q2(keys[i+1].data.X,keys[i+1].data.Y,keys[i+1].data.Z);     
    f32 interpolate = (time - keys[i].timeindex)/(keys[i+1].timeindex - keys[i].timeindex);
    q2 = q1.slerp(q1,q2,interpolate);
    q2.toEuler(outdata);
    return;
   }
  }
 }
}

SMS3DMeshBuffer类animate方法修改如下:
//find keyframe translation and roation
//getKeyframeData(Joints[i].TranslationKeys, time, translation);
//getKeyframeData(Joints[i].RotationKeys, time, rotation);
  
  getKeyframeData(Joints[i].TranslationKeys, time, translation,0);//rxue
  getKeyframeData(Joints[i].RotationKeys, time, rotation,1);//rxue 重新计算
至此,解决了模型动画的播放问题。在我们这里测试正常,有问题的朋友可以留言讨论。

原文地址:https://www.cnblogs.com/flysnow/p/461831.html