AnimationState.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. animation_(animation),
  34. startBone_(0),
  35. looped_(false),
  36. weight_(0.0f),
  37. time_(0.0f),
  38. layer_(0),
  39. useNlerp_(false)
  40. {
  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. if (!model_)
  53. return;
  54. Skeleton& skeleton = model_->GetSkeleton();
  55. Bone* rootBone = skeleton.GetRootBone();
  56. if (!rootBone)
  57. return;
  58. if (!startBone)
  59. startBone = rootBone;
  60. // Do not reassign if the start bone did not actually change, and we already have valid bone nodes
  61. if (startBone == startBone_ && !trackToBoneMap_.Empty())
  62. return;
  63. startBone_ = startBone;
  64. trackToBoneMap_.Clear();
  65. if (!startBone->node_)
  66. return;
  67. const Vector<AnimationTrack>& tracks = animation_->GetTracks();
  68. for (unsigned i = 0; i < tracks.Size(); ++i)
  69. {
  70. // Include those tracks that are either the start bone itself, or its children
  71. Bone* trackBone = 0;
  72. const StringHash& nameHash = tracks[i].nameHash_;
  73. if (nameHash == startBone->nameHash_)
  74. trackBone = startBone;
  75. else
  76. {
  77. Node* trackBoneNode = startBone->node_->GetChild(nameHash, true);
  78. if (trackBoneNode)
  79. trackBone = skeleton.GetBone(nameHash);
  80. }
  81. if (trackBone)
  82. trackToBoneMap_[i] = trackBone;
  83. }
  84. model_->MarkAnimationDirty();
  85. }
  86. void AnimationState::SetLooped(bool looped)
  87. {
  88. looped_ = looped;
  89. }
  90. void AnimationState::SetWeight(float weight)
  91. {
  92. weight = Clamp(weight, 0.0f, 1.0f);
  93. if (weight != weight_)
  94. {
  95. weight_ = weight;
  96. if (model_)
  97. model_->MarkAnimationDirty();
  98. }
  99. }
  100. void AnimationState::SetTime(float time)
  101. {
  102. time = Clamp(time, 0.0f, animation_->GetLength());
  103. if (time != time_)
  104. {
  105. time_ = time;
  106. if (model_)
  107. model_->MarkAnimationDirty();
  108. }
  109. }
  110. void AnimationState::AddWeight(float delta)
  111. {
  112. if (delta == 0.0f)
  113. return;
  114. SetWeight(GetWeight() + delta);
  115. }
  116. void AnimationState::AddTime(float delta)
  117. {
  118. float length = animation_->GetLength();
  119. if (delta == 0.0f || length == 0.0f)
  120. return;
  121. float time = GetTime() + delta;
  122. if (looped_)
  123. {
  124. while (time >= length)
  125. time -= length;
  126. while (time < 0.0f)
  127. time += length;
  128. }
  129. SetTime(time);
  130. }
  131. void AnimationState::SetLayer(unsigned char layer)
  132. {
  133. if (layer != layer_)
  134. {
  135. layer_ = layer;
  136. if (model_)
  137. model_->MarkAnimationOrderDirty();
  138. }
  139. }
  140. void AnimationState::SetUseNlerp(bool enable)
  141. {
  142. useNlerp_ = enable;
  143. }
  144. Bone* AnimationState::GetStartBone() const
  145. {
  146. return model_ ? startBone_ : 0;
  147. }
  148. float AnimationState::GetLength() const
  149. {
  150. return animation_->GetLength();
  151. }
  152. void AnimationState::Apply()
  153. {
  154. if (!IsEnabled())
  155. return;
  156. // Check first if full weight or blending
  157. if (weight_ == 1.0f)
  158. {
  159. for (HashMap<unsigned, Bone*>::ConstIterator i = trackToBoneMap_.Begin(); i != trackToBoneMap_.End(); ++i)
  160. {
  161. const AnimationTrack* track = animation_->GetTrack(i->first_);
  162. Bone* bone = i->second_;
  163. Node* boneNode = bone->node_;
  164. if (!boneNode || !bone->animated_ || !track->keyFrames_.Size())
  165. continue;
  166. unsigned& frame = lastKeyFrame_[i->first_];
  167. track->GetKeyFrameIndex(time_, frame);
  168. // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
  169. unsigned nextFrame = frame + 1;
  170. bool interpolate = true;
  171. if (nextFrame >= track->keyFrames_.Size())
  172. {
  173. if (!looped_)
  174. {
  175. nextFrame = frame;
  176. interpolate = false;
  177. }
  178. else
  179. nextFrame = 0;
  180. }
  181. const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
  182. unsigned char channelMask = track->channelMask_;
  183. if (!interpolate)
  184. {
  185. // No interpolation, full weight
  186. if (channelMask & CHANNEL_POSITION)
  187. boneNode->SetPosition(keyFrame->position_);
  188. if (channelMask & CHANNEL_ROTATION)
  189. boneNode->SetRotation(keyFrame->rotation_);
  190. if (channelMask & CHANNEL_SCALE)
  191. boneNode->SetScale(keyFrame->scale_);
  192. }
  193. else
  194. {
  195. const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
  196. float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
  197. if (timeInterval < 0.0f)
  198. timeInterval += animation_->GetLength();
  199. float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
  200. // Interpolation, full weight
  201. if (channelMask & CHANNEL_POSITION)
  202. boneNode->SetPosition(keyFrame->position_.Lerp(nextKeyFrame->position_, t));
  203. if (channelMask & CHANNEL_ROTATION)
  204. {
  205. if (!useNlerp_)
  206. boneNode->SetRotation(keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t));
  207. else
  208. boneNode->SetRotation(keyFrame->rotation_.NlerpFast(nextKeyFrame->rotation_, t));
  209. }
  210. if (channelMask & CHANNEL_SCALE)
  211. boneNode->SetScale(keyFrame->scale_.Lerp(nextKeyFrame->scale_, t));
  212. }
  213. }
  214. }
  215. else
  216. {
  217. for (HashMap<unsigned, Bone*>::ConstIterator i = trackToBoneMap_.Begin(); i != trackToBoneMap_.End(); ++i)
  218. {
  219. const AnimationTrack* track = animation_->GetTrack(i->first_);
  220. Bone* bone = i->second_;
  221. Node* boneNode = bone->node_;
  222. if (!boneNode || !bone->animated_ || !track->keyFrames_.Size())
  223. continue;
  224. unsigned& frame = lastKeyFrame_[i->first_];
  225. track->GetKeyFrameIndex(time_, frame);
  226. // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
  227. unsigned nextFrame = frame + 1;
  228. bool interpolate = true;
  229. if (nextFrame >= track->keyFrames_.Size())
  230. {
  231. if (!looped_)
  232. {
  233. nextFrame = frame;
  234. interpolate = false;
  235. }
  236. else
  237. nextFrame = 0;
  238. }
  239. const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
  240. unsigned char channelMask = track->channelMask_;
  241. if (!interpolate)
  242. {
  243. // No interpolation, blend between old transform & animation
  244. if (channelMask & CHANNEL_POSITION)
  245. boneNode->SetPosition(boneNode->GetPosition().Lerp(keyFrame->position_, weight_));
  246. if (channelMask & CHANNEL_ROTATION)
  247. {
  248. if (!useNlerp_)
  249. boneNode->SetRotation(boneNode->GetRotation().Slerp(keyFrame->rotation_, weight_));
  250. else
  251. boneNode->SetRotation(boneNode->GetRotation().NlerpFast(keyFrame->rotation_, weight_));
  252. }
  253. if (channelMask & CHANNEL_SCALE)
  254. boneNode->SetScale(boneNode->GetScale().Lerp(keyFrame->scale_, weight_));
  255. }
  256. else
  257. {
  258. const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
  259. float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
  260. if (timeInterval < 0.0f)
  261. timeInterval += animation_->GetLength();
  262. float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
  263. // Interpolation, blend between old transform & animation
  264. if (channelMask & CHANNEL_POSITION)
  265. {
  266. boneNode->SetPosition(boneNode->GetPosition().Lerp(
  267. keyFrame->position_.Lerp(nextKeyFrame->position_, t), weight_));
  268. }
  269. if (channelMask & CHANNEL_ROTATION)
  270. {
  271. if (!useNlerp_)
  272. {
  273. boneNode->SetRotation(boneNode->GetRotation().Slerp(
  274. keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t), weight_));
  275. }
  276. else
  277. {
  278. boneNode->SetRotation(boneNode->GetRotation().NlerpFast(
  279. keyFrame->rotation_.NlerpFast(nextKeyFrame->rotation_, t), weight_));
  280. }
  281. }
  282. if (channelMask & CHANNEL_SCALE)
  283. {
  284. boneNode->SetScale(boneNode->GetScale().Lerp(
  285. keyFrame->scale_.Lerp(nextKeyFrame->scale_, t), weight_));
  286. }
  287. }
  288. }
  289. }
  290. }