AnimationState.cpp 12 KB

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