AnimationState.cpp 12 KB

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