1 module tests.matrix_4d_test; 2 3 import std.stdio; 4 import tests.dunit_tests; 5 import matrix_4d; 6 import Math = math; 7 8 import vector_3d; 9 import vector_4d; 10 11 import matrix_3d; 12 13 /* 14 * The MIT License 15 * 16 * Copyright (c) 2015-2021 JOML. 17 ^%$# Translated by jordan4ibanez 18 * 19 * Permission is hereby granted, free of charge, to any person obtaining a copy 20 * of this software and associated documentation files (the "Software"), to deal 21 * in the Software without restriction, including without limitation the rights 22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 * copies of the Software, and to permit persons to whom the Software is 24 * furnished to do so, subject to the following conditions: 25 * 26 * The above copyright notice and this permission notice shall be included in 27 * all copies or substantial portions of the Software. 28 * 29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 * THE SOFTWARE. 36 */ 37 38 /** 39 * Tests for the {@link Matrix4d} class. 40 * 41 * @author Kai Burjack 42 */ 43 unittest { 44 45 writeln("\nTESTING MATRIX4D\n"); 46 47 /** 48 * Test that project and unproject are each other's inverse operations. 49 */ 50 // testProjectUnproject 51 { 52 /* Build some arbitrary viewport. */ 53 int[] viewport = [0, 0, 800, 800]; 54 55 Vector3d expected = Vector3d(1.0f, 2.0f, -3.0f); 56 Vector3d actual = Vector3d(); 57 58 /* Build a perspective projection and then project and unproject. */ 59 Matrix4d m = Matrix4d() 60 .perspective(cast(float) Math.toRadians(45.0f), 1.0f, 0.01f, 100.0f); 61 m.project(expected, viewport, actual); 62 m.unproject(actual, viewport, actual); 63 64 /* Check for equality of the components */ 65 assertEquals(expected.x, actual.x, MANY_OPS_AROUND_ZERO_PRECISION_FLOAT); 66 assertEquals(expected.y, actual.y, MANY_OPS_AROUND_ZERO_PRECISION_FLOAT); 67 assertEquals(expected.z, actual.z, MANY_OPS_AROUND_ZERO_PRECISION_FLOAT); 68 } 69 70 // testLookAt 71 { 72 Matrix4d m1 = Matrix4d(); 73 Matrix4d m2 = Matrix4d(); 74 75 writeln(m1 == m2); 76 77 m1 = Matrix4d().lookAt(0, 2, 3, 0, 0, 0, 0, 1, 0); 78 m2 = Matrix4d().translate(0, 0, -Math.sqrt(2 * 2 + 3 * 3)).rotateX(Math.atan2(2, 3)); 79 80 writeln(m1); 81 writeln(m2); 82 83 assertMatrix4dEquals(m1, m2, 1E-2f); 84 85 m1 = Matrix4d().lookAt(3, 2, 0, 0, 0, 0, 0, 1, 0); 86 m2 = Matrix4d().translate(0, 0, -cast(float) Math.sqrt(2 * 2 + 3 * 3)) 87 .rotateX(cast(float) Math.atan2(2, 3)).rotateY(cast(float) Math.toRadians(-90)); 88 assertMatrix4dEquals(m1, m2, 1E-2f); 89 } 90 91 /** 92 * Test computing the frustum planes with a combined view-projection matrix with translation. 93 */ 94 // testFrustumPlanePerspectiveRotateTranslate 95 { 96 Vector4d left = Vector4d(); 97 Vector4d right = Vector4d(); 98 Vector4d top = Vector4d(); 99 Vector4d bottom = Vector4d(); 100 Vector4d near = Vector4d(); 101 Vector4d far = Vector4d(); 102 103 /* 104 * Build a perspective transformation and 105 * move the camera 5 units "up" and rotate it clock-wise 90 degrees around Y. 106 */ 107 Matrix4d m = Matrix4d() 108 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 109 .rotateY(cast(float) Math.toRadians(90)) 110 .translate(0, -5, 0); 111 m.frustumPlane(Matrix4d.PLANE_NX, left); 112 m.frustumPlane(Matrix4d.PLANE_PX, right); 113 m.frustumPlane(Matrix4d.PLANE_NY, bottom); 114 m.frustumPlane(Matrix4d.PLANE_PY, top); 115 m.frustumPlane(Matrix4d.PLANE_NZ, near); 116 m.frustumPlane(Matrix4d.PLANE_PZ, far); 117 118 Vector4d expectedLeft = Vector4d(1, 0, 1, 0).normalize3(); 119 Vector4d expectedRight = Vector4d(1, 0, -1, 0).normalize3(); 120 Vector4d expectedTop = Vector4d(1, -1, 0, 5).normalize3(); 121 Vector4d expectedBottom = Vector4d(1, 1, 0, -5).normalize3(); 122 Vector4d expectedNear = Vector4d(1, 0, 0, -0.1f).normalize3(); 123 Vector4d expectedFar = Vector4d(-1, 0, 0, 100.0f).normalize3(); 124 125 assertVector4dEquals(expectedLeft, left, 1E-5f); 126 assertVector4dEquals(expectedRight, right, 1E-5f); 127 assertVector4dEquals(expectedTop, top, 1E-5f); 128 assertVector4dEquals(expectedBottom, bottom, 1E-5f); 129 assertVector4dEquals(expectedNear, near, 1E-5f); 130 assertVector4dEquals(expectedFar, far, 1E-4f); 131 } 132 133 // testFrustumRay 134 { 135 Vector3d dir = Vector3d(); 136 Matrix4d m = Matrix4d() 137 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 138 .rotateY(cast(float) Math.toRadians(90)); 139 Vector3d expectedDir; 140 m.frustumRayDir(0, 0, dir); 141 expectedDir = Vector3d(1, -1, -1).normalize(); 142 assertVector3dEquals(expectedDir, dir, 1E-5f); 143 m.frustumRayDir(1, 0, dir); 144 expectedDir = Vector3d(1, -1, 1).normalize(); 145 assertVector3dEquals(expectedDir, dir, 1E-5f); 146 m.frustumRayDir(0, 1, dir); 147 expectedDir = Vector3d(1, 1, -1).normalize(); 148 assertVector3dEquals(expectedDir, dir, 1E-5f); 149 m.frustumRayDir(1, 1, dir); 150 expectedDir = Vector3d(1, 1, 1).normalize(); 151 assertVector3dEquals(expectedDir, dir, 1E-5f); 152 } 153 154 // testFrustumRay2 155 { 156 Vector3d dir = Vector3d(); 157 Matrix4d m = Matrix4d() 158 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 159 .rotateZ(cast(float) Math.toRadians(45)); 160 Vector3d expectedDir; 161 m.frustumRayDir(0, 0, dir); 162 expectedDir = Vector3d(-cast(float)Math.sqrt(2), 0, -1).normalize(); 163 assertVector3dEquals(expectedDir, dir, 1E-5f); 164 m.frustumRayDir(1, 0, dir); 165 expectedDir = Vector3d(0, -cast(float)Math.sqrt(2), -1).normalize(); 166 assertVector3dEquals(expectedDir, dir, 1E-5f); 167 m.frustumRayDir(0, 1, dir); 168 expectedDir = Vector3d(0, cast(float)Math.sqrt(2), -1).normalize(); 169 assertVector3dEquals(expectedDir, dir, 1E-5f); 170 m.frustumRayDir(1, 1, dir); 171 expectedDir = Vector3d(cast(float)Math.sqrt(2), 0, -1).normalize(); 172 assertVector3dEquals(expectedDir, dir, 1E-5f); 173 } 174 175 // testMatrix4dTranspose 176 { 177 double m00 = 1, m01 = 2, m02 = 3, m03 = 4; 178 double m10 = 5, m11 = 6, m12 = 7, m13 = 8; 179 double m20 = 9, m21 = 10, m22 = 11, m23 = 12; 180 double m30 = 13, m31 = 14, m32 = 15, m33 = 16; 181 182 Matrix4d m = Matrix4d(m00,m01,m02,m03,m10,m11,m12,m13,m20,m21,m22,m23,m30,m31,m32,m33); 183 Matrix4d expect = Matrix4d(m00,m10,m20,m30,m01,m11,m21,m31,m02,m12,m22,m32,m03,m13,m23,m33); 184 assertMatrix4dEquals(Matrix4d(m).transpose(),expect, 1E-5f); 185 Matrix4d testUnit = Matrix4d(); 186 assertMatrix4dEquals(Matrix4d(m).transpose(testUnit),expect, 1E-5f); 187 } 188 189 // testMatrix4d3fTranspose 190 { 191 double m00 = 1, m01 = 2, m02 = 3, m03 = 4; 192 double m10 = 5, m11 = 6, m12 = 7, m13 = 8; 193 double m20 = 9, m21 = 10, m22 = 11, m23 = 12; 194 double m30 = 13, m31 = 14, m32 = 15, m33 = 16; 195 196 Matrix4d m = Matrix4d(m00,m01,m02,m03,m10,m11,m12,m13,m20,m21,m22,m23,m30,m31,m32,m33); 197 Matrix4d expect = Matrix4d(m00,m10,m20,m03,m01,m11,m21,m13,m02,m12,m22,m23,m30,m31,m32,m33); 198 199 Matrix4d testUnit3 = Matrix4d(m).transpose3x3(); 200 201 assertMatrix4dEquals(testUnit3,expect, 1E-5f); 202 Matrix3d expect1 = Matrix3d(m00,m10,m20,m01,m11,m21,m02,m12,m22); 203 Matrix4d expect2 = Matrix4d(expect1); 204 Matrix4d testUnit1 = Matrix4d(); 205 assertMatrix4dEquals(Matrix4d(m).transpose3x3(testUnit1),expect2, 1E-5f); 206 Matrix3d testUnit2 = Matrix3d(); 207 assertMatrix3dEquals(Matrix4d(m).transpose3x3(testUnit2),expect1, 1E-5f); 208 } 209 210 // testPositiveXRotateY 211 { 212 Vector3d dir = Vector3d(); 213 Matrix4d m = Matrix4d(); 214 m.rotateY(Math.toRadians(90)); 215 m.positiveX(dir); 216 Vector3d testUnit = Vector3d(0, 0, 1); 217 assertVector3dEquals(testUnit, dir, 1E-7f); 218 } 219 220 // testPositiveYRotateX 221 { 222 Vector3d dir = Vector3d(); 223 Matrix4d m = Matrix4d() 224 .rotateX(cast(float) Math.toRadians(90)); 225 m.positiveY(dir); 226 assertVector3dEquals(Vector3d(0, 0, -1), dir, 1E-7f); 227 } 228 229 // testPositiveZRotateX 230 { 231 Vector3d dir = Vector3d(); 232 Matrix4d m = Matrix4d() 233 .rotateX(cast(float) Math.toRadians(90)); 234 m.positiveZ(dir); 235 assertVector3dEquals(Vector3d(0, 1, 0), dir, 1E-7f); 236 } 237 238 // testPositiveXRotateXY 239 { 240 Vector3d dir = Vector3d(); 241 Matrix4d m = Matrix4d() 242 .rotateY(cast(float) Math.toRadians(90)).rotateX(cast(float) Math.toRadians(45)); 243 m.positiveX(dir); 244 assertVector3dEquals(Vector3d(0, 1, 1).normalize(), dir, 1E-7f); 245 } 246 247 // testPositiveXPerspectiveRotateY 248 { 249 Vector3d dir = Vector3d(); 250 Matrix4d m = Matrix4d() 251 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 252 .rotateY(cast(float) Math.toRadians(90)); 253 m.positiveX(dir); 254 assertVector3dEquals(Vector3d(0, 0, -1), dir, 1E-7f); 255 } 256 257 // testPositiveXPerspectiveRotateXY 258 { 259 Vector3d dir = Vector3d(); 260 Matrix4d m = Matrix4d() 261 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 262 .rotateY(cast(float) Math.toRadians(90)).rotateX(cast(float) Math.toRadians(45)); 263 m.positiveX(dir); 264 assertVector3dEquals(Vector3d(0, -1, -1).normalize(), dir, 1E-7f); 265 } 266 267 // testPositiveXYZLookAt 268 { 269 Vector3d dir = Vector3d(); 270 Matrix4d m = Matrix4d() 271 .lookAt(0, 0, 0, -1, 0, 0, 0, 1, 0); 272 m.positiveX(dir); 273 assertVector3dEquals(Vector3d(0, 0, -1).normalize(), dir, 1E-7f); 274 m.positiveY(dir); 275 assertVector3dEquals(Vector3d(0, 1, 0).normalize(), dir, 1E-7f); 276 m.positiveZ(dir); 277 assertVector3dEquals(Vector3d(1, 0, 0).normalize(), dir, 1E-7f); 278 } 279 280 // testPositiveXYZSameAsInvert 281 { 282 Vector3d dir = Vector3d(); 283 Vector3d dir2 = Vector3d(); 284 Matrix4d m = Matrix4d().rotateXYZ(0.12f, 1.25f, -2.56f); 285 Matrix4d inv = Matrix4d(m).invert(); 286 m.positiveX(dir); 287 dir2.set(1, 0, 0); 288 inv.transformDirection(dir2); 289 assertVector3dEquals(dir2, dir, 1E-6f); 290 m.positiveY(dir); 291 dir2.set(0, 1, 0); 292 inv.transformDirection(dir2); 293 assertVector3dEquals(dir2, dir, 1E-6f); 294 m.positiveZ(dir); 295 dir2.set(0, 0, 1); 296 inv.transformDirection(dir2); 297 assertVector3dEquals(dir2, dir, 1E-6f); 298 } 299 300 // testFrustumCornerIdentity 301 { 302 Matrix4d m = Matrix4d(); 303 Vector3d corner = Vector3d(); 304 m.frustumCorner(Matrix4d.CORNER_NXNYNZ, corner); // left, bottom, near 305 assertVector3dEquals(Vector3d(-1, -1, -1), corner, 1E-6f); 306 m.frustumCorner(Matrix4d.CORNER_PXNYNZ, corner); // right, bottom, near 307 assertVector3dEquals(Vector3d(1, -1, -1), corner, 1E-6f); 308 m.frustumCorner(Matrix4d.CORNER_PXNYPZ, corner); // right, bottom, far 309 assertVector3dEquals(Vector3d(1, -1, 1), corner, 1E-6f); 310 m.frustumCorner(Matrix4d.CORNER_NXPYPZ, corner); // left, top, far 311 assertVector3dEquals(Vector3d(-1, 1, 1), corner, 1E-6f); 312 } 313 314 // testFrustumCornerOrthoWide 315 { 316 Matrix4d m = Matrix4d().ortho2D(-2, 2, -1, 1); 317 Vector3d corner = Vector3d(); 318 m.frustumCorner(Matrix4d.CORNER_NXNYNZ, corner); // left, bottom, near 319 assertVector3dEquals(Vector3d(-2, -1, 1), corner, 1E-6f); 320 m.frustumCorner(Matrix4d.CORNER_PXNYNZ, corner); // right, bottom, near 321 assertVector3dEquals(Vector3d(2, -1, 1), corner, 1E-6f); 322 m.frustumCorner(Matrix4d.CORNER_PXNYPZ, corner); // right, bottom, far 323 assertVector3dEquals(Vector3d(2, -1, -1), corner, 1E-6f); 324 m.frustumCorner(Matrix4d.CORNER_NXPYPZ, corner); // left, top, far 325 assertVector3dEquals(Vector3d(-2, 1, -1), corner, 1E-6f); 326 } 327 328 // testFrustumCorner 329 { 330 Matrix4d m = Matrix4d() 331 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 332 .lookAt(0, 0, 10, 333 0, 0, 0, 334 0, 1, 0); 335 Vector3d corner = Vector3d(); 336 m.frustumCorner(Matrix4d.CORNER_NXNYNZ, corner); // left, bottom, near 337 assertVector3dEquals(Vector3d(-0.1f, -0.1f, 10 - 0.1f), corner, 1E-6f); 338 m.frustumCorner(Matrix4d.CORNER_PXNYNZ, corner); // right, bottom, near 339 assertVector3dEquals(Vector3d(0.1f, -0.1f, 10 - 0.1f), corner, 1E-6f); 340 m.frustumCorner(Matrix4d.CORNER_PXNYPZ, corner); // right, bottom, far 341 assertVector3dEquals(Vector3d(100.0f, -100, 10 - 100f), corner, 1E-3f); 342 } 343 344 // testFrustumCornerWide 345 { 346 Matrix4d m = Matrix4d() 347 .perspective(cast(float) Math.toRadians(90), 2.0f, 0.1f, 100.0f) 348 .lookAt(0, 0, 10, 349 0, 0, 0, 350 0, 1, 0); 351 Vector3d corner = Vector3d(); 352 m.frustumCorner(Matrix4d.CORNER_NXNYNZ, corner); // left, bottom, near 353 assertVector3dEquals(Vector3d(-0.2f, -0.1f, 10 - 0.1f), corner, 1E-5f); 354 m.frustumCorner(Matrix4d.CORNER_PXNYNZ, corner); // right, bottom, near 355 assertVector3dEquals(Vector3d(0.2f, -0.1f, 10 - 0.1f), corner, 1E-5f); 356 m.frustumCorner(Matrix4d.CORNER_PXNYPZ, corner); // right, bottom, far 357 assertVector3dEquals(Vector3d(200.0f, -100, 10 - 100f), corner, 1E-3f); 358 } 359 360 // testFrustumCornerRotate 361 { 362 Matrix4d m = Matrix4d() 363 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 364 .lookAt(10, 0, 0, 365 0, 0, 0, 366 0, 1, 0); 367 Vector3d corner = Vector3d(); 368 m.frustumCorner(Matrix4d.CORNER_NXNYNZ, corner); // left, bottom, near 369 assertVector3dEquals(Vector3d(10 - 0.1f, -0.1f, 0.1f), corner, 1E-6f); 370 m.frustumCorner(Matrix4d.CORNER_PXNYNZ, corner); // right, bottom, near 371 assertVector3dEquals(Vector3d(10 - 0.1f, -0.1f, -0.1f), corner, 1E-6f); 372 m.frustumCorner(Matrix4d.CORNER_PXNYPZ, corner); // right, bottom, far 373 assertVector3dEquals(Vector3d(-100.0f + 10, -100, -100f), corner, 1E-3f); 374 } 375 376 // testPerspectiveOrigin 377 { 378 Matrix4d m = Matrix4d() 379 // test symmetric frustum with some modelview translation and rotation 380 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 381 .lookAt(6, 0, 1, 382 0, 0, 0, 383 0, 1, 0); 384 Vector3d origin = Vector3d(); 385 m.perspectiveOrigin(origin); 386 assertVector3dEquals(Vector3d(6, 0, 1), origin, 1E-5f); 387 388 // test symmetric frustum with some modelview translation and rotation 389 m = Matrix4d() 390 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 391 .lookAt(-5, 2, 1, 392 0, 1, 0, 393 0, 1, 0); 394 m.perspectiveOrigin(origin); 395 assertVector3dEquals(Vector3d(-5, 2, 1), origin, 1E-5f); 396 397 // test asymmetric frustum 398 m = Matrix4d() 399 .frustum(-0.1f, 0.5f, -0.1f, 0.1f, 0.1f, 100.0f) 400 .lookAt(-5, 2, 1, 401 0, 1, 0, 402 0, 1, 0); 403 m.perspectiveOrigin(origin); 404 assertVector3dEquals(Vector3d(-5, 2, 1), origin, 1E-5f); 405 } 406 407 // testPerspectiveFov 408 { 409 Matrix4d m = Matrix4d() 410 .perspective(cast(float) Math.toRadians(45), 1.0f, 0.1f, 100.0f); 411 double fov = m.perspectiveFov(); 412 assertEquals(Math.toRadians(45), fov, 1E-5); 413 414 m = Matrix4d() 415 .perspective(cast(float) Math.toRadians(90), 1.0f, 0.1f, 100.0f) 416 .lookAt(6, 0, 1, 417 0, 0, 0, 418 0, 1, 0); 419 fov = m.perspectiveFov(); 420 assertEquals(Math.toRadians(90), fov, 1E-5); 421 } 422 423 // testNormal 424 { 425 Matrix4d r = Matrix4d().rotateY(cast(float) Math.PI / 2); 426 Matrix4d s = Matrix4d(r).scale(0.2f); 427 Matrix4d n = Matrix4d(); 428 s.normal(n); 429 n.normalize3x3(); 430 assertMatrix4dEquals(r, n, 1E-8f); 431 } 432 433 // testInvertAffine 434 { 435 Matrix4d invm = Matrix4d(); 436 Matrix4d m = Matrix4d(); 437 m.rotateX(1.2f).rotateY(0.2f).rotateZ(0.1f).translate(1, 2, 3).invertAffine(invm); 438 Vector3d orig = Vector3d(4, -6, 8); 439 Vector3d v = Vector3d(); 440 Vector3d w = Vector3d(); 441 m.transformPosition(orig, v); 442 invm.transformPosition(v, w); 443 assertVector3dEquals(orig, w, 1E-6f); 444 invm.invertAffine(); 445 assertMatrix4dEquals(m, invm, 1E-6f); 446 } 447 448 // testInvert 449 { 450 Matrix4d invm = Matrix4d(); 451 Matrix4d m = Matrix4d(); 452 m.perspective(0.1123f, 0.5f, 0.1f, 100.0f).rotateX(1.2f).rotateY(0.2f).rotateZ(0.1f).translate(1, 2, 3).invert(invm); 453 Vector4d orig = Vector4d(4, -6, 8, 1); 454 Vector4d v = Vector4d(); 455 Vector4d w = Vector4d(); 456 m.transform(orig, v); 457 invm.transform(v, w); 458 assertVector4dEquals(orig, w, 1E-4f); 459 invm.invert(); 460 assertMatrix4dEquals(m, invm, 1E-3f); 461 } 462 463 // testRotateXYZ 464 { 465 Matrix4d m = Matrix4d().rotateX(0.12f).rotateY(0.0623f).rotateZ(0.95f); 466 Matrix4d n = Matrix4d().rotateXYZ(0.12f, 0.0623f, 0.95f); 467 assertMatrix4dEquals(m, n, 1E-6f); 468 } 469 470 // testRotateZYX 471 { 472 Matrix4d m = Matrix4d().rotateZ(1.12f).rotateY(0.0623f).rotateX(0.95f); 473 Matrix4d n = Matrix4d().rotateZYX(1.12f, 0.0623f, 0.95f); 474 assertMatrix4dEquals(m, n, 1E-6f); 475 } 476 477 // testRotateYXZ 478 { 479 Matrix4d m = Matrix4d().rotateY(1.12f).rotateX(0.0623f).rotateZ(0.95f); 480 Matrix4d n = Matrix4d().rotateYXZ(1.12f, 0.0623f, 0.95f); 481 assertMatrix4dEquals(m, n, 1E-6f); 482 } 483 484 // testRotateAffineXYZ 485 { 486 Matrix4d m = Matrix4d().rotateX(0.12f).rotateY(0.0623f).rotateZ(0.95f); 487 Matrix4d n = Matrix4d().rotateAffineXYZ(0.12f, 0.0623f, 0.95f); 488 assertMatrix4dEquals(m, n, 1E-6f); 489 } 490 491 // testRotateAffineZYX 492 { 493 Matrix4d m = Matrix4d().rotateZ(1.12f).rotateY(0.0623f).rotateX(0.95f); 494 Matrix4d n = Matrix4d().rotateAffineZYX(1.12f, 0.0623f, 0.95f); 495 assertMatrix4dEquals(m, n, 1E-6f); 496 } 497 498 // testRotateAffineYXZ 499 { 500 Matrix4d m = Matrix4d().rotateY(1.12f).rotateX(0.0623f).rotateZ(0.95f); 501 Matrix4d n = Matrix4d().rotateAffineYXZ(1.12f, 0.0623f, 0.95f); 502 assertMatrix4dEquals(m, n, 1E-6f); 503 } 504 505 // testRotationXYZ 506 { 507 Matrix4d m = Matrix4d().rotationX(0.32f).rotateY(0.5623f).rotateZ(0.95f); 508 Matrix4d n = Matrix4d().rotationXYZ(0.32f, 0.5623f, 0.95f); 509 assertMatrix4dEquals(m, n, 1E-6f); 510 } 511 512 // testRotationZYX 513 { 514 Matrix4d m = Matrix4d().rotationZ(0.12f).rotateY(0.0623f).rotateX(0.95f); 515 Matrix4d n = Matrix4d().rotationZYX(0.12f, 0.0623f, 0.95f); 516 assertMatrix4dEquals(m, n, 1E-6f); 517 } 518 519 // testRotationYXZ 520 { 521 Matrix4d m = Matrix4d().rotationY(0.12f).rotateX(0.0623f).rotateZ(0.95f); 522 Matrix4d n = Matrix4d().rotationYXZ(0.12f, 0.0623f, 0.95f); 523 assertMatrix4dEquals(m, n, 1E-6f); 524 } 525 526 // testOrthoCrop 527 { 528 Matrix4d lightView = Matrix4d() 529 .lookAt(0, 5, 0, 530 0, 0, 0, 531 -1, 0, 0); 532 Matrix4d crop = Matrix4d(); 533 Matrix4d fin = Matrix4d(); 534 Matrix4d().ortho2D(-1, 1, -1, 1).invertAffine().orthoCrop(lightView, crop).mulOrthoAffine(lightView, fin); 535 Vector3d p = Vector3d(); 536 fin.transformProject(p.set(1, -1, -1)); 537 assertEquals(+1.0f, p.x, 1E-6f); 538 assertEquals(-1.0f, p.y, 1E-6f); 539 assertEquals(+1.0f, p.z, 1E-6f); 540 fin.transformProject(p.set(-1, -1, -1)); 541 assertEquals(+1.0f, p.x, 1E-6f); 542 assertEquals(+1.0f, p.y, 1E-6f); 543 assertEquals(+1.0f, p.z, 1E-6f); 544 } 545 546 // testOrthoCropWithPerspective 547 { 548 Matrix4d lightView = Matrix4d() 549 .lookAt(0, 5, 0, 550 0, 0, 0, 551 0, 0, -1); 552 Matrix4d crop = Matrix4d(); 553 Matrix4d fin = Matrix4d(); 554 Matrix4d().perspective(cast(float) Math.toRadians(90), 1.0f, 5, 10).invertPerspective().orthoCrop(lightView, crop).mulOrthoAffine(lightView, fin); 555 Vector3d p = Vector3d(); 556 fin.transformProject(p.set(0, 0, -5)); 557 assertEquals(+0.0f, p.x, 1E-6f); 558 assertEquals(-1.0f, p.y, 1E-6f); 559 assertEquals(+0.0f, p.z, 1E-6f); 560 fin.transformProject(p.set(0, 0, -10)); 561 assertEquals(+0.0f, p.x, 1E-6f); 562 assertEquals(+1.0f, p.y, 1E-6f); 563 assertEquals(+0.0f, p.z, 1E-6f); 564 fin.transformProject(p.set(-10, 10, -10)); 565 assertEquals(-1.0f, p.x, 1E-6f); 566 assertEquals(+1.0f, p.y, 1E-6f); 567 assertEquals(-1.0f, p.z, 1E-6f); 568 } 569 570 // testRotateTowardsXY 571 { 572 Vector3d v = Vector3d(1, 1, 0).normalize(); 573 Matrix4d testUnit = Matrix4d(); 574 Matrix4d m1 = Matrix4d().rotateZ(v.angle(Vector3d(1, 0, 0)), testUnit); 575 Matrix4d testUnit2 = Matrix4d(); 576 Matrix4d m2 = Matrix4d().rotateTowardsXY(v.x, v.y, testUnit2); 577 assertMatrix4dEquals(m1, m2, 1E-13); 578 Vector3d testUnit3 = Vector3d(0, 1, 0); 579 Vector3d t = m1.transformDirection(testUnit3); 580 Vector3d testUnit4 = Vector3d(-1, 1, 0).normalize(); 581 assertVector3dEquals(testUnit4, t, 1E-6f); 582 } 583 584 // testTestPoint 585 { 586 Matrix4d m = Matrix4d().perspective(cast(float)Math.toRadians(90), 1.0f, 0.1f, 10.0f).lookAt(0, 0, 10, 0, 0, 0, 0, 1, 0).scale(2); 587 assertTrue(m.testPoint(0, 0, 0)); 588 assertTrue(m.testPoint(9.999f*0.5f, 0, 0)); 589 assertFalse(m.testPoint(10.001f*0.5f, 0, 0)); 590 } 591 592 // testTestAab 593 { 594 Matrix4d m = Matrix4d().perspective(cast(float)Math.toRadians(90), 1.0f, 0.1f, 10.0f).lookAt(0, 0, 10, 0, 0, 0, 0, 1, 0).scale(2); 595 assertTrue(m.testAab(-1, -1, -1, 1, 1, 1)); 596 assertTrue(m.testAab(9.999f*0.5f, 0, 0, 10, 1, 1)); 597 assertFalse(m.testAab(10.001f*0.5f, 0, 0, 10, 1, 1)); 598 } 599 600 // testTransformTranspose 601 { 602 Matrix4d m = Matrix4d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); 603 Matrix4d testUnit = Matrix4d(); 604 Vector4d testUnit2 = Vector4d(4, 5, 6, 7); 605 Vector4d testUnit3 = Vector4d(4, 5, 6, 7); 606 assertVector4dEquals( 607 m.transformTranspose(testUnit2), 608 m.transpose(testUnit).transform(testUnit3), 609 1E-6f); 610 } 611 612 // testGet 613 { 614 Matrix4d m = Matrix4d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); 615 for (int c = 0; c < 4; c++) 616 for (int r = 0; r < 4; r++) 617 assertEquals(c*4+r+1, m.get(c, r), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 618 } 619 620 // testSet 621 { 622 assertMatrix4dEquals(Matrix4d().zero().set(0, 0, 3), Matrix4d(3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 623 assertMatrix4dEquals(Matrix4d().zero().set(0, 1, 3), Matrix4d(0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 624 assertMatrix4dEquals(Matrix4d().zero().set(0, 2, 3), Matrix4d(0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 625 assertMatrix4dEquals(Matrix4d().zero().set(0, 3, 3), Matrix4d(0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 626 assertMatrix4dEquals(Matrix4d().zero().set(1, 0, 3), Matrix4d(0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 627 assertMatrix4dEquals(Matrix4d().zero().set(1, 1, 3), Matrix4d(0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 628 assertMatrix4dEquals(Matrix4d().zero().set(1, 2, 3), Matrix4d(0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 629 assertMatrix4dEquals(Matrix4d().zero().set(1, 3, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 630 assertMatrix4dEquals(Matrix4d().zero().set(2, 0, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 631 assertMatrix4dEquals(Matrix4d().zero().set(2, 1, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 632 assertMatrix4dEquals(Matrix4d().zero().set(2, 2, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 633 assertMatrix4dEquals(Matrix4d().zero().set(2, 3, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 634 assertMatrix4dEquals(Matrix4d().zero().set(3, 0, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 635 assertMatrix4dEquals(Matrix4d().zero().set(3, 1, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 636 assertMatrix4dEquals(Matrix4d().zero().set(3, 2, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 637 assertMatrix4dEquals(Matrix4d().zero().set(3, 3, 3), Matrix4d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3), STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 638 } 639 640 /** 641 * https://github.com/JOML-CI/JOML/issues/266 642 */ 643 // testMulPerspectiveAffine 644 { 645 Matrix4d t = Matrix4d().lookAt(2, 3, 4, 5, 6, 7, 8, 9, 11); 646 Matrix4d p = Matrix4d().perspective(60.0f * cast(float)Math.PI / 180.0f, 4.0f/3.0f, 0.1f, 1000.0f); 647 Matrix4d testUnit1 = Matrix4d(); 648 Matrix4d result1 = t.invertAffine(testUnit1); 649 Matrix4d testUnit2 = Matrix4d(); 650 Matrix4d result2 = t.invertAffine(testUnit2); 651 p.mul(result1, result1); 652 p.mul0(result2, result2); 653 assertMatrix4dEquals(result1, result2, STANDARD_AROUND_ZERO_PRECISION_DOUBLE); 654 } 655 656 // testSetPerspectiveOffCenterFov 657 { 658 Matrix4d m1 = Matrix4d().setPerspective( 659 Math.toRadians(45), 660 1, 661 0.01, 662 10.0); 663 Matrix4d m2 = Matrix4d().setPerspectiveOffCenterFov( 664 -Math.toRadians(45/2.), 665 Math.toRadians(45/2.), 666 -Math.toRadians(45/2.), 667 Math.toRadians(45/2.), 668 0.01, 669 10.0); 670 assertMatrix4dEquals(m1, m2, 1E-6); 671 } 672 673 // testPerspectiveOffCenterFov 674 { 675 Matrix4d m1 = Matrix4d().perspective( 676 Math.toRadians(45), 677 1, 678 0.01, 679 10.0); 680 Matrix4d m2 = Matrix4d().perspectiveOffCenterFov( 681 -Math.toRadians(45/2.), 682 Math.toRadians(45/2.), 683 -Math.toRadians(45/2.), 684 Math.toRadians(45/2.), 685 0.01, 686 10.0); 687 assertMatrix4dEquals(m1, m2, 1E-6); 688 } 689 690 writeln("PASSED!"); 691 692 }