Mat44Tests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. #include <Jolt/Math/Mat44.h>
  6. TEST_SUITE("Mat44Tests")
  7. {
  8. TEST_CASE("TestMat44Zero")
  9. {
  10. Mat44 zero = Mat44::sZero();
  11. for (int row = 0; row < 4; ++row)
  12. for (int col = 0; col < 4; ++col)
  13. CHECK(zero(row, col) == 0.0f);
  14. }
  15. TEST_CASE("TestMat44NaN")
  16. {
  17. Mat44 nan = Mat44::sNaN();
  18. for (int row = 0; row < 4; ++row)
  19. for (int col = 0; col < 4; ++col)
  20. CHECK(isnan(nan(row, col)));
  21. }
  22. TEST_CASE("TestMat44Identity")
  23. {
  24. Mat44 identity = Mat44::sIdentity();
  25. for (int row = 0; row < 4; ++row)
  26. for (int col = 0; col < 4; ++col)
  27. if (row != col)
  28. CHECK(identity(row, col) == 0.0f);
  29. else
  30. CHECK(identity(row, col) == 1.0f);
  31. }
  32. TEST_CASE("TestMat44Construct")
  33. {
  34. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  35. CHECK(mat(0, 0) == 1.0f);
  36. CHECK(mat(1, 0) == 2.0f);
  37. CHECK(mat(2, 0) == 3.0f);
  38. CHECK(mat(3, 0) == 4.0f);
  39. CHECK(mat(0, 1) == 5.0f);
  40. CHECK(mat(1, 1) == 6.0f);
  41. CHECK(mat(2, 1) == 7.0f);
  42. CHECK(mat(3, 1) == 8.0f);
  43. CHECK(mat(0, 2) == 9.0f);
  44. CHECK(mat(1, 2) == 10.0f);
  45. CHECK(mat(2, 2) == 11.0f);
  46. CHECK(mat(3, 2) == 12.0f);
  47. CHECK(mat(0, 3) == 13.0f);
  48. CHECK(mat(1, 3) == 14.0f);
  49. CHECK(mat(2, 3) == 15.0f);
  50. CHECK(mat(3, 3) == 16.0f);
  51. Mat44 mat2(mat);
  52. CHECK(mat2(0, 0) == 1.0f);
  53. CHECK(mat2(1, 0) == 2.0f);
  54. CHECK(mat2(2, 0) == 3.0f);
  55. CHECK(mat2(3, 0) == 4.0f);
  56. CHECK(mat2(0, 1) == 5.0f);
  57. CHECK(mat2(1, 1) == 6.0f);
  58. CHECK(mat2(2, 1) == 7.0f);
  59. CHECK(mat2(3, 1) == 8.0f);
  60. CHECK(mat2(0, 2) == 9.0f);
  61. CHECK(mat2(1, 2) == 10.0f);
  62. CHECK(mat2(2, 2) == 11.0f);
  63. CHECK(mat2(3, 2) == 12.0f);
  64. CHECK(mat2(0, 3) == 13.0f);
  65. CHECK(mat2(1, 3) == 14.0f);
  66. CHECK(mat2(2, 3) == 15.0f);
  67. CHECK(mat2(3, 3) == 16.0f);
  68. // Check equal
  69. CHECK(mat == mat2);
  70. CHECK(!(mat != mat2));
  71. // Make unequal
  72. mat(3, 3) = 1;
  73. // Check non-equal
  74. CHECK(!(mat == mat2));
  75. CHECK(mat != mat2);
  76. }
  77. TEST_CASE("TestMat44IsClose")
  78. {
  79. Mat44 mat = Mat44::sIdentity();
  80. Mat44 mat2(mat);
  81. CHECK(mat.IsClose(mat2, Square(0.1f)));
  82. mat2(0, 1) = 0.09f;
  83. CHECK(mat.IsClose(mat2, Square(0.1f)));
  84. mat2(0, 1) = 0.11f;
  85. CHECK(!mat.IsClose(mat2, Square(0.1f)));
  86. }
  87. TEST_CASE("TestMat44Translation")
  88. {
  89. CHECK(Mat44::sTranslation(Vec3(2, 3, 4)) == Mat44(Vec4(1, 0, 0, 0), Vec4(0, 1, 0, 0), Vec4(0, 0, 1, 0), Vec4(2, 3, 4, 1)));
  90. }
  91. TEST_CASE("TestMat44Scale")
  92. {
  93. CHECK(Mat44::sScale(2) == Mat44(Vec4(2, 0, 0, 0), Vec4(0, 2, 0, 0), Vec4(0, 0, 2, 0), Vec4(0, 0, 0, 1)));
  94. CHECK(Mat44::sScale(Vec3(2, 3, 4)) == Mat44(Vec4(2, 0, 0, 0), Vec4(0, 3, 0, 0), Vec4(0, 0, 4, 0), Vec4(0, 0, 0, 1)));
  95. }
  96. TEST_CASE("TestMat44Rotation")
  97. {
  98. Mat44 mat(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), Vec4(13, 14, 15, 16));
  99. CHECK(mat.GetRotation() == Mat44(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), Vec4(0, 0, 0, 1)));
  100. }
  101. TEST_CASE("TestMat44SetRotation")
  102. {
  103. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  104. Mat44 mat2(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(29, 30, 31, 32));
  105. mat.SetRotation(mat2);
  106. CHECK(mat == Mat44(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(13, 14, 15, 16)));
  107. }
  108. TEST_CASE("TestMat44RotationSafe")
  109. {
  110. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  111. CHECK(mat.GetRotationSafe() == Mat44(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), Vec4(0, 0, 0, 1)));
  112. }
  113. TEST_CASE("TestMat44LoadStore")
  114. {
  115. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  116. Float4 storage[4];
  117. mat.StoreFloat4x4(storage);
  118. CHECK(storage[0].x == 1.0f);
  119. CHECK(storage[0].y == 2.0f);
  120. CHECK(storage[0].z == 3.0f);
  121. CHECK(storage[0].w == 4.0f);
  122. CHECK(storage[1].x == 5.0f);
  123. CHECK(storage[1].y == 6.0f);
  124. CHECK(storage[1].z == 7.0f);
  125. CHECK(storage[1].w == 8.0f);
  126. CHECK(storage[2].x == 9.0f);
  127. CHECK(storage[2].y == 10.0f);
  128. CHECK(storage[2].z == 11.0f);
  129. CHECK(storage[2].w == 12.0f);
  130. CHECK(storage[3].x == 13.0f);
  131. CHECK(storage[3].y == 14.0f);
  132. CHECK(storage[3].z == 15.0f);
  133. CHECK(storage[3].w == 16.0f);
  134. Mat44 mat2 = Mat44::sLoadFloat4x4(storage);
  135. CHECK(mat2 == mat);
  136. }
  137. TEST_CASE("TestMat44LoadAligned")
  138. {
  139. alignas(16) float values[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  140. Mat44 mat = Mat44::sLoadFloat4x4Aligned((const Float4 *)values);
  141. CHECK(mat == Mat44(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16)));
  142. }
  143. TEST_CASE("TestMat44MultiplyMat44")
  144. {
  145. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  146. Mat44 mat2(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(29, 30, 31, 32));
  147. Mat44 result = mat * mat2;
  148. CHECK(result == Mat44(Vec4(538, 612, 686, 760), Vec4(650, 740, 830, 920), Vec4(762, 868, 974, 1080), Vec4(874, 996, 1118, 1240)));
  149. }
  150. TEST_CASE("TestMat44Add")
  151. {
  152. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  153. Mat44 mat2(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(29, 30, 31, 32));
  154. Mat44 result = mat + mat2;
  155. CHECK(result == Mat44(Vec4(18, 20, 22, 24), Vec4(26, 28, 30, 32), Vec4(34, 36, 38, 40), Vec4(42, 44, 46, 48)));
  156. mat += mat2;
  157. CHECK(mat == Mat44(Vec4(18, 20, 22, 24), Vec4(26, 28, 30, 32), Vec4(34, 36, 38, 40), Vec4(42, 44, 46, 48)));
  158. }
  159. TEST_CASE("TestMat44Sub")
  160. {
  161. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  162. Mat44 mat2(Vec4(32, 31, 30, 29), Vec4(28, 27, 26, 25), Vec4(24, 23, 22, 21), Vec4(20, 19, 18, 17));
  163. Mat44 result = mat - mat2;
  164. CHECK(result == Mat44(Vec4(-31, -29, -27, -25), Vec4(-23, -21, -19, -17), Vec4(-15, -13, -11, -9), Vec4(-7, -5, -3, -1)));
  165. }
  166. TEST_CASE("TestMat44Negate")
  167. {
  168. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  169. Mat44 result = -mat;
  170. CHECK(result == Mat44(Vec4(-1, -2, -3, -4), Vec4(-5, -6, -7, -8), Vec4(-9, -10, -11, -12), Vec4(-13, -14, -15, -16)));
  171. }
  172. TEST_CASE("TestMat44MultiplyVec3")
  173. {
  174. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  175. Vec3 vec(17, 18, 19);
  176. Vec3 result = mat * vec;
  177. CHECK(result == Vec3(291, 346, 401));
  178. result = mat.Multiply3x3(vec);
  179. CHECK(result == Vec3(278, 332, 386));
  180. result = mat.Multiply3x3Transposed(vec);
  181. CHECK(result == Vec3(110, 326, 542));
  182. }
  183. TEST_CASE("TestMat44MultiplyVec4")
  184. {
  185. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  186. Vec4 vec(17, 18, 19, 20);
  187. Vec4 result = mat * vec;
  188. CHECK(result == Vec4(538, 612, 686, 760));
  189. }
  190. TEST_CASE("TestMat44Scale")
  191. {
  192. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  193. Mat44 result = mat * 2.0f;
  194. CHECK(result == Mat44(Vec4(2, 4, 6, 8), Vec4(10, 12, 14, 16), Vec4(18, 20, 22, 24), Vec4(26, 28, 30, 32)));
  195. CHECK(result != mat);
  196. result *= 0.5f;
  197. CHECK(result == mat);
  198. }
  199. TEST_CASE("TestMat44Transposed")
  200. {
  201. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  202. Mat44 result = mat.Transposed();
  203. CHECK(result == Mat44(Vec4(1, 5, 9, 13), Vec4(2, 6, 10, 14), Vec4(3, 7, 11, 15), Vec4(4, 8, 12, 16)));
  204. }
  205. TEST_CASE("TestMat44Transposed3x3")
  206. {
  207. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  208. Mat44 result = mat.Transposed3x3();
  209. CHECK(result == Mat44(Vec4(1, 5, 9, 0), Vec4(2, 6, 10, 0), Vec4(3, 7, 11, 0), Vec4(0, 0, 0, 1)));
  210. }
  211. TEST_CASE("TestMat44Multiply3x3")
  212. {
  213. Mat44 mat1(Vec4(1, 2, 3, 0), Vec4(4, 5, 6, 0), Vec4(7, 8, 9, 0), Vec4(10, 11, 12, 1));
  214. Mat44 mat2(Vec4(13, 14, 15, 0), Vec4(16, 17, 18, 0), Vec4(19, 20, 21, 0), Vec4(22, 23, 24, 1));
  215. Mat44 result = mat1.Multiply3x3(mat2);
  216. CHECK(result.GetColumn4(3) == Vec4(0, 0, 0, 1));
  217. Mat44 result2 = mat1.GetRotationSafe() * mat2.GetRotationSafe();
  218. CHECK(result == result2);
  219. }
  220. TEST_CASE("TestMat44Multiply3x3LeftTransposed")
  221. {
  222. Mat44 mat1(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  223. Mat44 mat2(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(29, 30, 31, 32));
  224. Mat44 result = mat1.Multiply3x3LeftTransposed(mat2);
  225. CHECK(result.GetColumn4(3) == Vec4(0, 0, 0, 1));
  226. Mat44 result2 = mat1.GetRotationSafe().Transposed() * mat2.GetRotationSafe();
  227. CHECK(result == result2);
  228. }
  229. TEST_CASE("TestMat44Multiply3x3RightTransposed")
  230. {
  231. Mat44 mat1(Vec4(1, 2, 3, 0), Vec4(4, 5, 6, 0), Vec4(7, 8, 9, 0), Vec4(10, 11, 12, 1));
  232. Mat44 mat2(Vec4(13, 14, 15, 0), Vec4(16, 17, 18, 0), Vec4(19, 20, 21, 0), Vec4(22, 23, 24, 1));
  233. Mat44 result = mat1.Multiply3x3RightTransposed(mat2);
  234. CHECK(result.GetColumn4(3) == Vec4(0, 0, 0, 1));
  235. Mat44 result2 = mat1.GetRotationSafe() * mat2.GetRotationSafe().Transposed();
  236. CHECK(result == result2);
  237. }
  238. TEST_CASE("TestMat44Inversed")
  239. {
  240. Mat44 mat(Vec4(0, 2, 0, 8), Vec4(4, 0, 16, 0), Vec4(0, 16, 0, 4), Vec4(8, 0, 2, 0));
  241. Mat44 inverse = mat.Inversed();
  242. Mat44 identity = mat * inverse;
  243. CHECK(identity == Mat44::sIdentity());
  244. }
  245. TEST_CASE("TestMat44Inversed3x3")
  246. {
  247. Mat44 mat(Vec4(1, 2, 0, 0), Vec4(4, 0, 8, 0), Vec4(0, 16, 0, 0), Vec4(1, 2, 3, 1));
  248. Mat44 inverse = mat.Inversed3x3();
  249. CHECK(inverse.GetColumn4(3) == Vec4(0, 0, 0, 1));
  250. Mat44 identity = mat.Multiply3x3(inverse);
  251. CHECK(identity == Mat44::sIdentity());
  252. }
  253. TEST_CASE("TestMat44SetInversed3x3")
  254. {
  255. Mat44 mat(Vec4(1, 2, 0, 0), Vec4(4, 0, 8, 0), Vec4(0, 16, 0, 0), Vec4(1, 2, 3, 1));
  256. // First test succeeding inverse
  257. Mat44 inverse;
  258. CHECK(inverse.SetInversed3x3(mat));
  259. CHECK(inverse.GetColumn4(3) == Vec4(0, 0, 0, 1));
  260. Mat44 identity = mat.Multiply3x3(inverse);
  261. CHECK(identity == Mat44::sIdentity());
  262. // Now make singular
  263. mat(0, 0) = 0.0f;
  264. CHECK(!inverse.SetInversed3x3(mat));
  265. }
  266. TEST_CASE("TestMat44GetDeterminant3x3")
  267. {
  268. Mat44 mat(Vec4(1, 2, 0, 0), Vec4(4, 0, 8, 0), Vec4(0, 16, 0, 0), Vec4(1, 2, 3, 1));
  269. CHECK(mat.GetDeterminant3x3() == -128);
  270. }
  271. TEST_CASE("TestMat44Adjointed3x3")
  272. {
  273. Mat44 mat(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), Vec4(13, 14, 15, 16));
  274. Mat44 result = mat.Adjointed3x3();
  275. CHECK(result == Mat44(Vec4(-4, 8, -4, 0), Vec4(8, -16, 8, 0), Vec4(-4, 8, -4, 0), Vec4(0, 0, 0, 1)));
  276. }
  277. TEST_CASE("TestMat44RotationXYZ")
  278. {
  279. Mat44 rot = Mat44::sRotationX(0.5f * JPH_PI);
  280. Vec3 v = rot * Vec3(1, 0, 0);
  281. CHECK(v == Vec3(1, 0, 0));
  282. v = rot * Vec3(0, 1, 0);
  283. CHECK_APPROX_EQUAL(v, Vec3(0, 0, 1));
  284. v = rot * Vec3(0, 0, 1);
  285. CHECK_APPROX_EQUAL(v, Vec3(0, -1, 0));
  286. rot = Mat44::sRotationY(0.5f * JPH_PI);
  287. v = rot * Vec3(1, 0, 0);
  288. CHECK_APPROX_EQUAL(v, Vec3(0, 0, -1));
  289. v = rot * Vec3(0, 1, 0);
  290. CHECK(v == Vec3(0, 1, 0));
  291. v = rot * Vec3(0, 0, 1);
  292. CHECK_APPROX_EQUAL(v, Vec3(1, 0, 0));
  293. rot = Mat44::sRotationZ(0.5f * JPH_PI);
  294. v = rot * Vec3(1, 0, 0);
  295. CHECK_APPROX_EQUAL(v, Vec3(0, 1, 0));
  296. v = rot * Vec3(0, 1, 0);
  297. CHECK_APPROX_EQUAL(v, Vec3(-1, 0, 0));
  298. v = rot * Vec3(0, 0, 1);
  299. CHECK(v == Vec3(0, 0, 1));
  300. }
  301. TEST_CASE("TestMat44RotationAxisAngle")
  302. {
  303. Mat44 r1 = Mat44::sRotationX(0.1f * JPH_PI);
  304. Mat44 r2 = Mat44::sRotation(Vec3(1, 0, 0), 0.1f * JPH_PI);
  305. CHECK_APPROX_EQUAL(r1, r2);
  306. r1 = Mat44::sRotationY(0.2f * JPH_PI);
  307. r2 = Mat44::sRotation(Vec3(0, 1, 0), 0.2f * JPH_PI);
  308. CHECK_APPROX_EQUAL(r1, r2);
  309. r1 = Mat44::sRotationZ(0.3f * JPH_PI);
  310. r2 = Mat44::sRotation(Vec3(0, 0, 1), 0.3f * JPH_PI);
  311. CHECK_APPROX_EQUAL(r1, r2);
  312. }
  313. TEST_CASE("TestMat44CrossProduct")
  314. {
  315. Vec3 v1(1, 2, 3);
  316. Vec3 v2(4, 5, 6);
  317. Vec3 v3 = v1.Cross(v2);
  318. Vec3 v4 = Mat44::sCrossProduct(v1) * v2;
  319. CHECK(v3 == v4);
  320. }
  321. TEST_CASE("TestMat44OuterProduct")
  322. {
  323. Vec3 v1(1, 2, 3);
  324. Vec3 v2(4, 5, 6);
  325. CHECK(Mat44::sOuterProduct(v1, v2) == Mat44(Vec4(1 * 4, 2 * 4, 3 * 4, 0), Vec4(1 * 5, 2 * 5, 3 * 5, 0), Vec4(1 * 6, 2 * 6, 3 * 6, 0), Vec4(0, 0, 0, 1)));
  326. }
  327. TEST_CASE("TestMat44QuatLeftMultiply")
  328. {
  329. Quat p(2, 3, 4, 1);
  330. Quat q(6, 7, 8, 5);
  331. Quat r1 = p * q;
  332. Quat r2 = Quat(Mat44::sQuatLeftMultiply(p) * q.GetXYZW());
  333. CHECK(r1 == r2);
  334. }
  335. TEST_CASE("TestMat44QuatRightMultiply")
  336. {
  337. Quat p(2, 3, 4, 1);
  338. Quat q(6, 7, 8, 5);
  339. Quat r1 = q * p;
  340. Quat r2 = Quat(Mat44::sQuatRightMultiply(p) * q.GetXYZW());
  341. CHECK(r1 == r2);
  342. }
  343. TEST_CASE("TestMat44InverseRotateTranslate")
  344. {
  345. Quat rot = Quat::sRotation(Vec3(0, 1, 0), 0.2f * JPH_PI);
  346. Vec3 pos(2, 3, 4);
  347. Mat44 m1 = Mat44::sRotationTranslation(rot, pos).Inversed();
  348. Mat44 m2 = Mat44::sInverseRotationTranslation(rot, pos);
  349. CHECK_APPROX_EQUAL(m1, m2);
  350. }
  351. TEST_CASE("TestMat44InversedRotationTranslation")
  352. {
  353. Quat rot = Quat::sRotation(Vec3(0, 1, 0), 0.2f * JPH_PI);
  354. Vec3 pos(2, 3, 4);
  355. Mat44 m1 = Mat44::sRotationTranslation(rot, pos).InversedRotationTranslation();
  356. Mat44 m2 = Mat44::sInverseRotationTranslation(rot, pos);
  357. CHECK_APPROX_EQUAL(m1, m2);
  358. }
  359. TEST_CASE("TestMat44Decompose")
  360. {
  361. Mat44 rotation = Mat44::sRotationX(0.1f * JPH_PI) * Mat44::sRotationZ(0.2f * JPH_PI);
  362. Vec3 scale = Vec3(-1, 2, 3);
  363. Mat44 mat = rotation * Mat44::sScale(scale);
  364. CHECK(mat.GetDeterminant3x3() < 0); // Left handed
  365. Vec3 new_scale;
  366. Mat44 new_rotation = mat.Decompose(new_scale);
  367. CHECK(new_rotation.GetDeterminant3x3() > 0); // Right handed
  368. Mat44 mat2 = new_rotation * Mat44::sScale(new_scale);
  369. CHECK(mat.IsClose(mat2));
  370. }
  371. TEST_CASE("TestMat44PrePostScaled")
  372. {
  373. Mat44 m(Vec4(2, 3, 4, 0), Vec4(5, 6, 7, 0), Vec4(8, 9, 10, 0), Vec4(11, 12, 13, 1));
  374. Vec3 v(14, 15, 16);
  375. CHECK(m.PreScaled(v) == m * Mat44::sScale(v));
  376. CHECK(m.PostScaled(v) == Mat44::sScale(v) * m);
  377. }
  378. TEST_CASE("TestMat44PrePostTranslated")
  379. {
  380. Mat44 m(Vec4(2, 3, 4, 0), Vec4(5, 6, 7, 0), Vec4(8, 9, 10, 0), Vec4(11, 12, 13, 1));
  381. Vec3 v(14, 15, 16);
  382. CHECK(m.PreTranslated(v) == m * Mat44::sTranslation(v));
  383. CHECK(m.PostTranslated(v) == Mat44::sTranslation(v) * m);
  384. }
  385. TEST_CASE("TestMat44Decompose")
  386. {
  387. // Create a rotation/translation matrix
  388. Quat rot = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
  389. Vec3 pos(2, 3, 4);
  390. Mat44 rotation_translation = Mat44::sRotationTranslation(rot, pos);
  391. // Scale the matrix
  392. Vec3 scale(2, 1, 3);
  393. Mat44 m1 = rotation_translation * Mat44::sScale(scale);
  394. // Decompose scale
  395. Vec3 scale_out;
  396. Mat44 m2 = m1.Decompose(scale_out);
  397. // Check individual components
  398. CHECK_APPROX_EQUAL(rotation_translation, m2);
  399. CHECK_APPROX_EQUAL(scale, scale_out);
  400. }
  401. TEST_CASE("TestMat44DecomposeSkewed")
  402. {
  403. // Create a rotation/translation matrix
  404. Quat rot = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
  405. Vec3 pos(2, 3, 4);
  406. Mat44 rotation_translation = Mat44::sRotationTranslation(rot, pos);
  407. // Skew the matrix by applying a non-uniform scale
  408. Mat44 skewed_rotation_translation = Mat44::sScale(Vec3(1.0f, 0.99f, 0.98f)) * rotation_translation;
  409. float val = skewed_rotation_translation.GetAxisX().Cross(skewed_rotation_translation.GetAxisY()).Dot(skewed_rotation_translation.GetAxisZ());
  410. CHECK(abs(val - 1.0f) > 0.01f); // Check not matrix is no longer perpendicular
  411. // Scale the matrix
  412. Vec3 scale(2, 1, 3);
  413. Mat44 m1 = skewed_rotation_translation * Mat44::sScale(scale);
  414. // Decompose scale
  415. Vec3 scale_out;
  416. Mat44 m2 = m1.Decompose(scale_out);
  417. // Check individual components
  418. CHECK_APPROX_EQUAL(m2.GetAxisX(), skewed_rotation_translation.GetAxisX().Normalized()); // Check X axis didn't change
  419. CHECK_APPROX_EQUAL(m2.GetAxisY(), skewed_rotation_translation.GetAxisY().Normalized(), 0.003f); // Y axis may move a bit
  420. CHECK_APPROX_EQUAL(m2.GetAxisZ(), skewed_rotation_translation.GetAxisZ().Normalized(), 0.02f); // Z axis may move a bit
  421. CHECK_APPROX_EQUAL(m2.GetAxisX().Cross(m2.GetAxisY()).Dot(m2.GetAxisZ()), 1.0f); // Check perpendicular
  422. CHECK_APPROX_EQUAL(scale, scale_out, 0.05f); // Scale may change a bit
  423. }
  424. }