Mat44Tests.cpp 17 KB

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