2
0

Mat44Tests.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include "UnitTestFramework.h"
  4. #include <Jolt/Math/Mat44.h>
  5. TEST_SUITE("Mat44Tests")
  6. {
  7. TEST_CASE("TestMat44Identity")
  8. {
  9. Mat44 identity = Mat44::sIdentity();
  10. for (int row = 0; row < 4; ++row)
  11. for (int col = 0; col < 4; ++col)
  12. if (row != col)
  13. CHECK(identity(row, col) == 0.0f);
  14. else
  15. CHECK(identity(row, col) == 1.0f);
  16. }
  17. TEST_CASE("TestMat44Construct")
  18. {
  19. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  20. CHECK(mat(0, 0) == 1.0f);
  21. CHECK(mat(1, 0) == 2.0f);
  22. CHECK(mat(2, 0) == 3.0f);
  23. CHECK(mat(3, 0) == 4.0f);
  24. CHECK(mat(0, 1) == 5.0f);
  25. CHECK(mat(1, 1) == 6.0f);
  26. CHECK(mat(2, 1) == 7.0f);
  27. CHECK(mat(3, 1) == 8.0f);
  28. CHECK(mat(0, 2) == 9.0f);
  29. CHECK(mat(1, 2) == 10.0f);
  30. CHECK(mat(2, 2) == 11.0f);
  31. CHECK(mat(3, 2) == 12.0f);
  32. CHECK(mat(0, 3) == 13.0f);
  33. CHECK(mat(1, 3) == 14.0f);
  34. CHECK(mat(2, 3) == 15.0f);
  35. CHECK(mat(3, 3) == 16.0f);
  36. Mat44 mat2(mat);
  37. CHECK(mat2(0, 0) == 1.0f);
  38. CHECK(mat2(1, 0) == 2.0f);
  39. CHECK(mat2(2, 0) == 3.0f);
  40. CHECK(mat2(3, 0) == 4.0f);
  41. CHECK(mat2(0, 1) == 5.0f);
  42. CHECK(mat2(1, 1) == 6.0f);
  43. CHECK(mat2(2, 1) == 7.0f);
  44. CHECK(mat2(3, 1) == 8.0f);
  45. CHECK(mat2(0, 2) == 9.0f);
  46. CHECK(mat2(1, 2) == 10.0f);
  47. CHECK(mat2(2, 2) == 11.0f);
  48. CHECK(mat2(3, 2) == 12.0f);
  49. CHECK(mat2(0, 3) == 13.0f);
  50. CHECK(mat2(1, 3) == 14.0f);
  51. CHECK(mat2(2, 3) == 15.0f);
  52. CHECK(mat2(3, 3) == 16.0f);
  53. }
  54. TEST_CASE("TestMat44Translation")
  55. {
  56. 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)));
  57. }
  58. TEST_CASE("TestMat44Scale")
  59. {
  60. 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)));
  61. 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)));
  62. }
  63. TEST_CASE("TestMat44RotationSafe")
  64. {
  65. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  66. CHECK(mat.GetRotationSafe() == Mat44(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), Vec4(0, 0, 0, 1)));
  67. }
  68. TEST_CASE("TestMat44LoadStore")
  69. {
  70. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  71. Float4 storage[4];
  72. mat.StoreFloat4x4(storage);
  73. CHECK(storage[0].x == 1.0f);
  74. CHECK(storage[0].y == 2.0f);
  75. CHECK(storage[0].z == 3.0f);
  76. CHECK(storage[0].w == 4.0f);
  77. CHECK(storage[1].x == 5.0f);
  78. CHECK(storage[1].y == 6.0f);
  79. CHECK(storage[1].z == 7.0f);
  80. CHECK(storage[1].w == 8.0f);
  81. CHECK(storage[2].x == 9.0f);
  82. CHECK(storage[2].y == 10.0f);
  83. CHECK(storage[2].z == 11.0f);
  84. CHECK(storage[2].w == 12.0f);
  85. CHECK(storage[3].x == 13.0f);
  86. CHECK(storage[3].y == 14.0f);
  87. CHECK(storage[3].z == 15.0f);
  88. CHECK(storage[3].w == 16.0f);
  89. Mat44 mat2 = Mat44::sLoadFloat4x4(storage);
  90. CHECK(mat2 == mat);
  91. }
  92. TEST_CASE("TestMat44MultiplyMat44")
  93. {
  94. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  95. Mat44 mat2(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(29, 30, 31, 32));
  96. Mat44 result = mat * mat2;
  97. CHECK(result == Mat44(Vec4(538, 612, 686, 760), Vec4(650, 740, 830, 920), Vec4(762, 868, 974, 1080), Vec4(874, 996, 1118, 1240)));
  98. }
  99. TEST_CASE("TestMat44MultiplyVec3")
  100. {
  101. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  102. Vec3 vec(17, 18, 19);
  103. Vec3 result = mat * vec;
  104. CHECK(result == Vec3(291, 346, 401));
  105. result = mat.Multiply3x3(vec);
  106. CHECK(result == Vec3(278, 332, 386));
  107. result = mat.Multiply3x3Transposed(vec);
  108. CHECK(result == Vec3(110, 326, 542));
  109. }
  110. TEST_CASE("TestMat44MultiplyVec4")
  111. {
  112. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  113. Vec4 vec(17, 18, 19, 20);
  114. Vec4 result = mat * vec;
  115. CHECK(result == Vec4(538, 612, 686, 760));
  116. }
  117. TEST_CASE("TestMat44Scale")
  118. {
  119. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  120. Mat44 result = mat * 2.0f;
  121. CHECK(result == Mat44(Vec4(2, 4, 6, 8), Vec4(10, 12, 14, 16), Vec4(18, 20, 22, 24), Vec4(26, 28, 30, 32)));
  122. CHECK(result != mat);
  123. result *= 0.5f;
  124. CHECK(result == mat);
  125. }
  126. TEST_CASE("TestMat44Transposed")
  127. {
  128. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  129. Mat44 result = mat.Transposed();
  130. CHECK(result == Mat44(Vec4(1, 5, 9, 13), Vec4(2, 6, 10, 14), Vec4(3, 7, 11, 15), Vec4(4, 8, 12, 16)));
  131. }
  132. TEST_CASE("TestMat44Transposed3x3")
  133. {
  134. Mat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  135. Mat44 result = mat.Transposed3x3();
  136. CHECK(result == Mat44(Vec4(1, 5, 9, 0), Vec4(2, 6, 10, 0), Vec4(3, 7, 11, 0), Vec4(0, 0, 0, 1)));
  137. }
  138. TEST_CASE("TestMat44Multiply3x3")
  139. {
  140. Mat44 mat1(Vec4(1, 2, 3, 0), Vec4(4, 5, 6, 0), Vec4(7, 8, 9, 0), Vec4(10, 11, 12, 1));
  141. Mat44 mat2(Vec4(13, 14, 15, 0), Vec4(16, 17, 18, 0), Vec4(19, 20, 21, 0), Vec4(22, 23, 24, 1));
  142. Mat44 result = mat1.Multiply3x3(mat2);
  143. CHECK(result.GetColumn4(3) == Vec4(0, 0, 0, 1));
  144. Mat44 result2 = mat1.GetRotationSafe() * mat2.GetRotationSafe();
  145. CHECK(result == result2);
  146. }
  147. TEST_CASE("TestMat44Multiply3x3LeftTransposed")
  148. {
  149. Mat44 mat1(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
  150. Mat44 mat2(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), Vec4(29, 30, 31, 32));
  151. Mat44 result = mat1.Multiply3x3LeftTransposed(mat2);
  152. CHECK(result.GetColumn4(3) == Vec4(0, 0, 0, 1));
  153. Mat44 result2 = mat1.GetRotationSafe().Transposed() * mat2.GetRotationSafe();
  154. CHECK(result == result2);
  155. }
  156. TEST_CASE("TestMat44Multiply3x3RightTransposed")
  157. {
  158. Mat44 mat1(Vec4(1, 2, 3, 0), Vec4(4, 5, 6, 0), Vec4(7, 8, 9, 0), Vec4(10, 11, 12, 1));
  159. Mat44 mat2(Vec4(13, 14, 15, 0), Vec4(16, 17, 18, 0), Vec4(19, 20, 21, 0), Vec4(22, 23, 24, 1));
  160. Mat44 result = mat1.Multiply3x3RightTransposed(mat2);
  161. CHECK(result.GetColumn4(3) == Vec4(0, 0, 0, 1));
  162. Mat44 result2 = mat1.GetRotationSafe() * mat2.GetRotationSafe().Transposed();
  163. CHECK(result == result2);
  164. }
  165. TEST_CASE("TestMat44Inversed")
  166. {
  167. Mat44 mat(Vec4(0, 2, 0, 8), Vec4(4, 0, 16, 0), Vec4(0, 16, 0, 4), Vec4(8, 0, 2, 0));
  168. Mat44 inverse = mat.Inversed();
  169. Mat44 identity = mat * inverse;
  170. CHECK(identity == Mat44::sIdentity());
  171. }
  172. TEST_CASE("TestMat44Inversed3x3")
  173. {
  174. Mat44 mat(Vec4(1, 2, 0, 0), Vec4(4, 0, 8, 0), Vec4(0, 16, 0, 0), Vec4(1, 2, 3, 1));
  175. Mat44 inverse = mat.Inversed3x3();
  176. CHECK(inverse.GetColumn4(3) == Vec4(0, 0, 0, 1));
  177. Mat44 identity = mat.Multiply3x3(inverse);
  178. CHECK(identity == Mat44::sIdentity());
  179. }
  180. TEST_CASE("TestMat44GetDeterminant3x3")
  181. {
  182. Mat44 mat(Vec4(1, 2, 0, 0), Vec4(4, 0, 8, 0), Vec4(0, 16, 0, 0), Vec4(1, 2, 3, 1));
  183. CHECK(mat.GetDeterminant3x3() == -128);
  184. }
  185. TEST_CASE("TestMat44Adjointed3x3")
  186. {
  187. Mat44 mat(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), Vec4(13, 14, 15, 16));
  188. Mat44 result = mat.Adjointed3x3();
  189. CHECK(result == Mat44(Vec4(-4, 8, -4, 0), Vec4(8, -16, 8, 0), Vec4(-4, 8, -4, 0), Vec4(0, 0, 0, 1)));
  190. }
  191. TEST_CASE("TestMat44RotationXYZ")
  192. {
  193. Mat44 rot = Mat44::sRotationX(0.5f * JPH_PI);
  194. Vec3 v = rot * Vec3(1, 0, 0);
  195. CHECK(v == Vec3(1, 0, 0));
  196. v = rot * Vec3(0, 1, 0);
  197. CHECK_APPROX_EQUAL(v, Vec3(0, 0, 1));
  198. v = rot * Vec3(0, 0, 1);
  199. CHECK_APPROX_EQUAL(v, Vec3(0, -1, 0));
  200. rot = Mat44::sRotationY(0.5f * JPH_PI);
  201. v = rot * Vec3(1, 0, 0);
  202. CHECK_APPROX_EQUAL(v, Vec3(0, 0, -1));
  203. v = rot * Vec3(0, 1, 0);
  204. CHECK(v == Vec3(0, 1, 0));
  205. v = rot * Vec3(0, 0, 1);
  206. CHECK_APPROX_EQUAL(v, Vec3(1, 0, 0));
  207. rot = Mat44::sRotationZ(0.5f * JPH_PI);
  208. v = rot * Vec3(1, 0, 0);
  209. CHECK_APPROX_EQUAL(v, Vec3(0, 1, 0));
  210. v = rot * Vec3(0, 1, 0);
  211. CHECK_APPROX_EQUAL(v, Vec3(-1, 0, 0));
  212. v = rot * Vec3(0, 0, 1);
  213. CHECK(v == Vec3(0, 0, 1));
  214. }
  215. TEST_CASE("TestMat44RotationAxisAngle")
  216. {
  217. Mat44 r1 = Mat44::sRotationX(0.1f * JPH_PI);
  218. Mat44 r2 = Mat44::sRotation(Vec3(1, 0, 0), 0.1f * JPH_PI);
  219. CHECK_APPROX_EQUAL(r1, r2);
  220. r1 = Mat44::sRotationY(0.2f * JPH_PI);
  221. r2 = Mat44::sRotation(Vec3(0, 1, 0), 0.2f * JPH_PI);
  222. CHECK_APPROX_EQUAL(r1, r2);
  223. r1 = Mat44::sRotationZ(0.3f * JPH_PI);
  224. r2 = Mat44::sRotation(Vec3(0, 0, 1), 0.3f * JPH_PI);
  225. CHECK_APPROX_EQUAL(r1, r2);
  226. }
  227. TEST_CASE("TestMat44CrossProduct")
  228. {
  229. Vec3 v1(1, 2, 3);
  230. Vec3 v2(4, 5, 6);
  231. Vec3 v3 = v1.Cross(v2);
  232. Vec3 v4 = Mat44::sCrossProduct(v1) * v2;
  233. CHECK(v3 == v4);
  234. }
  235. TEST_CASE("TestMat44OuterProduct")
  236. {
  237. Vec3 v1(1, 2, 3);
  238. Vec3 v2(4, 5, 6);
  239. 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)));
  240. }
  241. TEST_CASE("TestMat44QuatLeftMultiply")
  242. {
  243. Quat p(2, 3, 4, 1);
  244. Quat q(6, 7, 8, 5);
  245. Quat r1 = p * q;
  246. Quat r2 = Quat(Mat44::sQuatLeftMultiply(p) * q.GetXYZW());
  247. CHECK(r1 == r2);
  248. }
  249. TEST_CASE("TestMat44QuatRightMultiply")
  250. {
  251. Quat p(2, 3, 4, 1);
  252. Quat q(6, 7, 8, 5);
  253. Quat r1 = q * p;
  254. Quat r2 = Quat(Mat44::sQuatRightMultiply(p) * q.GetXYZW());
  255. CHECK(r1 == r2);
  256. }
  257. TEST_CASE("TestMat44InverseRotateTranslate")
  258. {
  259. Quat rot = Quat::sRotation(Vec3(0, 1, 0), 0.2f * JPH_PI);
  260. Vec3 pos(2, 3, 4);
  261. Mat44 m1 = Mat44::sRotationTranslation(rot, pos).Inversed();
  262. Mat44 m2 = Mat44::sInverseRotationTranslation(rot, pos);
  263. CHECK_APPROX_EQUAL(m1, m2);
  264. }
  265. TEST_CASE("TestMat44InversedRotationTranslation")
  266. {
  267. Quat rot = Quat::sRotation(Vec3(0, 1, 0), 0.2f * JPH_PI);
  268. Vec3 pos(2, 3, 4);
  269. Mat44 m1 = Mat44::sRotationTranslation(rot, pos).InversedRotationTranslation();
  270. Mat44 m2 = Mat44::sInverseRotationTranslation(rot, pos);
  271. CHECK_APPROX_EQUAL(m1, m2);
  272. }
  273. TEST_CASE("TestMat44PrePostScaled")
  274. {
  275. Mat44 m(Vec4(2, 3, 4, 0), Vec4(5, 6, 7, 0), Vec4(8, 9, 10, 0), Vec4(11, 12, 13, 1));
  276. Vec3 v(14, 15, 16);
  277. CHECK(m.PreScaled(v) == m * Mat44::sScale(v));
  278. CHECK(m.PostScaled(v) == Mat44::sScale(v) * m);
  279. }
  280. TEST_CASE("TestMat44PrePostTranslated")
  281. {
  282. Mat44 m(Vec4(2, 3, 4, 0), Vec4(5, 6, 7, 0), Vec4(8, 9, 10, 0), Vec4(11, 12, 13, 1));
  283. Vec3 v(14, 15, 16);
  284. CHECK(m.PreTranslated(v) == m * Mat44::sTranslation(v));
  285. CHECK(m.PostTranslated(v) == Mat44::sTranslation(v) * m);
  286. }
  287. TEST_CASE("TestMat44Decompose")
  288. {
  289. // Create a rotation/translation matrix
  290. Quat rot = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
  291. Vec3 pos(2, 3, 4);
  292. Mat44 rotation_translation = Mat44::sRotationTranslation(rot, pos);
  293. // Scale the matrix
  294. Vec3 scale(2, 1, 3);
  295. Mat44 m1 = rotation_translation * Mat44::sScale(scale);
  296. // Decompose scale
  297. Vec3 scale_out;
  298. Mat44 m2 = m1.Decompose(scale_out);
  299. // Check individual components
  300. CHECK_APPROX_EQUAL(rotation_translation, m2);
  301. CHECK_APPROX_EQUAL(scale, scale_out);
  302. }
  303. TEST_CASE("TestMat44DecomposeSkewed")
  304. {
  305. // Create a rotation/translation matrix
  306. Quat rot = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
  307. Vec3 pos(2, 3, 4);
  308. Mat44 rotation_translation = Mat44::sRotationTranslation(rot, pos);
  309. // Skew the matrix by applying a non-uniform scale
  310. Mat44 skewed_rotation_translation = Mat44::sScale(Vec3(1.0f, 0.99f, 0.98f)) * rotation_translation;
  311. float val = skewed_rotation_translation.GetAxisX().Cross(skewed_rotation_translation.GetAxisY()).Dot(skewed_rotation_translation.GetAxisZ());
  312. CHECK(abs(val - 1.0f) > 0.01f); // Check not matrix is no longer perpendicular
  313. // Scale the matrix
  314. Vec3 scale(2, 1, 3);
  315. Mat44 m1 = skewed_rotation_translation * Mat44::sScale(scale);
  316. // Decompose scale
  317. Vec3 scale_out;
  318. Mat44 m2 = m1.Decompose(scale_out);
  319. // Check individual components
  320. CHECK_APPROX_EQUAL(m2.GetAxisX(), skewed_rotation_translation.GetAxisX().Normalized()); // Check X axis didn't change
  321. CHECK_APPROX_EQUAL(m2.GetAxisY(), skewed_rotation_translation.GetAxisY().Normalized(), 0.003f); // Y axis may move a bit
  322. CHECK_APPROX_EQUAL(m2.GetAxisZ(), skewed_rotation_translation.GetAxisZ().Normalized(), 0.02f); // Z axis may move a bit
  323. CHECK_APPROX_EQUAL(m2.GetAxisX().Cross(m2.GetAxisY()).Dot(m2.GetAxisZ()), 1.0f); // Check perpendicular
  324. CHECK_APPROX_EQUAL(scale, scale_out, 0.05f); // Scale may change a bit
  325. }
  326. }