AnimationState.cpp 12 KB

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