2
0

AnimationState.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "AnimatedModel.h"
  25. #include "Animation.h"
  26. #include "AnimationState.h"
  27. #include "Deserializer.h"
  28. #include "Serializer.h"
  29. #include "XMLElement.h"
  30. #include "DebugNew.h"
  31. AnimationState::AnimationState(AnimatedModel* model, Animation* animation) :
  32. model_(model),
  33. startBone_(0),
  34. looped_(false),
  35. weight_(0.0f),
  36. time_(0.0f),
  37. priority_(0),
  38. useNlerp_(false)
  39. {
  40. animation_ = animation;
  41. SetStartBone(0);
  42. // Setup a cache for last keyframe of each track
  43. lastKeyFrame_.resize(animation_->GetNumTracks());
  44. for (unsigned i = 0; i < lastKeyFrame_.size(); ++i)
  45. lastKeyFrame_[i] = 0;
  46. }
  47. AnimationState::~AnimationState()
  48. {
  49. }
  50. void AnimationState::SetStartBone(Bone* startBone)
  51. {
  52. Skeleton& skeleton = model_->GetSkeleton();
  53. const std::vector<Bone>& bones = skeleton.GetBones();
  54. Bone* rootBone = skeleton.GetRootBone();
  55. if (!rootBone)
  56. return;
  57. if (!startBone)
  58. startBone = rootBone;
  59. startBone_ = startBone;
  60. trackToBoneMap_.clear();
  61. if (!startBone->node_)
  62. return;
  63. const std::vector<AnimationTrack>& tracks = animation_->GetTracks();
  64. for (unsigned i = 0; i < tracks.size(); ++i)
  65. {
  66. // Include those tracks that are either the startbone itself, or its children
  67. Bone* trackBone = 0;
  68. const StringHash& nameHash = tracks[i].nameHash_;
  69. if (nameHash == startBone->nameHash_)
  70. trackBone = startBone;
  71. else
  72. {
  73. Node* trackBoneNode = startBone->node_->GetChild(nameHash, true);
  74. if (trackBoneNode)
  75. trackBone = skeleton.GetBone(nameHash);
  76. }
  77. if (trackBone)
  78. trackToBoneMap_[i] = trackBone;
  79. }
  80. model_->MarkAnimationDirty();
  81. }
  82. void AnimationState::SetLooped(bool looped)
  83. {
  84. looped_ = looped;
  85. }
  86. void AnimationState::SetWeight(float weight)
  87. {
  88. weight = Clamp(weight, 0.0f, 1.0f);
  89. if (weight != weight_)
  90. {
  91. weight_ = weight;
  92. model_->MarkAnimationDirty();
  93. }
  94. }
  95. void AnimationState::SetTime(float time)
  96. {
  97. time = Clamp(time, 0.0f, animation_->GetLength());
  98. if (time != time_)
  99. {
  100. time_ = time;
  101. model_->MarkAnimationDirty();
  102. }
  103. }
  104. void AnimationState::AddWeight(float delta)
  105. {
  106. if (delta == 0.0f)
  107. return;
  108. SetWeight(GetWeight() + delta);
  109. }
  110. void AnimationState::AddTime(float delta)
  111. {
  112. float length = animation_->GetLength();
  113. if ((delta == 0.0f) || (length == 0.0f))
  114. return;
  115. float time = GetTime() + delta;
  116. if (looped_)
  117. {
  118. while (time >= length)
  119. time -= length;
  120. while (time < 0.0f)
  121. time += length;
  122. }
  123. SetTime(time);
  124. }
  125. void AnimationState::SetPriority(int priority)
  126. {
  127. priority = Clamp(priority, 0, 255);
  128. if (priority != priority_)
  129. {
  130. priority_ = priority;
  131. model_->MarkAnimationOrderDirty();
  132. }
  133. }
  134. void AnimationState::SetUseNlerp(bool enable)
  135. {
  136. useNlerp_ = enable;
  137. }
  138. float AnimationState::GetLength() const
  139. {
  140. return animation_->GetLength();
  141. }
  142. void AnimationState::Apply()
  143. {
  144. if (!IsEnabled())
  145. return;
  146. // Check first if full weight or blending
  147. if (weight_ == 1.0f)
  148. {
  149. for (std::map<unsigned, Bone*>::const_iterator i = trackToBoneMap_.begin(); i != trackToBoneMap_.end(); ++i)
  150. {
  151. const AnimationTrack* track = animation_->GetTrack(i->first);
  152. Bone* bone = i->second;
  153. Node* boneNode = bone->node_;
  154. if ((!boneNode) || (!bone->animated_) || (!track->keyFrames_.size()))
  155. continue;
  156. unsigned& frame = lastKeyFrame_[i->first];
  157. track->GetKeyFrameIndex(time_, frame);
  158. // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
  159. unsigned nextFrame = frame + 1;
  160. bool interpolate = true;
  161. if (nextFrame >= track->keyFrames_.size())
  162. {
  163. if (!looped_)
  164. {
  165. nextFrame = frame;
  166. interpolate = false;
  167. }
  168. else
  169. nextFrame = 0;
  170. }
  171. const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
  172. unsigned char channelMask = track->channelMask_;
  173. if (!interpolate)
  174. {
  175. // No interpolation, full weight
  176. if (channelMask & CHANNEL_POSITION)
  177. boneNode->SetPosition(keyFrame->position_);
  178. if (channelMask & CHANNEL_ROTATION)
  179. boneNode->SetRotation(keyFrame->rotation_);
  180. if (channelMask & CHANNEL_SCALE)
  181. boneNode->SetScale(keyFrame->scale_);
  182. }
  183. else
  184. {
  185. const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
  186. float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
  187. if (timeInterval < 0.0f)
  188. timeInterval += animation_->GetLength();
  189. float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
  190. // Interpolation, full weight
  191. if (channelMask & CHANNEL_POSITION)
  192. boneNode->SetPosition(keyFrame->position_.Lerp(nextKeyFrame->position_, t));
  193. if (channelMask & CHANNEL_ROTATION)
  194. {
  195. if (!useNlerp_)
  196. boneNode->SetRotation(keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t));
  197. else
  198. boneNode->SetRotation(keyFrame->rotation_.NlerpFast(nextKeyFrame->rotation_, t));
  199. }
  200. if (channelMask & CHANNEL_SCALE)
  201. boneNode->SetScale(keyFrame->scale_.Lerp(nextKeyFrame->scale_, t));
  202. }
  203. }
  204. }
  205. else
  206. {
  207. for (std::map<unsigned, Bone*>::const_iterator i = trackToBoneMap_.begin(); i != trackToBoneMap_.end(); ++i)
  208. {
  209. const AnimationTrack* track = animation_->GetTrack(i->first);
  210. Bone* bone = i->second;
  211. Node* boneNode = bone->node_;
  212. if ((!boneNode) || (!bone->animated_) || (!track->keyFrames_.size()))
  213. continue;
  214. unsigned& frame = lastKeyFrame_[i->first];
  215. track->GetKeyFrameIndex(time_, frame);
  216. // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
  217. unsigned nextFrame = frame + 1;
  218. bool interpolate = true;
  219. if (nextFrame >= track->keyFrames_.size())
  220. {
  221. if (!looped_)
  222. {
  223. nextFrame = frame;
  224. interpolate = false;
  225. }
  226. else
  227. nextFrame = 0;
  228. }
  229. const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
  230. unsigned char channelMask = track->channelMask_;
  231. if (!interpolate)
  232. {
  233. // No interpolation, blend between old transform & animation
  234. if (channelMask & CHANNEL_POSITION)
  235. boneNode->SetPosition(boneNode->GetPosition().Lerp(keyFrame->position_, weight_));
  236. if (channelMask & CHANNEL_ROTATION)
  237. {
  238. if (!useNlerp_)
  239. boneNode->SetRotation(boneNode->GetRotation().Slerp(keyFrame->rotation_, weight_));
  240. else
  241. boneNode->SetRotation(boneNode->GetRotation().NlerpFast(keyFrame->rotation_, weight_));
  242. }
  243. if (channelMask & CHANNEL_SCALE)
  244. boneNode->SetScale(boneNode->GetScale().Lerp(keyFrame->scale_, weight_));
  245. }
  246. else
  247. {
  248. const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
  249. float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
  250. if (timeInterval < 0.0f)
  251. timeInterval += animation_->GetLength();
  252. float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
  253. // Interpolation, blend between old transform & animation
  254. if (channelMask & CHANNEL_POSITION)
  255. {
  256. boneNode->SetPosition(boneNode->GetPosition().Lerp(
  257. keyFrame->position_.Lerp(nextKeyFrame->position_, t), weight_));
  258. }
  259. if (channelMask & CHANNEL_ROTATION)
  260. {
  261. if (!useNlerp_)
  262. {
  263. boneNode->SetRotation(boneNode->GetRotation().Slerp(
  264. keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t), weight_));
  265. }
  266. else
  267. {
  268. boneNode->SetRotation(boneNode->GetRotation().NlerpFast(
  269. keyFrame->rotation_.NlerpFast(nextKeyFrame->rotation_, t), weight_));
  270. }
  271. }
  272. if (channelMask & CHANNEL_SCALE)
  273. {
  274. boneNode->SetScale(boneNode->GetScale().Lerp(
  275. keyFrame->scale_.Lerp(nextKeyFrame->scale_, t), weight_));
  276. }
  277. }
  278. }
  279. }
  280. }
  281. void AnimationState::Sync(AnimationState* src)
  282. {
  283. Bone* srcStartBone = src->GetStartBone();
  284. if (!srcStartBone)
  285. return;
  286. if (startBone_->name_ != srcStartBone->name_)
  287. SetStartBone(model_->GetSkeleton().GetBone(srcStartBone->name_));
  288. SetLooped(src->IsLooped());
  289. SetPriority(src->GetPriority());
  290. SetTime(src->GetTime());
  291. SetWeight(src->GetWeight());
  292. }