3
0

SimpleMotionComponent.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Asset/AssetSerializer.h>
  9. #include <AzCore/Component/Entity.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzCore/RTTI/BehaviorContext.h>
  13. #include <AzCore/Script/ScriptContext.h>
  14. #include <Integration/Components/SimpleMotionComponent.h>
  15. #include <MCore/Source/AttributeString.h>
  16. #include <EMotionFX/Source/ActorInstance.h>
  17. #include <EMotionFX/Source/MotionSystem.h>
  18. #include <EMotionFX/Source/MotionInstance.h>
  19. namespace EMotionFX
  20. {
  21. namespace Integration
  22. {
  23. void SimpleMotionComponent::Configuration::Reflect(AZ::ReflectContext *context)
  24. {
  25. auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  26. if (serializeContext)
  27. {
  28. serializeContext->Class<Configuration>()
  29. ->Version(3)
  30. ->Field("MotionAsset", &Configuration::m_motionAsset)
  31. ->Field("Loop", &Configuration::m_loop)
  32. ->Field("Retarget", &Configuration::m_retarget)
  33. ->Field("Reverse", &Configuration::m_reverse)
  34. ->Field("Mirror", &Configuration::m_mirror)
  35. ->Field("PlaySpeed", &Configuration::m_playspeed)
  36. ->Field("BlendIn", &Configuration::m_blendInTime)
  37. ->Field("BlendOut", &Configuration::m_blendOutTime)
  38. ->Field("PlayOnActivation", &Configuration::m_playOnActivation)
  39. ->Field("InPlace", &Configuration::m_inPlace)
  40. ->Field("FreezeAtLastFrame", &Configuration::m_freezeAtLastFrame)
  41. ;
  42. AZ::EditContext* editContext = serializeContext->GetEditContext();
  43. if (editContext)
  44. {
  45. editContext->Class<Configuration>( "Configuration", "Settings for this Simple Motion")
  46. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  47. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_motionAsset, "Motion", "EMotion FX motion to be loaded for this actor")
  48. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_loop, "Loop motion", "Toggles looping of the animation")
  49. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  50. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_retarget, "Retarget motion", "Toggles retargeting of the animation")
  51. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_reverse, "Reverse motion", "Toggles reversing of the animation")
  52. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_mirror, "Mirror motion", "Toggles mirroring of the animation")
  53. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_playspeed, "Play speed", "Determines the rate at which the motion is played")
  54. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  55. ->Attribute(AZ::Edit::Attributes::Max, 100.0f)
  56. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_blendInTime, "Blend In Time", "Determines the blend in time in seconds")
  57. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  58. ->Attribute(AZ::Edit::Attributes::Max, 100.0f)
  59. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_blendOutTime, "Blend Out Time", "Determines the blend out time in seconds")
  60. ->Attribute(AZ::Edit::Attributes::Visibility, &Configuration::GetBlendOutTimeVisibility)
  61. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  62. ->Attribute(AZ::Edit::Attributes::Max, 100.0f)
  63. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_playOnActivation, "Play on active", "Playing animation immediately after activation.")
  64. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_inPlace, "In-place",
  65. "Plays the animation in-place and removes any positional and rotational changes from root joints.")
  66. ->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_freezeAtLastFrame, "Freeze At Last Frame",
  67. "Go back to bind pose after finishing the motion or freeze at the last frame. This only applies for non-looping motions.")
  68. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  69. ->Attribute(AZ::Edit::Attributes::Visibility, &Configuration::GetFreezeAtLastFrameVisibility)
  70. ;
  71. }
  72. }
  73. }
  74. AZ::Crc32 SimpleMotionComponent::Configuration::GetBlendOutTimeVisibility() const
  75. {
  76. if (!m_loop && !m_freezeAtLastFrame)
  77. {
  78. return AZ::Edit::PropertyVisibility::Show;
  79. }
  80. return AZ::Edit::PropertyVisibility::Hide;
  81. }
  82. AZ::Crc32 SimpleMotionComponent::Configuration::GetFreezeAtLastFrameVisibility() const
  83. {
  84. return m_loop ? AZ::Edit::PropertyVisibility::Hide : AZ::Edit::PropertyVisibility::Show;
  85. }
  86. void SimpleMotionComponent::Reflect(AZ::ReflectContext* context)
  87. {
  88. Configuration::Reflect(context);
  89. auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  90. if (serializeContext)
  91. {
  92. serializeContext->Class<SimpleMotionComponent, AZ::Component>()
  93. ->Version(1)
  94. ->Field("Configuration", &SimpleMotionComponent::m_configuration)
  95. ;
  96. }
  97. auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
  98. if (behaviorContext)
  99. {
  100. behaviorContext->EBus<SimpleMotionComponentRequestBus>("SimpleMotionComponentRequestBus")
  101. ->Event("LoopMotion", &SimpleMotionComponentRequestBus::Events::LoopMotion)
  102. ->Event("GetLoopMotion", &SimpleMotionComponentRequestBus::Events::GetLoopMotion)
  103. ->Attribute("Hidden", AZ::Edit::Attributes::PropertyHidden)
  104. ->VirtualProperty("LoopMotion", "GetLoopMotion", "LoopMotion")
  105. ->Event("RetargetMotion", &SimpleMotionComponentRequestBus::Events::RetargetMotion)
  106. ->Event("ReverseMotion", &SimpleMotionComponentRequestBus::Events::ReverseMotion)
  107. ->Event("MirrorMotion", &SimpleMotionComponentRequestBus::Events::MirrorMotion)
  108. ->Event("SetPlaySpeed", &SimpleMotionComponentRequestBus::Events::SetPlaySpeed)
  109. ->Event("GetPlaySpeed", &SimpleMotionComponentRequestBus::Events::GetPlaySpeed)
  110. ->Attribute("Hidden", AZ::Edit::Attributes::PropertyHidden)
  111. ->VirtualProperty("PlaySpeed", "GetPlaySpeed", "SetPlaySpeed")
  112. ->Event("PlayTime", &SimpleMotionComponentRequestBus::Events::PlayTime)
  113. ->Event("GetPlayTime", &SimpleMotionComponentRequestBus::Events::GetPlayTime)
  114. ->Attribute("Hidden", AZ::Edit::Attributes::PropertyHidden)
  115. ->VirtualProperty("PlayTime", "GetPlayTime", "PlayTime")
  116. ->Event("Motion", &SimpleMotionComponentRequestBus::Events::Motion)
  117. ->Event("GetMotion", &SimpleMotionComponentRequestBus::Events::GetMotion)
  118. ->VirtualProperty("Motion", "GetMotion", "Motion")
  119. ->Event("BlendInTime", &SimpleMotionComponentRequestBus::Events::BlendInTime)
  120. ->Event("GetBlendInTime", &SimpleMotionComponentRequestBus::Events::GetBlendInTime)
  121. ->Attribute("Hidden", AZ::Edit::Attributes::PropertyHidden)
  122. ->VirtualProperty("BlendInTime", "GetBlendInTime", "BlendInTime")
  123. ->Event("BlendOutTime", &SimpleMotionComponentRequestBus::Events::BlendOutTime)
  124. ->Event("GetBlendOutTime", &SimpleMotionComponentRequestBus::Events::GetBlendOutTime)
  125. ->Attribute("Hidden", AZ::Edit::Attributes::PropertyHidden)
  126. ->VirtualProperty("BlendOutTime", "GetBlendOutTime", "BlendOutTime")
  127. ->Event("PlayMotion", &SimpleMotionComponentRequestBus::Events::PlayMotion)
  128. ->Event("GetDuration", &SimpleMotionComponentRequestBus::Events::GetDuration)
  129. ;
  130. behaviorContext->Class<SimpleMotionComponent>()->RequestBus("SimpleMotionComponentRequestBus");
  131. }
  132. }
  133. SimpleMotionComponent::Configuration::Configuration()
  134. : m_loop(false)
  135. , m_retarget(false)
  136. , m_reverse(false)
  137. , m_mirror(false)
  138. , m_playspeed(1.f)
  139. , m_blendInTime(0.0f)
  140. , m_blendOutTime(0.0f)
  141. , m_playOnActivation(true)
  142. , m_inPlace(false)
  143. {
  144. }
  145. SimpleMotionComponent::SimpleMotionComponent(const Configuration* config)
  146. : m_actorInstance(nullptr)
  147. , m_motionInstance(nullptr)
  148. , m_lastMotionInstance(nullptr)
  149. {
  150. if (config)
  151. {
  152. m_configuration = *config;
  153. }
  154. }
  155. SimpleMotionComponent::~SimpleMotionComponent()
  156. {
  157. }
  158. void SimpleMotionComponent::Init()
  159. {
  160. }
  161. void SimpleMotionComponent::Activate()
  162. {
  163. m_motionInstance = nullptr;
  164. AZ::Data::AssetBus::MultiHandler::BusDisconnect();
  165. SimpleMotionComponentRequestBus::Handler::BusConnect(GetEntityId());
  166. auto& cfg = m_configuration;
  167. if (cfg.m_motionAsset.GetId().IsValid())
  168. {
  169. AZ::Data::AssetBus::MultiHandler::BusConnect(cfg.m_motionAsset.GetId());
  170. cfg.m_motionAsset.QueueLoad();
  171. }
  172. ActorComponentNotificationBus::Handler::BusConnect(GetEntityId());
  173. }
  174. void SimpleMotionComponent::Deactivate()
  175. {
  176. SimpleMotionComponentRequestBus::Handler::BusDisconnect();
  177. ActorComponentNotificationBus::Handler::BusDisconnect();
  178. AZ::Data::AssetBus::MultiHandler::BusDisconnect();
  179. RemoveMotionInstanceFromActor(m_motionInstance);
  180. m_motionInstance = nullptr;
  181. RemoveMotionInstanceFromActor(m_lastMotionInstance);
  182. m_lastMotionInstance = nullptr;
  183. m_configuration.m_motionAsset.Release();
  184. m_lastMotionAsset.Release();
  185. m_actorInstance.reset();
  186. }
  187. const MotionInstance* SimpleMotionComponent::GetMotionInstance()
  188. {
  189. return m_motionInstance;
  190. }
  191. void SimpleMotionComponent::SetMotionAssetId(const AZ::Data::AssetId& assetId)
  192. {
  193. m_configuration.m_motionAsset = AZ::Data::Asset<MotionAsset>(assetId, azrtti_typeid<MotionAsset>());
  194. }
  195. void SimpleMotionComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
  196. {
  197. auto& cfg = m_configuration;
  198. if (asset.GetId() == cfg.m_motionAsset.GetId())
  199. {
  200. cfg.m_motionAsset = asset;
  201. if (m_configuration.m_playOnActivation)
  202. {
  203. PlayMotion();
  204. }
  205. }
  206. }
  207. void SimpleMotionComponent::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
  208. {
  209. OnAssetReady(asset);
  210. }
  211. void SimpleMotionComponent::OnActorInstanceCreated(EMotionFX::ActorInstance* actorInstance)
  212. {
  213. m_actorInstance = actorInstance;
  214. if (m_configuration.m_playOnActivation)
  215. {
  216. PlayMotion();
  217. }
  218. }
  219. void SimpleMotionComponent::OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance)
  220. {
  221. AZ_UNUSED(actorInstance);
  222. RemoveMotionInstanceFromActor(m_motionInstance);
  223. m_motionInstance = nullptr;
  224. RemoveMotionInstanceFromActor(m_lastMotionInstance);
  225. m_lastMotionInstance = nullptr;
  226. m_actorInstance.reset();
  227. }
  228. void SimpleMotionComponent::PlayMotion()
  229. {
  230. m_motionInstance = PlayMotionInternal(m_actorInstance.get(), m_configuration, /*deleteOnZeroWeight*/true);
  231. }
  232. void SimpleMotionComponent::RemoveMotionInstanceFromActor(EMotionFX::MotionInstance* motionInstance)
  233. {
  234. if (motionInstance)
  235. {
  236. if (m_actorInstance && m_actorInstance->GetMotionSystem())
  237. {
  238. m_actorInstance->GetMotionSystem()->RemoveMotionInstance(motionInstance);
  239. }
  240. }
  241. }
  242. void SimpleMotionComponent::LoopMotion(bool enable)
  243. {
  244. m_configuration.m_loop = enable;
  245. if (m_motionInstance)
  246. {
  247. m_motionInstance->SetMaxLoops(enable ? EMFX_LOOPFOREVER : 1);
  248. }
  249. }
  250. bool SimpleMotionComponent::GetLoopMotion() const
  251. {
  252. return m_configuration.m_loop;
  253. }
  254. void SimpleMotionComponent::RetargetMotion(bool enable)
  255. {
  256. m_configuration.m_retarget = enable;
  257. if (m_motionInstance)
  258. {
  259. m_motionInstance->SetRetargetingEnabled(enable);
  260. }
  261. }
  262. void SimpleMotionComponent::ReverseMotion(bool enable)
  263. {
  264. m_configuration.m_reverse = enable;
  265. if (m_motionInstance)
  266. {
  267. m_motionInstance->SetPlayMode(enable ? EMotionFX::EPlayMode::PLAYMODE_BACKWARD : EMotionFX::EPlayMode::PLAYMODE_FORWARD);
  268. }
  269. }
  270. void SimpleMotionComponent::MirrorMotion(bool enable)
  271. {
  272. m_configuration.m_mirror = enable;
  273. if (m_motionInstance)
  274. {
  275. m_motionInstance->SetMirrorMotion(enable);
  276. }
  277. }
  278. void SimpleMotionComponent::SetPlaySpeed(float speed)
  279. {
  280. m_configuration.m_playspeed = speed;
  281. if (m_motionInstance)
  282. {
  283. m_motionInstance->SetPlaySpeed(speed);
  284. }
  285. }
  286. float SimpleMotionComponent::GetPlaySpeed() const
  287. {
  288. return m_configuration.m_playspeed;
  289. }
  290. void SimpleMotionComponent::PlayTime(float time)
  291. {
  292. if (m_motionInstance)
  293. {
  294. float delta = time - m_motionInstance->GetLastCurrentTime();
  295. m_motionInstance->SetCurrentTime(time, false);
  296. // Apply the same time step to the last animation
  297. // so blend out will be good. Otherwise we are just blending
  298. // from the last frame played of the last animation.
  299. if (m_lastMotionInstance && m_lastMotionInstance->GetIsBlending())
  300. {
  301. m_lastMotionInstance->SetCurrentTime(m_lastMotionInstance->GetLastCurrentTime() + delta, false);
  302. }
  303. }
  304. }
  305. float SimpleMotionComponent::GetPlayTime() const
  306. {
  307. float result = 0.0f;
  308. if (m_motionInstance)
  309. {
  310. result = m_motionInstance->GetCurrentTimeNormalized();
  311. }
  312. return result;
  313. }
  314. float SimpleMotionComponent::GetDuration() const
  315. {
  316. return m_motionInstance ? m_motionInstance->GetDuration() : 0.0f;
  317. }
  318. void SimpleMotionComponent::Motion(AZ::Data::AssetId assetId)
  319. {
  320. if (m_configuration.m_motionAsset.GetId() != assetId)
  321. {
  322. // Disconnect the old asset bus
  323. if (AZ::Data::AssetBus::MultiHandler::BusIsConnectedId(m_configuration.m_motionAsset.GetId()))
  324. {
  325. AZ::Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_motionAsset.GetId());
  326. }
  327. // Save the motion asset that we are about to be remove in case it can be reused.
  328. AZ::Data::Asset<MotionAsset> oldLastMotionAsset = m_lastMotionAsset;
  329. if (m_lastMotionInstance)
  330. {
  331. RemoveMotionInstanceFromActor(m_lastMotionInstance);
  332. }
  333. // Store the current motion asset as the last one for possible blending.
  334. // If we don't keep a reference to the motion asset, the motion instance will be
  335. // automatically released.
  336. if (m_configuration.m_motionAsset.GetId().IsValid())
  337. {
  338. m_lastMotionAsset = m_configuration.m_motionAsset;
  339. }
  340. // Set the current motion instance as the last motion instance. The new current motion
  341. // instance will then be set when the load is complete.
  342. m_lastMotionInstance = m_motionInstance;
  343. m_motionInstance = nullptr;
  344. // Start the fade out if there is a blend out time. Otherwise just leave the
  345. // m_lastMotionInstance where it is at so the next anim can blend from that frame.
  346. if (m_lastMotionInstance && m_configuration.m_blendOutTime > 0.0f)
  347. {
  348. m_lastMotionInstance->Stop(m_configuration.m_blendOutTime);
  349. }
  350. // Reuse the old, last motion asset if possible. Otherwise, request a load.
  351. if (assetId.IsValid() && oldLastMotionAsset.GetData() && assetId == oldLastMotionAsset.GetId())
  352. {
  353. // Even though we are not calling GetAsset here, OnAssetReady
  354. // will be fired when the bus is connected because this asset is already loaded.
  355. m_configuration.m_motionAsset = oldLastMotionAsset;
  356. }
  357. else
  358. {
  359. // Won't be able to reuse oldLastMotionAsset, release it.
  360. oldLastMotionAsset.Release();
  361. // Clear the old asset.
  362. m_configuration.m_motionAsset.Release();
  363. // Create a new asset
  364. if (assetId.IsValid())
  365. {
  366. m_configuration.m_motionAsset = AZ::Data::AssetManager::Instance().GetAsset<MotionAsset>(assetId, m_configuration.m_motionAsset.GetAutoLoadBehavior());
  367. }
  368. }
  369. // Connect the bus if the asset is is valid.
  370. if (m_configuration.m_motionAsset.GetId().IsValid())
  371. {
  372. AZ::Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_motionAsset.GetId());
  373. }
  374. }
  375. }
  376. AZ::Data::AssetId SimpleMotionComponent::GetMotion() const
  377. {
  378. return m_configuration.m_motionAsset.GetId();
  379. }
  380. void SimpleMotionComponent::BlendInTime(float time)
  381. {
  382. m_configuration.m_blendInTime = time;
  383. }
  384. float SimpleMotionComponent::GetBlendInTime() const
  385. {
  386. return m_configuration.m_blendInTime;
  387. }
  388. void SimpleMotionComponent::BlendOutTime(float time)
  389. {
  390. m_configuration.m_blendOutTime = time;
  391. }
  392. float SimpleMotionComponent::GetBlendOutTime() const
  393. {
  394. return m_configuration.m_blendOutTime;
  395. }
  396. EMotionFX::MotionInstance* SimpleMotionComponent::PlayMotionInternal(const EMotionFX::ActorInstance* actorInstance, const SimpleMotionComponent::Configuration& cfg, bool deleteOnZeroWeight)
  397. {
  398. if (!actorInstance || !cfg.m_motionAsset.IsReady())
  399. {
  400. return nullptr;
  401. }
  402. if (!actorInstance->GetMotionSystem())
  403. {
  404. return nullptr;
  405. }
  406. auto* motionAsset = cfg.m_motionAsset.GetAs<MotionAsset>();
  407. if (!motionAsset)
  408. {
  409. AZ_Error("EMotionFX", motionAsset, "Motion asset is not valid.");
  410. return nullptr;
  411. }
  412. //init the PlaybackInfo based on our config
  413. EMotionFX::PlayBackInfo info;
  414. info.m_numLoops = cfg.m_loop ? EMFX_LOOPFOREVER : 1;
  415. info.m_retarget = cfg.m_retarget;
  416. info.m_playMode = cfg.m_reverse ? EMotionFX::EPlayMode::PLAYMODE_BACKWARD : EMotionFX::EPlayMode::PLAYMODE_FORWARD;
  417. info.m_freezeAtLastFrame = info.m_numLoops == 1;
  418. info.m_mirrorMotion = cfg.m_mirror;
  419. info.m_playSpeed = cfg.m_playspeed;
  420. info.m_playNow = true;
  421. info.m_deleteOnZeroWeight = deleteOnZeroWeight;
  422. info.m_canOverwrite = false;
  423. info.m_blendInTime = cfg.m_blendInTime;
  424. info.m_blendOutTime = cfg.m_blendOutTime;
  425. info.m_inPlace = cfg.m_inPlace;
  426. info.m_freezeAtLastFrame = cfg.m_freezeAtLastFrame;
  427. return actorInstance->GetMotionSystem()->PlayMotion(motionAsset->m_emfxMotion.get(), &info);
  428. }
  429. } // namespace integration
  430. } // namespace EMotionFX