UniformMotionDataTests.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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/UnitTest/UnitTest.h>
  9. #include <AzCore/std/string/string.h>
  10. #include <AzCore/std/tuple.h>
  11. #include <AzCore/std/smart_ptr/unique_ptr.h>
  12. #include <AzCore/Math/Vector3.h>
  13. #include <AzCore/Math/Quaternion.h>
  14. #include <EMotionFX/Source/Actor.h>
  15. #include <EMotionFX/Source/ActorInstance.h>
  16. #include <EMotionFX/Source/MotionData/UniformMotionData.h>
  17. #include <EMotionFX/Source/Node.h>
  18. #include <EMotionFX/Source/Skeleton.h>
  19. #include <EMotionFX/Source/TransformData.h>
  20. #include <MCore/Source/AzCoreConversions.h>
  21. #include <Tests/ActorFixture.h>
  22. #include <Tests/Matchers.h>
  23. namespace EMotionFX
  24. {
  25. class UniformMotionDataTests
  26. : public ActorFixture
  27. , public UnitTest::TraceBusRedirector
  28. {
  29. public:
  30. void SetUp()
  31. {
  32. UnitTest::TraceBusRedirector::BusConnect();
  33. ActorFixture::SetUp();
  34. }
  35. void TearDown()
  36. {
  37. ActorFixture::TearDown();
  38. UnitTest::TraceBusRedirector::BusDisconnect();
  39. }
  40. };
  41. TEST_F(UniformMotionDataTests, ZeroInit)
  42. {
  43. UniformMotionData motionData;
  44. UniformMotionData::InitSettings settings;
  45. settings.m_sampleSpacing = 1.0f / 30.0f;
  46. settings.m_numSamples = 0;
  47. settings.m_numJoints = 0;
  48. settings.m_numMorphs = 0;
  49. settings.m_numFloats = 0;
  50. motionData.Init(settings);
  51. EXPECT_FLOAT_EQ(motionData.GetDuration(), 0.0f);
  52. EXPECT_FLOAT_EQ(motionData.GetSampleSpacing(), 1.0f / 30.0f);
  53. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 30.0f);
  54. EXPECT_EQ(motionData.GetNumSamples(), 0);
  55. }
  56. TEST_F(UniformMotionDataTests, Init)
  57. {
  58. UniformMotionData motionData;
  59. UniformMotionData::InitSettings settings;
  60. settings.m_sampleSpacing = 1.0f / 30.0f;
  61. settings.m_numSamples = 301;
  62. settings.m_numJoints = 3;
  63. settings.m_numMorphs = 4;
  64. settings.m_numFloats = 5;
  65. motionData.Init(settings);
  66. EXPECT_FLOAT_EQ(motionData.GetDuration(), 10.0f);
  67. EXPECT_FLOAT_EQ(motionData.GetSampleSpacing(), 1.0f / 30.0f);
  68. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 30.0f);
  69. EXPECT_EQ(motionData.GetNumSamples(), 301);
  70. EXPECT_EQ(motionData.GetNumJoints(), 3);
  71. EXPECT_EQ(motionData.GetNumMorphs(), 4);
  72. EXPECT_EQ(motionData.GetNumFloats(), 5);
  73. }
  74. TEST_F(UniformMotionDataTests, Clear)
  75. {
  76. UniformMotionData motionData;
  77. UniformMotionData::InitSettings settings;
  78. settings.m_sampleSpacing = 1.0f / 30.0f;
  79. settings.m_numSamples = 31;
  80. settings.m_numJoints = 3;
  81. settings.m_numMorphs = 4;
  82. settings.m_numFloats = 5;
  83. motionData.Init(settings);
  84. EXPECT_FLOAT_EQ(motionData.GetDuration(), 1.0f);
  85. EXPECT_EQ(motionData.GetNumSamples(), 31);
  86. EXPECT_EQ(motionData.GetNumJoints(), 3);
  87. EXPECT_EQ(motionData.GetNumMorphs(), 4);
  88. EXPECT_EQ(motionData.GetNumFloats(), 5);
  89. motionData.Clear();
  90. EXPECT_EQ(motionData.GetNumSamples(), 0);
  91. EXPECT_FLOAT_EQ(motionData.GetSampleSpacing(), 1.0f / 30.0f);
  92. EXPECT_FLOAT_EQ(motionData.GetDuration(), 0.0f);
  93. EXPECT_EQ(motionData.GetNumSamples(), 0);
  94. EXPECT_EQ(motionData.GetNumJoints(), 0);
  95. EXPECT_EQ(motionData.GetNumMorphs(), 0);
  96. EXPECT_EQ(motionData.GetNumFloats(), 0);
  97. }
  98. TEST_F(UniformMotionDataTests, CalculateSampleRate)
  99. {
  100. UniformMotionData motionData;
  101. UniformMotionData::InitSettings settings;
  102. settings.m_sampleSpacing = 1.0f / 30.0f;
  103. settings.m_numSamples = 31;
  104. motionData.Init(settings);
  105. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 30.0f);
  106. EXPECT_FLOAT_EQ(motionData.GetDuration(), 1.0f);
  107. settings.m_sampleSpacing = 1.0f / 60.0f;
  108. settings.m_numSamples = 121;
  109. motionData.Init(settings);
  110. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 60.0f);
  111. EXPECT_FLOAT_EQ(motionData.GetDuration(), 2.0f);
  112. settings.m_sampleSpacing = 1.0f / 30.0f;
  113. settings.m_numSamples = 0;
  114. motionData.Init(settings);
  115. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 30.0f);
  116. EXPECT_FLOAT_EQ(motionData.GetDuration(), 0.0f);
  117. /*
  118. settings.m_sampleSpacing = 0.0f;
  119. settings.m_numSamples = 31;
  120. AZ_TEST_START_TRACE_SUPPRESSION;
  121. motionData.Init(settings);
  122. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  123. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 0.0f);
  124. EXPECT_FLOAT_EQ(motionData.GetDuration(), 0.0f);
  125. settings.m_sampleSpacing = -1.0f;
  126. settings.m_numSamples = 31;
  127. AZ_TEST_START_TRACE_SUPPRESSION;
  128. motionData.Init(settings);
  129. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  130. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 0.0f);
  131. EXPECT_FLOAT_EQ(motionData.GetDuration(), 0.0f);
  132. */
  133. }
  134. TEST_F(UniformMotionDataTests, FindMotionLinkData)
  135. {
  136. UniformMotionData motionData;
  137. UniformMotionData::InitSettings settings;
  138. settings.m_sampleSpacing = 1.0f / 10.0f;
  139. settings.m_numSamples = 11;
  140. motionData.Init(settings);
  141. EXPECT_FLOAT_EQ(motionData.GetDuration(), 1.0f);
  142. EXPECT_FLOAT_EQ(motionData.GetSampleSpacing(), 1.0f / 10.0f);
  143. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 10.0f);
  144. EXPECT_EQ(motionData.GetNumSamples(), 11);
  145. EXPECT_EQ(motionData.GetNumMotionLinkCacheEntries(), 0);
  146. AZStd::unique_ptr<Actor> clonedActor(m_actor->Clone());
  147. const MotionLinkData* linkDataA = motionData.FindMotionLinkData(m_actor.get());
  148. EXPECT_EQ(motionData.GetNumMotionLinkCacheEntries(), 1);
  149. const MotionLinkData* linkDataB = motionData.FindMotionLinkData(m_actor.get());
  150. EXPECT_EQ(motionData.GetNumMotionLinkCacheEntries(), 1);
  151. const MotionLinkData* linkDataC = motionData.FindMotionLinkData(const_cast<Actor*>(clonedActor.get()));
  152. EXPECT_EQ(motionData.GetNumMotionLinkCacheEntries(), 2);
  153. const MotionLinkData* linkDataD = motionData.FindMotionLinkData(const_cast<Actor*>(clonedActor.get()));
  154. EXPECT_EQ(motionData.GetNumMotionLinkCacheEntries(), 2);
  155. EXPECT_NE(linkDataA, nullptr);
  156. EXPECT_NE(linkDataB, nullptr);
  157. EXPECT_NE(linkDataC, nullptr);
  158. EXPECT_NE(linkDataD, nullptr);
  159. EXPECT_EQ(linkDataA, linkDataB);
  160. EXPECT_NE(linkDataA, linkDataC);
  161. EXPECT_EQ(linkDataC, linkDataD);
  162. clonedActor.reset(nullptr);
  163. EXPECT_EQ(motionData.GetNumMotionLinkCacheEntries(), 1);
  164. }
  165. TEST_F(UniformMotionDataTests, RemoveItems)
  166. {
  167. UniformMotionData motionData;
  168. UniformMotionData::InitSettings settings;
  169. settings.m_sampleSpacing = 1.0f / 30.0f;
  170. settings.m_numSamples = 300;
  171. settings.m_numJoints = 4;
  172. settings.m_numMorphs = 4;
  173. settings.m_numFloats = 4;
  174. motionData.Init(settings);
  175. ASSERT_EQ(motionData.GetNumJoints(), 4);
  176. ASSERT_EQ(motionData.GetNumMorphs(), 4);
  177. ASSERT_EQ(motionData.GetNumFloats(), 4);
  178. motionData.SetJointName(0, "Joint1");
  179. motionData.SetJointName(1, "Joint2");
  180. motionData.SetJointName(2, "Joint3");
  181. motionData.SetJointName(3, "Joint4");
  182. motionData.SetMorphName(0, "Morph1");
  183. motionData.SetMorphName(1, "Morph2");
  184. motionData.SetMorphName(2, "Morph3");
  185. motionData.SetMorphName(3, "Morph4");
  186. motionData.SetFloatName(0, "Float1");
  187. motionData.SetFloatName(1, "Float2");
  188. motionData.SetFloatName(2, "Float3");
  189. motionData.SetFloatName(3, "Float4");
  190. motionData.RemoveJoint(0);
  191. motionData.RemoveMorph(1);
  192. motionData.RemoveFloat(2);
  193. ASSERT_EQ(motionData.GetNumJoints(), 3);
  194. ASSERT_EQ(motionData.GetNumMorphs(), 3);
  195. ASSERT_EQ(motionData.GetNumFloats(), 3);
  196. EXPECT_STREQ(motionData.GetJointName(0).c_str(), "Joint2");
  197. EXPECT_STREQ(motionData.GetJointName(1).c_str(), "Joint3");
  198. EXPECT_STREQ(motionData.GetJointName(2).c_str(), "Joint4");
  199. EXPECT_STREQ(motionData.GetMorphName(0).c_str(), "Morph1");
  200. EXPECT_STREQ(motionData.GetMorphName(1).c_str(), "Morph3");
  201. EXPECT_STREQ(motionData.GetMorphName(2).c_str(), "Morph4");
  202. EXPECT_STREQ(motionData.GetFloatName(0).c_str(), "Float1");
  203. EXPECT_STREQ(motionData.GetFloatName(1).c_str(), "Float2");
  204. EXPECT_STREQ(motionData.GetFloatName(2).c_str(), "Float4");
  205. }
  206. TEST_F(UniformMotionDataTests, FindData)
  207. {
  208. UniformMotionData motionData;
  209. UniformMotionData::InitSettings settings;
  210. settings.m_numJoints = 3;
  211. settings.m_numMorphs = 3;
  212. settings.m_numFloats = 3;
  213. motionData.Init(settings);
  214. ASSERT_EQ(motionData.GetNumJoints(), 3);
  215. ASSERT_EQ(motionData.GetNumMorphs(), 3);
  216. ASSERT_EQ(motionData.GetNumFloats(), 3);
  217. motionData.SetJointName(0, "Joint1");
  218. motionData.SetJointName(1, "Joint2");
  219. motionData.SetJointName(2, "Joint3");
  220. motionData.SetMorphName(0, "Morph1");
  221. motionData.SetMorphName(1, "Morph2");
  222. motionData.SetMorphName(2, "Morph3");
  223. motionData.SetFloatName(0, "Float1");
  224. motionData.SetFloatName(1, "Float2");
  225. motionData.SetFloatName(2, "Float3");
  226. EXPECT_FALSE(motionData.FindJointIndexByName("Blah").IsSuccess());
  227. EXPECT_FALSE(motionData.FindMorphIndexByName("Blah").IsSuccess());
  228. EXPECT_FALSE(motionData.FindFloatIndexByName("Blah").IsSuccess());
  229. ASSERT_TRUE(motionData.FindJointIndexByName("Joint1").IsSuccess());
  230. ASSERT_TRUE(motionData.FindJointIndexByName("Joint2").IsSuccess());
  231. ASSERT_TRUE(motionData.FindJointIndexByName("Joint3").IsSuccess());
  232. ASSERT_TRUE(motionData.FindMorphIndexByName("Morph1").IsSuccess());
  233. ASSERT_TRUE(motionData.FindMorphIndexByName("Morph2").IsSuccess());
  234. ASSERT_TRUE(motionData.FindMorphIndexByName("Morph3").IsSuccess());
  235. ASSERT_TRUE(motionData.FindFloatIndexByName("Float1").IsSuccess());
  236. ASSERT_TRUE(motionData.FindFloatIndexByName("Float2").IsSuccess());
  237. ASSERT_TRUE(motionData.FindFloatIndexByName("Float3").IsSuccess());
  238. EXPECT_EQ(motionData.FindJointIndexByName("Joint1").GetValue(), 0);
  239. EXPECT_EQ(motionData.FindJointIndexByName("Joint2").GetValue(), 1);
  240. EXPECT_EQ(motionData.FindJointIndexByName("Joint3").GetValue(), 2);
  241. EXPECT_EQ(motionData.FindMorphIndexByName("Morph1").GetValue(), 0);
  242. EXPECT_EQ(motionData.FindMorphIndexByName("Morph2").GetValue(), 1);
  243. EXPECT_EQ(motionData.FindMorphIndexByName("Morph3").GetValue(), 2);
  244. EXPECT_EQ(motionData.FindFloatIndexByName("Float1").GetValue(), 0);
  245. EXPECT_EQ(motionData.FindFloatIndexByName("Float2").GetValue(), 1);
  246. EXPECT_EQ(motionData.FindFloatIndexByName("Float3").GetValue(), 2);
  247. }
  248. TEST_F(UniformMotionDataTests, MainTest)
  249. {
  250. UniformMotionData motionData;
  251. UniformMotionData::InitSettings settings;
  252. settings.m_sampleSpacing = 1.0f / 30.0f;
  253. settings.m_numSamples = 301;
  254. settings.m_numJoints = 3;
  255. settings.m_numMorphs = 3;
  256. settings.m_numFloats = 3;
  257. motionData.Init(settings);
  258. EXPECT_FLOAT_EQ(motionData.GetDuration(), 10.0f);
  259. EXPECT_FLOAT_EQ(motionData.GetSampleSpacing(), 1.0f / 30.0f);
  260. EXPECT_FLOAT_EQ(motionData.CalculateSampleRate(), 30.0f);
  261. EXPECT_EQ(motionData.GetNumSamples(), 301);
  262. EXPECT_EQ(motionData.GetNumJoints(), 3);
  263. EXPECT_EQ(motionData.GetNumMorphs(), 3);
  264. EXPECT_EQ(motionData.GetNumFloats(), 3);
  265. motionData.SetJointName(0, "Joint1");
  266. motionData.SetJointName(1, "Joint2");
  267. motionData.SetJointName(2, "Joint3");
  268. motionData.SetMorphName(0, "Morph1");
  269. motionData.SetMorphName(1, "Morph2");
  270. motionData.SetMorphName(2, "Morph3");
  271. motionData.SetFloatName(0, "Float1");
  272. motionData.SetFloatName(1, "Float2");
  273. motionData.SetFloatName(2, "Float3");
  274. for (size_t i = 0; i < 3; ++i)
  275. {
  276. const float iFloat = static_cast<float>(i);
  277. motionData.SetMorphPoseValue(i, iFloat);
  278. motionData.SetFloatPoseValue(i, iFloat);
  279. EXPECT_FLOAT_EQ(motionData.GetMorphPoseValue(i), iFloat);
  280. EXPECT_FLOAT_EQ(motionData.GetFloatPoseValue(i), iFloat);
  281. }
  282. motionData.AllocateMorphSamples(0);
  283. motionData.AllocateFloatSamples(0);
  284. EXPECT_TRUE(motionData.IsMorphAnimated(0));
  285. EXPECT_TRUE(motionData.IsFloatAnimated(0));
  286. EXPECT_FALSE(motionData.IsMorphAnimated(1));
  287. EXPECT_FALSE(motionData.IsFloatAnimated(1));
  288. EXPECT_FALSE(motionData.IsMorphAnimated(2));
  289. EXPECT_FALSE(motionData.IsFloatAnimated(2));
  290. for (size_t i = 0; i < motionData.GetNumSamples(); ++i)
  291. {
  292. const float iFloat = static_cast<float>(i);
  293. motionData.SetMorphSample(0, i, iFloat);
  294. motionData.SetFloatSample(0, i, iFloat * 10.0f);
  295. EXPECT_FLOAT_EQ(motionData.GetMorphSample(0, i).m_value, iFloat);
  296. EXPECT_FLOAT_EQ(motionData.GetMorphSample(0, i).m_time, static_cast<float>(i * motionData.GetSampleSpacing()));
  297. EXPECT_FLOAT_EQ(motionData.GetFloatSample(0, i).m_value, iFloat * 10.0f);
  298. EXPECT_FLOAT_EQ(motionData.GetFloatSample(0, i).m_time, static_cast<float>(i * motionData.GetSampleSpacing()));
  299. }
  300. // Test morph sampling.
  301. AZ::Outcome<size_t> index = motionData.FindMorphIndexByName("Morph1");
  302. ASSERT_TRUE(index.IsSuccess());
  303. if (index.IsSuccess())
  304. {
  305. float result = -1.0f;
  306. const AZ::u32 id = motionData.GetMorphNameId(index.GetValue());
  307. using ValuePair = AZStd::pair<float, float>; // First = time, second = expectedValue.
  308. const AZStd::vector<ValuePair> values{
  309. { -1.0f, 0.0f },
  310. { 0.0f, 0.0f },
  311. { motionData.GetSampleSpacing() * 0.25f, 0.25f },
  312. { motionData.GetSampleSpacing() * 0.5f, 0.5f },
  313. { motionData.GetSampleSpacing() * 0.75f, 0.75f },
  314. { motionData.GetSampleSpacing(), 1.0f },
  315. { motionData.GetDuration() * 0.5f, static_cast<float>(motionData.GetNumSamples() / 2) },
  316. { motionData.GetDuration(), static_cast<float>(motionData.GetNumSamples() - 1) },
  317. { motionData.GetDuration() + 1.0f, static_cast<float>(motionData.GetNumSamples() - 1) }
  318. };
  319. for (const ValuePair& valuePair : values)
  320. {
  321. MotionData::SampleSettings sampleSettings;
  322. sampleSettings.m_sampleTime = valuePair.first;
  323. sampleSettings.m_actorInstance = m_actorInstance;
  324. const bool success = motionData.SampleMorph(sampleSettings, id, result);
  325. EXPECT_TRUE(success);
  326. EXPECT_FLOAT_EQ(result, valuePair.second);
  327. }
  328. }
  329. // Test float sampling.
  330. index = motionData.FindFloatIndexByName("Float1");
  331. ASSERT_TRUE(index.IsSuccess());
  332. if (index.IsSuccess())
  333. {
  334. float result = -1.0f;
  335. const AZ::u32 id = motionData.GetFloatNameId(index.GetValue());
  336. using ValuePair = AZStd::pair<float, float>; // First = time, second = expectedValue.
  337. const AZStd::vector<ValuePair> values{
  338. { -1.0f, 0.0f },
  339. { 0.0f, 0.0f },
  340. { motionData.GetSampleSpacing() * 0.25f, 2.5f },
  341. { motionData.GetSampleSpacing() * 0.5f, 5.0f },
  342. { motionData.GetSampleSpacing() * 0.75f, 7.5f },
  343. { motionData.GetSampleSpacing(), 10.0f },
  344. { motionData.GetDuration() * 0.5f, static_cast<float>(motionData.GetNumSamples() / 2) * 10.0f },
  345. { motionData.GetDuration(), static_cast<float>(motionData.GetNumSamples() - 1) * 10.0f },
  346. { motionData.GetDuration() + 1.0f, static_cast<float>(motionData.GetNumSamples() - 1) * 10.0f }
  347. };
  348. for (const ValuePair& valuePair : values)
  349. {
  350. MotionData::SampleSettings sampleSettings;
  351. sampleSettings.m_sampleTime = valuePair.first;
  352. sampleSettings.m_actorInstance = m_actorInstance;
  353. const bool success = motionData.SampleFloat(sampleSettings, id, result);
  354. EXPECT_TRUE(success);
  355. EXPECT_FLOAT_EQ(result, valuePair.second);
  356. }
  357. }
  358. // Test sampling morphs and floats without any animation data.
  359. MotionData::SampleSettings sampleSettings;
  360. sampleSettings.m_actorInstance = m_actorInstance;
  361. sampleSettings.m_sampleTime = motionData.GetDuration() / 2.0f;
  362. float sampleResult = motionData.SampleFloat(sampleSettings, 1);
  363. EXPECT_FLOAT_EQ(sampleResult, 1.0f);
  364. sampleResult = motionData.SampleFloat(sampleSettings, 2);
  365. EXPECT_FLOAT_EQ(sampleResult, 2.0f);
  366. sampleResult = motionData.SampleMorph(sampleSettings, 1);
  367. EXPECT_FLOAT_EQ(sampleResult, 1.0f);
  368. sampleResult = motionData.SampleMorph(sampleSettings, 2);
  369. EXPECT_FLOAT_EQ(sampleResult, 2.0f);
  370. // Test adding a joint.
  371. AZ::Quaternion q1, q2;
  372. q1.SetFromEulerDegrees(AZ::Vector3(0.1f, 0.2f, 0.3f));
  373. q2.SetFromEulerDegrees(AZ::Vector3(0.4f, 0.5f, 0.6f));
  374. const Transform poseTransform(AZ::Vector3(1.0f, 2.0f, 3.0f), q1, AZ::Vector3(1.0f, 2.0f, 3.0f));
  375. const Transform bindTransform(AZ::Vector3(4.0f, 5.0f, 6.0f), q2, AZ::Vector3(4.0f, 5.0f, 6.0f));
  376. const size_t jointIndex = motionData.AddJoint("Joint4", poseTransform, bindTransform);
  377. EXPECT_EQ(jointIndex, 3);
  378. EXPECT_FALSE(motionData.IsJointAnimated(3));
  379. EXPECT_STREQ(motionData.GetJointName(3).c_str(), "Joint4");
  380. EXPECT_THAT(motionData.GetJointPoseTransform(3).m_position, IsClose(poseTransform.m_position));
  381. EXPECT_THAT(motionData.GetJointPoseTransform(3).m_rotation, IsClose(poseTransform.m_rotation));
  382. #ifndef EMFX_SCALE_DISABLED
  383. EXPECT_THAT(motionData.GetJointPoseTransform(3).m_scale, IsClose(poseTransform.m_scale));
  384. #endif
  385. EXPECT_THAT(motionData.GetJointBindPoseTransform(3).m_position, IsClose(bindTransform.m_position));
  386. EXPECT_THAT(motionData.GetJointBindPoseTransform(3).m_rotation, IsClose(bindTransform.m_rotation));
  387. #ifndef EMFX_SCALE_DISABLED
  388. EXPECT_THAT(motionData.GetJointBindPoseTransform(3).m_scale, IsClose(bindTransform.m_scale));
  389. #endif
  390. // Test adding a morph.
  391. const size_t morphIndex = motionData.AddMorph("Morph4", 1.0f);
  392. EXPECT_EQ(morphIndex, 3);
  393. EXPECT_FALSE(motionData.IsMorphAnimated(3));
  394. EXPECT_STREQ(motionData.GetMorphName(3).c_str(), "Morph4");
  395. EXPECT_FLOAT_EQ(motionData.GetMorphPoseValue(3), 1.0f);
  396. // Test adding a float.
  397. const size_t floatIndex = motionData.AddFloat("Float4", 1.0f);
  398. EXPECT_EQ(floatIndex, 3);
  399. EXPECT_FALSE(motionData.IsFloatAnimated(3));
  400. EXPECT_STREQ(motionData.GetFloatName(3).c_str(), "Float4");
  401. EXPECT_FLOAT_EQ(motionData.GetFloatPoseValue(3), 1.0f);
  402. // Construct some transform tracks.
  403. EXPECT_FALSE(motionData.IsJointAnimated(0));
  404. EXPECT_FALSE(motionData.IsJointPositionAnimated(0));
  405. EXPECT_FALSE(motionData.IsJointRotationAnimated(0));
  406. #ifndef EMFX_SCALE_DISABLED
  407. EXPECT_FALSE(motionData.IsJointScaleAnimated(0));
  408. #endif
  409. motionData.AllocateJointPositionSamples(0);
  410. motionData.AllocateJointRotationSamples(0);
  411. EXPECT_TRUE(motionData.IsJointPositionAnimated(0));
  412. EXPECT_TRUE(motionData.IsJointRotationAnimated(0));
  413. #ifndef EMFX_SCALE_DISABLED
  414. EXPECT_FALSE(motionData.IsJointScaleAnimated(0));
  415. motionData.AllocateJointScaleSamples(0);
  416. EXPECT_TRUE(motionData.IsJointScaleAnimated(0));
  417. #endif
  418. // Set the values for the transform samples.
  419. for (size_t i = 0; i < motionData.GetNumSamples(); ++i)
  420. {
  421. const float iFloat = static_cast<float>(i);
  422. const float expectedKeyTime = static_cast<float>(motionData.GetSampleSpacing() * i);
  423. const AZ::Vector3 position(iFloat, 1.0f, 2.0f);
  424. motionData.SetJointPositionSample(0, i, position);
  425. EXPECT_THAT(motionData.GetJointPositionSample(0, i).m_value, IsClose(position));
  426. EXPECT_NEAR(motionData.GetJointPositionSample(0, i).m_time, expectedKeyTime, 0.00001f);
  427. const AZ::Quaternion rotation = AZ::Quaternion::CreateRotationZ((iFloat / static_cast<float>(motionData.GetNumSamples())) * 180.0f).GetNormalized();
  428. motionData.SetJointRotationSample(0, i, rotation);
  429. EXPECT_THAT(motionData.GetJointRotationSample(0, i).m_value, IsClose(rotation));
  430. EXPECT_NEAR(motionData.GetJointRotationSample(0, i).m_time, expectedKeyTime, 0.00001f);
  431. #ifndef EMFX_SCALE_DISABLED
  432. const AZ::Vector3 scale(iFloat + 1.0f, iFloat * 2.0f + 1.0f, iFloat * 3.0f + 1.0f);
  433. motionData.SetJointScaleSample(0, i, scale);
  434. EXPECT_THAT(motionData.GetJointScaleSample(0, i).m_value, IsClose(scale));
  435. EXPECT_NEAR(motionData.GetJointScaleSample(0, i).m_time, expectedKeyTime, 0.00001f);
  436. #endif
  437. }
  438. // Rename our sub motion data to match our actor.
  439. const Skeleton* skeleton = m_actor->GetSkeleton();
  440. for (size_t i = 0; i < 3; ++i)
  441. {
  442. motionData.SetJointName(i, skeleton->GetNode(static_cast<AZ::u32>(i))->GetNameString());
  443. EXPECT_STREQ(motionData.GetJointName(i).c_str(), skeleton->GetNode(static_cast<AZ::u32>(i))->GetName());
  444. }
  445. // Adjust bind pose of our fourth joint.
  446. Pose* bindPose = m_actorInstance->GetTransformData()->GetBindPose();
  447. #ifndef EMFX_SCALE_DISABLED
  448. const Transform expectedBindTransform(AZ::Vector3(0.0f, 1.0f, 2.0f), AZ::Quaternion::CreateIdentity(), AZ::Vector3(10.0f, 20.0f, 30.0f));
  449. #else
  450. const Transform expectedBindTransform(AZ::Vector3(0.0f, 1.0f, 2.0f), AZ::Quaternion::CreateIdentity());
  451. #endif
  452. bindPose->SetLocalSpaceTransform(3, expectedBindTransform);
  453. // Now sample the joint transforms.
  454. const size_t lastSampleIndex = motionData.GetNumSamples() - 1;
  455. #ifndef EMFX_SCALE_DISABLED
  456. const AZ::Vector3 firstScaleSample = motionData.GetJointScaleSample(0, 0).m_value;
  457. const AZ::Vector3 lastScaleSample = motionData.GetJointScaleSample(0, lastSampleIndex).m_value;
  458. #else
  459. const AZ::Vector3 firstScaleSample(1.0f, 1.0f, 1.0f);
  460. const AZ::Vector3 lastScaleSample(1.0f, 1.0f, 1.0f);
  461. #endif
  462. using TransformPair = AZStd::pair<float, Transform>; // First = time, second = expectedValue.
  463. const AZStd::vector<TransformPair> values{
  464. { -1.0f,
  465. Transform(
  466. motionData.GetJointPositionSample(0, 0).m_value,
  467. motionData.GetJointRotationSample(0, 0).m_value,
  468. firstScaleSample) },
  469. { 0.0f,
  470. Transform(
  471. motionData.GetJointPositionSample(0, 0).m_value,
  472. motionData.GetJointRotationSample(0, 0).m_value,
  473. firstScaleSample) },
  474. { motionData.GetSampleSpacing() * 0.25f,
  475. Transform(
  476. AZ::Vector3(0.25f, 1.0f, 2.0f),
  477. AZ::Quaternion::CreateRotationZ((0.25f / static_cast<float>(motionData.GetNumSamples())) * 180.0f).GetNormalized(),
  478. AZ::Vector3(1.25f, 1.5f, 1.75f)) },
  479. { motionData.GetSampleSpacing() * 0.5f,
  480. Transform(
  481. AZ::Vector3(0.5f, 1.0f, 2.0f),
  482. AZ::Quaternion::CreateRotationZ((0.5f / static_cast<float>(motionData.GetNumSamples())) * 180.0f).GetNormalized(),
  483. AZ::Vector3(1.5f, 2.0f, 2.5f)) },
  484. { motionData.GetSampleSpacing() * 0.75f,
  485. Transform(
  486. AZ::Vector3(0.75f, 1.0f, 2.0f),
  487. AZ::Quaternion::CreateRotationZ((0.75f / static_cast<float>(motionData.GetNumSamples())) * 180.0f).GetNormalized(),
  488. AZ::Vector3(1.75f, 2.5f, 3.25f)) },
  489. { motionData.GetSampleSpacing(),
  490. Transform(
  491. AZ::Vector3(1.0f, 1.0f, 2.0f),
  492. AZ::Quaternion::CreateRotationZ((1.0f / static_cast<float>(motionData.GetNumSamples())) * 180.0f).GetNormalized(),
  493. AZ::Vector3(2.0f, 3.0f, 4.0f)) },
  494. { motionData.GetSampleSpacing() * 5.5f,
  495. Transform(
  496. AZ::Vector3(5.5f, 1.0f, 2.0f),
  497. AZ::Quaternion::CreateRotationZ((5.5f / static_cast<float>(motionData.GetNumSamples())) * 180.0f).GetNormalized(),
  498. AZ::Vector3(6.5f, 12.0f, 17.5f)) },
  499. { motionData.GetDuration() + 1.0f,
  500. Transform(
  501. motionData.GetJointPositionSample(0, lastSampleIndex).m_value,
  502. motionData.GetJointRotationSample(0, lastSampleIndex).m_value,
  503. lastScaleSample) }
  504. };
  505. for (const TransformPair& expectation : values)
  506. {
  507. MotionData::SampleSettings sampleSettings;
  508. sampleSettings.m_actorInstance = m_actorInstance;
  509. sampleSettings.m_sampleTime = expectation.first;
  510. const Transform sampledResult = motionData.SampleJointTransform(sampleSettings, 0);
  511. EXPECT_THAT(sampledResult.m_position, IsClose(expectation.second.m_position));
  512. EXPECT_THAT(sampledResult.m_rotation, IsClose(expectation.second.m_rotation));
  513. #ifndef EMFX_SCALE_DISABLED
  514. EXPECT_THAT(sampledResult.m_scale, IsClose(expectation.second.m_scale));
  515. #endif
  516. // Fourth joint has no motion data to apply to our actor, so expect a bind pose.
  517. // It has motion data, but there is no joint in the skeleton that matches its name, so it is like motion data for a joint that doesn't exist in our actor.
  518. const Transform fourthJointTransform = motionData.SampleJointTransform(sampleSettings, 3);
  519. EXPECT_THAT(fourthJointTransform.m_position, IsClose(expectedBindTransform.m_position));
  520. EXPECT_THAT(fourthJointTransform.m_rotation, IsClose(expectedBindTransform.m_rotation));
  521. #ifndef EMFX_SCALE_DISABLED
  522. EXPECT_THAT(fourthJointTransform.m_scale, IsClose(expectedBindTransform.m_scale));
  523. #endif
  524. }
  525. // Sample the entire pose.
  526. for (const TransformPair& expectation : values)
  527. {
  528. Pose pose;
  529. pose.LinkToActorInstance(m_actorInstance);
  530. MotionData::SampleSettings sampleSettings;
  531. sampleSettings.m_actorInstance = m_actorInstance;
  532. sampleSettings.m_sampleTime = expectation.first;
  533. motionData.SamplePose(sampleSettings, &pose);
  534. // We only verify the first joint, to see if it interpolated fine.
  535. const Transform sampledResult = pose.GetLocalSpaceTransform(0);
  536. EXPECT_THAT(sampledResult.m_position, IsClose(expectation.second.m_position));
  537. EXPECT_THAT(sampledResult.m_rotation, IsClose(expectation.second.m_rotation));
  538. #ifndef EMFX_SCALE_DISABLED
  539. EXPECT_THAT(sampledResult.m_scale, IsClose(expectation.second.m_scale));
  540. #endif
  541. // Fourth joint has no motion data to apply to our actor, so expect a bind pose.
  542. // It has motion data, but there is no joint in the skeleton that matches its name, so it is like motion data for a joint that doesn't exist in our actor.
  543. const Transform fourthJointTransform = pose.GetLocalSpaceTransform(3);
  544. EXPECT_THAT(fourthJointTransform.m_position, IsClose(expectedBindTransform.m_position));
  545. EXPECT_THAT(fourthJointTransform.m_rotation, IsClose(expectedBindTransform.m_rotation));
  546. #ifndef EMFX_SCALE_DISABLED
  547. EXPECT_THAT(fourthJointTransform.m_scale, IsClose(expectedBindTransform.m_scale));
  548. #endif
  549. }
  550. }
  551. } // namespace EMotionFX