AnimationState.cpp 12 KB

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