1 module matrix_4d; 2 3 import Math = math; 4 import MemUtil = mem_util; 5 6 import matrix_3d; 7 import matrix_4x3d; 8 import matrix_3x2d; 9 10 import vector_2d; 11 import vector_3d; 12 import vector_4d; 13 14 import axis_angle_4d; 15 import quaternion_d; 16 17 /* 18 * The MIT License 19 $!#@$@ Translated by jordan4ibanez 20 * 21 * Copyright (c) 2015-2021 Richard Greenlees 22 * 23 * Permission is hereby granted, free of charge, to any person obtaining a copy 24 * of this software and associated documentation files (the "Software"), to deal 25 * in the Software without restriction, including without limitation the rights 26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 27 * copies of the Software, and to permit persons to whom the Software is 28 * furnished to do so, subject to the following conditions: 29 * 30 * The above copyright notice and this permission notice shall be included in 31 * all copies or substantial portions of the Software. 32 * 33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 39 * THE SOFTWARE. 40 */ 41 42 /** 43 * Contains the definition of a 4x4 Matrix of doubles, and associated functions to transform 44 * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this: 45 * <p> 46 * m00 m10 m20 m30<br> 47 * m01 m11 m21 m31<br> 48 * m02 m12 m22 m32<br> 49 * m03 m13 m23 m33<br> 50 * 51 * @author Richard Greenlees 52 * @author Kai Burjack 53 */ 54 55 56 57 struct Matrix4d { 58 59 double m00 = 1.0; 60 double m01 = 0.0; 61 double m02 = 0.0; 62 double m03 = 0.0; 63 64 double m10 = 0.0; 65 double m11 = 1.0; 66 double m12 = 0.0; 67 double m13 = 0.0; 68 69 double m20 = 0.0; 70 double m21 = 0.0; 71 double m22 = 1.0; 72 double m23 = 0.0; 73 74 double m30 = 0.0; 75 double m31 = 0.0; 76 double m32 = 0.0; 77 double m33 = 1.0; 78 79 /** 80 81 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 82 * identifying the plane with equation <code>x=-1</code> when using the identity matrix. 83 */ 84 static immutable int PLANE_NX = 0; 85 /** 86 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 87 * identifying the plane with equation <code>x=1</code> when using the identity matrix. 88 */ 89 static immutable int PLANE_PX = 1; 90 /** 91 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 92 * identifying the plane with equation <code>y=-1</code> when using the identity matrix. 93 */ 94 static immutable int PLANE_NY = 2; 95 /** 96 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 97 * identifying the plane with equation <code>y=1</code> when using the identity matrix. 98 */ 99 static immutable int PLANE_PY = 3; 100 /** 101 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 102 * identifying the plane with equation <code>z=-1</code> when using the identity matrix. 103 */ 104 static immutable int PLANE_NZ = 4; 105 /** 106 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 107 * identifying the plane with equation <code>z=1</code> when using the identity matrix. 108 */ 109 static immutable int PLANE_PZ = 5; 110 /** 111 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 112 * identifying the corner <code>(-1, -1, -1)</code> when using the identity matrix. 113 */ 114 static immutable int CORNER_NXNYNZ = 0; 115 /** 116 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 117 * identifying the corner <code>(1, -1, -1)</code> when using the identity matrix. 118 */ 119 static immutable int CORNER_PXNYNZ = 1; 120 /** 121 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 122 * identifying the corner <code>(1, 1, -1)</code> when using the identity matrix. 123 */ 124 static immutable int CORNER_PXPYNZ = 2; 125 /** 126 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 127 * identifying the corner <code>(-1, 1, -1)</code> when using the identity matrix. 128 */ 129 static immutable int CORNER_NXPYNZ = 3; 130 /** 131 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 132 * identifying the corner <code>(1, -1, 1)</code> when using the identity matrix. 133 */ 134 static immutable int CORNER_PXNYPZ = 4; 135 /** 136 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 137 * identifying the corner <code>(-1, -1, 1)</code> when using the identity matrix. 138 */ 139 static immutable int CORNER_NXNYPZ = 5; 140 /** 141 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 142 * identifying the corner <code>(-1, 1, 1)</code> when using the identity matrix. 143 */ 144 static immutable int CORNER_NXPYPZ = 6; 145 /** 146 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 147 * identifying the corner <code>(1, 1, 1)</code> when using the identity matrix. 148 */ 149 static immutable int CORNER_PXPYPZ = 7; 150 151 /** 152 * Bit returned by {@link #properties()} to indicate that the matrix represents a perspective transformation. 153 */ 154 static immutable byte PROPERTY_PERSPECTIVE = 1<<0; 155 /** 156 * Bit returned by {@link #properties()} to indicate that the matrix represents an affine transformation. 157 */ 158 static immutable byte PROPERTY_AFFINE = 1<<1; 159 /** 160 * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation. 161 */ 162 static immutable byte PROPERTY_IDENTITY = 1<<2; 163 /** 164 * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation. 165 */ 166 static immutable byte PROPERTY_TRANSLATION = 1<<3; 167 /** 168 * Bit returned by {@link #properties()} to indicate that the upper-left 3x3 submatrix represents an orthogonal 169 * matrix (i.e. orthonormal basis). For practical reasons, this property also always implies 170 * {@link #PROPERTY_AFFINE} in this implementation. 171 */ 172 static immutable byte PROPERTY_ORTHONORMAL = 1<<4; 173 174 175 176 int properties = PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL; 177 178 /** 179 * Create a new {@link Matrix4d} and make it a copy of the given matrix. 180 * 181 * @param mat 182 * the {@link Matrix4d} to copy the values from 183 */ 184 this(Matrix4d mat) { 185 set(mat); 186 } 187 188 /** 189 * Create a new {@link Matrix4d} and set its upper 4x3 submatrix to the given matrix <code>mat</code> 190 * and all other elements to identity. 191 * 192 * @param mat 193 * the {@link Matrix4x3d} to copy the values from 194 */ 195 this(Matrix4x3d mat) { 196 set(mat); 197 } 198 199 /** 200 * Create a new {@link Matrix4d} by setting its uppper left 3x3 submatrix to the values of the given {@link Matrix3d} 201 * and the rest to identity. 202 * 203 * @param mat 204 * the {@link Matrix3d} 205 */ 206 this(Matrix3d mat) { 207 set(mat); 208 } 209 210 /** 211 * Create a new 4x4 matrix using the supplied double values. 212 * <p> 213 * The matrix layout will be:<br><br> 214 * m00, m10, m20, m30<br> 215 * m01, m11, m21, m31<br> 216 * m02, m12, m22, m32<br> 217 * m03, m13, m23, m33 218 * 219 * @param m00 220 * the value of m00 221 * @param m01 222 * the value of m01 223 * @param m02 224 * the value of m02 225 * @param m03 226 * the value of m03 227 * @param m10 228 * the value of m10 229 * @param m11 230 * the value of m11 231 * @param m12 232 * the value of m12 233 * @param m13 234 * the value of m13 235 * @param m20 236 * the value of m20 237 * @param m21 238 * the value of m21 239 * @param m22 240 * the value of m22 241 * @param m23 242 * the value of m23 243 * @param m30 244 * the value of m30 245 * @param m31 246 * the value of m31 247 * @param m32 248 * the value of m32 249 * @param m33 250 * the value of m33 251 */ 252 this(double m00, double m01, double m02, double m03, 253 double m10, double m11, double m12, double m13, 254 double m20, double m21, double m22, double m23, 255 double m30, double m31, double m32, double m33) { 256 setm00(m00); 257 setm01(m01); 258 setm02(m02); 259 setm03(m03); 260 setm10(m10); 261 setm11(m11); 262 setm12(m12); 263 setm13(m13); 264 setm20(m20); 265 setm21(m21); 266 setm22(m22); 267 setm23(m23); 268 setm30(m30); 269 setm31(m31); 270 setm32(m32); 271 setm33(m33); 272 determineProperties(); 273 } 274 275 /** 276 * Create a new {@link Matrix4d} and initialize its four columns using the supplied vectors. 277 * 278 * @param col0 279 * the first column 280 * @param col1 281 * the second column 282 * @param col2 283 * the third column 284 * @param col3 285 * the fourth column 286 */ 287 this(ref Vector4d col0, Vector4d col1, Vector4d col2, Vector4d col3) { 288 set(col0, col1, col2, col3); 289 } 290 291 /** 292 * Assume the given properties about this matrix. 293 * <p> 294 * Use one or multiple of 0, {@link Matrix4d#PROPERTY_IDENTITY}, 295 * {@link Matrix4d#PROPERTY_TRANSLATION}, {@link Matrix4d#PROPERTY_AFFINE}, 296 * {@link Matrix4d#PROPERTY_PERSPECTIVE}, {@link Matrix4fc#PROPERTY_ORTHONORMAL}. 297 * 298 * @param properties 299 * bitset of the properties to assume about this matrix 300 * @return this 301 */ 302 ref public Matrix4d assume(int properties) return { 303 this.properties = cast(byte) properties; 304 return this; 305 } 306 307 /** 308 * Compute and set the matrix properties returned by {@link #properties()} based 309 * on the current matrix element values. 310 * 311 * @return this 312 */ 313 ref public Matrix4d determineProperties() return { 314 int __properties = 0; 315 if (m03 == 0.0 && m13 == 0.0) { 316 if (m23 == 0.0 && m33 == 1.0) { 317 __properties |= PROPERTY_AFFINE; 318 if (m00 == 1.0 && m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m11 == 1.0 && m12 == 0.0 && m20 == 0.0 319 && m21 == 0.0 && m22 == 1.0) { 320 __properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL; 321 if (m30 == 0.0 && m31 == 0.0 && m32 == 0.0) 322 __properties |= PROPERTY_IDENTITY; 323 } 324 /* 325 * We do not determine orthogonality, since it would require arbitrary epsilons 326 * and is rather expensive (6 dot products) in the worst case. 327 */ 328 } else if (m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m12 == 0.0 && m20 == 0.0 && m21 == 0.0 && m30 == 0.0 329 && m31 == 0.0 && m33 == 0.0) { 330 __properties |= PROPERTY_PERSPECTIVE; 331 } 332 } 333 this.properties = __properties; 334 return this; 335 } 336 337 public int getProperties() { 338 return this.properties; 339 } 340 341 /** 342 * Set the value of the matrix element at column 0 and row 0. 343 * 344 * @param m00 345 * the new value 346 * @return this 347 */ 348 ref public Matrix4d setm00(double m00) return { 349 this.m00 = m00; 350 properties &= ~PROPERTY_ORTHONORMAL; 351 if (m00 != 1.0) 352 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 353 return this; 354 } 355 /** 356 * Set the value of the matrix element at column 0 and row 1. 357 * 358 * @param m01 359 * the new value 360 * @return this 361 */ 362 ref public Matrix4d setm01(double m01) return { 363 this.m01 = m01; 364 properties &= ~PROPERTY_ORTHONORMAL; 365 if (m01 != 0.0) 366 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 367 return this; 368 } 369 /** 370 * Set the value of the matrix element at column 0 and row 2. 371 * 372 * @param m02 373 * the new value 374 * @return this 375 */ 376 ref public Matrix4d setm02(double m02) return { 377 this.m02 = m02; 378 properties &= ~PROPERTY_ORTHONORMAL; 379 if (m02 != 0.0) 380 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 381 return this; 382 } 383 /** 384 * Set the value of the matrix element at column 0 and row 3. 385 * 386 * @param m03 387 * the new value 388 * @return this 389 */ 390 ref public Matrix4d setm03(double m03) return { 391 this.m03 = m03; 392 if (m03 != 0.0) 393 properties = 0; 394 return this; 395 } 396 /** 397 * Set the value of the matrix element at column 1 and row 0. 398 * 399 * @param m10 400 * the new value 401 * @return this 402 */ 403 ref public Matrix4d setm10(double m10) return { 404 this.m10 = m10; 405 properties &= ~PROPERTY_ORTHONORMAL; 406 if (m10 != 0.0) 407 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 408 return this; 409 } 410 /** 411 * Set the value of the matrix element at column 1 and row 1. 412 * 413 * @param m11 414 * the new value 415 * @return this 416 */ 417 ref public Matrix4d setm11(double m11) return { 418 this.m11 = m11; 419 properties &= ~PROPERTY_ORTHONORMAL; 420 if (m11 != 1.0) 421 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 422 return this; 423 } 424 /** 425 * Set the value of the matrix element at column 1 and row 2. 426 * 427 * @param m12 428 * the new value 429 * @return this 430 */ 431 ref public Matrix4d setm12(double m12) return { 432 this.m12 = m12; 433 properties &= ~PROPERTY_ORTHONORMAL; 434 if (m12 != 0.0) 435 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 436 return this; 437 } 438 /** 439 * Set the value of the matrix element at column 1 and row 3. 440 * 441 * @param m13 442 * the new value 443 * @return this 444 */ 445 ref public Matrix4d setm13(double m13) return { 446 this.m13 = m13; 447 if (m03 != 0.0) 448 properties = 0; 449 return this; 450 } 451 /** 452 * Set the value of the matrix element at column 2 and row 0. 453 * 454 * @param m20 455 * the new value 456 * @return this 457 */ 458 ref public Matrix4d setm20(double m20) return { 459 this.m20 = m20; 460 properties &= ~PROPERTY_ORTHONORMAL; 461 if (m20 != 0.0) 462 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 463 return this; 464 } 465 /** 466 * Set the value of the matrix element at column 2 and row 1. 467 * 468 * @param m21 469 * the new value 470 * @return this 471 */ 472 ref public Matrix4d setm21(double m21) return { 473 this.m21 = m21; 474 properties &= ~PROPERTY_ORTHONORMAL; 475 if (m21 != 0.0) 476 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 477 return this; 478 } 479 /** 480 * Set the value of the matrix element at column 2 and row 2. 481 * 482 * @param m22 483 * the new value 484 * @return this 485 */ 486 ref public Matrix4d setm22(double m22) return { 487 this.m22 = m22; 488 properties &= ~PROPERTY_ORTHONORMAL; 489 if (m22 != 1.0) 490 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 491 return this; 492 } 493 /** 494 * Set the value of the matrix element at column 2 and row 3. 495 * 496 * @param m23 497 * the new value 498 * @return this 499 */ 500 ref public Matrix4d setm23(double m23) return { 501 this.m23 = m23; 502 if (m23 != 0.0) 503 properties &= ~(PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL); 504 return this; 505 } 506 /** 507 * Set the value of the matrix element at column 3 and row 0. 508 * 509 * @param m30 510 * the new value 511 * @return this 512 */ 513 ref public Matrix4d setm30(double m30) return { 514 this.m30 = m30; 515 if (m30 != 0.0) 516 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE); 517 return this; 518 } 519 /** 520 * Set the value of the matrix element at column 3 and row 1. 521 * 522 * @param m31 523 * the new value 524 * @return this 525 */ 526 ref public Matrix4d setm31(double m31) return { 527 this.m31 = m31; 528 if (m31 != 0.0) 529 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE); 530 return this; 531 } 532 /** 533 * Set the value of the matrix element at column 3 and row 2. 534 * 535 * @param m32 536 * the new value 537 * @return this 538 */ 539 ref public Matrix4d setm32(double m32) return { 540 this.m32 = m32; 541 if (m32 != 0.0) 542 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE); 543 return this; 544 } 545 /** 546 * Set the value of the matrix element at column 3 and row 3. 547 * 548 * @param m33 549 * the new value 550 * @return this 551 */ 552 ref public Matrix4d setm33(double m33) return { 553 this.m33 = m33; 554 if (m33 != 0.0) 555 properties &= ~(PROPERTY_PERSPECTIVE); 556 if (m33 != 1.0) 557 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL | PROPERTY_AFFINE); 558 return this; 559 } 560 561 ref Matrix4d _properties(int properties) return { 562 this.properties = properties; 563 return this; 564 } 565 566 /** 567 * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix. 568 * 569 * @param m00 570 * the new value 571 * @return this 572 */ 573 ref Matrix4d _m00(double m00) return { 574 setm00(m00); 575 return this; 576 } 577 /** 578 * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix. 579 * 580 * @param m01 581 * the new value 582 * @return this 583 */ 584 ref Matrix4d _m01(double m01) return { 585 setm01(m01); 586 return this; 587 } 588 /** 589 * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix. 590 * 591 * @param m02 592 * the new value 593 * @return this 594 */ 595 ref Matrix4d _m02(double m02) return { 596 setm02(m02); 597 return this; 598 } 599 /** 600 * Set the value of the matrix element at column 0 and row 3 without updating the properties of the matrix. 601 * 602 * @param m03 603 * the new value 604 * @return this 605 */ 606 ref Matrix4d _m03(double m03) return { 607 setm03(m03); 608 return this; 609 } 610 /** 611 * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix. 612 * 613 * @param m10 614 * the new value 615 * @return this 616 */ 617 ref Matrix4d _m10(double m10) return { 618 setm10(m10); 619 return this; 620 } 621 /** 622 * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix. 623 * 624 * @param m11 625 * the new value 626 * @return this 627 */ 628 ref Matrix4d _m11(double m11) return { 629 setm11(m11); 630 return this; 631 } 632 /** 633 * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix. 634 * 635 * @param m12 636 * the new value 637 * @return this 638 */ 639 ref Matrix4d _m12(double m12) return { 640 setm12(m12); 641 return this; 642 } 643 /** 644 * Set the value of the matrix element at column 1 and row 3 without updating the properties of the matrix. 645 * 646 * @param m13 647 * the new value 648 * @return this 649 */ 650 ref Matrix4d _m13(double m13) return { 651 setm13(m13); 652 return this; 653 } 654 /** 655 * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix. 656 * 657 * @param m20 658 * the new value 659 * @return this 660 */ 661 ref Matrix4d _m20(double m20) return { 662 setm20(m20); 663 return this; 664 } 665 /** 666 * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix. 667 * 668 * @param m21 669 * the new value 670 * @return this 671 */ 672 ref Matrix4d _m21(double m21) return { 673 setm21(m21); 674 return this; 675 } 676 /** 677 * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix. 678 * 679 * @param m22 680 * the new value 681 * @return this 682 */ 683 ref Matrix4d _m22(double m22) return { 684 setm22(m22); 685 return this; 686 } 687 /** 688 * Set the value of the matrix element at column 2 and row 3 without updating the properties of the matrix. 689 * 690 * @param m23 691 * the new value 692 * @return this 693 */ 694 ref Matrix4d _m23(double m23) return { 695 setm23(m23); 696 return this; 697 } 698 /** 699 * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix. 700 * 701 * @param m30 702 * the new value 703 * @return this 704 */ 705 ref Matrix4d _m30(double m30) return { 706 setm30(m30); 707 return this; 708 } 709 /** 710 * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix. 711 * 712 * @param m31 713 * the new value 714 * @return this 715 */ 716 ref Matrix4d _m31(double m31) return { 717 setm31(m31); 718 return this; 719 } 720 /** 721 * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix. 722 * 723 * @param m32 724 * the new value 725 * @return this 726 */ 727 ref Matrix4d _m32(double m32) return { 728 setm32(m32); 729 return this; 730 } 731 /** 732 * Set the value of the matrix element at column 3 and row 3 without updating the properties of the matrix. 733 * 734 * @param m33 735 * the new value 736 * @return this 737 */ 738 ref Matrix4d _m33(double m33) return { 739 setm33(m33); 740 return this; 741 } 742 743 /** 744 * Reset this matrix to the identity. 745 * <p> 746 * Please note that if a call to {@link #identity()} is immediately followed by a call to: 747 * {@link #translate(double, double, double) translate}, 748 * {@link #rotate(double, double, double, double) rotate}, 749 * {@link #scale(double, double, double) scale}, 750 * {@link #perspective(double, double, double, double) perspective}, 751 * {@link #frustum(double, double, double, double, double, double) frustum}, 752 * {@link #ortho(double, double, double, double, double, double) ortho}, 753 * {@link #ortho2D(double, double, double, double) ortho2D}, 754 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}, 755 * {@link #lookAlong(double, double, double, double, double, double) lookAlong}, 756 * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with: 757 * {@link #translation(double, double, double) translation}, 758 * {@link #rotation(double, double, double, double) rotation}, 759 * {@link #scaling(double, double, double) scaling}, 760 * {@link #setPerspective(double, double, double, double) setPerspective}, 761 * {@link #setFrustum(double, double, double, double, double, double) setFrustum}, 762 * {@link #setOrtho(double, double, double, double, double, double) setOrtho}, 763 * {@link #setOrtho2D(double, double, double, double) setOrtho2D}, 764 * {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt}, 765 * {@link #setLookAlong(double, double, double, double, double, double) setLookAlong}, 766 * or any of their overloads. 767 * 768 * @return this 769 */ 770 ref public Matrix4d identity() return { 771 if ((properties & PROPERTY_IDENTITY) != 0) 772 return this; 773 _identity(); 774 properties = PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL; 775 return this; 776 } 777 private void _identity() { 778 _m00(1.0). 779 _m10(0.0). 780 _m20(0.0). 781 _m30(0.0). 782 _m01(0.0). 783 _m11(1.0). 784 _m21(0.0). 785 _m31(0.0). 786 _m02(0.0). 787 _m12(0.0). 788 _m22(1.0). 789 _m32(0.0). 790 _m03(0.0). 791 _m13(0.0). 792 _m23(0.0). 793 _m33(1.0); 794 } 795 796 /** 797 * Store the values of the given matrix <code>m</code> into <code>this</code> matrix. 798 * 799 * @see #Matrix4d(Matrix4d) 800 * @see #get(Matrix4d) 801 * 802 * @param m 803 * the matrix to copy the values from 804 * @return this 805 */ 806 ref public Matrix4d set(Matrix4d m) return { 807 return 808 _m00(m.m00). 809 _m01(m.m01). 810 _m02(m.m02). 811 _m03(m.m03). 812 _m10(m.m10). 813 _m11(m.m11). 814 _m12(m.m12). 815 _m13(m.m13). 816 _m20(m.m20). 817 _m21(m.m21). 818 _m22(m.m22). 819 _m23(m.m23). 820 _m30(m.m30). 821 _m31(m.m31). 822 _m32(m.m32). 823 _m33(m.m33). 824 _properties(m.properties); 825 } 826 827 828 /** 829 * Store the values of the transpose of the given matrix <code>m</code> into <code>this</code> matrix. 830 * 831 * @param m 832 * the matrix to copy the transposed values from 833 * @return this 834 */ 835 ref public Matrix4d setTransposed(Matrix4d m) return { 836 if ((m.properties & PROPERTY_IDENTITY) != 0) 837 return this.identity(); 838 return setTransposedInternal(m); 839 } 840 ref private Matrix4d setTransposedInternal(Matrix4d m) return { 841 double nm10 = m.m01, nm12 = m.m21, nm13 = m.m31; 842 double nm20 = m.m02, nm21 = m.m12, nm30 = m.m03; 843 double nm31 = m.m13, nm32 = m.m23; 844 return this 845 ._m00(m.m00)._m01(m.m10)._m02(m.m20)._m03(m.m30) 846 ._m10(nm10)._m11(m.m11)._m12(nm12)._m13(nm13) 847 ._m20(nm20)._m21(nm21)._m22(m.m22)._m23(m.m32) 848 ._m30(nm30)._m31(nm31)._m32(nm32)._m33(m.m33) 849 ._properties(m.properties & PROPERTY_IDENTITY); 850 } 851 852 /** 853 * Store the values of the given matrix <code>m</code> into <code>this</code> matrix 854 * and set the other matrix elements to identity. 855 * 856 * @see #Matrix4d(Matrix4x3d) 857 * 858 * @param m 859 * the matrix to copy the values from 860 * @return this 861 */ 862 ref public Matrix4d set(Matrix4x3d m) return { 863 return 864 _m00(m.m00). 865 _m01(m.m01). 866 _m02(m.m02). 867 _m03(0.0). 868 _m10(m.m10). 869 _m11(m.m11). 870 _m12(m.m12). 871 _m13(0.0). 872 _m20(m.m20). 873 _m21(m.m21). 874 _m22(m.m22). 875 _m23(0.0). 876 _m30(m.m30). 877 _m31(m.m31). 878 _m32(m.m32). 879 _m33(1.0). 880 _properties(m.properties | PROPERTY_AFFINE); 881 } 882 883 884 /** 885 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3d} 886 * and the rest to identity. 887 * 888 * @see #Matrix4d(Matrix3d) 889 * 890 * @param mat 891 * the {@link Matrix3d} 892 * @return this 893 */ 894 ref public Matrix4d set(Matrix3d mat) return { 895 return 896 _m00(mat.m00). 897 _m01(mat.m01). 898 _m02(mat.m02). 899 _m03(0.0). 900 _m10(mat.m10). 901 _m11(mat.m11). 902 _m12(mat.m12). 903 _m13(0.0). 904 _m20(mat.m20). 905 _m21(mat.m21). 906 _m22(mat.m22). 907 _m23(0.0). 908 _m30(0.0). 909 _m31(0.0). 910 _m32(0.0). 911 _m33(1.0). 912 _properties(PROPERTY_AFFINE); 913 } 914 915 /** 916 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to that of the given {@link Matrix4d} 917 * and don't change the other elements. 918 * 919 * @param mat 920 * the {@link Matrix4d} 921 * @return this 922 */ 923 ref public Matrix4d set3x3(Matrix4d mat) return { 924 return 925 _m00(mat.m00). 926 _m01(mat.m01). 927 _m02(mat.m02). 928 _m10(mat.m10). 929 _m11(mat.m11). 930 _m12(mat.m12). 931 _m20(mat.m20). 932 _m21(mat.m21). 933 _m22(mat.m22). 934 _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE)); 935 } 936 937 /** 938 * Set the upper 4x3 submatrix of this {@link Matrix4d} to the given {@link Matrix4x3d} 939 * and don't change the other elements. 940 * 941 * @see Matrix4x3d#get(Matrix4d) 942 * 943 * @param mat 944 * the {@link Matrix4x3d} 945 * @return this 946 */ 947 ref public Matrix4d set4x3(Matrix4x3d mat) return { 948 return 949 _m00(mat.m00). 950 _m01(mat.m01). 951 _m02(mat.m02). 952 _m10(mat.m10). 953 _m11(mat.m11). 954 _m12(mat.m12). 955 _m20(mat.m20). 956 _m21(mat.m21). 957 _m22(mat.m22). 958 _m30(mat.m30). 959 _m31(mat.m31). 960 _m32(mat.m32). 961 _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE)); 962 } 963 964 965 /** 966 * Set the upper 4x3 submatrix of this {@link Matrix4d} to the upper 4x3 submatrix of the given {@link Matrix4d} 967 * and don't change the other elements. 968 * 969 * @param mat 970 * the {@link Matrix4d} 971 * @return this 972 */ 973 ref public Matrix4d set4x3(Matrix4d mat) return { 974 return 975 _m00(mat.m00). 976 _m01(mat.m01). 977 _m02(mat.m02). 978 _m10(mat.m10). 979 _m11(mat.m11). 980 _m12(mat.m12). 981 _m20(mat.m20). 982 _m21(mat.m21). 983 _m22(mat.m22). 984 _m30(mat.m30). 985 _m31(mat.m31). 986 _m32(mat.m32). 987 _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE)); 988 } 989 990 /** 991 * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}. 992 * 993 * @param axisAngle 994 * the {@link AxisAngle4d} 995 * @return this 996 */ 997 ref public Matrix4d set(ref AxisAngle4d axisAngle) return { 998 double x = axisAngle.x; 999 double y = axisAngle.y; 1000 double z = axisAngle.z; 1001 double angle = axisAngle.angle; 1002 double invLength = Math.invsqrt(x*x + y*y + z*z); 1003 x *= invLength; 1004 y *= invLength; 1005 z *= invLength; 1006 double s = Math.sin(angle); 1007 double c = Math.cosFromSin(s, angle); 1008 double omc = 1.0 - c; 1009 _m00(c + x*x*omc). 1010 _m11(c + y*y*omc). 1011 _m22(c + z*z*omc); 1012 double tmp1 = x*y*omc; 1013 double tmp2 = z*s; 1014 _m10(tmp1 - tmp2). 1015 _m01(tmp1 + tmp2); 1016 tmp1 = x*z*omc; 1017 tmp2 = y*s; 1018 _m20(tmp1 + tmp2). 1019 _m02(tmp1 - tmp2); 1020 tmp1 = y*z*omc; 1021 tmp2 = x*s; 1022 _m21(tmp1 - tmp2). 1023 _m12(tmp1 + tmp2). 1024 _m03(0.0). 1025 _m13(0.0). 1026 _m23(0.0). 1027 _m30(0.0). 1028 _m31(0.0). 1029 _m32(0.0). 1030 _m33(1.0). 1031 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 1032 return this; 1033 } 1034 1035 1036 /** 1037 * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniond}. 1038 * <p> 1039 * This method is equivalent to calling: <code>rotation(q)</code> 1040 * <p> 1041 * Reference: <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/">http://www.euclideanspace.com/</a> 1042 * 1043 * @see #rotation(ref Quaterniond) 1044 * 1045 * @param q 1046 * the {@link Quaterniond} 1047 * @return this 1048 */ 1049 ref public Matrix4d set(ref Quaterniond q) return { 1050 return rotation(q); 1051 } 1052 1053 /** 1054 * Multiply this matrix by the supplied <code>right</code> matrix. 1055 * <p> 1056 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1057 * then the new matrix will be <code>M * R</code>. So when transforming a 1058 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1059 * transformation of the right matrix will be applied first! 1060 * 1061 * @param right 1062 * the right operand of the multiplication 1063 * @return this 1064 */ 1065 ref public Matrix4d mul(Matrix4d right) return { 1066 mul(right, this); 1067 return this; 1068 } 1069 1070 public Matrix4d mul(Matrix4d right, ref Matrix4d dest) { 1071 if ((properties & PROPERTY_IDENTITY) != 0) 1072 return dest.set(right); 1073 else if ((right.properties & PROPERTY_IDENTITY) != 0) 1074 return dest.set(this); 1075 else if ((properties & PROPERTY_TRANSLATION) != 0 && (right.properties & PROPERTY_AFFINE) != 0) 1076 return mulTranslationAffine(right, dest); 1077 else if ((properties & PROPERTY_AFFINE) != 0 && (right.properties & PROPERTY_AFFINE) != 0) 1078 return mulAffine(right, dest); 1079 else if ((properties & PROPERTY_PERSPECTIVE) != 0 && (right.properties & PROPERTY_AFFINE) != 0) 1080 return mulPerspectiveAffine(right, dest); 1081 else if ((right.properties & PROPERTY_AFFINE) != 0) 1082 return mulAffineR(right, dest); 1083 return mul0(right, dest); 1084 } 1085 1086 /** 1087 * Multiply this matrix by the supplied <code>right</code> matrix. 1088 * <p> 1089 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1090 * then the new matrix will be <code>M * R</code>. So when transforming a 1091 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1092 * transformation of the right matrix will be applied first! 1093 * <p> 1094 * This method neither assumes nor checks for any matrix properties of <code>this</code> or <code>right</code> 1095 * and will always perform a complete 4x4 matrix multiplication. This method should only be used whenever the 1096 * multiplied matrices do not have any properties for which there are optimized multiplication methods available. 1097 * 1098 * @param right 1099 * the right operand of the matrix multiplication 1100 * @return this 1101 */ 1102 ref public Matrix4d mul0(Matrix4d right) return { 1103 mul0(right, this); 1104 return this; 1105 } 1106 1107 public Matrix4d mul0(Matrix4d right, ref Matrix4d dest) { 1108 double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, Math.fma(m20, right.m02, m30 * right.m03))); 1109 double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, Math.fma(m21, right.m02, m31 * right.m03))); 1110 double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, Math.fma(m22, right.m02, m32 * right.m03))); 1111 double nm03 = Math.fma(m03, right.m00, Math.fma(m13, right.m01, Math.fma(m23, right.m02, m33 * right.m03))); 1112 double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, Math.fma(m20, right.m12, m30 * right.m13))); 1113 double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, Math.fma(m21, right.m12, m31 * right.m13))); 1114 double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, Math.fma(m22, right.m12, m32 * right.m13))); 1115 double nm13 = Math.fma(m03, right.m10, Math.fma(m13, right.m11, Math.fma(m23, right.m12, m33 * right.m13))); 1116 double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, Math.fma(m20, right.m22, m30 * right.m23))); 1117 double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, Math.fma(m21, right.m22, m31 * right.m23))); 1118 double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, Math.fma(m22, right.m22, m32 * right.m23))); 1119 double nm23 = Math.fma(m03, right.m20, Math.fma(m13, right.m21, Math.fma(m23, right.m22, m33 * right.m23))); 1120 double nm30 = Math.fma(m00, right.m30, Math.fma(m10, right.m31, Math.fma(m20, right.m32, m30 * right.m33))); 1121 double nm31 = Math.fma(m01, right.m30, Math.fma(m11, right.m31, Math.fma(m21, right.m32, m31 * right.m33))); 1122 double nm32 = Math.fma(m02, right.m30, Math.fma(m12, right.m31, Math.fma(m22, right.m32, m32 * right.m33))); 1123 double nm33 = Math.fma(m03, right.m30, Math.fma(m13, right.m31, Math.fma(m23, right.m32, m33 * right.m33))); 1124 return dest 1125 ._m00(nm00) 1126 ._m01(nm01) 1127 ._m02(nm02) 1128 ._m03(nm03) 1129 ._m10(nm10) 1130 ._m11(nm11) 1131 ._m12(nm12) 1132 ._m13(nm13) 1133 ._m20(nm20) 1134 ._m21(nm21) 1135 ._m22(nm22) 1136 ._m23(nm23) 1137 ._m30(nm30) 1138 ._m31(nm31) 1139 ._m32(nm32) 1140 ._m33(nm33) 1141 ._properties(0); 1142 } 1143 1144 /** 1145 * Multiply this matrix by the matrix with the supplied elements. 1146 * <p> 1147 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix whose 1148 * elements are supplied via the parameters, then the new matrix will be <code>M * R</code>. 1149 * So when transforming a vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1150 * transformation of the right matrix will be applied first! 1151 * 1152 * @param r00 1153 * the m00 element of the right matrix 1154 * @param r01 1155 * the m01 element of the right matrix 1156 * @param r02 1157 * the m02 element of the right matrix 1158 * @param r03 1159 * the m03 element of the right matrix 1160 * @param r10 1161 * the m10 element of the right matrix 1162 * @param r11 1163 * the m11 element of the right matrix 1164 * @param r12 1165 * the m12 element of the right matrix 1166 * @param r13 1167 * the m13 element of the right matrix 1168 * @param r20 1169 * the m20 element of the right matrix 1170 * @param r21 1171 * the m21 element of the right matrix 1172 * @param r22 1173 * the m22 element of the right matrix 1174 * @param r23 1175 * the m23 element of the right matrix 1176 * @param r30 1177 * the m30 element of the right matrix 1178 * @param r31 1179 * the m31 element of the right matrix 1180 * @param r32 1181 * the m32 element of the right matrix 1182 * @param r33 1183 * the m33 element of the right matrix 1184 * @return this 1185 */ 1186 ref public Matrix4d mul( 1187 double r00, double r01, double r02, double r03, 1188 double r10, double r11, double r12, double r13, 1189 double r20, double r21, double r22, double r23, 1190 double r30, double r31, double r32, double r33) return { 1191 mul(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, this); 1192 return this; 1193 } 1194 1195 public Matrix4d mul( 1196 double r00, double r01, double r02, double r03, 1197 double r10, double r11, double r12, double r13, 1198 double r20, double r21, double r22, double r23, 1199 double r30, double r31, double r32, double r33, ref Matrix4d dest) { 1200 if ((properties & PROPERTY_IDENTITY) != 0) 1201 return dest.set(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33); 1202 else if ((properties & PROPERTY_AFFINE) != 0) 1203 return mulAffineL(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest); 1204 return mulGeneric(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest); 1205 } 1206 private Matrix4d mulAffineL( 1207 double r00, double r01, double r02, double r03, 1208 double r10, double r11, double r12, double r13, 1209 double r20, double r21, double r22, double r23, 1210 double r30, double r31, double r32, double r33, ref Matrix4d dest) { 1211 double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03))); 1212 double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03))); 1213 double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03))); 1214 double nm03 = r03; 1215 double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13))); 1216 double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13))); 1217 double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13))); 1218 double nm13 = r13; 1219 double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23))); 1220 double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23))); 1221 double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23))); 1222 double nm23 = r23; 1223 double nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33))); 1224 double nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33))); 1225 double nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33))); 1226 double nm33 = r33; 1227 return dest 1228 ._m00(nm00) 1229 ._m01(nm01) 1230 ._m02(nm02) 1231 ._m03(nm03) 1232 ._m10(nm10) 1233 ._m11(nm11) 1234 ._m12(nm12) 1235 ._m13(nm13) 1236 ._m20(nm20) 1237 ._m21(nm21) 1238 ._m22(nm22) 1239 ._m23(nm23) 1240 ._m30(nm30) 1241 ._m31(nm31) 1242 ._m32(nm32) 1243 ._m33(nm33) 1244 ._properties(PROPERTY_AFFINE); 1245 } 1246 private Matrix4d mulGeneric( 1247 double r00, double r01, double r02, double r03, 1248 double r10, double r11, double r12, double r13, 1249 double r20, double r21, double r22, double r23, 1250 double r30, double r31, double r32, double r33, ref Matrix4d dest) { 1251 double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03))); 1252 double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03))); 1253 double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03))); 1254 double nm03 = Math.fma(m03, r00, Math.fma(m13, r01, Math.fma(m23, r02, m33 * r03))); 1255 double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13))); 1256 double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13))); 1257 double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13))); 1258 double nm13 = Math.fma(m03, r10, Math.fma(m13, r11, Math.fma(m23, r12, m33 * r13))); 1259 double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23))); 1260 double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23))); 1261 double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23))); 1262 double nm23 = Math.fma(m03, r20, Math.fma(m13, r21, Math.fma(m23, r22, m33 * r23))); 1263 double nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33))); 1264 double nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33))); 1265 double nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33))); 1266 double nm33 = Math.fma(m03, r30, Math.fma(m13, r31, Math.fma(m23, r32, m33 * r33))); 1267 return dest 1268 ._m00(nm00) 1269 ._m01(nm01) 1270 ._m02(nm02) 1271 ._m03(nm03) 1272 ._m10(nm10) 1273 ._m11(nm11) 1274 ._m12(nm12) 1275 ._m13(nm13) 1276 ._m20(nm20) 1277 ._m21(nm21) 1278 ._m22(nm22) 1279 ._m23(nm23) 1280 ._m30(nm30) 1281 ._m31(nm31) 1282 ._m32(nm32) 1283 ._m33(nm33) 1284 ._properties(0); 1285 } 1286 1287 /** 1288 * Multiply this matrix by the 3x3 matrix with the supplied elements expanded to a 4x4 matrix with 1289 * all other matrix elements set to identity. 1290 * <p> 1291 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix whose 1292 * elements are supplied via the parameters, then the new matrix will be <code>M * R</code>. 1293 * So when transforming a vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1294 * transformation of the right matrix will be applied first! 1295 * 1296 * @param r00 1297 * the m00 element of the right matrix 1298 * @param r01 1299 * the m01 element of the right matrix 1300 * @param r02 1301 * the m02 element of the right matrix 1302 * @param r10 1303 * the m10 element of the right matrix 1304 * @param r11 1305 * the m11 element of the right matrix 1306 * @param r12 1307 * the m12 element of the right matrix 1308 * @param r20 1309 * the m20 element of the right matrix 1310 * @param r21 1311 * the m21 element of the right matrix 1312 * @param r22 1313 * the m22 element of the right matrix 1314 * @return this 1315 */ 1316 ref public Matrix4d mul3x3( 1317 double r00, double r01, double r02, 1318 double r10, double r11, double r12, 1319 double r20, double r21, double r22) return { 1320 mul3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, this); 1321 return this; 1322 } 1323 public Matrix4d mul3x3( 1324 double r00, double r01, double r02, 1325 double r10, double r11, double r12, 1326 double r20, double r21, double r22, ref Matrix4d dest) { 1327 if ((properties & PROPERTY_IDENTITY) != 0) 1328 return dest.set(r00, r01, r02, 0, r10, r11, r12, 0, r20, r21, r22, 0, 0, 0, 0, 1); 1329 return mulGeneric3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, dest); 1330 } 1331 private Matrix4d mulGeneric3x3( 1332 double r00, double r01, double r02, 1333 double r10, double r11, double r12, 1334 double r20, double r21, double r22, ref Matrix4d dest) { 1335 double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, m20 * r02)); 1336 double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, m21 * r02)); 1337 double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, m22 * r02)); 1338 double nm03 = Math.fma(m03, r00, Math.fma(m13, r01, m23 * r02)); 1339 double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, m20 * r12)); 1340 double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, m21 * r12)); 1341 double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, m22 * r12)); 1342 double nm13 = Math.fma(m03, r10, Math.fma(m13, r11, m23 * r12)); 1343 double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, m20 * r22)); 1344 double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, m21 * r22)); 1345 double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, m22 * r22)); 1346 double nm23 = Math.fma(m03, r20, Math.fma(m13, r21, m23 * r22)); 1347 return dest 1348 ._m00(nm00) 1349 ._m01(nm01) 1350 ._m02(nm02) 1351 ._m03(nm03) 1352 ._m10(nm10) 1353 ._m11(nm11) 1354 ._m12(nm12) 1355 ._m13(nm13) 1356 ._m20(nm20) 1357 ._m21(nm21) 1358 ._m22(nm22) 1359 ._m23(nm23) 1360 ._m30(m30) 1361 ._m31(m31) 1362 ._m32(m32) 1363 ._m33(m33) 1364 ._properties(this.properties & PROPERTY_AFFINE); 1365 } 1366 1367 /** 1368 * Pre-multiply this matrix by the supplied <code>left</code> matrix and store the result in <code>this</code>. 1369 * <p> 1370 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix, 1371 * then the new matrix will be <code>L * M</code>. So when transforming a 1372 * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the 1373 * transformation of <code>this</code> matrix will be applied first! 1374 * 1375 * @param left 1376 * the left operand of the matrix multiplication 1377 * @return this 1378 */ 1379 ref public Matrix4d mulLocal(Matrix4d left) return { 1380 mulLocal(left, this); 1381 return this; 1382 } 1383 1384 public Matrix4d mulLocal(Matrix4d left, ref Matrix4d dest) { 1385 if ((properties & PROPERTY_IDENTITY) != 0) 1386 return dest.set(left); 1387 else if ((left.properties & PROPERTY_IDENTITY) != 0) 1388 return dest.set(this); 1389 else if ((properties & PROPERTY_AFFINE) != 0 && (left.properties & PROPERTY_AFFINE) != 0) 1390 return mulLocalAffine(left, dest); 1391 return mulLocalGeneric(left, dest); 1392 } 1393 private Matrix4d mulLocalGeneric(Matrix4d left, ref Matrix4d dest) { 1394 double nm00 = Math.fma(left.m00, m00, Math.fma(left.m10, m01, Math.fma(left.m20, m02, left.m30 * m03))); 1395 double nm01 = Math.fma(left.m01, m00, Math.fma(left.m11, m01, Math.fma(left.m21, m02, left.m31 * m03))); 1396 double nm02 = Math.fma(left.m02, m00, Math.fma(left.m12, m01, Math.fma(left.m22, m02, left.m32 * m03))); 1397 double nm03 = Math.fma(left.m03, m00, Math.fma(left.m13, m01, Math.fma(left.m23, m02, left.m33 * m03))); 1398 double nm10 = Math.fma(left.m00, m10, Math.fma(left.m10, m11, Math.fma(left.m20, m12, left.m30 * m13))); 1399 double nm11 = Math.fma(left.m01, m10, Math.fma(left.m11, m11, Math.fma(left.m21, m12, left.m31 * m13))); 1400 double nm12 = Math.fma(left.m02, m10, Math.fma(left.m12, m11, Math.fma(left.m22, m12, left.m32 * m13))); 1401 double nm13 = Math.fma(left.m03, m10, Math.fma(left.m13, m11, Math.fma(left.m23, m12, left.m33 * m13))); 1402 double nm20 = Math.fma(left.m00, m20, Math.fma(left.m10, m21, Math.fma(left.m20, m22, left.m30 * m23))); 1403 double nm21 = Math.fma(left.m01, m20, Math.fma(left.m11, m21, Math.fma(left.m21, m22, left.m31 * m23))); 1404 double nm22 = Math.fma(left.m02, m20, Math.fma(left.m12, m21, Math.fma(left.m22, m22, left.m32 * m23))); 1405 double nm23 = Math.fma(left.m03, m20, Math.fma(left.m13, m21, Math.fma(left.m23, m22, left.m33 * m23))); 1406 double nm30 = Math.fma(left.m00, m30, Math.fma(left.m10, m31, Math.fma(left.m20, m32, left.m30 * m33))); 1407 double nm31 = Math.fma(left.m01, m30, Math.fma(left.m11, m31, Math.fma(left.m21, m32, left.m31 * m33))); 1408 double nm32 = Math.fma(left.m02, m30, Math.fma(left.m12, m31, Math.fma(left.m22, m32, left.m32 * m33))); 1409 double nm33 = Math.fma(left.m03, m30, Math.fma(left.m13, m31, Math.fma(left.m23, m32, left.m33 * m33))); 1410 return dest 1411 ._m00(nm00) 1412 ._m01(nm01) 1413 ._m02(nm02) 1414 ._m03(nm03) 1415 ._m10(nm10) 1416 ._m11(nm11) 1417 ._m12(nm12) 1418 ._m13(nm13) 1419 ._m20(nm20) 1420 ._m21(nm21) 1421 ._m22(nm22) 1422 ._m23(nm23) 1423 ._m30(nm30) 1424 ._m31(nm31) 1425 ._m32(nm32) 1426 ._m33(nm33) 1427 ._properties(0); 1428 } 1429 1430 /** 1431 * Pre-multiply this matrix by the supplied <code>left</code> matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in <code>this</code>. 1432 * <p> 1433 * This method assumes that <code>this</code> matrix and the given <code>left</code> matrix both represent an {@link #isAffine() affine} transformation 1434 * (i.e. their last rows are equal to <code>(0, 0, 0, 1)</code>) 1435 * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination). 1436 * <p> 1437 * This method will not modify either the last row of <code>this</code> or the last row of <code>left</code>. 1438 * <p> 1439 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix, 1440 * then the new matrix will be <code>L * M</code>. So when transforming a 1441 * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the 1442 * transformation of <code>this</code> matrix will be applied first! 1443 * 1444 * @param left 1445 * the left operand of the matrix multiplication (the last row is assumed to be <code>(0, 0, 0, 1)</code>) 1446 * @return this 1447 */ 1448 ref public Matrix4d mulLocalAffine(Matrix4d left) return { 1449 mulLocalAffine(left, this); 1450 return this; 1451 } 1452 1453 public Matrix4d mulLocalAffine(Matrix4d left, ref Matrix4d dest) { 1454 double nm00 = left.m00 * m00 + left.m10 * m01 + left.m20 * m02; 1455 double nm01 = left.m01 * m00 + left.m11 * m01 + left.m21 * m02; 1456 double nm02 = left.m02 * m00 + left.m12 * m01 + left.m22 * m02; 1457 double nm03 = left.m03; 1458 double nm10 = left.m00 * m10 + left.m10 * m11 + left.m20 * m12; 1459 double nm11 = left.m01 * m10 + left.m11 * m11 + left.m21 * m12; 1460 double nm12 = left.m02 * m10 + left.m12 * m11 + left.m22 * m12; 1461 double nm13 = left.m13; 1462 double nm20 = left.m00 * m20 + left.m10 * m21 + left.m20 * m22; 1463 double nm21 = left.m01 * m20 + left.m11 * m21 + left.m21 * m22; 1464 double nm22 = left.m02 * m20 + left.m12 * m21 + left.m22 * m22; 1465 double nm23 = left.m23; 1466 double nm30 = left.m00 * m30 + left.m10 * m31 + left.m20 * m32 + left.m30; 1467 double nm31 = left.m01 * m30 + left.m11 * m31 + left.m21 * m32 + left.m31; 1468 double nm32 = left.m02 * m30 + left.m12 * m31 + left.m22 * m32 + left.m32; 1469 double nm33 = left.m33; 1470 dest._m00(nm00) 1471 ._m01(nm01) 1472 ._m02(nm02) 1473 ._m03(nm03) 1474 ._m10(nm10) 1475 ._m11(nm11) 1476 ._m12(nm12) 1477 ._m13(nm13) 1478 ._m20(nm20) 1479 ._m21(nm21) 1480 ._m22(nm22) 1481 ._m23(nm23) 1482 ._m30(nm30) 1483 ._m31(nm31) 1484 ._m32(nm32) 1485 ._m33(nm33) 1486 ._properties(PROPERTY_AFFINE); 1487 return dest; 1488 } 1489 1490 /** 1491 * Multiply this matrix by the supplied <code>right</code> matrix. 1492 * <p> 1493 * The last row of the <code>right</code> matrix is assumed to be <code>(0, 0, 0, 1)</code>. 1494 * <p> 1495 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1496 * then the new matrix will be <code>M * R</code>. So when transforming a 1497 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1498 * transformation of the right matrix will be applied first! 1499 * 1500 * @param right 1501 * the right operand of the matrix multiplication 1502 * @return this 1503 */ 1504 ref public Matrix4d mul(Matrix4x3d right) return { 1505 mul(right, this); 1506 return this; 1507 } 1508 1509 public Matrix4d mul(Matrix4x3d right, ref Matrix4d dest) { 1510 if ((properties & PROPERTY_IDENTITY) != 0) 1511 return dest.set(right); 1512 else if ((right.properties & PROPERTY_IDENTITY) != 0) 1513 return dest.set(this); 1514 else if ((properties & PROPERTY_TRANSLATION) != 0) 1515 return mulTranslation(right, dest); 1516 else if ((properties & PROPERTY_AFFINE) != 0) 1517 return mulAffine(right, dest); 1518 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 1519 return mulPerspectiveAffine(right, dest); 1520 return mulGeneric(right, dest); 1521 } 1522 private Matrix4d mulTranslation(Matrix4x3d right, ref Matrix4d dest) { 1523 return dest 1524 ._m00(right.m00) 1525 ._m01(right.m01) 1526 ._m02(right.m02) 1527 ._m03(m03) 1528 ._m10(right.m10) 1529 ._m11(right.m11) 1530 ._m12(right.m12) 1531 ._m13(m13) 1532 ._m20(right.m20) 1533 ._m21(right.m21) 1534 ._m22(right.m22) 1535 ._m23(m23) 1536 ._m30(right.m30 + m30) 1537 ._m31(right.m31 + m31) 1538 ._m32(right.m32 + m32) 1539 ._m33(m33) 1540 ._properties(PROPERTY_AFFINE | (right.properties & PROPERTY_ORTHONORMAL)); 1541 } 1542 private Matrix4d mulAffine(Matrix4x3d right, ref Matrix4d dest) { 1543 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 1544 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 1545 double m20 = this.m20, m21 = this.m21, m22 = this.m22; 1546 double rm00 = right.m00, rm01 = right.m01, rm02 = right.m02; 1547 double rm10 = right.m10, rm11 = right.m11, rm12 = right.m12; 1548 double rm20 = right.m20, rm21 = right.m21, rm22 = right.m22; 1549 double rm30 = right.m30, rm31 = right.m31, rm32 = right.m32; 1550 return dest 1551 ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02))) 1552 ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02))) 1553 ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02))) 1554 ._m03(m03) 1555 ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12))) 1556 ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12))) 1557 ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12))) 1558 ._m13(m13) 1559 ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22))) 1560 ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22))) 1561 ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22))) 1562 ._m23(m23) 1563 ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30)))) 1564 ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31)))) 1565 ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32)))) 1566 ._m33(m33) 1567 ._properties(PROPERTY_AFFINE | (this.properties & right.properties & PROPERTY_ORTHONORMAL)); 1568 } 1569 private Matrix4d mulGeneric(Matrix4x3d right, ref Matrix4d dest) { 1570 double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, m20 * right.m02)); 1571 double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, m21 * right.m02)); 1572 double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, m22 * right.m02)); 1573 double nm03 = Math.fma(m03, right.m00, Math.fma(m13, right.m01, m23 * right.m02)); 1574 double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, m20 * right.m12)); 1575 double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, m21 * right.m12)); 1576 double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, m22 * right.m12)); 1577 double nm13 = Math.fma(m03, right.m10, Math.fma(m13, right.m11, m23 * right.m12)); 1578 double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, m20 * right.m22)); 1579 double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, m21 * right.m22)); 1580 double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, m22 * right.m22)); 1581 double nm23 = Math.fma(m03, right.m20, Math.fma(m13, right.m21, m23 * right.m22)); 1582 double nm30 = Math.fma(m00, right.m30, Math.fma(m10, right.m31, Math.fma(m20, right.m32, m30))); 1583 double nm31 = Math.fma(m01, right.m30, Math.fma(m11, right.m31, Math.fma(m21, right.m32, m31))); 1584 double nm32 = Math.fma(m02, right.m30, Math.fma(m12, right.m31, Math.fma(m22, right.m32, m32))); 1585 double nm33 = Math.fma(m03, right.m30, Math.fma(m13, right.m31, Math.fma(m23, right.m32, m33))); 1586 dest._m00(nm00) 1587 ._m01(nm01) 1588 ._m02(nm02) 1589 ._m03(nm03) 1590 ._m10(nm10) 1591 ._m11(nm11) 1592 ._m12(nm12) 1593 ._m13(nm13) 1594 ._m20(nm20) 1595 ._m21(nm21) 1596 ._m22(nm22) 1597 ._m23(nm23) 1598 ._m30(nm30) 1599 ._m31(nm31) 1600 ._m32(nm32) 1601 ._m33(nm33) 1602 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 1603 return dest; 1604 } 1605 public Matrix4d mulPerspectiveAffine(Matrix4x3d view, ref Matrix4d dest) { 1606 double lm00 = m00, lm11 = m11, lm22 = m22, lm23 = m23; 1607 dest._m00(lm00 * view.m00)._m01(lm11 * view.m01)._m02(lm22 * view.m02)._m03(lm23 * view.m02). 1608 _m10(lm00 * view.m10)._m11(lm11 * view.m11)._m12(lm22 * view.m12)._m13(lm23 * view.m12). 1609 _m20(lm00 * view.m20)._m21(lm11 * view.m21)._m22(lm22 * view.m22)._m23(lm23 * view.m22). 1610 _m30(lm00 * view.m30)._m31(lm11 * view.m31)._m32(lm22 * view.m32 + m32)._m33(lm23 * view.m32) 1611 ._properties(0); 1612 return dest; 1613 } 1614 1615 1616 /** 1617 * Multiply this matrix by the supplied <code>right</code> matrix and store the result in <code>this</code>. 1618 * <p> 1619 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1620 * then the new matrix will be <code>M * R</code>. So when transforming a 1621 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1622 * transformation of the right matrix will be applied first! 1623 * 1624 * @param right 1625 * the right operand of the matrix multiplication 1626 * @return this 1627 */ 1628 ref public Matrix4d mul(Matrix3x2d right) return { 1629 mul(right, this); 1630 return this; 1631 } 1632 1633 public Matrix4d mul(Matrix3x2d right, ref Matrix4d dest) { 1634 double nm00 = m00 * right.m00 + m10 * right.m01; 1635 double nm01 = m01 * right.m00 + m11 * right.m01; 1636 double nm02 = m02 * right.m00 + m12 * right.m01; 1637 double nm03 = m03 * right.m00 + m13 * right.m01; 1638 double nm10 = m00 * right.m10 + m10 * right.m11; 1639 double nm11 = m01 * right.m10 + m11 * right.m11; 1640 double nm12 = m02 * right.m10 + m12 * right.m11; 1641 double nm13 = m03 * right.m10 + m13 * right.m11; 1642 double nm30 = m00 * right.m20 + m10 * right.m21 + m30; 1643 double nm31 = m01 * right.m20 + m11 * right.m21 + m31; 1644 double nm32 = m02 * right.m20 + m12 * right.m21 + m32; 1645 double nm33 = m03 * right.m20 + m13 * right.m21 + m33; 1646 dest._m00(nm00) 1647 ._m01(nm01) 1648 ._m02(nm02) 1649 ._m03(nm03) 1650 ._m10(nm10) 1651 ._m11(nm11) 1652 ._m12(nm12) 1653 ._m13(nm13) 1654 ._m20(m20) 1655 ._m21(m21) 1656 ._m22(m22) 1657 ._m23(m23) 1658 ._m30(nm30) 1659 ._m31(nm31) 1660 ._m32(nm32) 1661 ._m33(nm33) 1662 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 1663 return dest; 1664 } 1665 1666 1667 1668 1669 /** 1670 * Multiply <code>this</code> symmetric perspective projection matrix by the supplied {@link #isAffine() affine} <code>view</code> matrix. 1671 * <p> 1672 * If <code>P</code> is <code>this</code> matrix and <code>V</code> the <code>view</code> matrix, 1673 * then the new matrix will be <code>P * V</code>. So when transforming a 1674 * vector <code>v</code> with the new matrix by using <code>P * V * v</code>, the 1675 * transformation of the <code>view</code> matrix will be applied first! 1676 * 1677 * @param view 1678 * the {@link #isAffine() affine} matrix to multiply <code>this</code> symmetric perspective projection matrix by 1679 * @return this 1680 */ 1681 ref public Matrix4d mulPerspectiveAffine(Matrix4d view) return { 1682 mulPerspectiveAffine(view, this); 1683 return this; 1684 } 1685 1686 public Matrix4d mulPerspectiveAffine(Matrix4d view, ref Matrix4d dest) { 1687 double nm00 = m00 * view.m00, nm01 = m11 * view.m01, nm02 = m22 * view.m02, nm03 = m23 * view.m02; 1688 double nm10 = m00 * view.m10, nm11 = m11 * view.m11, nm12 = m22 * view.m12, nm13 = m23 * view.m12; 1689 double nm20 = m00 * view.m20, nm21 = m11 * view.m21, nm22 = m22 * view.m22, nm23 = m23 * view.m22; 1690 double nm30 = m00 * view.m30, nm31 = m11 * view.m31, nm32 = m22 * view.m32 + m32, nm33 = m23 * view.m32; 1691 return dest 1692 ._m00(nm00)._m01(nm01)._m02(nm02)._m03(nm03) 1693 ._m10(nm10)._m11(nm11)._m12(nm12)._m13(nm13) 1694 ._m20(nm20)._m21(nm21)._m22(nm22)._m23(nm23) 1695 ._m30(nm30)._m31(nm31)._m32(nm32)._m33(nm33) 1696 ._properties(0); 1697 } 1698 1699 /** 1700 * Multiply this matrix by the supplied <code>right</code> matrix, which is assumed to be {@link #isAffine() affine}, and store the result in <code>this</code>. 1701 * <p> 1702 * This method assumes that the given <code>right</code> matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to <code>(0, 0, 0, 1)</code>) 1703 * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination). 1704 * <p> 1705 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1706 * then the new matrix will be <code>M * R</code>. So when transforming a 1707 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1708 * transformation of the right matrix will be applied first! 1709 * 1710 * @param right 1711 * the right operand of the matrix multiplication (the last row is assumed to be <code>(0, 0, 0, 1)</code>) 1712 * @return this 1713 */ 1714 ref public Matrix4d mulAffineR(Matrix4d right) return { 1715 mulAffineR(right, this); 1716 return this; 1717 } 1718 1719 public Matrix4d mulAffineR(Matrix4d right, ref Matrix4d dest) { 1720 double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, m20 * right.m02)); 1721 double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, m21 * right.m02)); 1722 double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, m22 * right.m02)); 1723 double nm03 = Math.fma(m03, right.m00, Math.fma(m13, right.m01, m23 * right.m02)); 1724 double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, m20 * right.m12)); 1725 double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, m21 * right.m12)); 1726 double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, m22 * right.m12)); 1727 double nm13 = Math.fma(m03, right.m10, Math.fma(m13, right.m11, m23 * right.m12)); 1728 double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, m20 * right.m22)); 1729 double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, m21 * right.m22)); 1730 double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, m22 * right.m22)); 1731 double nm23 = Math.fma(m03, right.m20, Math.fma(m13, right.m21, m23 * right.m22)); 1732 double nm30 = Math.fma(m00, right.m30, Math.fma(m10, right.m31, Math.fma(m20, right.m32, m30))); 1733 double nm31 = Math.fma(m01, right.m30, Math.fma(m11, right.m31, Math.fma(m21, right.m32, m31))); 1734 double nm32 = Math.fma(m02, right.m30, Math.fma(m12, right.m31, Math.fma(m22, right.m32, m32))); 1735 double nm33 = Math.fma(m03, right.m30, Math.fma(m13, right.m31, Math.fma(m23, right.m32, m33))); 1736 dest._m00(nm00) 1737 ._m01(nm01) 1738 ._m02(nm02) 1739 ._m03(nm03) 1740 ._m10(nm10) 1741 ._m11(nm11) 1742 ._m12(nm12) 1743 ._m13(nm13) 1744 ._m20(nm20) 1745 ._m21(nm21) 1746 ._m22(nm22) 1747 ._m23(nm23) 1748 ._m30(nm30) 1749 ._m31(nm31) 1750 ._m32(nm32) 1751 ._m33(nm33) 1752 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 1753 return dest; 1754 } 1755 1756 /** 1757 * Multiply this matrix by the supplied <code>right</code> matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in <code>this</code>. 1758 * <p> 1759 * This method assumes that <code>this</code> matrix and the given <code>right</code> matrix both represent an {@link #isAffine() affine} transformation 1760 * (i.e. their last rows are equal to <code>(0, 0, 0, 1)</code>) 1761 * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination). 1762 * <p> 1763 * This method will not modify either the last row of <code>this</code> or the last row of <code>right</code>. 1764 * <p> 1765 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1766 * then the new matrix will be <code>M * R</code>. So when transforming a 1767 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1768 * transformation of the right matrix will be applied first! 1769 * 1770 * @param right 1771 * the right operand of the matrix multiplication (the last row is assumed to be <code>(0, 0, 0, 1)</code>) 1772 * @return this 1773 */ 1774 ref public Matrix4d mulAffine(Matrix4d right) return { 1775 mulAffine(right, this); 1776 return this; 1777 } 1778 1779 public Matrix4d mulAffine(Matrix4d right, ref Matrix4d dest) { 1780 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 1781 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 1782 double m20 = this.m20, m21 = this.m21, m22 = this.m22; 1783 double rm00 = right.m00, rm01 = right.m01, rm02 = right.m02; 1784 double rm10 = right.m10, rm11 = right.m11, rm12 = right.m12; 1785 double rm20 = right.m20, rm21 = right.m21, rm22 = right.m22; 1786 double rm30 = right.m30, rm31 = right.m31, rm32 = right.m32; 1787 return dest 1788 ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02))) 1789 ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02))) 1790 ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02))) 1791 ._m03(m03) 1792 ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12))) 1793 ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12))) 1794 ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12))) 1795 ._m13(m13) 1796 ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22))) 1797 ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22))) 1798 ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22))) 1799 ._m23(m23) 1800 ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30)))) 1801 ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31)))) 1802 ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32)))) 1803 ._m33(m33) 1804 ._properties(PROPERTY_AFFINE | (this.properties & right.properties & PROPERTY_ORTHONORMAL)); 1805 } 1806 1807 public Matrix4d mulTranslationAffine(Matrix4d right, ref Matrix4d dest) { 1808 return dest 1809 ._m00(right.m00) 1810 ._m01(right.m01) 1811 ._m02(right.m02) 1812 ._m03(m03) 1813 ._m10(right.m10) 1814 ._m11(right.m11) 1815 ._m12(right.m12) 1816 ._m13(m13) 1817 ._m20(right.m20) 1818 ._m21(right.m21) 1819 ._m22(right.m22) 1820 ._m23(m23) 1821 ._m30(right.m30 + m30) 1822 ._m31(right.m31 + m31) 1823 ._m32(right.m32 + m32) 1824 ._m33(m33) 1825 ._properties(PROPERTY_AFFINE | (right.properties & PROPERTY_ORTHONORMAL)); 1826 } 1827 1828 /** 1829 * Multiply <code>this</code> orthographic projection matrix by the supplied {@link #isAffine() affine} <code>view</code> matrix. 1830 * <p> 1831 * If <code>M</code> is <code>this</code> matrix and <code>V</code> the <code>view</code> matrix, 1832 * then the new matrix will be <code>M * V</code>. So when transforming a 1833 * vector <code>v</code> with the new matrix by using <code>M * V * v</code>, the 1834 * transformation of the <code>view</code> matrix will be applied first! 1835 * 1836 * @param view 1837 * the affine matrix which to multiply <code>this</code> with 1838 * @return this 1839 */ 1840 ref public Matrix4d mulOrthoAffine(Matrix4d view) return { 1841 mulOrthoAffine(view, this); 1842 return this; 1843 } 1844 1845 public Matrix4d mulOrthoAffine(Matrix4d view, ref Matrix4d dest) { 1846 double nm00 = m00 * view.m00; 1847 double nm01 = m11 * view.m01; 1848 double nm02 = m22 * view.m02; 1849 double nm03 = 0.0; 1850 double nm10 = m00 * view.m10; 1851 double nm11 = m11 * view.m11; 1852 double nm12 = m22 * view.m12; 1853 double nm13 = 0.0; 1854 double nm20 = m00 * view.m20; 1855 double nm21 = m11 * view.m21; 1856 double nm22 = m22 * view.m22; 1857 double nm23 = 0.0; 1858 double nm30 = m00 * view.m30 + m30; 1859 double nm31 = m11 * view.m31 + m31; 1860 double nm32 = m22 * view.m32 + m32; 1861 double nm33 = 1.0; 1862 dest._m00(nm00) 1863 ._m01(nm01) 1864 ._m02(nm02) 1865 ._m03(nm03) 1866 ._m10(nm10) 1867 ._m11(nm11) 1868 ._m12(nm12) 1869 ._m13(nm13) 1870 ._m20(nm20) 1871 ._m21(nm21) 1872 ._m22(nm22) 1873 ._m23(nm23) 1874 ._m30(nm30) 1875 ._m31(nm31) 1876 ._m32(nm32) 1877 ._m33(nm33) 1878 ._properties(PROPERTY_AFFINE); 1879 return dest; 1880 } 1881 1882 /** 1883 * Component-wise add the upper 4x3 submatrices of <code>this</code> and <code>other</code> 1884 * by first multiplying each component of <code>other</code>'s 4x3 submatrix by <code>otherFactor</code> and 1885 * adding that result to <code>this</code>. 1886 * <p> 1887 * The matrix <code>other</code> will not be changed. 1888 * 1889 * @param other 1890 * the other matrix 1891 * @param otherFactor 1892 * the factor to multiply each of the other matrix's 4x3 components 1893 * @return this 1894 */ 1895 ref public Matrix4d fma4x3(Matrix4d other, double otherFactor) return { 1896 fma4x3(other, otherFactor, this); 1897 return this; 1898 } 1899 1900 public Matrix4d fma4x3(Matrix4d other, double otherFactor, ref Matrix4d dest) { 1901 dest._m00(Math.fma(other.m00, otherFactor, m00)) 1902 ._m01(Math.fma(other.m01, otherFactor, m01)) 1903 ._m02(Math.fma(other.m02, otherFactor, m02)) 1904 ._m03(m03) 1905 ._m10(Math.fma(other.m10, otherFactor, m10)) 1906 ._m11(Math.fma(other.m11, otherFactor, m11)) 1907 ._m12(Math.fma(other.m12, otherFactor, m12)) 1908 ._m13(m13) 1909 ._m20(Math.fma(other.m20, otherFactor, m20)) 1910 ._m21(Math.fma(other.m21, otherFactor, m21)) 1911 ._m22(Math.fma(other.m22, otherFactor, m22)) 1912 ._m23(m23) 1913 ._m30(Math.fma(other.m30, otherFactor, m30)) 1914 ._m31(Math.fma(other.m31, otherFactor, m31)) 1915 ._m32(Math.fma(other.m32, otherFactor, m32)) 1916 ._m33(m33) 1917 ._properties(0); 1918 return dest; 1919 } 1920 1921 /** 1922 * Component-wise add <code>this</code> and <code>other</code>. 1923 * 1924 * @param other 1925 * the other addend 1926 * @return this 1927 */ 1928 ref public Matrix4d add(Matrix4d other) return { 1929 add(other, this); 1930 return this; 1931 } 1932 1933 public Matrix4d add(Matrix4d other, ref Matrix4d dest) { 1934 dest._m00(m00 + other.m00) 1935 ._m01(m01 + other.m01) 1936 ._m02(m02 + other.m02) 1937 ._m03(m03 + other.m03) 1938 ._m10(m10 + other.m10) 1939 ._m11(m11 + other.m11) 1940 ._m12(m12 + other.m12) 1941 ._m13(m13 + other.m13) 1942 ._m20(m20 + other.m20) 1943 ._m21(m21 + other.m21) 1944 ._m22(m22 + other.m22) 1945 ._m23(m23 + other.m23) 1946 ._m30(m30 + other.m30) 1947 ._m31(m31 + other.m31) 1948 ._m32(m32 + other.m32) 1949 ._m33(m33 + other.m33) 1950 ._properties(0); 1951 return dest; 1952 } 1953 1954 /** 1955 * Component-wise subtract <code>subtrahend</code> from <code>this</code>. 1956 * 1957 * @param subtrahend 1958 * the subtrahend 1959 * @return this 1960 */ 1961 ref public Matrix4d sub(Matrix4d subtrahend) return { 1962 sub(subtrahend, this); 1963 return this; 1964 } 1965 1966 public Matrix4d sub(Matrix4d subtrahend, ref Matrix4d dest) { 1967 dest._m00(m00 - subtrahend.m00) 1968 ._m01(m01 - subtrahend.m01) 1969 ._m02(m02 - subtrahend.m02) 1970 ._m03(m03 - subtrahend.m03) 1971 ._m10(m10 - subtrahend.m10) 1972 ._m11(m11 - subtrahend.m11) 1973 ._m12(m12 - subtrahend.m12) 1974 ._m13(m13 - subtrahend.m13) 1975 ._m20(m20 - subtrahend.m20) 1976 ._m21(m21 - subtrahend.m21) 1977 ._m22(m22 - subtrahend.m22) 1978 ._m23(m23 - subtrahend.m23) 1979 ._m30(m30 - subtrahend.m30) 1980 ._m31(m31 - subtrahend.m31) 1981 ._m32(m32 - subtrahend.m32) 1982 ._m33(m33 - subtrahend.m33) 1983 ._properties(0); 1984 return dest; 1985 } 1986 1987 /** 1988 * Component-wise multiply <code>this</code> by <code>other</code>. 1989 * 1990 * @param other 1991 * the other matrix 1992 * @return this 1993 */ 1994 ref public Matrix4d mulComponentWise(Matrix4d other) return { 1995 mulComponentWise(other, this); 1996 return this; 1997 } 1998 1999 public Matrix4d mulComponentWise(Matrix4d other, ref Matrix4d dest) { 2000 dest._m00(m00 * other.m00) 2001 ._m01(m01 * other.m01) 2002 ._m02(m02 * other.m02) 2003 ._m03(m03 * other.m03) 2004 ._m10(m10 * other.m10) 2005 ._m11(m11 * other.m11) 2006 ._m12(m12 * other.m12) 2007 ._m13(m13 * other.m13) 2008 ._m20(m20 * other.m20) 2009 ._m21(m21 * other.m21) 2010 ._m22(m22 * other.m22) 2011 ._m23(m23 * other.m23) 2012 ._m30(m30 * other.m30) 2013 ._m31(m31 * other.m31) 2014 ._m32(m32 * other.m32) 2015 ._m33(m33 * other.m33) 2016 ._properties(0); 2017 return dest; 2018 } 2019 2020 /** 2021 * Component-wise add the upper 4x3 submatrices of <code>this</code> and <code>other</code>. 2022 * 2023 * @param other 2024 * the other addend 2025 * @return this 2026 */ 2027 ref public Matrix4d add4x3(Matrix4d other) return { 2028 add4x3(other, this); 2029 return this; 2030 } 2031 2032 public Matrix4d add4x3(Matrix4d other, ref Matrix4d dest) { 2033 dest._m00(m00 + other.m00) 2034 ._m01(m01 + other.m01) 2035 ._m02(m02 + other.m02) 2036 ._m03(m03) 2037 ._m10(m10 + other.m10) 2038 ._m11(m11 + other.m11) 2039 ._m12(m12 + other.m12) 2040 ._m13(m13) 2041 ._m20(m20 + other.m20) 2042 ._m21(m21 + other.m21) 2043 ._m22(m22 + other.m22) 2044 ._m23(m23) 2045 ._m30(m30 + other.m30) 2046 ._m31(m31 + other.m31) 2047 ._m32(m32 + other.m32) 2048 ._m33(m33) 2049 ._properties(0); 2050 return dest; 2051 } 2052 2053 /** 2054 * Component-wise subtract the upper 4x3 submatrices of <code>subtrahend</code> from <code>this</code>. 2055 * 2056 * @param subtrahend 2057 * the subtrahend 2058 * @return this 2059 */ 2060 ref public Matrix4d sub4x3(Matrix4d subtrahend) return { 2061 sub4x3(subtrahend, this); 2062 return this; 2063 } 2064 2065 public Matrix4d sub4x3(Matrix4d subtrahend, ref Matrix4d dest) { 2066 dest._m00(m00 - subtrahend.m00) 2067 ._m01(m01 - subtrahend.m01) 2068 ._m02(m02 - subtrahend.m02) 2069 ._m03(m03) 2070 ._m10(m10 - subtrahend.m10) 2071 ._m11(m11 - subtrahend.m11) 2072 ._m12(m12 - subtrahend.m12) 2073 ._m13(m13) 2074 ._m20(m20 - subtrahend.m20) 2075 ._m21(m21 - subtrahend.m21) 2076 ._m22(m22 - subtrahend.m22) 2077 ._m23(m23) 2078 ._m30(m30 - subtrahend.m30) 2079 ._m31(m31 - subtrahend.m31) 2080 ._m32(m32 - subtrahend.m32) 2081 ._m33(m33) 2082 ._properties(0); 2083 return dest; 2084 } 2085 2086 /** 2087 * Component-wise multiply the upper 4x3 submatrices of <code>this</code> by <code>other</code>. 2088 * 2089 * @param other 2090 * the other matrix 2091 * @return this 2092 */ 2093 ref public Matrix4d mul4x3ComponentWise(Matrix4d other) return { 2094 mul4x3ComponentWise(other, this); 2095 return this; 2096 } 2097 2098 public Matrix4d mul4x3ComponentWise(Matrix4d other, ref Matrix4d dest) { 2099 dest._m00(m00 * other.m00) 2100 ._m01(m01 * other.m01) 2101 ._m02(m02 * other.m02) 2102 ._m03(m03) 2103 ._m10(m10 * other.m10) 2104 ._m11(m11 * other.m11) 2105 ._m12(m12 * other.m12) 2106 ._m13(m13) 2107 ._m20(m20 * other.m20) 2108 ._m21(m21 * other.m21) 2109 ._m22(m22 * other.m22) 2110 ._m23(m23) 2111 ._m30(m30 * other.m30) 2112 ._m31(m31 * other.m31) 2113 ._m32(m32 * other.m32) 2114 ._m33(m33) 2115 ._properties(0); 2116 return dest; 2117 } 2118 2119 /** Set the values within this matrix to the supplied double values. The matrix will look like this:<br><br> 2120 * 2121 * m00, m10, m20, m30<br> 2122 * m01, m11, m21, m31<br> 2123 * m02, m12, m22, m32<br> 2124 * m03, m13, m23, m33 2125 * 2126 * @param m00 2127 * the new value of m00 2128 * @param m01 2129 * the new value of m01 2130 * @param m02 2131 * the new value of m02 2132 * @param m03 2133 * the new value of m03 2134 * @param m10 2135 * the new value of m10 2136 * @param m11 2137 * the new value of m11 2138 * @param m12 2139 * the new value of m12 2140 * @param m13 2141 * the new value of m13 2142 * @param m20 2143 * the new value of m20 2144 * @param m21 2145 * the new value of m21 2146 * @param m22 2147 * the new value of m22 2148 * @param m23 2149 * the new value of m23 2150 * @param m30 2151 * the new value of m30 2152 * @param m31 2153 * the new value of m31 2154 * @param m32 2155 * the new value of m32 2156 * @param m33 2157 * the new value of m33 2158 * @return this 2159 */ 2160 ref public Matrix4d set(double m00, double m01, double m02,double m03, 2161 double m10, double m11, double m12, double m13, 2162 double m20, double m21, double m22, double m23, 2163 double m30, double m31, double m32, double m33) return { 2164 setm00(m00); 2165 setm10(m10); 2166 setm20(m20); 2167 setm30(m30); 2168 setm01(m01); 2169 setm11(m11); 2170 setm21(m21); 2171 setm31(m31); 2172 setm02(m02); 2173 setm12(m12); 2174 setm22(m22); 2175 setm32(m32); 2176 setm03(m03); 2177 setm13(m13); 2178 setm23(m23); 2179 setm33(m33); 2180 return determineProperties(); 2181 } 2182 2183 /** 2184 * Set the values in the matrix using a double array that contains the matrix elements in column-major order. 2185 * <p> 2186 * The results will look like this:<br><br> 2187 * 2188 * 0, 4, 8, 12<br> 2189 * 1, 5, 9, 13<br> 2190 * 2, 6, 10, 14<br> 2191 * 3, 7, 11, 15<br> 2192 * 2193 * @see #set(double[]) 2194 * 2195 * @param m 2196 * the array to read the matrix values from 2197 * @param off 2198 * the offset into the array 2199 * @return this 2200 */ 2201 ref public Matrix4d set(double[] m, int off) return { 2202 return 2203 _m00(m[off+0]). 2204 _m01(m[off+1]). 2205 _m02(m[off+2]). 2206 _m03(m[off+3]). 2207 _m10(m[off+4]). 2208 _m11(m[off+5]). 2209 _m12(m[off+6]). 2210 _m13(m[off+7]). 2211 _m20(m[off+8]). 2212 _m21(m[off+9]). 2213 _m22(m[off+10]). 2214 _m23(m[off+11]). 2215 _m30(m[off+12]). 2216 _m31(m[off+13]). 2217 _m32(m[off+14]). 2218 _m33(m[off+15]). 2219 determineProperties(); 2220 } 2221 2222 /** 2223 * Set the values in the matrix using a double array that contains the matrix elements in column-major order. 2224 * <p> 2225 * The results will look like this:<br><br> 2226 * 2227 * 0, 4, 8, 12<br> 2228 * 1, 5, 9, 13<br> 2229 * 2, 6, 10, 14<br> 2230 * 3, 7, 11, 15<br> 2231 * 2232 * @see #set(double[], int) 2233 * 2234 * @param m 2235 * the array to read the matrix values from 2236 * @return this 2237 */ 2238 ref public Matrix4d set(double[] m) return { 2239 return set(m, 0); 2240 } 2241 2242 /** 2243 * Set the values in the matrix using a float array that contains the matrix elements in column-major order. 2244 * <p> 2245 * The results will look like this:<br><br> 2246 * 2247 * 0, 4, 8, 12<br> 2248 * 1, 5, 9, 13<br> 2249 * 2, 6, 10, 14<br> 2250 * 3, 7, 11, 15<br> 2251 * 2252 * @see #set(float[]) 2253 * 2254 * @param m 2255 * the array to read the matrix values from 2256 * @param off 2257 * the offset into the array 2258 * @return this 2259 */ 2260 ref public Matrix4d set(float[] m, int off) return { 2261 return 2262 _m00(m[off+0]). 2263 _m01(m[off+1]). 2264 _m02(m[off+2]). 2265 _m03(m[off+3]). 2266 _m10(m[off+4]). 2267 _m11(m[off+5]). 2268 _m12(m[off+6]). 2269 _m13(m[off+7]). 2270 _m20(m[off+8]). 2271 _m21(m[off+9]). 2272 _m22(m[off+10]). 2273 _m23(m[off+11]). 2274 _m30(m[off+12]). 2275 _m31(m[off+13]). 2276 _m32(m[off+14]). 2277 _m33(m[off+15]). 2278 determineProperties(); 2279 } 2280 2281 /** 2282 * Set the values in the matrix using a float array that contains the matrix elements in column-major order. 2283 * <p> 2284 * The results will look like this:<br><br> 2285 * 2286 * 0, 4, 8, 12<br> 2287 * 1, 5, 9, 13<br> 2288 * 2, 6, 10, 14<br> 2289 * 3, 7, 11, 15<br> 2290 * 2291 * @see #set(float[], int) 2292 * 2293 * @param m 2294 * the array to read the matrix values from 2295 * @return this 2296 */ 2297 ref public Matrix4d set(float[] m) return { 2298 return set(m, 0); 2299 } 2300 2301 2302 /** 2303 * Set the four columns of this matrix to the supplied vectors, respectively. 2304 * 2305 * @param col0 2306 * the first column 2307 * @param col1 2308 * the second column 2309 * @param col2 2310 * the third column 2311 * @param col3 2312 * the fourth column 2313 * @return this 2314 */ 2315 ref public Matrix4d set(ref Vector4d col0, Vector4d col1, Vector4d col2, Vector4d col3) return { 2316 return 2317 _m00(col0.x). 2318 _m01(col0.y). 2319 _m02(col0.z). 2320 _m03(col0.w). 2321 _m10(col1.x). 2322 _m11(col1.y). 2323 _m12(col1.z). 2324 _m13(col1.w). 2325 _m20(col2.x). 2326 _m21(col2.y). 2327 _m22(col2.z). 2328 _m23(col2.w). 2329 _m30(col3.x). 2330 _m31(col3.y). 2331 _m32(col3.z). 2332 _m33(col3.w). 2333 determineProperties(); 2334 } 2335 2336 public double determinant() { 2337 if ((properties & PROPERTY_AFFINE) != 0) 2338 return determinantAffine(); 2339 return (m00 * m11 - m01 * m10) * (m22 * m33 - m23 * m32) 2340 + (m02 * m10 - m00 * m12) * (m21 * m33 - m23 * m31) 2341 + (m00 * m13 - m03 * m10) * (m21 * m32 - m22 * m31) 2342 + (m01 * m12 - m02 * m11) * (m20 * m33 - m23 * m30) 2343 + (m03 * m11 - m01 * m13) * (m20 * m32 - m22 * m30) 2344 + (m02 * m13 - m03 * m12) * (m20 * m31 - m21 * m30); 2345 } 2346 2347 public double determinant3x3() { 2348 return (m00 * m11 - m01 * m10) * m22 2349 + (m02 * m10 - m00 * m12) * m21 2350 + (m01 * m12 - m02 * m11) * m20; 2351 } 2352 2353 public double determinantAffine() { 2354 return (m00 * m11 - m01 * m10) * m22 2355 + (m02 * m10 - m00 * m12) * m21 2356 + (m01 * m12 - m02 * m11) * m20; 2357 } 2358 2359 /** 2360 * Invert this matrix. 2361 * <p> 2362 * If <code>this</code> matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing, 2363 * and thus its last row is equal to <code>(0, 0, 0, 1)</code>, then {@link #invertAffine()} can be used instead of this method. 2364 * 2365 * @see #invertAffine() 2366 * 2367 * @return this 2368 */ 2369 ref public Matrix4d invert() return { 2370 invert(this); 2371 return this; 2372 } 2373 2374 public Matrix4d invert(ref Matrix4d dest) { 2375 if ((properties & PROPERTY_IDENTITY) != 0) 2376 return dest.identity(); 2377 else if ((properties & PROPERTY_TRANSLATION) != 0) 2378 return invertTranslation(dest); 2379 else if ((properties & PROPERTY_ORTHONORMAL) != 0) 2380 return invertOrthonormal(dest); 2381 else if ((properties & PROPERTY_AFFINE) != 0) 2382 return invertAffine(dest); 2383 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 2384 return invertPerspective(dest); 2385 return invertGeneric(dest); 2386 } 2387 private Matrix4d invertTranslation(ref Matrix4d dest) { 2388 if (dest != this) 2389 dest.set(this); 2390 dest._m30(-m30) 2391 ._m31(-m31) 2392 ._m32(-m32) 2393 ._properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL); 2394 return dest; 2395 } 2396 private Matrix4d invertOrthonormal(ref Matrix4d dest) { 2397 double nm30 = -(m00 * m30 + m01 * m31 + m02 * m32); 2398 double nm31 = -(m10 * m30 + m11 * m31 + m12 * m32); 2399 double nm32 = -(m20 * m30 + m21 * m31 + m22 * m32); 2400 double m01 = this.m01; 2401 double m02 = this.m02; 2402 double m12 = this.m12; 2403 dest._m00(m00) 2404 ._m01(m10) 2405 ._m02(m20) 2406 ._m03(0.0) 2407 ._m10(m01) 2408 ._m11(m11) 2409 ._m12(m21) 2410 ._m13(0.0) 2411 ._m20(m02) 2412 ._m21(m12) 2413 ._m22(m22) 2414 ._m23(0.0) 2415 ._m30(nm30) 2416 ._m31(nm31) 2417 ._m32(nm32) 2418 ._m33(1.0) 2419 ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 2420 return dest; 2421 } 2422 private Matrix4d invertGeneric(ref Matrix4d dest) { 2423 if (this != dest) 2424 return invertGenericNonThis(dest); 2425 return invertGenericThis(dest); 2426 } 2427 private Matrix4d invertGenericNonThis(ref Matrix4d dest) { 2428 double a = m00 * m11 - m01 * m10; 2429 double b = m00 * m12 - m02 * m10; 2430 double c = m00 * m13 - m03 * m10; 2431 double d = m01 * m12 - m02 * m11; 2432 double e = m01 * m13 - m03 * m11; 2433 double f = m02 * m13 - m03 * m12; 2434 double g = m20 * m31 - m21 * m30; 2435 double h = m20 * m32 - m22 * m30; 2436 double i = m20 * m33 - m23 * m30; 2437 double j = m21 * m32 - m22 * m31; 2438 double k = m21 * m33 - m23 * m31; 2439 double l = m22 * m33 - m23 * m32; 2440 double det = a * l - b * k + c * j + d * i - e * h + f * g; 2441 det = 1.0 / det; 2442 return dest 2443 ._m00(Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det) 2444 ._m01(Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det) 2445 ._m02(Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det) 2446 ._m03(Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det) 2447 ._m10(Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det) 2448 ._m11(Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det) 2449 ._m12(Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det) 2450 ._m13(Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det) 2451 ._m20(Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det) 2452 ._m21(Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det) 2453 ._m22(Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det) 2454 ._m23(Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det) 2455 ._m30(Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det) 2456 ._m31(Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det) 2457 ._m32(Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det) 2458 ._m33(Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det) 2459 ._properties(0); 2460 } 2461 private Matrix4d invertGenericThis(ref Matrix4d dest) { 2462 double a = m00 * m11 - m01 * m10; 2463 double b = m00 * m12 - m02 * m10; 2464 double c = m00 * m13 - m03 * m10; 2465 double d = m01 * m12 - m02 * m11; 2466 double e = m01 * m13 - m03 * m11; 2467 double f = m02 * m13 - m03 * m12; 2468 double g = m20 * m31 - m21 * m30; 2469 double h = m20 * m32 - m22 * m30; 2470 double i = m20 * m33 - m23 * m30; 2471 double j = m21 * m32 - m22 * m31; 2472 double k = m21 * m33 - m23 * m31; 2473 double l = m22 * m33 - m23 * m32; 2474 double det = a * l - b * k + c * j + d * i - e * h + f * g; 2475 det = 1.0 / det; 2476 double nm00 = Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det; 2477 double nm01 = Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det; 2478 double nm02 = Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det; 2479 double nm03 = Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det; 2480 double nm10 = Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det; 2481 double nm11 = Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det; 2482 double nm12 = Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det; 2483 double nm13 = Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det; 2484 double nm20 = Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det; 2485 double nm21 = Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det; 2486 double nm22 = Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det; 2487 double nm23 = Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det; 2488 double nm30 = Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det; 2489 double nm31 = Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det; 2490 double nm32 = Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det; 2491 double nm33 = Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det; 2492 return dest 2493 ._m00(nm00) 2494 ._m01(nm01) 2495 ._m02(nm02) 2496 ._m03(nm03) 2497 ._m10(nm10) 2498 ._m11(nm11) 2499 ._m12(nm12) 2500 ._m13(nm13) 2501 ._m20(nm20) 2502 ._m21(nm21) 2503 ._m22(nm22) 2504 ._m23(nm23) 2505 ._m30(nm30) 2506 ._m31(nm31) 2507 ._m32(nm32) 2508 ._m33(nm33) 2509 ._properties(0); 2510 } 2511 2512 public Matrix4d invertPerspective(ref Matrix4d dest) { 2513 double a = 1.0 / (m00 * m11); 2514 double l = -1.0 / (m23 * m32); 2515 dest.set(m11 * a, 0, 0, 0, 2516 0, m00 * a, 0, 0, 2517 0, 0, 0, -m23 * l, 2518 0, 0, -m32 * l, m22 * l); 2519 return dest; 2520 } 2521 2522 /** 2523 * If <code>this</code> is a perspective projection matrix obtained via one of the {@link #perspective(double, double, double, double) perspective()} methods 2524 * or via {@link #setPerspective(double, double, double, double) setPerspective()}, that is, if <code>this</code> is a symmetrical perspective frustum transformation, 2525 * then this method builds the inverse of <code>this</code>. 2526 * <p> 2527 * This method can be used to quickly obtain the inverse of a perspective projection matrix when being obtained via {@link #perspective(double, double, double, double) perspective()}. 2528 * 2529 * @see #perspective(double, double, double, double) 2530 * 2531 * @return this 2532 */ 2533 ref public Matrix4d invertPerspective() return { 2534 invertPerspective(this); 2535 return this; 2536 } 2537 2538 public Matrix4d invertFrustum(ref Matrix4d dest) { 2539 double invM00 = 1.0 / m00; 2540 double invM11 = 1.0 / m11; 2541 double invM23 = 1.0 / m23; 2542 double invM32 = 1.0 / m32; 2543 dest.set(invM00, 0, 0, 0, 2544 0, invM11, 0, 0, 2545 0, 0, 0, invM32, 2546 -m20 * invM00 * invM23, -m21 * invM11 * invM23, invM23, -m22 * invM23 * invM32); 2547 return dest; 2548 } 2549 2550 /** 2551 * If <code>this</code> is an arbitrary perspective projection matrix obtained via one of the {@link #frustum(double, double, double, double, double, double) frustum()} methods 2552 * or via {@link #setFrustum(double, double, double, double, double, double) setFrustum()}, 2553 * then this method builds the inverse of <code>this</code>. 2554 * <p> 2555 * This method can be used to quickly obtain the inverse of a perspective projection matrix. 2556 * <p> 2557 * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(double, double, double, double) perspective()}, then 2558 * {@link #invertPerspective()} should be used instead. 2559 * 2560 * @see #frustum(double, double, double, double, double, double) 2561 * @see #invertPerspective() 2562 * 2563 * @return this 2564 */ 2565 ref public Matrix4d invertFrustum() return { 2566 invertFrustum(this); 2567 return this; 2568 } 2569 2570 public Matrix4d invertOrtho(ref Matrix4d dest) { 2571 double invM00 = 1.0 / m00; 2572 double invM11 = 1.0 / m11; 2573 double invM22 = 1.0 / m22; 2574 dest.set(invM00, 0, 0, 0, 2575 0, invM11, 0, 0, 2576 0, 0, invM22, 0, 2577 -m30 * invM00, -m31 * invM11, -m32 * invM22, 1) 2578 ._properties(PROPERTY_AFFINE | (this.properties & PROPERTY_ORTHONORMAL)); 2579 return dest; 2580 } 2581 2582 /** 2583 * Invert <code>this</code> orthographic projection matrix. 2584 * <p> 2585 * This method can be used to quickly obtain the inverse of an orthographic projection matrix. 2586 * 2587 * @return this 2588 */ 2589 ref public Matrix4d invertOrtho() return { 2590 invertOrtho(this); 2591 return this; 2592 } 2593 2594 public Matrix4d invertPerspectiveView(Matrix4d view, ref Matrix4d dest) { 2595 double a = 1.0 / (m00 * m11); 2596 double l = -1.0 / (m23 * m32); 2597 double pm00 = m11 * a; 2598 double pm11 = m00 * a; 2599 double pm23 = -m23 * l; 2600 double pm32 = -m32 * l; 2601 double pm33 = m22 * l; 2602 double vm30 = -view.m00 * view.m30 - view.m01 * view.m31 - view.m02 * view.m32; 2603 double vm31 = -view.m10 * view.m30 - view.m11 * view.m31 - view.m12 * view.m32; 2604 double vm32 = -view.m20 * view.m30 - view.m21 * view.m31 - view.m22 * view.m32; 2605 double nm10 = view.m01 * pm11; 2606 double nm30 = view.m02 * pm32 + vm30 * pm33; 2607 double nm31 = view.m12 * pm32 + vm31 * pm33; 2608 double nm32 = view.m22 * pm32 + vm32 * pm33; 2609 return dest 2610 ._m00(view.m00 * pm00) 2611 ._m01(view.m10 * pm00) 2612 ._m02(view.m20 * pm00) 2613 ._m03(0.0) 2614 ._m10(nm10) 2615 ._m11(view.m11 * pm11) 2616 ._m12(view.m21 * pm11) 2617 ._m13(0.0) 2618 ._m20(vm30 * pm23) 2619 ._m21(vm31 * pm23) 2620 ._m22(vm32 * pm23) 2621 ._m23(pm23) 2622 ._m30(nm30) 2623 ._m31(nm31) 2624 ._m32(nm32) 2625 ._m33(pm33) 2626 ._properties(0); 2627 } 2628 2629 public Matrix4d invertPerspectiveView(Matrix4x3d view, ref Matrix4d dest) { 2630 double a = 1.0 / (m00 * m11); 2631 double l = -1.0 / (m23 * m32); 2632 double pm00 = m11 * a; 2633 double pm11 = m00 * a; 2634 double pm23 = -m23 * l; 2635 double pm32 = -m32 * l; 2636 double pm33 = m22 * l; 2637 double vm30 = -view.m00 * view.m30 - view.m01 * view.m31 - view.m02 * view.m32; 2638 double vm31 = -view.m10 * view.m30 - view.m11 * view.m31 - view.m12 * view.m32; 2639 double vm32 = -view.m20 * view.m30 - view.m21 * view.m31 - view.m22 * view.m32; 2640 return dest 2641 ._m00(view.m00 * pm00) 2642 ._m01(view.m10 * pm00) 2643 ._m02(view.m20 * pm00) 2644 ._m03(0.0) 2645 ._m10(view.m01 * pm11) 2646 ._m11(view.m11 * pm11) 2647 ._m12(view.m21 * pm11) 2648 ._m13(0.0) 2649 ._m20(vm30 * pm23) 2650 ._m21(vm31 * pm23) 2651 ._m22(vm32 * pm23) 2652 ._m23(pm23) 2653 ._m30(view.m02 * pm32 + vm30 * pm33) 2654 ._m31(view.m12 * pm32 + vm31 * pm33) 2655 ._m32(view.m22 * pm32 + vm32 * pm33) 2656 ._m33(pm33) 2657 ._properties(0); 2658 } 2659 2660 public Matrix4d invertAffine(ref Matrix4d dest) { 2661 double m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10; 2662 double m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11; 2663 double s = 1.0 / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20); 2664 double m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22; 2665 double m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20; 2666 double m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02; 2667 double m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00; 2668 double nm00 = (m11m22 - m12m21) * s; 2669 double nm01 = (m21m02 - m22m01) * s; 2670 double nm02 = (m12m01 - m11m02) * s; 2671 double nm10 = (m12m20 - m10m22) * s; 2672 double nm11 = (m22m00 - m20m02) * s; 2673 double nm12 = (m10m02 - m12m00) * s; 2674 double nm20 = (m10m21 - m11m20) * s; 2675 double nm21 = (m20m01 - m21m00) * s; 2676 double nm22 = (m11m00 - m10m01) * s; 2677 double nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s; 2678 double nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s; 2679 double nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s; 2680 dest._m00(nm00) 2681 ._m01(nm01) 2682 ._m02(nm02) 2683 ._m03(0.0) 2684 ._m10(nm10) 2685 ._m11(nm11) 2686 ._m12(nm12) 2687 ._m13(0.0) 2688 ._m20(nm20) 2689 ._m21(nm21) 2690 ._m22(nm22) 2691 ._m23(0.0) 2692 ._m30(nm30) 2693 ._m31(nm31) 2694 ._m32(nm32) 2695 ._m33(1.0) 2696 ._properties(PROPERTY_AFFINE); 2697 return dest; 2698 } 2699 2700 /** 2701 * Invert this matrix by assuming that it is an {@link #isAffine() affine} transformation (i.e. its last row is equal to <code>(0, 0, 0, 1)</code>). 2702 * 2703 * @return this 2704 */ 2705 ref public Matrix4d invertAffine() return { 2706 invertAffine(this); 2707 return this; 2708 } 2709 2710 /** 2711 * Transpose this matrix. 2712 * 2713 * @return this 2714 */ 2715 ref public Matrix4d transpose() return { 2716 transpose(this); 2717 return this; 2718 } 2719 2720 public Matrix4d transpose(ref Matrix4d dest) { 2721 if ((properties & PROPERTY_IDENTITY) != 0) 2722 return dest.identity(); 2723 else if (this != dest) 2724 return transposeNonThisGeneric(dest); 2725 return transposeThisGeneric(dest); 2726 } 2727 private Matrix4d transposeNonThisGeneric(ref Matrix4d dest) { 2728 return dest 2729 ._m00(m00) 2730 ._m01(m10) 2731 ._m02(m20) 2732 ._m03(m30) 2733 ._m10(m01) 2734 ._m11(m11) 2735 ._m12(m21) 2736 ._m13(m31) 2737 ._m20(m02) 2738 ._m21(m12) 2739 ._m22(m22) 2740 ._m23(m32) 2741 ._m30(m03) 2742 ._m31(m13) 2743 ._m32(m23) 2744 ._m33(m33) 2745 ._properties(0); 2746 } 2747 private Matrix4d transposeThisGeneric(ref Matrix4d dest) { 2748 double nm10 = m01; 2749 double nm20 = m02; 2750 double nm21 = m12; 2751 double nm30 = m03; 2752 double nm31 = m13; 2753 double nm32 = m23; 2754 return dest 2755 ._m01(m10) 2756 ._m02(m20) 2757 ._m03(m30) 2758 ._m10(nm10) 2759 ._m12(m21) 2760 ._m13(m31) 2761 ._m20(nm20) 2762 ._m21(nm21) 2763 ._m23(m32) 2764 ._m30(nm30) 2765 ._m31(nm31) 2766 ._m32(nm32) 2767 ._properties(0); 2768 } 2769 2770 /** 2771 * Transpose only the upper left 3x3 submatrix of this matrix. 2772 * <p> 2773 * All other matrix elements are left unchanged. 2774 * 2775 * @return this 2776 */ 2777 ref public Matrix4d transpose3x3() return { 2778 transpose3x3(this); 2779 return this; 2780 } 2781 2782 public Matrix4d transpose3x3(ref Matrix4d dest) { 2783 double nm10 = m01, nm20 = m02, nm21 = m12; 2784 return dest 2785 ._m00(m00) 2786 ._m01(m10) 2787 ._m02(m20) 2788 ._m10(nm10) 2789 ._m11(m11) 2790 ._m12(m21) 2791 ._m20(nm20) 2792 ._m21(nm21) 2793 ._m22(m22) 2794 ._properties(this.properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 2795 } 2796 2797 public Matrix3d transpose3x3(ref Matrix3d dest) { 2798 return dest 2799 ._m00(m00) 2800 ._m01(m10) 2801 ._m02(m20) 2802 ._m10(m01) 2803 ._m11(m11) 2804 ._m12(m21) 2805 ._m20(m02) 2806 ._m21(m12) 2807 ._m22(m22); 2808 } 2809 2810 /** 2811 * Set this matrix to be a simple translation matrix. 2812 * <p> 2813 * The resulting matrix can be multiplied against another transformation 2814 * matrix to obtain an additional translation. 2815 * 2816 * @param x 2817 * the offset to translate in x 2818 * @param y 2819 * the offset to translate in y 2820 * @param z 2821 * the offset to translate in z 2822 * @return this 2823 */ 2824 ref public Matrix4d translation(double x, double y, double z) return { 2825 if ((properties & PROPERTY_IDENTITY) == 0) 2826 this._identity(); 2827 return this. 2828 _m30(x). 2829 _m31(y). 2830 _m32(z). 2831 _m33(1.0). 2832 _properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL); 2833 } 2834 2835 2836 /** 2837 * Set this matrix to be a simple translation matrix. 2838 * <p> 2839 * The resulting matrix can be multiplied against another transformation 2840 * matrix to obtain an additional translation. 2841 * 2842 * @param offset 2843 * the offsets in x, y and z to translate 2844 * @return this 2845 */ 2846 ref public Matrix4d translation(ref Vector3d offset) return { 2847 return translation(offset.x, offset.y, offset.z); 2848 } 2849 2850 /** 2851 * Set only the translation components <code>(m30, m31, m32)</code> of this matrix to the given values <code>(x, y, z)</code>. 2852 * <p> 2853 * To build a translation matrix instead, use {@link #translation(double, double, double)}. 2854 * To apply a translation, use {@link #translate(double, double, double)}. 2855 * 2856 * @see #translation(double, double, double) 2857 * @see #translate(double, double, double) 2858 * 2859 * @param x 2860 * the units to translate in x 2861 * @param y 2862 * the units to translate in y 2863 * @param z 2864 * the units to translate in z 2865 * @return this 2866 */ 2867 ref public Matrix4d setTranslation(double x, double y, double z) return { 2868 _m30(x). 2869 _m31(y). 2870 _m32(z). 2871 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY); 2872 return this; 2873 } 2874 2875 /** 2876 * Set only the translation components <code>(m30, m31, m32)</code> of this matrix to the given values <code>(xyz.x, xyz.y, xyz.z)</code>. 2877 * <p> 2878 * To build a translation matrix instead, use {@link #translation(ref Vector3d)}. 2879 * To apply a translation, use {@link #translate(ref Vector3d)}. 2880 * 2881 * @see #translation(ref Vector3d) 2882 * @see #translate(ref Vector3d) 2883 * 2884 * @param xyz 2885 * the units to translate in <code>(x, y, z)</code> 2886 * @return this 2887 */ 2888 ref public Matrix4d setTranslation(ref Vector3d xyz) return { 2889 return setTranslation(xyz.x, xyz.y, xyz.z); 2890 } 2891 2892 public Vector3d getTranslation(ref Vector3d dest) { 2893 dest.x = m30; 2894 dest.y = m31; 2895 dest.z = m32; 2896 return dest; 2897 } 2898 2899 public Vector3d getScale(ref Vector3d dest) { 2900 dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02); 2901 dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12); 2902 dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22); 2903 return dest; 2904 } 2905 2906 public Matrix4d get(ref Matrix4d dest) { 2907 return dest.set(this); 2908 } 2909 2910 public Matrix4x3d get4x3(ref Matrix4x3d dest) { 2911 return dest.set(this); 2912 } 2913 2914 public Matrix3d get3x3(ref Matrix3d dest) { 2915 return dest.set(this); 2916 } 2917 2918 public Quaterniond getUnnormalizedRotation(ref Quaterniond dest) { 2919 return dest.setFromUnnormalized(this); 2920 } 2921 2922 public Quaterniond getNormalizedRotation(ref Quaterniond dest) { 2923 return dest.setFromNormalized(this); 2924 } 2925 2926 // Additional functionality for D (becomes a FloatBuffer) 2927 public float[16] getFloatArray() { 2928 float[16] dest; 2929 dest[0] = cast(float)m00; 2930 dest[1] = cast(float)m01; 2931 dest[2] = cast(float)m02; 2932 dest[3] = cast(float)m03; 2933 dest[4] = cast(float)m10; 2934 dest[5] = cast(float)m11; 2935 dest[6] = cast(float)m12; 2936 dest[7] = cast(float)m13; 2937 dest[8] = cast(float)m20; 2938 dest[9] = cast(float)m21; 2939 dest[10] = cast(float)m22; 2940 dest[11] = cast(float)m23; 2941 dest[12] = cast(float)m30; 2942 dest[13] = cast(float)m31; 2943 dest[14] = cast(float)m32; 2944 dest[15] = cast(float)m33; 2945 return dest; 2946 } 2947 2948 // Additional functionality for D (becomes a FloatBuffer) 2949 public float[16] getFloatArray(ref float[16] dest, int offset) { 2950 dest[offset+0] = cast(float)m00; 2951 dest[offset+1] = cast(float)m01; 2952 dest[offset+2] = cast(float)m02; 2953 dest[offset+3] = cast(float)m03; 2954 dest[offset+4] = cast(float)m10; 2955 dest[offset+5] = cast(float)m11; 2956 dest[offset+6] = cast(float)m12; 2957 dest[offset+7] = cast(float)m13; 2958 dest[offset+8] = cast(float)m20; 2959 dest[offset+9] = cast(float)m21; 2960 dest[offset+10] = cast(float)m22; 2961 dest[offset+11] = cast(float)m23; 2962 dest[offset+12] = cast(float)m30; 2963 dest[offset+13] = cast(float)m31; 2964 dest[offset+14] = cast(float)m32; 2965 dest[offset+15] = cast(float)m33; 2966 return dest; 2967 } 2968 2969 public double[] get(ref double[] dest, int offset) { 2970 dest[offset+0] = m00; 2971 dest[offset+1] = m01; 2972 dest[offset+2] = m02; 2973 dest[offset+3] = m03; 2974 dest[offset+4] = m10; 2975 dest[offset+5] = m11; 2976 dest[offset+6] = m12; 2977 dest[offset+7] = m13; 2978 dest[offset+8] = m20; 2979 dest[offset+9] = m21; 2980 dest[offset+10] = m22; 2981 dest[offset+11] = m23; 2982 dest[offset+12] = m30; 2983 dest[offset+13] = m31; 2984 dest[offset+14] = m32; 2985 dest[offset+15] = m33; 2986 return dest; 2987 } 2988 2989 public double[] get(ref double[] dest) { 2990 return get(dest, 0); 2991 } 2992 2993 /** 2994 * Set all the values within this matrix to 0. 2995 * 2996 * @return this 2997 */ 2998 ref public Matrix4d zero() return { 2999 return 3000 _m00(0.0). 3001 _m01(0.0). 3002 _m02(0.0). 3003 _m03(0.0). 3004 _m10(0.0). 3005 _m11(0.0). 3006 _m12(0.0). 3007 _m13(0.0). 3008 _m20(0.0). 3009 _m21(0.0). 3010 _m22(0.0). 3011 _m23(0.0). 3012 _m30(0.0). 3013 _m31(0.0). 3014 _m32(0.0). 3015 _m33(0.0). 3016 _properties(0); 3017 } 3018 3019 /** 3020 * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor. 3021 * <p> 3022 * The resulting matrix can be multiplied against another transformation 3023 * matrix to obtain an additional scaling. 3024 * <p> 3025 * In order to post-multiply a scaling transformation directly to a 3026 * matrix, use {@link #scale(double) scale()} instead. 3027 * 3028 * @see #scale(double) 3029 * 3030 * @param factor 3031 * the scale factor in x, y and z 3032 * @return this 3033 */ 3034 ref public Matrix4d scaling(double factor) return { 3035 return scaling(factor, factor, factor); 3036 } 3037 3038 /** 3039 * Set this matrix to be a simple scale matrix. 3040 * 3041 * @param x 3042 * the scale in x 3043 * @param y 3044 * the scale in y 3045 * @param z 3046 * the scale in z 3047 * @return this 3048 */ 3049 ref public Matrix4d scaling(double x, double y, double z) return { 3050 if ((properties & PROPERTY_IDENTITY) == 0) 3051 identity(); 3052 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3053 _m00(x). 3054 _m11(y). 3055 _m22(z). 3056 properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0); 3057 return this; 3058 } 3059 3060 /** 3061 * Set this matrix to be a simple scale matrix which scales the base axes by 3062 * <code>xyz.x</code>, <code>xyz.y</code> and <code>xyz.z</code>, respectively. 3063 * <p> 3064 * The resulting matrix can be multiplied against another transformation 3065 * matrix to obtain an additional scaling. 3066 * <p> 3067 * In order to post-multiply a scaling transformation directly to a 3068 * matrix use {@link #scale(ref Vector3d) scale()} instead. 3069 * 3070 * @see #scale(ref Vector3d) 3071 * 3072 * @param xyz 3073 * the scale in x, y and z, respectively 3074 * @return this 3075 */ 3076 ref public Matrix4d scaling(ref Vector3d xyz) return { 3077 return scaling(xyz.x, xyz.y, xyz.z); 3078 } 3079 3080 /** 3081 * Set this matrix to a rotation matrix which rotates the given radians about a given axis. 3082 * <p> 3083 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3084 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3085 * When used with a left-handed coordinate system, the rotation is clockwise. 3086 * <p> 3087 * From <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">Wikipedia</a> 3088 * 3089 * @param angle 3090 * the angle in radians 3091 * @param x 3092 * the x-coordinate of the axis to rotate about 3093 * @param y 3094 * the y-coordinate of the axis to rotate about 3095 * @param z 3096 * the z-coordinate of the axis to rotate about 3097 * @return this 3098 */ 3099 ref public Matrix4d rotation(double angle, double x, double y, double z) return { 3100 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 3101 rotationX(x * angle); 3102 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 3103 rotationY(y * angle); 3104 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 3105 rotationZ(z * angle); 3106 else 3107 rotationInternal(angle, x, y, z); 3108 return this; 3109 } 3110 private Matrix4d rotationInternal(double angle, double x, double y, double z) { 3111 double sin = Math.sin(angle); 3112 double cos = Math.cosFromSin(sin, angle); 3113 double C = 1.0 - cos; 3114 double xy = x * y, xz = x * z, yz = y * z; 3115 if ((properties & PROPERTY_IDENTITY) == 0) 3116 this._identity(); 3117 _m00(cos + x * x * C). 3118 _m10(xy * C - z * sin). 3119 _m20(xz * C + y * sin). 3120 _m01(xy * C + z * sin). 3121 _m11(cos + y * y * C). 3122 _m21(yz * C - x * sin). 3123 _m02(xz * C - y * sin). 3124 _m12(yz * C + x * sin). 3125 _m22(cos + z * z * C). 3126 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3127 return this; 3128 } 3129 3130 /** 3131 * Set this matrix to a rotation transformation about the X axis. 3132 * <p> 3133 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3134 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3135 * When used with a left-handed coordinate system, the rotation is clockwise. 3136 * <p> 3137 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3138 * 3139 * @param ang 3140 * the angle in radians 3141 * @return this 3142 */ 3143 ref public Matrix4d rotationX(double ang) return { 3144 double sin, cos; 3145 sin = Math.sin(ang); 3146 cos = Math.cosFromSin(sin, ang); 3147 if ((properties & PROPERTY_IDENTITY) == 0) 3148 this._identity(); 3149 _m11(cos). 3150 _m12(sin). 3151 _m21(-sin). 3152 _m22(cos). 3153 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3154 return this; 3155 } 3156 3157 /** 3158 * Set this matrix to a rotation transformation about the Y axis. 3159 * <p> 3160 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3161 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3162 * When used with a left-handed coordinate system, the rotation is clockwise. 3163 * <p> 3164 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3165 * 3166 * @param ang 3167 * the angle in radians 3168 * @return this 3169 */ 3170 ref public Matrix4d rotationY(double ang) return { 3171 double sin, cos; 3172 sin = Math.sin(ang); 3173 cos = Math.cosFromSin(sin, ang); 3174 if ((properties & PROPERTY_IDENTITY) == 0) 3175 this._identity(); 3176 _m00(cos). 3177 _m02(-sin). 3178 _m20(sin). 3179 _m22(cos). 3180 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3181 return this; 3182 } 3183 3184 /** 3185 * Set this matrix to a rotation transformation about the Z axis. 3186 * <p> 3187 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3188 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3189 * When used with a left-handed coordinate system, the rotation is clockwise. 3190 * <p> 3191 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3192 * 3193 * @param ang 3194 * the angle in radians 3195 * @return this 3196 */ 3197 ref public Matrix4d rotationZ(double ang) return { 3198 double sin, cos; 3199 sin = Math.sin(ang); 3200 cos = Math.cosFromSin(sin, ang); 3201 if ((properties & PROPERTY_IDENTITY) == 0) 3202 this._identity(); 3203 _m00(cos). 3204 _m01(sin). 3205 _m10(-sin). 3206 _m11(cos). 3207 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3208 return this; 3209 } 3210 3211 /** 3212 * Set this matrix to a rotation transformation about the Z axis to align the local <code>+X</code> towards <code>(dirX, dirY)</code>. 3213 * <p> 3214 * The vector <code>(dirX, dirY)</code> must be a unit vector. 3215 * 3216 * @param dirX 3217 * the x component of the normalized direction 3218 * @param dirY 3219 * the y component of the normalized direction 3220 * @return this 3221 */ 3222 ref public Matrix4d rotationTowardsXY(double dirX, double dirY) return { 3223 if ((properties & PROPERTY_IDENTITY) == 0) 3224 this._identity(); 3225 setm00(dirY); 3226 setm01(dirX); 3227 setm10(-dirX); 3228 setm11(dirY); 3229 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3230 return this; 3231 } 3232 3233 /** 3234 * Set this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation 3235 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3236 * <p> 3237 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3238 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3239 * When used with a left-handed coordinate system, the rotation is clockwise. 3240 * <p> 3241 * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 3242 * 3243 * @param angleX 3244 * the angle to rotate about X 3245 * @param angleY 3246 * the angle to rotate about Y 3247 * @param angleZ 3248 * the angle to rotate about Z 3249 * @return this 3250 */ 3251 ref public Matrix4d rotationXYZ(double angleX, double angleY, double angleZ) return { 3252 double sinX = Math.sin(angleX); 3253 double cosX = Math.cosFromSin(sinX, angleX); 3254 double sinY = Math.sin(angleY); 3255 double cosY = Math.cosFromSin(sinY, angleY); 3256 double sinZ = Math.sin(angleZ); 3257 double cosZ = Math.cosFromSin(sinZ, angleZ); 3258 double m_sinX = -sinX; 3259 double m_sinY = -sinY; 3260 double m_sinZ = -sinZ; 3261 if ((properties & PROPERTY_IDENTITY) == 0) 3262 this._identity(); 3263 3264 // rotateX 3265 double nm11 = cosX; 3266 double nm12 = sinX; 3267 double nm21 = m_sinX; 3268 double nm22 = cosX; 3269 // rotateY 3270 double nm00 = cosY; 3271 double nm01 = nm21 * m_sinY; 3272 double nm02 = nm22 * m_sinY; 3273 _m20(sinY). 3274 _m21(nm21 * cosY). 3275 _m22(nm22 * cosY). 3276 // rotateZ 3277 _m00(nm00 * cosZ). 3278 _m01(nm01 * cosZ + nm11 * sinZ). 3279 _m02(nm02 * cosZ + nm12 * sinZ). 3280 _m10(nm00 * m_sinZ). 3281 _m11(nm01 * m_sinZ + nm11 * cosZ). 3282 _m12(nm02 * m_sinZ + nm12 * cosZ). 3283 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3284 return this; 3285 } 3286 3287 /** 3288 * Set this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation 3289 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis. 3290 * <p> 3291 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3292 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3293 * When used with a left-handed coordinate system, the rotation is clockwise. 3294 * <p> 3295 * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 3296 * 3297 * @param angleZ 3298 * the angle to rotate about Z 3299 * @param angleY 3300 * the angle to rotate about Y 3301 * @param angleX 3302 * the angle to rotate about X 3303 * @return this 3304 */ 3305 ref public Matrix4d rotationZYX(double angleZ, double angleY, double angleX) return { 3306 double sinX = Math.sin(angleX); 3307 double cosX = Math.cosFromSin(sinX, angleX); 3308 double sinY = Math.sin(angleY); 3309 double cosY = Math.cosFromSin(sinY, angleY); 3310 double sinZ = Math.sin(angleZ); 3311 double cosZ = Math.cosFromSin(sinZ, angleZ); 3312 double m_sinZ = -sinZ; 3313 double m_sinY = -sinY; 3314 double m_sinX = -sinX; 3315 if ((properties & PROPERTY_IDENTITY) == 0) 3316 this._identity(); 3317 3318 // rotateZ 3319 double nm00 = cosZ; 3320 double nm01 = sinZ; 3321 double nm10 = m_sinZ; 3322 double nm11 = cosZ; 3323 // rotateY 3324 double nm20 = nm00 * sinY; 3325 double nm21 = nm01 * sinY; 3326 double nm22 = cosY; 3327 _m00(nm00 * cosY). 3328 _m01(nm01 * cosY). 3329 _m02(m_sinY). 3330 // rotateX 3331 _m10(nm10 * cosX + nm20 * sinX). 3332 _m11(nm11 * cosX + nm21 * sinX). 3333 _m12(nm22 * sinX). 3334 _m20(nm10 * m_sinX + nm20 * cosX). 3335 _m21(nm11 * m_sinX + nm21 * cosX). 3336 _m22(nm22 * cosX). 3337 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3338 return this; 3339 } 3340 3341 /** 3342 * Set this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation 3343 * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3344 * <p> 3345 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3346 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3347 * When used with a left-handed coordinate system, the rotation is clockwise. 3348 * <p> 3349 * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 3350 * 3351 * @param angleY 3352 * the angle to rotate about Y 3353 * @param angleX 3354 * the angle to rotate about X 3355 * @param angleZ 3356 * the angle to rotate about Z 3357 * @return this 3358 */ 3359 ref public Matrix4d rotationYXZ(double angleY, double angleX, double angleZ) return { 3360 double sinX = Math.sin(angleX); 3361 double cosX = Math.cosFromSin(sinX, angleX); 3362 double sinY = Math.sin(angleY); 3363 double cosY = Math.cosFromSin(sinY, angleY); 3364 double sinZ = Math.sin(angleZ); 3365 double cosZ = Math.cosFromSin(sinZ, angleZ); 3366 double m_sinY = -sinY; 3367 double m_sinX = -sinX; 3368 double m_sinZ = -sinZ; 3369 3370 // rotateY 3371 double nm00 = cosY; 3372 double nm02 = m_sinY; 3373 double nm20 = sinY; 3374 double nm22 = cosY; 3375 // rotateX 3376 double nm10 = nm20 * sinX; 3377 double nm11 = cosX; 3378 double nm12 = nm22 * sinX; 3379 _m20(nm20 * cosX). 3380 _m21(m_sinX). 3381 _m22(nm22 * cosX). 3382 _m23(0.0). 3383 // rotateZ 3384 _m00(nm00 * cosZ + nm10 * sinZ). 3385 _m01(nm11 * sinZ). 3386 _m02(nm02 * cosZ + nm12 * sinZ). 3387 _m03(0.0). 3388 _m10(nm00 * m_sinZ + nm10 * cosZ). 3389 _m11(nm11 * cosZ). 3390 _m12(nm02 * m_sinZ + nm12 * cosZ). 3391 _m13(0.0). 3392 // set last column to identity 3393 _m30(0.0). 3394 _m31(0.0). 3395 _m32(0.0). 3396 _m33(1.0). 3397 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3398 return this; 3399 } 3400 3401 /** 3402 * Set only the upper left 3x3 submatrix of this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation 3403 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3404 * <p> 3405 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3406 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3407 * When used with a left-handed coordinate system, the rotation is clockwise. 3408 * 3409 * @param angleX 3410 * the angle to rotate about X 3411 * @param angleY 3412 * the angle to rotate about Y 3413 * @param angleZ 3414 * the angle to rotate about Z 3415 * @return this 3416 */ 3417 ref public Matrix4d setRotationXYZ(double angleX, double angleY, double angleZ) return { 3418 double sinX = Math.sin(angleX); 3419 double cosX = Math.cosFromSin(sinX, angleX); 3420 double sinY = Math.sin(angleY); 3421 double cosY = Math.cosFromSin(sinY, angleY); 3422 double sinZ = Math.sin(angleZ); 3423 double cosZ = Math.cosFromSin(sinZ, angleZ); 3424 double m_sinX = -sinX; 3425 double m_sinY = -sinY; 3426 double m_sinZ = -sinZ; 3427 3428 // rotateX 3429 double nm11 = cosX; 3430 double nm12 = sinX; 3431 double nm21 = m_sinX; 3432 double nm22 = cosX; 3433 // rotateY 3434 double nm00 = cosY; 3435 double nm01 = nm21 * m_sinY; 3436 double nm02 = nm22 * m_sinY; 3437 _m20(sinY). 3438 _m21(nm21 * cosY). 3439 _m22(nm22 * cosY). 3440 // rotateZ 3441 _m00(nm00 * cosZ). 3442 _m01(nm01 * cosZ + nm11 * sinZ). 3443 _m02(nm02 * cosZ + nm12 * sinZ). 3444 _m10(nm00 * m_sinZ). 3445 _m11(nm01 * m_sinZ + nm11 * cosZ). 3446 _m12(nm02 * m_sinZ + nm12 * cosZ). 3447 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3448 return this; 3449 } 3450 3451 /** 3452 * Set only the upper left 3x3 submatrix of this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation 3453 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis. 3454 * <p> 3455 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3456 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3457 * When used with a left-handed coordinate system, the rotation is clockwise. 3458 * 3459 * @param angleZ 3460 * the angle to rotate about Z 3461 * @param angleY 3462 * the angle to rotate about Y 3463 * @param angleX 3464 * the angle to rotate about X 3465 * @return this 3466 */ 3467 ref public Matrix4d setRotationZYX(double angleZ, double angleY, double angleX) return { 3468 double sinX = Math.sin(angleX); 3469 double cosX = Math.cosFromSin(sinX, angleX); 3470 double sinY = Math.sin(angleY); 3471 double cosY = Math.cosFromSin(sinY, angleY); 3472 double sinZ = Math.sin(angleZ); 3473 double cosZ = Math.cosFromSin(sinZ, angleZ); 3474 double m_sinZ = -sinZ; 3475 double m_sinY = -sinY; 3476 double m_sinX = -sinX; 3477 3478 // rotateZ 3479 double nm00 = cosZ; 3480 double nm01 = sinZ; 3481 double nm10 = m_sinZ; 3482 double nm11 = cosZ; 3483 // rotateY 3484 double nm20 = nm00 * sinY; 3485 double nm21 = nm01 * sinY; 3486 double nm22 = cosY; 3487 _m00(nm00 * cosY). 3488 _m01(nm01 * cosY). 3489 _m02(m_sinY). 3490 // rotateX 3491 _m10(nm10 * cosX + nm20 * sinX). 3492 _m11(nm11 * cosX + nm21 * sinX). 3493 _m12(nm22 * sinX). 3494 _m20(nm10 * m_sinX + nm20 * cosX). 3495 _m21(nm11 * m_sinX + nm21 * cosX). 3496 _m22(nm22 * cosX). 3497 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3498 return this; 3499 } 3500 3501 /** 3502 * Set only the upper left 3x3 submatrix of this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation 3503 * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3504 * <p> 3505 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3506 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3507 * When used with a left-handed coordinate system, the rotation is clockwise. 3508 * 3509 * @param angleY 3510 * the angle to rotate about Y 3511 * @param angleX 3512 * the angle to rotate about X 3513 * @param angleZ 3514 * the angle to rotate about Z 3515 * @return this 3516 */ 3517 ref public Matrix4d setRotationYXZ(double angleY, double angleX, double angleZ) return { 3518 double sinX = Math.sin(angleX); 3519 double cosX = Math.cosFromSin(sinX, angleX); 3520 double sinY = Math.sin(angleY); 3521 double cosY = Math.cosFromSin(sinY, angleY); 3522 double sinZ = Math.sin(angleZ); 3523 double cosZ = Math.cosFromSin(sinZ, angleZ); 3524 double m_sinY = -sinY; 3525 double m_sinX = -sinX; 3526 double m_sinZ = -sinZ; 3527 3528 // rotateY 3529 double nm00 = cosY; 3530 double nm02 = m_sinY; 3531 double nm20 = sinY; 3532 double nm22 = cosY; 3533 // rotateX 3534 double nm10 = nm20 * sinX; 3535 double nm11 = cosX; 3536 double nm12 = nm22 * sinX; 3537 _m20(nm20 * cosX). 3538 _m21(m_sinX). 3539 _m22(nm22 * cosX). 3540 // rotateZ 3541 _m00(nm00 * cosZ + nm10 * sinZ). 3542 _m01(nm11 * sinZ). 3543 _m02(nm02 * cosZ + nm12 * sinZ). 3544 _m10(nm00 * m_sinZ + nm10 * cosZ). 3545 _m11(nm11 * cosZ). 3546 _m12(nm02 * m_sinZ + nm12 * cosZ). 3547 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3548 return this; 3549 } 3550 3551 /** 3552 * Set this matrix to a rotation matrix which rotates the given radians about a given axis. 3553 * <p> 3554 * The axis described by the <code>axis</code> vector needs to be a unit vector. 3555 * <p> 3556 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3557 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3558 * When used with a left-handed coordinate system, the rotation is clockwise. 3559 * 3560 * @param angle 3561 * the angle in radians 3562 * @param axis 3563 * the axis to rotate about 3564 * @return this 3565 */ 3566 ref public Matrix4d rotation(double angle, Vector3d axis) return { 3567 return rotation(angle, axis.x, axis.y, axis.z); 3568 } 3569 3570 3571 public Vector4d transform(ref Vector4d v) { 3572 return v.mul(this); 3573 } 3574 3575 public Vector4d transform(ref Vector4d v, ref Vector4d dest) { 3576 return v.mul(this, dest); 3577 } 3578 3579 public Vector4d transform(double x, double y, double z, double w, ref Vector4d dest) { 3580 return dest.set(m00 * x + m10 * y + m20 * z + m30 * w, 3581 m01 * x + m11 * y + m21 * z + m31 * w, 3582 m02 * x + m12 * y + m22 * z + m32 * w, 3583 m03 * x + m13 * y + m23 * z + m33 * w); 3584 } 3585 3586 public Vector4d transformTranspose(ref Vector4d v) { 3587 return v.mulTranspose(this); 3588 } 3589 public Vector4d transformTranspose(ref Vector4d v, ref Vector4d dest) { 3590 return v.mulTranspose(this, dest); 3591 } 3592 public Vector4d transformTranspose(double x, double y, double z, double w, ref Vector4d dest) { 3593 return dest.set(x, y, z, w).mulTranspose(this); 3594 } 3595 3596 public Vector4d transformProject(ref Vector4d v) { 3597 return v.mulProject(this); 3598 } 3599 3600 public Vector4d transformProject(ref Vector4d v, ref Vector4d dest) { 3601 return v.mulProject(this, dest); 3602 } 3603 3604 public Vector4d transformProject(double x, double y, double z, double w, ref Vector4d dest) { 3605 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33 * w); 3606 return dest.set((m00 * x + m10 * y + m20 * z + m30 * w) * invW, 3607 (m01 * x + m11 * y + m21 * z + m31 * w) * invW, 3608 (m02 * x + m12 * y + m22 * z + m32 * w) * invW, 3609 1.0); 3610 } 3611 3612 public Vector3d transformProject(ref Vector3d v) { 3613 return v.mulProject(this); 3614 } 3615 3616 public Vector3d transformProject(ref Vector3d v, ref Vector3d dest) { 3617 return v.mulProject(this, dest); 3618 } 3619 3620 public Vector3d transformProject(double x, double y, double z, ref Vector3d dest) { 3621 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 3622 return dest.set((m00 * x + m10 * y + m20 * z + m30) * invW, 3623 (m01 * x + m11 * y + m21 * z + m31) * invW, 3624 (m02 * x + m12 * y + m22 * z + m32) * invW); 3625 } 3626 3627 public Vector3d transformProject(ref Vector4d v, ref Vector3d dest) { 3628 return v.mulProject(this, dest); 3629 } 3630 3631 public Vector3d transformProject(double x, double y, double z, double w, ref Vector3d dest) { 3632 dest.x = x; 3633 dest.y = y; 3634 dest.z = z; 3635 return dest.mulProject(this, w, dest); 3636 } 3637 3638 public Vector3d transformPosition(ref Vector3d dest) { 3639 return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z + m30, 3640 m01 * dest.x + m11 * dest.y + m21 * dest.z + m31, 3641 m02 * dest.x + m12 * dest.y + m22 * dest.z + m32); 3642 } 3643 3644 public Vector3d transformPosition(ref Vector3d v, ref Vector3d dest) { 3645 return transformPosition(v.x, v.y, v.z, dest); 3646 } 3647 3648 public Vector3d transformPosition(double x, double y, double z, ref Vector3d dest) { 3649 return dest.set(m00 * x + m10 * y + m20 * z + m30, 3650 m01 * x + m11 * y + m21 * z + m31, 3651 m02 * x + m12 * y + m22 * z + m32); 3652 } 3653 3654 public Vector3d transformDirection(ref Vector3d dest) { 3655 return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z, 3656 m01 * dest.x + m11 * dest.y + m21 * dest.z, 3657 m02 * dest.x + m12 * dest.y + m22 * dest.z); 3658 } 3659 3660 public Vector3d transformDirection(ref Vector3d v, ref Vector3d dest) { 3661 return dest.set(m00 * v.x + m10 * v.y + m20 * v.z, 3662 m01 * v.x + m11 * v.y + m21 * v.z, 3663 m02 * v.x + m12 * v.y + m22 * v.z); 3664 } 3665 3666 public Vector3d transformDirection(double x, double y, double z, ref Vector3d dest) { 3667 return dest.set(m00 * x + m10 * y + m20 * z, 3668 m01 * x + m11 * y + m21 * z, 3669 m02 * x + m12 * y + m22 * z); 3670 } 3671 3672 public Vector4d transformAffine(ref Vector4d dest) { 3673 return dest.mulAffine(this, dest); 3674 } 3675 3676 public Vector4d transformAffine(ref Vector4d v, ref Vector4d dest) { 3677 return transformAffine(v.x, v.y, v.z, v.w, dest); 3678 } 3679 3680 public Vector4d transformAffine(double x, double y, double z, double w, ref Vector4d dest) { 3681 double rx = m00 * x + m10 * y + m20 * z + m30 * w; 3682 double ry = m01 * x + m11 * y + m21 * z + m31 * w; 3683 double rz = m02 * x + m12 * y + m22 * z + m32 * w; 3684 dest.x = rx; 3685 dest.y = ry; 3686 dest.z = rz; 3687 dest.w = w; 3688 return dest; 3689 } 3690 3691 /** 3692 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3d} and don't change the other elements. 3693 * 3694 * @param mat 3695 * the 3x3 matrix 3696 * @return this 3697 */ 3698 ref public Matrix4d set3x3(Matrix3d mat) return { 3699 return 3700 _m00(mat.m00). 3701 _m01(mat.m01). 3702 _m02(mat.m02). 3703 _m10(mat.m10). 3704 _m11(mat.m11). 3705 _m12(mat.m12). 3706 _m20(mat.m20). 3707 _m21(mat.m21). 3708 _m22(mat.m22). 3709 _properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 3710 } 3711 3712 public Matrix4d scale(ref Vector3d xyz, ref Matrix4d dest) { 3713 return scale(xyz.x, xyz.y, xyz.z, dest); 3714 } 3715 3716 /** 3717 * Apply scaling to this matrix by scaling the base axes by the given <code>xyz.x</code>, 3718 * <code>xyz.y</code> and <code>xyz.z</code> factors, respectively. 3719 * <p> 3720 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3721 * then the new matrix will be <code>M * S</code>. So when transforming a 3722 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3723 * scaling will be applied first! 3724 * 3725 * @param xyz 3726 * the factors of the x, y and z component, respectively 3727 * @return this 3728 */ 3729 ref public Matrix4d scale(ref Vector3d xyz) return { 3730 scale(xyz.x, xyz.y, xyz.z, this); 3731 return this; 3732 } 3733 3734 public Matrix4d scale(double x, double y, double z, ref Matrix4d dest) { 3735 if ((properties & PROPERTY_IDENTITY) != 0) 3736 return dest.scaling(x, y, z); 3737 return scaleGeneric(x, y, z, dest); 3738 } 3739 private Matrix4d scaleGeneric(double x, double y, double z, ref Matrix4d dest) { 3740 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3741 dest._m00(m00 * x) 3742 ._m01(m01 * x) 3743 ._m02(m02 * x) 3744 ._m03(m03 * x) 3745 ._m10(m10 * y) 3746 ._m11(m11 * y) 3747 ._m12(m12 * y) 3748 ._m13(m13 * y) 3749 ._m20(m20 * z) 3750 ._m21(m21 * z) 3751 ._m22(m22 * z) 3752 ._m23(m23 * z) 3753 ._m30(m30) 3754 ._m31(m31) 3755 ._m32(m32) 3756 ._m33(m33) 3757 ._properties(properties 3758 & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL))); 3759 return dest; 3760 } 3761 3762 /** 3763 * Apply scaling to <code>this</code> matrix by scaling the base axes by the given x, 3764 * y and z factors. 3765 * <p> 3766 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3767 * then the new matrix will be <code>M * S</code>. So when transforming a 3768 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 3769 * , the scaling will be applied first! 3770 * 3771 * @param x 3772 * the factor of the x component 3773 * @param y 3774 * the factor of the y component 3775 * @param z 3776 * the factor of the z component 3777 * @return this 3778 */ 3779 ref public Matrix4d scale(double x, double y, double z) return { 3780 scale(x, y, z, this); 3781 return this; 3782 } 3783 3784 public Matrix4d scale(double xyz, ref Matrix4d dest) { 3785 return scale(xyz, xyz, xyz, dest); 3786 } 3787 3788 /** 3789 * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor. 3790 * <p> 3791 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3792 * then the new matrix will be <code>M * S</code>. So when transforming a 3793 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 3794 * , the scaling will be applied first! 3795 * 3796 * @see #scale(double, double, double) 3797 * 3798 * @param xyz 3799 * the factor for all components 3800 * @return this 3801 */ 3802 ref public Matrix4d scale(double xyz) return { 3803 return scale(xyz, xyz, xyz); 3804 } 3805 3806 public Matrix4d scaleXY(double x, double y, ref Matrix4d dest) { 3807 return scale(x, y, 1.0, dest); 3808 } 3809 3810 /** 3811 * Apply scaling to this matrix by scaling the X axis by <code>x</code> and the Y axis by <code>y</code>. 3812 * <p> 3813 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3814 * then the new matrix will be <code>M * S</code>. So when transforming a 3815 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3816 * scaling will be applied first! 3817 * 3818 * @param x 3819 * the factor of the x component 3820 * @param y 3821 * the factor of the y component 3822 * @return this 3823 */ 3824 ref public Matrix4d scaleXY(double x, double y) return { 3825 return scale(x, y, 1.0); 3826 } 3827 3828 public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4d dest) { 3829 double nm30 = m00 * ox + m10 * oy + m20 * oz + m30; 3830 double nm31 = m01 * ox + m11 * oy + m21 * oz + m31; 3831 double nm32 = m02 * ox + m12 * oy + m22 * oz + m32; 3832 double nm33 = m03 * ox + m13 * oy + m23 * oz + m33; 3833 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 3834 return dest 3835 ._m00(m00 * sx) 3836 ._m01(m01 * sx) 3837 ._m02(m02 * sx) 3838 ._m03(m03 * sx) 3839 ._m10(m10 * sy) 3840 ._m11(m11 * sy) 3841 ._m12(m12 * sy) 3842 ._m13(m13 * sy) 3843 ._m20(m20 * sz) 3844 ._m21(m21 * sz) 3845 ._m22(m22 * sz) 3846 ._m23(m23 * sz) 3847 ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30) 3848 ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31) 3849 ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32) 3850 ._m33(-dest.m03 * ox - dest.m13 * oy - dest.m23 * oz + nm33) 3851 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3852 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3853 } 3854 3855 /** 3856 * Apply scaling to this matrix by scaling the base axes by the given sx, 3857 * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin. 3858 * <p> 3859 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3860 * then the new matrix will be <code>M * S</code>. So when transforming a 3861 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3862 * scaling will be applied first! 3863 * <p> 3864 * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)</code> 3865 * 3866 * @param sx 3867 * the scaling factor of the x component 3868 * @param sy 3869 * the scaling factor of the y component 3870 * @param sz 3871 * the scaling factor of the z component 3872 * @param ox 3873 * the x coordinate of the scaling origin 3874 * @param oy 3875 * the y coordinate of the scaling origin 3876 * @param oz 3877 * the z coordinate of the scaling origin 3878 * @return this 3879 */ 3880 ref public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) return { 3881 scaleAround(sx, sy, sz, ox, oy, oz, this); 3882 return this; 3883 } 3884 3885 /** 3886 * Apply scaling to this matrix by scaling all three base axes by the given <code>factor</code> 3887 * while using <code>(ox, oy, oz)</code> as the scaling origin. 3888 * <p> 3889 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3890 * then the new matrix will be <code>M * S</code>. So when transforming a 3891 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3892 * scaling will be applied first! 3893 * <p> 3894 * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)</code> 3895 * 3896 * @param factor 3897 * the scaling factor for all three axes 3898 * @param ox 3899 * the x coordinate of the scaling origin 3900 * @param oy 3901 * the y coordinate of the scaling origin 3902 * @param oz 3903 * the z coordinate of the scaling origin 3904 * @return this 3905 */ 3906 ref public Matrix4d scaleAround(double factor, double ox, double oy, double oz) return { 3907 scaleAround(factor, factor, factor, ox, oy, oz, this); 3908 return this; 3909 } 3910 3911 public Matrix4d scaleAround(double factor, double ox, double oy, double oz, ref Matrix4d dest) { 3912 return scaleAround(factor, factor, factor, ox, oy, oz, dest); 3913 } 3914 3915 public Matrix4d scaleLocal(double x, double y, double z, ref Matrix4d dest) { 3916 if ((properties & PROPERTY_IDENTITY) != 0) 3917 return dest.scaling(x, y, z); 3918 return scaleLocalGeneric(x, y, z, dest); 3919 } 3920 private Matrix4d scaleLocalGeneric(double x, double y, double z, ref Matrix4d dest) { 3921 double nm00 = x * m00; 3922 double nm01 = y * m01; 3923 double nm02 = z * m02; 3924 double nm10 = x * m10; 3925 double nm11 = y * m11; 3926 double nm12 = z * m12; 3927 double nm20 = x * m20; 3928 double nm21 = y * m21; 3929 double nm22 = z * m22; 3930 double nm30 = x * m30; 3931 double nm31 = y * m31; 3932 double nm32 = z * m32; 3933 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3934 dest._m00(nm00) 3935 ._m01(nm01) 3936 ._m02(nm02) 3937 ._m03(m03) 3938 ._m10(nm10) 3939 ._m11(nm11) 3940 ._m12(nm12) 3941 ._m13(m13) 3942 ._m20(nm20) 3943 ._m21(nm21) 3944 ._m22(nm22) 3945 ._m23(m23) 3946 ._m30(nm30) 3947 ._m31(nm31) 3948 ._m32(nm32) 3949 ._m33(m33) 3950 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3951 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3952 return dest; 3953 } 3954 3955 public Matrix4d scaleLocal(double xyz, ref Matrix4d dest) { 3956 return scaleLocal(xyz, xyz, xyz, dest); 3957 } 3958 3959 /** 3960 * Pre-multiply scaling to this matrix by scaling the base axes by the given xyz factor. 3961 * <p> 3962 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3963 * then the new matrix will be <code>S * M</code>. So when transforming a 3964 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3965 * scaling will be applied last! 3966 * 3967 * @param xyz 3968 * the factor of the x, y and z component 3969 * @return this 3970 */ 3971 ref public Matrix4d scaleLocal(double xyz) return { 3972 scaleLocal(xyz, this); 3973 return this; 3974 } 3975 3976 /** 3977 * Pre-multiply scaling to this matrix by scaling the base axes by the given x, 3978 * y and z factors. 3979 * <p> 3980 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3981 * then the new matrix will be <code>S * M</code>. So when transforming a 3982 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3983 * scaling will be applied last! 3984 * 3985 * @param x 3986 * the factor of the x component 3987 * @param y 3988 * the factor of the y component 3989 * @param z 3990 * the factor of the z component 3991 * @return this 3992 */ 3993 ref public Matrix4d scaleLocal(double x, double y, double z) return { 3994 scaleLocal(x, y, z, this); 3995 return this; 3996 } 3997 3998 public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4d dest) { 3999 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 4000 dest._m00(sx * (m00 - ox * m03) + ox * m03) 4001 ._m01(sy * (m01 - oy * m03) + oy * m03) 4002 ._m02(sz * (m02 - oz * m03) + oz * m03) 4003 ._m03(m03) 4004 ._m10(sx * (m10 - ox * m13) + ox * m13) 4005 ._m11(sy * (m11 - oy * m13) + oy * m13) 4006 ._m12(sz * (m12 - oz * m13) + oz * m13) 4007 ._m13(m13) 4008 ._m20(sx * (m20 - ox * m23) + ox * m23) 4009 ._m21(sy * (m21 - oy * m23) + oy * m23) 4010 ._m22(sz * (m22 - oz * m23) + oz * m23) 4011 ._m23(m23) 4012 ._m30(sx * (m30 - ox * m33) + ox * m33) 4013 ._m31(sy * (m31 - oy * m33) + oy * m33) 4014 ._m32(sz * (m32 - oz * m33) + oz * m33) 4015 ._m33(m33) 4016 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 4017 | (one ? 0 : PROPERTY_ORTHONORMAL))); 4018 return dest; 4019 } 4020 4021 /** 4022 * Pre-multiply scaling to this matrix by scaling the base axes by the given sx, 4023 * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin. 4024 * <p> 4025 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 4026 * then the new matrix will be <code>S * M</code>. So when transforming a 4027 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 4028 * scaling will be applied last! 4029 * <p> 4030 * This method is equivalent to calling: <code>new Matrix4d().translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz).mul(this, this)</code> 4031 * 4032 * @param sx 4033 * the scaling factor of the x component 4034 * @param sy 4035 * the scaling factor of the y component 4036 * @param sz 4037 * the scaling factor of the z component 4038 * @param ox 4039 * the x coordinate of the scaling origin 4040 * @param oy 4041 * the y coordinate of the scaling origin 4042 * @param oz 4043 * the z coordinate of the scaling origin 4044 * @return this 4045 */ 4046 ref public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz) return { 4047 scaleAroundLocal(sx, sy, sz, ox, oy, oz, this); 4048 return this; 4049 } 4050 4051 /** 4052 * Pre-multiply scaling to this matrix by scaling all three base axes by the given <code>factor</code> 4053 * while using <code>(ox, oy, oz)</code> as the scaling origin. 4054 * <p> 4055 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 4056 * then the new matrix will be <code>S * M</code>. So when transforming a 4057 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 4058 * scaling will be applied last! 4059 * <p> 4060 * This method is equivalent to calling: <code>new Matrix4d().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, this)</code> 4061 * 4062 * @param factor 4063 * the scaling factor for all three axes 4064 * @param ox 4065 * the x coordinate of the scaling origin 4066 * @param oy 4067 * the y coordinate of the scaling origin 4068 * @param oz 4069 * the z coordinate of the scaling origin 4070 * @return this 4071 */ 4072 ref public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz) return { 4073 scaleAroundLocal(factor, factor, factor, ox, oy, oz, this); 4074 return this; 4075 } 4076 4077 public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz, ref Matrix4d dest) { 4078 return scaleAroundLocal(factor, factor, factor, ox, oy, oz, dest); 4079 } 4080 4081 public Matrix4d rotate(double ang, double x, double y, double z, ref Matrix4d dest) { 4082 if ((properties & PROPERTY_IDENTITY) != 0) 4083 return dest.rotation(ang, x, y, z); 4084 else if ((properties & PROPERTY_TRANSLATION) != 0) 4085 return rotateTranslation(ang, x, y, z, dest); 4086 else if ((properties & PROPERTY_AFFINE) != 0) 4087 return rotateAffine(ang, x, y, z, dest); 4088 return rotateGeneric(ang, x, y, z, dest); 4089 } 4090 private Matrix4d rotateGeneric(double ang, double x, double y, double z, ref Matrix4d dest) { 4091 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4092 return rotateX(x * ang, dest); 4093 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4094 return rotateY(y * ang, dest); 4095 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4096 return rotateZ(z * ang, dest); 4097 return rotateGenericInternal(ang, x, y, z, dest); 4098 } 4099 private Matrix4d rotateGenericInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4100 double s = Math.sin(ang); 4101 double c = Math.cosFromSin(s, ang); 4102 double C = 1.0 - c; 4103 double xx = x * x, xy = x * y, xz = x * z; 4104 double yy = y * y, yz = y * z; 4105 double zz = z * z; 4106 double rm00 = xx * C + c; 4107 double rm01 = xy * C + z * s; 4108 double rm02 = xz * C - y * s; 4109 double rm10 = xy * C - z * s; 4110 double rm11 = yy * C + c; 4111 double rm12 = yz * C + x * s; 4112 double rm20 = xz * C + y * s; 4113 double rm21 = yz * C - x * s; 4114 double rm22 = zz * C + c; 4115 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4116 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4117 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4118 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 4119 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4120 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4121 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4122 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 4123 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4124 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4125 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4126 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 4127 ._m00(nm00) 4128 ._m01(nm01) 4129 ._m02(nm02) 4130 ._m03(nm03) 4131 ._m10(nm10) 4132 ._m11(nm11) 4133 ._m12(nm12) 4134 ._m13(nm13) 4135 ._m30(m30) 4136 ._m31(m31) 4137 ._m32(m32) 4138 ._m33(m33) 4139 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4140 return dest; 4141 } 4142 4143 /** 4144 * Apply rotation to this matrix by rotating the given amount of radians 4145 * about the given axis specified as x, y and z components. 4146 * <p> 4147 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4148 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4149 * When used with a left-handed coordinate system, the rotation is clockwise. 4150 * <p> 4151 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4152 * then the new matrix will be <code>M * R</code>. So when transforming a 4153 * vector <code>v</code> with the new matrix by using <code>M * R * v</code> 4154 * , the rotation will be applied first! 4155 * <p> 4156 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4157 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4158 * 4159 * @see #rotation(double, double, double, double) 4160 * 4161 * @param ang 4162 * the angle is in radians 4163 * @param x 4164 * the x component of the axis 4165 * @param y 4166 * the y component of the axis 4167 * @param z 4168 * the z component of the axis 4169 * @return this 4170 */ 4171 ref public Matrix4d rotate(double ang, double x, double y, double z) return { 4172 rotate(ang, x, y, z, this); 4173 return this; 4174 } 4175 4176 /** 4177 * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians 4178 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4179 * <p> 4180 * This method assumes <code>this</code> to only contain a translation. 4181 * <p> 4182 * The axis described by the three components needs to be a unit vector. 4183 * <p> 4184 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4185 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4186 * When used with a left-handed coordinate system, the rotation is clockwise. 4187 * <p> 4188 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4189 * then the new matrix will be <code>M * R</code>. So when transforming a 4190 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4191 * rotation will be applied first! 4192 * <p> 4193 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4194 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4195 * <p> 4196 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4197 * 4198 * @see #rotation(double, double, double, double) 4199 * 4200 * @param ang 4201 * the angle in radians 4202 * @param x 4203 * the x component of the axis 4204 * @param y 4205 * the y component of the axis 4206 * @param z 4207 * the z component of the axis 4208 * @param dest 4209 * will hold the result 4210 * @return dest 4211 */ 4212 public Matrix4d rotateTranslation(double ang, double x, double y, double z, ref Matrix4d dest) { 4213 double tx = m30, ty = m31, tz = m32; 4214 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4215 return dest.rotationX(x * ang).setTranslation(tx, ty, tz); 4216 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4217 return dest.rotationY(y * ang).setTranslation(tx, ty, tz); 4218 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4219 return dest.rotationZ(z * ang).setTranslation(tx, ty, tz); 4220 return rotateTranslationInternal(ang, x, y, z, dest); 4221 } 4222 private Matrix4d rotateTranslationInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4223 double s = Math.sin(ang); 4224 double c = Math.cosFromSin(s, ang); 4225 double C = 1.0 - c; 4226 double xx = x * x, xy = x * y, xz = x * z; 4227 double yy = y * y, yz = y * z; 4228 double zz = z * z; 4229 double rm00 = xx * C + c; 4230 double rm01 = xy * C + z * s; 4231 double rm02 = xz * C - y * s; 4232 double rm10 = xy * C - z * s; 4233 double rm11 = yy * C + c; 4234 double rm12 = yz * C + x * s; 4235 double rm20 = xz * C + y * s; 4236 double rm21 = yz * C - x * s; 4237 double rm22 = zz * C + c; 4238 return dest 4239 ._m20(rm20) 4240 ._m21(rm21) 4241 ._m22(rm22) 4242 ._m23(0.0) 4243 ._m00(rm00) 4244 ._m01(rm01) 4245 ._m02(rm02) 4246 ._m03(0.0) 4247 ._m10(rm10) 4248 ._m11(rm11) 4249 ._m12(rm12) 4250 ._m13(0.0) 4251 ._m30(m30) 4252 ._m31(m31) 4253 ._m32(m32) 4254 ._m33(1.0) 4255 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4256 } 4257 4258 /** 4259 * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians 4260 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4261 * <p> 4262 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 4263 * <p> 4264 * The axis described by the three components needs to be a unit vector. 4265 * <p> 4266 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4267 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4268 * When used with a left-handed coordinate system, the rotation is clockwise. 4269 * <p> 4270 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4271 * then the new matrix will be <code>M * R</code>. So when transforming a 4272 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4273 * rotation will be applied first! 4274 * <p> 4275 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4276 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4277 * <p> 4278 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4279 * 4280 * @see #rotation(double, double, double, double) 4281 * 4282 * @param ang 4283 * the angle in radians 4284 * @param x 4285 * the x component of the axis 4286 * @param y 4287 * the y component of the axis 4288 * @param z 4289 * the z component of the axis 4290 * @param dest 4291 * will hold the result 4292 * @return dest 4293 */ 4294 public Matrix4d rotateAffine(double ang, double x, double y, double z, ref Matrix4d dest) { 4295 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4296 return rotateX(x * ang, dest); 4297 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4298 return rotateY(y * ang, dest); 4299 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4300 return rotateZ(z * ang, dest); 4301 return rotateAffineInternal(ang, x, y, z, dest); 4302 } 4303 private Matrix4d rotateAffineInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4304 double s = Math.sin(ang); 4305 double c = Math.cosFromSin(s, ang); 4306 double C = 1.0 - c; 4307 double xx = x * x, xy = x * y, xz = x * z; 4308 double yy = y * y, yz = y * z; 4309 double zz = z * z; 4310 double rm00 = xx * C + c; 4311 double rm01 = xy * C + z * s; 4312 double rm02 = xz * C - y * s; 4313 double rm10 = xy * C - z * s; 4314 double rm11 = yy * C + c; 4315 double rm12 = yz * C + x * s; 4316 double rm20 = xz * C + y * s; 4317 double rm21 = yz * C - x * s; 4318 double rm22 = zz * C + c; 4319 // add temporaries for dependent values 4320 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4321 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4322 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4323 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4324 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4325 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4326 // set non-dependent values directly 4327 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4328 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4329 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4330 ._m23(0.0) 4331 // set other values 4332 ._m00(nm00) 4333 ._m01(nm01) 4334 ._m02(nm02) 4335 ._m03(0.0) 4336 ._m10(nm10) 4337 ._m11(nm11) 4338 ._m12(nm12) 4339 ._m13(0.0) 4340 ._m30(m30) 4341 ._m31(m31) 4342 ._m32(m32) 4343 ._m33(m33) 4344 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4345 return dest; 4346 } 4347 4348 /** 4349 * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians 4350 * about the specified <code>(x, y, z)</code> axis. 4351 * <p> 4352 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 4353 * <p> 4354 * The axis described by the three components needs to be a unit vector. 4355 * <p> 4356 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4357 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4358 * When used with a left-handed coordinate system, the rotation is clockwise. 4359 * <p> 4360 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4361 * then the new matrix will be <code>M * R</code>. So when transforming a 4362 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4363 * rotation will be applied first! 4364 * <p> 4365 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4366 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4367 * <p> 4368 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4369 * 4370 * @see #rotation(double, double, double, double) 4371 * 4372 * @param ang 4373 * the angle in radians 4374 * @param x 4375 * the x component of the axis 4376 * @param y 4377 * the y component of the axis 4378 * @param z 4379 * the z component of the axis 4380 * @return this 4381 */ 4382 ref public Matrix4d rotateAffine(double ang, double x, double y, double z) return { 4383 rotateAffine(ang, x, y, z, this); 4384 return this; 4385 } 4386 4387 /** 4388 * Apply the rotation transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> as the rotation origin. 4389 * <p> 4390 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4391 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4392 * When used with a left-handed coordinate system, the rotation is clockwise. 4393 * <p> 4394 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 4395 * then the new matrix will be <code>M * Q</code>. So when transforming a 4396 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 4397 * the quaternion rotation will be applied first! 4398 * <p> 4399 * This method is equivalent to calling: <code>translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code> 4400 * <p> 4401 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4402 * 4403 * @param quat 4404 * the {@link Quaterniond} 4405 * @param ox 4406 * the x coordinate of the rotation origin 4407 * @param oy 4408 * the y coordinate of the rotation origin 4409 * @param oz 4410 * the z coordinate of the rotation origin 4411 * @return this 4412 */ 4413 ref public Matrix4d rotateAround(ref Quaterniond quat, double ox, double oy, double oz) return { 4414 rotateAround(quat, ox, oy, oz, this); 4415 return this; 4416 } 4417 4418 public Matrix4d rotateAroundAffine(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4419 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4420 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4421 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4422 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4423 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4424 double rm00 = w2 + x2 - z2 - y2; 4425 double rm01 = dxy + dzw; 4426 double rm02 = dxz - dyw; 4427 double rm10 = -dzw + dxy; 4428 double rm11 = y2 - z2 + w2 - x2; 4429 double rm12 = dyz + dxw; 4430 double rm20 = dyw + dxz; 4431 double rm21 = dyz - dxw; 4432 double rm22 = z2 - y2 - x2 + w2; 4433 double tm30 = m00 * ox + m10 * oy + m20 * oz + m30; 4434 double tm31 = m01 * ox + m11 * oy + m21 * oz + m31; 4435 double tm32 = m02 * ox + m12 * oy + m22 * oz + m32; 4436 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4437 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4438 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4439 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4440 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4441 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4442 dest 4443 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4444 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4445 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4446 ._m23(0.0) 4447 ._m00(nm00) 4448 ._m01(nm01) 4449 ._m02(nm02) 4450 ._m03(0.0) 4451 ._m10(nm10) 4452 ._m11(nm11) 4453 ._m12(nm12) 4454 ._m13(0.0) 4455 ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30) 4456 ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31) 4457 ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32) 4458 ._m33(1.0) 4459 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4460 return dest; 4461 } 4462 4463 public Matrix4d rotateAround(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4464 if ((properties & PROPERTY_IDENTITY) != 0) 4465 return rotationAround(quat, ox, oy, oz); 4466 else if ((properties & PROPERTY_AFFINE) != 0) 4467 return rotateAroundAffine(quat, ox, oy, oz, this); 4468 return rotateAroundGeneric(quat, ox, oy, oz, this); 4469 } 4470 private Matrix4d rotateAroundGeneric(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4471 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4472 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4473 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4474 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4475 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4476 double rm00 = w2 + x2 - z2 - y2; 4477 double rm01 = dxy + dzw; 4478 double rm02 = dxz - dyw; 4479 double rm10 = -dzw + dxy; 4480 double rm11 = y2 - z2 + w2 - x2; 4481 double rm12 = dyz + dxw; 4482 double rm20 = dyw + dxz; 4483 double rm21 = dyz - dxw; 4484 double rm22 = z2 - y2 - x2 + w2; 4485 double tm30 = m00 * ox + m10 * oy + m20 * oz + m30; 4486 double tm31 = m01 * ox + m11 * oy + m21 * oz + m31; 4487 double tm32 = m02 * ox + m12 * oy + m22 * oz + m32; 4488 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4489 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4490 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4491 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 4492 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4493 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4494 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4495 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 4496 dest 4497 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4498 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4499 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4500 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 4501 ._m00(nm00) 4502 ._m01(nm01) 4503 ._m02(nm02) 4504 ._m03(nm03) 4505 ._m10(nm10) 4506 ._m11(nm11) 4507 ._m12(nm12) 4508 ._m13(nm13) 4509 ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30) 4510 ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31) 4511 ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32) 4512 ._m33(m33) 4513 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4514 return dest; 4515 } 4516 4517 /** 4518 * Set this matrix to a transformation composed of a rotation of the specified {@link Quaterniond} while using <code>(ox, oy, oz)</code> as the rotation origin. 4519 * <p> 4520 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4521 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4522 * When used with a left-handed coordinate system, the rotation is clockwise. 4523 * <p> 4524 * This method is equivalent to calling: <code>translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code> 4525 * <p> 4526 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4527 * 4528 * @param quat 4529 * the {@link Quaterniond} 4530 * @param ox 4531 * the x coordinate of the rotation origin 4532 * @param oy 4533 * the y coordinate of the rotation origin 4534 * @param oz 4535 * the z coordinate of the rotation origin 4536 * @return this 4537 */ 4538 ref public Matrix4d rotationAround(ref Quaterniond quat, double ox, double oy, double oz) return { 4539 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4540 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4541 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4542 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4543 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4544 this._m20(dyw + dxz); 4545 this._m21(dyz - dxw); 4546 this._m22(z2 - y2 - x2 + w2); 4547 this._m23(0.0); 4548 this._m00(w2 + x2 - z2 - y2); 4549 this._m01(dxy + dzw); 4550 this._m02(dxz - dyw); 4551 this._m03(0.0); 4552 this._m10(-dzw + dxy); 4553 this._m11(y2 - z2 + w2 - x2); 4554 this._m12(dyz + dxw); 4555 this._m13(0.0); 4556 this._m30(-m00 * ox - m10 * oy - m20 * oz + ox); 4557 this._m31(-m01 * ox - m11 * oy - m21 * oz + oy); 4558 this._m32(-m02 * ox - m12 * oy - m22 * oz + oz); 4559 this._m33(1.0); 4560 this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 4561 return this; 4562 } 4563 4564 /** 4565 * Pre-multiply a rotation to this matrix by rotating the given amount of radians 4566 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4567 * <p> 4568 * The axis described by the three components needs to be a unit vector. 4569 * <p> 4570 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4571 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4572 * When used with a left-handed coordinate system, the rotation is clockwise. 4573 * <p> 4574 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4575 * then the new matrix will be <code>R * M</code>. So when transforming a 4576 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 4577 * rotation will be applied last! 4578 * <p> 4579 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 4580 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4581 * <p> 4582 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4583 * 4584 * @see #rotation(double, double, double, double) 4585 * 4586 * @param ang 4587 * the angle in radians 4588 * @param x 4589 * the x component of the axis 4590 * @param y 4591 * the y component of the axis 4592 * @param z 4593 * the z component of the axis 4594 * @param dest 4595 * will hold the result 4596 * @return dest 4597 */ 4598 public Matrix4d rotateLocal(double ang, double x, double y, double z, ref Matrix4d dest) { 4599 if ((properties & PROPERTY_IDENTITY) != 0) 4600 return dest.rotation(ang, x, y, z); 4601 return rotateLocalGeneric(ang, x, y, z, dest); 4602 } 4603 private Matrix4d rotateLocalGeneric(double ang, double x, double y, double z, ref Matrix4d dest) { 4604 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4605 return rotateLocalX(x * ang, dest); 4606 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4607 return rotateLocalY(y * ang, dest); 4608 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4609 return rotateLocalZ(z * ang, dest); 4610 return rotateLocalGenericInternal(ang, x, y, z, dest); 4611 } 4612 private Matrix4d rotateLocalGenericInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4613 double s = Math.sin(ang); 4614 double c = Math.cosFromSin(s, ang); 4615 double C = 1.0 - c; 4616 double xx = x * x, xy = x * y, xz = x * z; 4617 double yy = y * y, yz = y * z; 4618 double zz = z * z; 4619 double lm00 = xx * C + c; 4620 double lm01 = xy * C + z * s; 4621 double lm02 = xz * C - y * s; 4622 double lm10 = xy * C - z * s; 4623 double lm11 = yy * C + c; 4624 double lm12 = yz * C + x * s; 4625 double lm20 = xz * C + y * s; 4626 double lm21 = yz * C - x * s; 4627 double lm22 = zz * C + c; 4628 double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; 4629 double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; 4630 double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; 4631 double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; 4632 double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; 4633 double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; 4634 double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; 4635 double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; 4636 double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; 4637 double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32; 4638 double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32; 4639 double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32; 4640 dest._m00(nm00) 4641 ._m01(nm01) 4642 ._m02(nm02) 4643 ._m03(m03) 4644 ._m10(nm10) 4645 ._m11(nm11) 4646 ._m12(nm12) 4647 ._m13(m13) 4648 ._m20(nm20) 4649 ._m21(nm21) 4650 ._m22(nm22) 4651 ._m23(m23) 4652 ._m30(nm30) 4653 ._m31(nm31) 4654 ._m32(nm32) 4655 ._m33(m33) 4656 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4657 return dest; 4658 } 4659 4660 /** 4661 * Pre-multiply a rotation to this matrix by rotating the given amount of radians 4662 * about the specified <code>(x, y, z)</code> axis. 4663 * <p> 4664 * The axis described by the three components needs to be a unit vector. 4665 * <p> 4666 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4667 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4668 * When used with a left-handed coordinate system, the rotation is clockwise. 4669 * <p> 4670 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4671 * then the new matrix will be <code>R * M</code>. So when transforming a 4672 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 4673 * rotation will be applied last! 4674 * <p> 4675 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 4676 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4677 * <p> 4678 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4679 * 4680 * @see #rotation(double, double, double, double) 4681 * 4682 * @param ang 4683 * the angle in radians 4684 * @param x 4685 * the x component of the axis 4686 * @param y 4687 * the y component of the axis 4688 * @param z 4689 * the z component of the axis 4690 * @return this 4691 */ 4692 ref public Matrix4d rotateLocal(double ang, double x, double y, double z) return { 4693 rotateLocal(ang, x, y, z, this); 4694 return this; 4695 } 4696 4697 public Matrix4d rotateAroundLocal(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4698 double w2 = quat.w * quat.w; 4699 double x2 = quat.x * quat.x; 4700 double y2 = quat.y * quat.y; 4701 double z2 = quat.z * quat.z; 4702 double zw = quat.z * quat.w; 4703 double xy = quat.x * quat.y; 4704 double xz = quat.x * quat.z; 4705 double yw = quat.y * quat.w; 4706 double yz = quat.y * quat.z; 4707 double xw = quat.x * quat.w; 4708 double lm00 = w2 + x2 - z2 - y2; 4709 double lm01 = xy + zw + zw + xy; 4710 double lm02 = xz - yw + xz - yw; 4711 double lm10 = -zw + xy - zw + xy; 4712 double lm11 = y2 - z2 + w2 - x2; 4713 double lm12 = yz + yz + xw + xw; 4714 double lm20 = yw + xz + xz + yw; 4715 double lm21 = yz + yz - xw - xw; 4716 double lm22 = z2 - y2 - x2 + w2; 4717 double tm00 = m00 - ox * m03; 4718 double tm01 = m01 - oy * m03; 4719 double tm02 = m02 - oz * m03; 4720 double tm10 = m10 - ox * m13; 4721 double tm11 = m11 - oy * m13; 4722 double tm12 = m12 - oz * m13; 4723 double tm20 = m20 - ox * m23; 4724 double tm21 = m21 - oy * m23; 4725 double tm22 = m22 - oz * m23; 4726 double tm30 = m30 - ox * m33; 4727 double tm31 = m31 - oy * m33; 4728 double tm32 = m32 - oz * m33; 4729 dest._m00(lm00 * tm00 + lm10 * tm01 + lm20 * tm02 + ox * m03) 4730 ._m01(lm01 * tm00 + lm11 * tm01 + lm21 * tm02 + oy * m03) 4731 ._m02(lm02 * tm00 + lm12 * tm01 + lm22 * tm02 + oz * m03) 4732 ._m03(m03) 4733 ._m10(lm00 * tm10 + lm10 * tm11 + lm20 * tm12 + ox * m13) 4734 ._m11(lm01 * tm10 + lm11 * tm11 + lm21 * tm12 + oy * m13) 4735 ._m12(lm02 * tm10 + lm12 * tm11 + lm22 * tm12 + oz * m13) 4736 ._m13(m13) 4737 ._m20(lm00 * tm20 + lm10 * tm21 + lm20 * tm22 + ox * m23) 4738 ._m21(lm01 * tm20 + lm11 * tm21 + lm21 * tm22 + oy * m23) 4739 ._m22(lm02 * tm20 + lm12 * tm21 + lm22 * tm22 + oz * m23) 4740 ._m23(m23) 4741 ._m30(lm00 * tm30 + lm10 * tm31 + lm20 * tm32 + ox * m33) 4742 ._m31(lm01 * tm30 + lm11 * tm31 + lm21 * tm32 + oy * m33) 4743 ._m32(lm02 * tm30 + lm12 * tm31 + lm22 * tm32 + oz * m33) 4744 ._m33(m33) 4745 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4746 return dest; 4747 } 4748 4749 /** 4750 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> 4751 * as the rotation origin. 4752 * <p> 4753 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4754 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4755 * When used with a left-handed coordinate system, the rotation is clockwise. 4756 * <p> 4757 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 4758 * then the new matrix will be <code>Q * M</code>. So when transforming a 4759 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 4760 * the quaternion rotation will be applied last! 4761 * <p> 4762 * This method is equivalent to calling: <code>translateLocal(-ox, -oy, -oz).rotateLocal(quat).translateLocal(ox, oy, oz)</code> 4763 * <p> 4764 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4765 * 4766 * @param quat 4767 * the {@link Quaterniond} 4768 * @param ox 4769 * the x coordinate of the rotation origin 4770 * @param oy 4771 * the y coordinate of the rotation origin 4772 * @param oz 4773 * the z coordinate of the rotation origin 4774 * @return this 4775 */ 4776 ref public Matrix4d rotateAroundLocal(ref Quaterniond quat, double ox, double oy, double oz) return { 4777 rotateAroundLocal(quat, ox, oy, oz, this); 4778 return this; 4779 } 4780 4781 /** 4782 * Apply a translation to this matrix by translating by the given number of 4783 * units in x, y and z. 4784 * <p> 4785 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4786 * matrix, then the new matrix will be <code>M * T</code>. So when 4787 * transforming a vector <code>v</code> with the new matrix by using 4788 * <code>M * T * v</code>, the translation will be applied first! 4789 * <p> 4790 * In order to set the matrix to a translation transformation without post-multiplying 4791 * it, use {@link #translation(ref Vector3d)}. 4792 * 4793 * @see #translation(ref Vector3d) 4794 * 4795 * @param offset 4796 * the number of units in x, y and z by which to translate 4797 * @return this 4798 */ 4799 ref public Matrix4d translate(ref Vector3d offset) return { 4800 return translate(offset.x, offset.y, offset.z); 4801 } 4802 4803 /** 4804 * Apply a translation to this matrix by translating by the given number of 4805 * units in x, y and z and store the result in <code>dest</code>. 4806 * <p> 4807 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4808 * matrix, then the new matrix will be <code>M * T</code>. So when 4809 * transforming a vector <code>v</code> with the new matrix by using 4810 * <code>M * T * v</code>, the translation will be applied first! 4811 * <p> 4812 * In order to set the matrix to a translation transformation without post-multiplying 4813 * it, use {@link #translation(ref Vector3d)}. 4814 * 4815 * @see #translation(ref Vector3d) 4816 * 4817 * @param offset 4818 * the number of units in x, y and z by which to translate 4819 * @param dest 4820 * will hold the result 4821 * @return dest 4822 */ 4823 public Matrix4d translate(ref Vector3d offset, ref Matrix4d dest) { 4824 return translate(offset.x, offset.y, offset.z, dest); 4825 } 4826 4827 4828 4829 /** 4830 * Apply a translation to this matrix by translating by the given number of 4831 * units in x, y and z and store the result in <code>dest</code>. 4832 * <p> 4833 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4834 * matrix, then the new matrix will be <code>M * T</code>. So when 4835 * transforming a vector <code>v</code> with the new matrix by using 4836 * <code>M * T * v</code>, the translation will be applied first! 4837 * <p> 4838 * In order to set the matrix to a translation transformation without post-multiplying 4839 * it, use {@link #translation(double, double, double)}. 4840 * 4841 * @see #translation(double, double, double) 4842 * 4843 * @param x 4844 * the offset to translate in x 4845 * @param y 4846 * the offset to translate in y 4847 * @param z 4848 * the offset to translate in z 4849 * @param dest 4850 * will hold the result 4851 * @return dest 4852 */ 4853 public Matrix4d translate(double x, double y, double z, ref Matrix4d dest) { 4854 if ((properties & PROPERTY_IDENTITY) != 0) 4855 return dest.translation(x, y, z); 4856 return translateGeneric(x, y, z, dest); 4857 } 4858 private Matrix4d translateGeneric(double x, double y, double z, ref Matrix4d dest) { 4859 dest._m00(m00) 4860 ._m01(m01) 4861 ._m02(m02) 4862 ._m03(m03) 4863 ._m10(m10) 4864 ._m11(m11) 4865 ._m12(m12) 4866 ._m13(m13) 4867 ._m20(m20) 4868 ._m21(m21) 4869 ._m22(m22) 4870 ._m23(m23) 4871 ._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30)))) 4872 ._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31)))) 4873 ._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32)))) 4874 ._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)))) 4875 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY)); 4876 return dest; 4877 } 4878 4879 /** 4880 * Apply a translation to this matrix by translating by the given number of 4881 * units in x, y and z. 4882 * <p> 4883 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4884 * matrix, then the new matrix will be <code>M * T</code>. So when 4885 * transforming a vector <code>v</code> with the new matrix by using 4886 * <code>M * T * v</code>, the translation will be applied first! 4887 * <p> 4888 * In order to set the matrix to a translation transformation without post-multiplying 4889 * it, use {@link #translation(double, double, double)}. 4890 * 4891 * @see #translation(double, double, double) 4892 * 4893 * @param x 4894 * the offset to translate in x 4895 * @param y 4896 * the offset to translate in y 4897 * @param z 4898 * the offset to translate in z 4899 * @return this 4900 */ 4901 ref public Matrix4d translate(double x, double y, double z) return { 4902 if ((properties & PROPERTY_IDENTITY) != 0) 4903 return translation(x, y, z); 4904 this._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30)))); 4905 this._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31)))); 4906 this._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32)))); 4907 this._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)))); 4908 this.properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY); 4909 return this; 4910 } 4911 4912 /** 4913 * Pre-multiply a translation to this matrix by translating by the given number of 4914 * units in x, y and z. 4915 * <p> 4916 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4917 * matrix, then the new matrix will be <code>T * M</code>. So when 4918 * transforming a vector <code>v</code> with the new matrix by using 4919 * <code>T * M * v</code>, the translation will be applied last! 4920 * <p> 4921 * In order to set the matrix to a translation transformation without pre-multiplying 4922 * it, use {@link #translation(ref Vector3d)}. 4923 * 4924 * @see #translation(ref Vector3d) 4925 * 4926 * @param offset 4927 * the number of units in x, y and z by which to translate 4928 * @return this 4929 */ 4930 ref public Matrix4d translateLocal(ref Vector3d offset) return { 4931 return translateLocal(offset.x, offset.y, offset.z); 4932 } 4933 4934 /** 4935 * Pre-multiply a translation to this matrix by translating by the given number of 4936 * units in x, y and z and store the result in <code>dest</code>. 4937 * <p> 4938 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4939 * matrix, then the new matrix will be <code>T * M</code>. So when 4940 * transforming a vector <code>v</code> with the new matrix by using 4941 * <code>T * M * v</code>, the translation will be applied last! 4942 * <p> 4943 * In order to set the matrix to a translation transformation without pre-multiplying 4944 * it, use {@link #translation(ref Vector3d)}. 4945 * 4946 * @see #translation(ref Vector3d) 4947 * 4948 * @param offset 4949 * the number of units in x, y and z by which to translate 4950 * @param dest 4951 * will hold the result 4952 * @return dest 4953 */ 4954 public Matrix4d translateLocal(ref Vector3d offset, ref Matrix4d dest) { 4955 return translateLocal(offset.x, offset.y, offset.z, dest); 4956 } 4957 4958 /** 4959 * Pre-multiply a translation to this matrix by translating by the given number of 4960 * units in x, y and z and store the result in <code>dest</code>. 4961 * <p> 4962 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4963 * matrix, then the new matrix will be <code>T * M</code>. So when 4964 * transforming a vector <code>v</code> with the new matrix by using 4965 * <code>T * M * v</code>, the translation will be applied last! 4966 * <p> 4967 * In order to set the matrix to a translation transformation without pre-multiplying 4968 * it, use {@link #translation(double, double, double)}. 4969 * 4970 * @see #translation(double, double, double) 4971 * 4972 * @param x 4973 * the offset to translate in x 4974 * @param y 4975 * the offset to translate in y 4976 * @param z 4977 * the offset to translate in z 4978 * @param dest 4979 * will hold the result 4980 * @return dest 4981 */ 4982 public Matrix4d translateLocal(double x, double y, double z, ref Matrix4d dest) { 4983 if ((properties & PROPERTY_IDENTITY) != 0) 4984 return dest.translation(x, y, z); 4985 return translateLocalGeneric(x, y, z, dest); 4986 } 4987 private Matrix4d translateLocalGeneric(double x, double y, double z, ref Matrix4d dest) { 4988 double nm00 = m00 + x * m03; 4989 double nm01 = m01 + y * m03; 4990 double nm02 = m02 + z * m03; 4991 double nm10 = m10 + x * m13; 4992 double nm11 = m11 + y * m13; 4993 double nm12 = m12 + z * m13; 4994 double nm20 = m20 + x * m23; 4995 double nm21 = m21 + y * m23; 4996 double nm22 = m22 + z * m23; 4997 double nm30 = m30 + x * m33; 4998 double nm31 = m31 + y * m33; 4999 double nm32 = m32 + z * m33; 5000 return dest 5001 ._m00(nm00) 5002 ._m01(nm01) 5003 ._m02(nm02) 5004 ._m03(m03) 5005 ._m10(nm10) 5006 ._m11(nm11) 5007 ._m12(nm12) 5008 ._m13(m13) 5009 ._m20(nm20) 5010 ._m21(nm21) 5011 ._m22(nm22) 5012 ._m23(m23) 5013 ._m30(nm30) 5014 ._m31(nm31) 5015 ._m32(nm32) 5016 ._m33(m33) 5017 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY)); 5018 } 5019 5020 /** 5021 * Pre-multiply a translation to this matrix by translating by the given number of 5022 * units in x, y and z. 5023 * <p> 5024 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 5025 * matrix, then the new matrix will be <code>T * M</code>. So when 5026 * transforming a vector <code>v</code> with the new matrix by using 5027 * <code>T * M * v</code>, the translation will be applied last! 5028 * <p> 5029 * In order to set the matrix to a translation transformation without pre-multiplying 5030 * it, use {@link #translation(double, double, double)}. 5031 * 5032 * @see #translation(double, double, double) 5033 * 5034 * @param x 5035 * the offset to translate in x 5036 * @param y 5037 * the offset to translate in y 5038 * @param z 5039 * the offset to translate in z 5040 * @return this 5041 */ 5042 ref public Matrix4d translateLocal(double x, double y, double z) return { 5043 translateLocal(x, y, z, this); 5044 return this; 5045 } 5046 5047 /** 5048 * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians 5049 * about the X axis and store the result in <code>dest</code>. 5050 * <p> 5051 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5052 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5053 * When used with a left-handed coordinate system, the rotation is clockwise. 5054 * <p> 5055 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5056 * then the new matrix will be <code>R * M</code>. So when transforming a 5057 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5058 * rotation will be applied last! 5059 * <p> 5060 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5061 * transformation, use {@link #rotationX(double) rotationX()}. 5062 * <p> 5063 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5064 * 5065 * @see #rotationX(double) 5066 * 5067 * @param ang 5068 * the angle in radians to rotate about the X axis 5069 * @param dest 5070 * will hold the result 5071 * @return dest 5072 */ 5073 public Matrix4d rotateLocalX(double ang, ref Matrix4d dest) { 5074 double sin = Math.sin(ang); 5075 double cos = Math.cosFromSin(sin, ang); 5076 double nm02 = sin * m01 + cos * m02; 5077 double nm12 = sin * m11 + cos * m12; 5078 double nm22 = sin * m21 + cos * m22; 5079 double nm32 = sin * m31 + cos * m32; 5080 dest 5081 ._m00(m00) 5082 ._m01(cos * m01 - sin * m02) 5083 ._m02(nm02) 5084 ._m03(m03) 5085 ._m10(m10) 5086 ._m11(cos * m11 - sin * m12) 5087 ._m12(nm12) 5088 ._m13(m13) 5089 ._m20(m20) 5090 ._m21(cos * m21 - sin * m22) 5091 ._m22(nm22) 5092 ._m23(m23) 5093 ._m30(m30) 5094 ._m31(cos * m31 - sin * m32) 5095 ._m32(nm32) 5096 ._m33(m33) 5097 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5098 return dest; 5099 } 5100 5101 /** 5102 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis. 5103 * <p> 5104 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5105 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5106 * When used with a left-handed coordinate system, the rotation is clockwise. 5107 * <p> 5108 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5109 * then the new matrix will be <code>R * M</code>. So when transforming a 5110 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5111 * rotation will be applied last! 5112 * <p> 5113 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5114 * transformation, use {@link #rotationX(double) rotationX()}. 5115 * <p> 5116 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5117 * 5118 * @see #rotationX(double) 5119 * 5120 * @param ang 5121 * the angle in radians to rotate about the X axis 5122 * @return this 5123 */ 5124 ref public Matrix4d rotateLocalX(double ang) return { 5125 rotateLocalX(ang, this); 5126 return this; 5127 } 5128 5129 /** 5130 * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians 5131 * about the Y axis and store the result in <code>dest</code>. 5132 * <p> 5133 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5134 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5135 * When used with a left-handed coordinate system, the rotation is clockwise. 5136 * <p> 5137 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5138 * then the new matrix will be <code>R * M</code>. So when transforming a 5139 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5140 * rotation will be applied last! 5141 * <p> 5142 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5143 * transformation, use {@link #rotationY(double) rotationY()}. 5144 * <p> 5145 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5146 * 5147 * @see #rotationY(double) 5148 * 5149 * @param ang 5150 * the angle in radians to rotate about the Y axis 5151 * @param dest 5152 * will hold the result 5153 * @return dest 5154 */ 5155 public Matrix4d rotateLocalY(double ang, ref Matrix4d dest) { 5156 double sin = Math.sin(ang); 5157 double cos = Math.cosFromSin(sin, ang); 5158 double nm02 = -sin * m00 + cos * m02; 5159 double nm12 = -sin * m10 + cos * m12; 5160 double nm22 = -sin * m20 + cos * m22; 5161 double nm32 = -sin * m30 + cos * m32; 5162 dest 5163 ._m00(cos * m00 + sin * m02) 5164 ._m01(m01) 5165 ._m02(nm02) 5166 ._m03(m03) 5167 ._m10(cos * m10 + sin * m12) 5168 ._m11(m11) 5169 ._m12(nm12) 5170 ._m13(m13) 5171 ._m20(cos * m20 + sin * m22) 5172 ._m21(m21) 5173 ._m22(nm22) 5174 ._m23(m23) 5175 ._m30(cos * m30 + sin * m32) 5176 ._m31(m31) 5177 ._m32(nm32) 5178 ._m33(m33) 5179 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5180 return dest; 5181 } 5182 5183 /** 5184 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis. 5185 * <p> 5186 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5187 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5188 * When used with a left-handed coordinate system, the rotation is clockwise. 5189 * <p> 5190 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5191 * then the new matrix will be <code>R * M</code>. So when transforming a 5192 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5193 * rotation will be applied last! 5194 * <p> 5195 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5196 * transformation, use {@link #rotationY(double) rotationY()}. 5197 * <p> 5198 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5199 * 5200 * @see #rotationY(double) 5201 * 5202 * @param ang 5203 * the angle in radians to rotate about the Y axis 5204 * @return this 5205 */ 5206 ref public Matrix4d rotateLocalY(double ang) return { 5207 rotateLocalY(ang, this); 5208 return this; 5209 } 5210 5211 /** 5212 * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians 5213 * about the Z axis and store the result in <code>dest</code>. 5214 * <p> 5215 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5216 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5217 * When used with a left-handed coordinate system, the rotation is clockwise. 5218 * <p> 5219 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5220 * then the new matrix will be <code>R * M</code>. So when transforming a 5221 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5222 * rotation will be applied last! 5223 * <p> 5224 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5225 * transformation, use {@link #rotationZ(double) rotationZ()}. 5226 * <p> 5227 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5228 * 5229 * @see #rotationZ(double) 5230 * 5231 * @param ang 5232 * the angle in radians to rotate about the Z axis 5233 * @param dest 5234 * will hold the result 5235 * @return dest 5236 */ 5237 public Matrix4d rotateLocalZ(double ang, ref Matrix4d dest) { 5238 double sin = Math.sin(ang); 5239 double cos = Math.cosFromSin(sin, ang); 5240 double nm01 = sin * m00 + cos * m01; 5241 double nm11 = sin * m10 + cos * m11; 5242 double nm21 = sin * m20 + cos * m21; 5243 double nm31 = sin * m30 + cos * m31; 5244 dest 5245 ._m00(cos * m00 - sin * m01) 5246 ._m01(nm01) 5247 ._m02(m02) 5248 ._m03(m03) 5249 ._m10(cos * m10 - sin * m11) 5250 ._m11(nm11) 5251 ._m12(m12) 5252 ._m13(m13) 5253 ._m20(cos * m20 - sin * m21) 5254 ._m21(nm21) 5255 ._m22(m22) 5256 ._m23(m23) 5257 ._m30(cos * m30 - sin * m31) 5258 ._m31(nm31) 5259 ._m32(m32) 5260 ._m33(m33) 5261 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5262 return dest; 5263 } 5264 5265 /** 5266 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis. 5267 * <p> 5268 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5269 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5270 * When used with a left-handed coordinate system, the rotation is clockwise. 5271 * <p> 5272 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5273 * then the new matrix will be <code>R * M</code>. So when transforming a 5274 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5275 * rotation will be applied last! 5276 * <p> 5277 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5278 * transformation, use {@link #rotationZ(double) rotationY()}. 5279 * <p> 5280 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5281 * 5282 * @see #rotationY(double) 5283 * 5284 * @param ang 5285 * the angle in radians to rotate about the Z axis 5286 * @return this 5287 */ 5288 ref public Matrix4d rotateLocalZ(double ang) return { 5289 rotateLocalZ(ang, this); 5290 return this; 5291 } 5292 5293 public Matrix4d rotateX(double ang, ref Matrix4d dest) { 5294 if ((properties & PROPERTY_IDENTITY) != 0) 5295 return dest.rotationX(ang); 5296 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5297 double x = m30, y = m31, z = m32; 5298 return dest.rotationX(ang).setTranslation(x, y, z); 5299 } 5300 return rotateXInternal(ang, dest); 5301 } 5302 private Matrix4d rotateXInternal(double ang, ref Matrix4d dest) { 5303 double sin, cos; 5304 sin = Math.sin(ang); 5305 cos = Math.cosFromSin(sin, ang); 5306 double rm11 = cos; 5307 double rm12 = sin; 5308 double rm21 = -sin; 5309 double rm22 = cos; 5310 5311 // add temporaries for dependent values 5312 double nm10 = m10 * rm11 + m20 * rm12; 5313 double nm11 = m11 * rm11 + m21 * rm12; 5314 double nm12 = m12 * rm11 + m22 * rm12; 5315 double nm13 = m13 * rm11 + m23 * rm12; 5316 // set non-dependent values directly 5317 dest._m20(m10 * rm21 + m20 * rm22) 5318 ._m21(m11 * rm21 + m21 * rm22) 5319 ._m22(m12 * rm21 + m22 * rm22) 5320 ._m23(m13 * rm21 + m23 * rm22) 5321 // set other values 5322 ._m10(nm10) 5323 ._m11(nm11) 5324 ._m12(nm12) 5325 ._m13(nm13) 5326 ._m00(m00) 5327 ._m01(m01) 5328 ._m02(m02) 5329 ._m03(m03) 5330 ._m30(m30) 5331 ._m31(m31) 5332 ._m32(m32) 5333 ._m33(m33) 5334 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5335 return dest; 5336 } 5337 5338 /** 5339 * Apply rotation about the X axis to this matrix by rotating the given amount of radians. 5340 * <p> 5341 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5342 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5343 * When used with a left-handed coordinate system, the rotation is clockwise. 5344 * <p> 5345 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5346 * then the new matrix will be <code>M * R</code>. So when transforming a 5347 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5348 * rotation will be applied first! 5349 * <p> 5350 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5351 * 5352 * @param ang 5353 * the angle in radians 5354 * @return this 5355 */ 5356 ref public Matrix4d rotateX(double ang) return { 5357 rotateX(ang, this); 5358 return this; 5359 } 5360 5361 public Matrix4d rotateY(double ang, ref Matrix4d dest) { 5362 if ((properties & PROPERTY_IDENTITY) != 0) 5363 return dest.rotationY(ang); 5364 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5365 double x = m30, y = m31, z = m32; 5366 return dest.rotationY(ang).setTranslation(x, y, z); 5367 } 5368 return rotateYInternal(ang, dest); 5369 } 5370 private Matrix4d rotateYInternal(double ang, ref Matrix4d dest) { 5371 double sin, cos; 5372 sin = Math.sin(ang); 5373 cos = Math.cosFromSin(sin, ang); 5374 double rm00 = cos; 5375 double rm02 = -sin; 5376 double rm20 = sin; 5377 double rm22 = cos; 5378 5379 // add temporaries for dependent values 5380 double nm00 = m00 * rm00 + m20 * rm02; 5381 double nm01 = m01 * rm00 + m21 * rm02; 5382 double nm02 = m02 * rm00 + m22 * rm02; 5383 double nm03 = m03 * rm00 + m23 * rm02; 5384 // set non-dependent values directly 5385 dest._m20(m00 * rm20 + m20 * rm22) 5386 ._m21(m01 * rm20 + m21 * rm22) 5387 ._m22(m02 * rm20 + m22 * rm22) 5388 ._m23(m03 * rm20 + m23 * rm22) 5389 // set other values 5390 ._m00(nm00) 5391 ._m01(nm01) 5392 ._m02(nm02) 5393 ._m03(nm03) 5394 ._m10(m10) 5395 ._m11(m11) 5396 ._m12(m12) 5397 ._m13(m13) 5398 ._m30(m30) 5399 ._m31(m31) 5400 ._m32(m32) 5401 ._m33(m33) 5402 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5403 return dest; 5404 } 5405 5406 /** 5407 * Apply rotation about the Y axis to this matrix by rotating the given amount of radians. 5408 * <p> 5409 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5410 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5411 * When used with a left-handed coordinate system, the rotation is clockwise. 5412 * <p> 5413 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5414 * then the new matrix will be <code>M * R</code>. So when transforming a 5415 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5416 * rotation will be applied first! 5417 * <p> 5418 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5419 * 5420 * @param ang 5421 * the angle in radians 5422 * @return this 5423 */ 5424 ref public Matrix4d rotateY(double ang) return { 5425 rotateY(ang, this); 5426 return this; 5427 } 5428 5429 public Matrix4d rotateZ(double ang, ref Matrix4d dest) { 5430 if ((properties & PROPERTY_IDENTITY) != 0) 5431 return dest.rotationZ(ang); 5432 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5433 double x = m30, y = m31, z = m32; 5434 return dest.rotationZ(ang).setTranslation(x, y, z); 5435 } 5436 return rotateZInternal(ang, dest); 5437 } 5438 private Matrix4d rotateZInternal(double ang, ref Matrix4d dest) { 5439 double sin = Math.sin(ang); 5440 double cos = Math.cosFromSin(sin, ang); 5441 return rotateTowardsXY(sin, cos, dest); 5442 } 5443 5444 /** 5445 * Apply rotation about the Z axis to this matrix by rotating the given amount of radians. 5446 * <p> 5447 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5448 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5449 * When used with a left-handed coordinate system, the rotation is clockwise. 5450 * <p> 5451 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5452 * then the new matrix will be <code>M * R</code>. So when transforming a 5453 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5454 * rotation will be applied first! 5455 * <p> 5456 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5457 * 5458 * @param ang 5459 * the angle in radians 5460 * @return this 5461 */ 5462 ref public Matrix4d rotateZ(double ang) return { 5463 rotateZ(ang, this); 5464 return this; 5465 } 5466 5467 /** 5468 * Apply rotation about the Z axis to align the local <code>+X</code> towards <code>(dirX, dirY)</code>. 5469 * <p> 5470 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5471 * then the new matrix will be <code>M * R</code>. So when transforming a 5472 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5473 * rotation will be applied first! 5474 * <p> 5475 * The vector <code>(dirX, dirY)</code> must be a unit vector. 5476 * 5477 * @param dirX 5478 * the x component of the normalized direction 5479 * @param dirY 5480 * the y component of the normalized direction 5481 * @return this 5482 */ 5483 ref public Matrix4d rotateTowardsXY(double dirX, double dirY) return { 5484 rotateTowardsXY(dirX, dirY, this); 5485 return this; 5486 } 5487 5488 public Matrix4d rotateTowardsXY(double dirX, double dirY, ref Matrix4d dest) { 5489 if ((properties & PROPERTY_IDENTITY) != 0) 5490 return dest.rotationTowardsXY(dirX, dirY); 5491 double rm00 = dirY; 5492 double rm01 = dirX; 5493 double rm10 = -dirX; 5494 double rm11 = dirY; 5495 double nm00 = m00 * rm00 + m10 * rm01; 5496 double nm01 = m01 * rm00 + m11 * rm01; 5497 double nm02 = m02 * rm00 + m12 * rm01; 5498 double nm03 = m03 * rm00 + m13 * rm01; 5499 dest._m10(m00 * rm10 + m10 * rm11) 5500 ._m11(m01 * rm10 + m11 * rm11) 5501 ._m12(m02 * rm10 + m12 * rm11) 5502 ._m13(m03 * rm10 + m13 * rm11) 5503 ._m00(nm00) 5504 ._m01(nm01) 5505 ._m02(nm02) 5506 ._m03(nm03) 5507 ._m20(m20) 5508 ._m21(m21) 5509 ._m22(m22) 5510 ._m23(m23) 5511 ._m30(m30) 5512 ._m31(m31) 5513 ._m32(m32) 5514 ._m33(m33) 5515 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5516 return dest; 5517 } 5518 5519 /** 5520 * Apply rotation of <code>angles.x</code> radians about the X axis, followed by a rotation of <code>angles.y</code> radians about the Y axis and 5521 * followed by a rotation of <code>angles.z</code> radians about the Z axis. 5522 * <p> 5523 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5524 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5525 * When used with a left-handed coordinate system, the rotation is clockwise. 5526 * <p> 5527 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5528 * then the new matrix will be <code>M * R</code>. So when transforming a 5529 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5530 * rotation will be applied first! 5531 * <p> 5532 * This method is equivalent to calling: <code>rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)</code> 5533 * 5534 * @param angles 5535 * the Euler angles 5536 * @return this 5537 */ 5538 ref public Matrix4d rotateXYZ(ref Vector3d angles) return { 5539 return rotateXYZ(angles.x, angles.y, angles.z); 5540 } 5541 5542 /** 5543 * Apply rotation of <code>angleX</code> radians about the X axis, followed by a rotation of <code>angleY</code> radians about the Y axis and 5544 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5545 * <p> 5546 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5547 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5548 * When used with a left-handed coordinate system, the rotation is clockwise. 5549 * <p> 5550 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5551 * then the new matrix will be <code>M * R</code>. So when transforming a 5552 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5553 * rotation will be applied first! 5554 * <p> 5555 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 5556 * 5557 * @param angleX 5558 * the angle to rotate about X 5559 * @param angleY 5560 * the angle to rotate about Y 5561 * @param angleZ 5562 * the angle to rotate about Z 5563 * @return this 5564 */ 5565 ref public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ) return { 5566 rotateXYZ(angleX, angleY, angleZ, this); 5567 return this; 5568 } 5569 5570 public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5571 if ((properties & PROPERTY_IDENTITY) != 0) 5572 return dest.rotationXYZ(angleX, angleY, angleZ); 5573 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5574 double tx = m30, ty = m31, tz = m32; 5575 return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz); 5576 } else if ((properties & PROPERTY_AFFINE) != 0) 5577 return dest.rotateAffineXYZ(angleX, angleY, angleZ); 5578 return rotateXYZInternal(angleX, angleY, angleZ, dest); 5579 } 5580 private Matrix4d rotateXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5581 double sinX = Math.sin(angleX); 5582 double cosX = Math.cosFromSin(sinX, angleX); 5583 double sinY = Math.sin(angleY); 5584 double cosY = Math.cosFromSin(sinY, angleY); 5585 double sinZ = Math.sin(angleZ); 5586 double cosZ = Math.cosFromSin(sinZ, angleZ); 5587 double m_sinX = -sinX; 5588 double m_sinY = -sinY; 5589 double m_sinZ = -sinZ; 5590 5591 // rotateX 5592 double nm10 = m10 * cosX + m20 * sinX; 5593 double nm11 = m11 * cosX + m21 * sinX; 5594 double nm12 = m12 * cosX + m22 * sinX; 5595 double nm13 = m13 * cosX + m23 * sinX; 5596 double nm20 = m10 * m_sinX + m20 * cosX; 5597 double nm21 = m11 * m_sinX + m21 * cosX; 5598 double nm22 = m12 * m_sinX + m22 * cosX; 5599 double nm23 = m13 * m_sinX + m23 * cosX; 5600 // rotateY 5601 double nm00 = m00 * cosY + nm20 * m_sinY; 5602 double nm01 = m01 * cosY + nm21 * m_sinY; 5603 double nm02 = m02 * cosY + nm22 * m_sinY; 5604 double nm03 = m03 * cosY + nm23 * m_sinY; 5605 dest._m20(m00 * sinY + nm20 * cosY) 5606 ._m21(m01 * sinY + nm21 * cosY) 5607 ._m22(m02 * sinY + nm22 * cosY) 5608 ._m23(m03 * sinY + nm23 * cosY) 5609 // rotateZ 5610 ._m00(nm00 * cosZ + nm10 * sinZ) 5611 ._m01(nm01 * cosZ + nm11 * sinZ) 5612 ._m02(nm02 * cosZ + nm12 * sinZ) 5613 ._m03(nm03 * cosZ + nm13 * sinZ) 5614 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5615 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5616 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5617 ._m13(nm03 * m_sinZ + nm13 * cosZ) 5618 // copy last column from 'this' 5619 ._m30(m30) 5620 ._m31(m31) 5621 ._m32(m32) 5622 ._m33(m33) 5623 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5624 return dest; 5625 } 5626 5627 /** 5628 * Apply rotation of <code>angleX</code> radians about the X axis, followed by a rotation of <code>angleY</code> radians about the Y axis and 5629 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5630 * <p> 5631 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5632 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5633 * When used with a left-handed coordinate system, the rotation is clockwise. 5634 * <p> 5635 * This method assumes that <code>this</code> matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to <code>(0, 0, 0, 1)</code>) 5636 * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination). 5637 * <p> 5638 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5639 * then the new matrix will be <code>M * R</code>. So when transforming a 5640 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5641 * rotation will be applied first! 5642 * <p> 5643 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 5644 * 5645 * @param angleX 5646 * the angle to rotate about X 5647 * @param angleY 5648 * the angle to rotate about Y 5649 * @param angleZ 5650 * the angle to rotate about Z 5651 * @return this 5652 */ 5653 ref public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ) return { 5654 rotateAffineXYZ(angleX, angleY, angleZ, this); 5655 return this; 5656 } 5657 5658 public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5659 if ((properties & PROPERTY_IDENTITY) != 0) 5660 return dest.rotationXYZ(angleX, angleY, angleZ); 5661 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5662 double tx = m30, ty = m31, tz = m32; 5663 return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz); 5664 } 5665 return rotateAffineXYZInternal(angleX, angleY, angleZ, dest); 5666 } 5667 private Matrix4d rotateAffineXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5668 double sinX = Math.sin(angleX); 5669 double cosX = Math.cosFromSin(sinX, angleX); 5670 double sinY = Math.sin(angleY); 5671 double cosY = Math.cosFromSin(sinY, angleY); 5672 double sinZ = Math.sin(angleZ); 5673 double cosZ = Math.cosFromSin(sinZ, angleZ); 5674 double m_sinX = -sinX; 5675 double m_sinY = -sinY; 5676 double m_sinZ = -sinZ; 5677 5678 // rotateX 5679 double nm10 = m10 * cosX + m20 * sinX; 5680 double nm11 = m11 * cosX + m21 * sinX; 5681 double nm12 = m12 * cosX + m22 * sinX; 5682 double nm20 = m10 * m_sinX + m20 * cosX; 5683 double nm21 = m11 * m_sinX + m21 * cosX; 5684 double nm22 = m12 * m_sinX + m22 * cosX; 5685 // rotateY 5686 double nm00 = m00 * cosY + nm20 * m_sinY; 5687 double nm01 = m01 * cosY + nm21 * m_sinY; 5688 double nm02 = m02 * cosY + nm22 * m_sinY; 5689 dest._m20(m00 * sinY + nm20 * cosY) 5690 ._m21(m01 * sinY + nm21 * cosY) 5691 ._m22(m02 * sinY + nm22 * cosY) 5692 ._m23(0.0) 5693 // rotateZ 5694 ._m00(nm00 * cosZ + nm10 * sinZ) 5695 ._m01(nm01 * cosZ + nm11 * sinZ) 5696 ._m02(nm02 * cosZ + nm12 * sinZ) 5697 ._m03(0.0) 5698 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5699 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5700 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5701 ._m13(0.0) 5702 // copy last column from 'this' 5703 ._m30(m30) 5704 ._m31(m31) 5705 ._m32(m32) 5706 ._m33(m33) 5707 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5708 return dest; 5709 } 5710 5711 /** 5712 * Apply rotation of <code>angles.z</code> radians about the Z axis, followed by a rotation of <code>angles.y</code> radians about the Y axis and 5713 * followed by a rotation of <code>angles.x</code> radians about the X axis. 5714 * <p> 5715 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5716 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5717 * When used with a left-handed coordinate system, the rotation is clockwise. 5718 * <p> 5719 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5720 * then the new matrix will be <code>M * R</code>. So when transforming a 5721 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5722 * rotation will be applied first! 5723 * <p> 5724 * This method is equivalent to calling: <code>rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)</code> 5725 * 5726 * @param angles 5727 * the Euler angles 5728 * @return this 5729 */ 5730 ref public Matrix4d rotateZYX(ref Vector3d angles) return { 5731 return rotateZYX(angles.z, angles.y, angles.x); 5732 } 5733 5734 /** 5735 * Apply rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation of <code>angleY</code> radians about the Y axis and 5736 * followed by a rotation of <code>angleX</code> radians about the X axis. 5737 * <p> 5738 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5739 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5740 * When used with a left-handed coordinate system, the rotation is clockwise. 5741 * <p> 5742 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5743 * then the new matrix will be <code>M * R</code>. So when transforming a 5744 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5745 * rotation will be applied first! 5746 * <p> 5747 * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 5748 * 5749 * @param angleZ 5750 * the angle to rotate about Z 5751 * @param angleY 5752 * the angle to rotate about Y 5753 * @param angleX 5754 * the angle to rotate about X 5755 * @return this 5756 */ 5757 ref public Matrix4d rotateZYX(double angleZ, double angleY, double angleX) return { 5758 rotateZYX(angleZ, angleY, angleX, this); 5759 return this; 5760 } 5761 5762 public Matrix4d rotateZYX(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5763 if ((properties & PROPERTY_IDENTITY) != 0) 5764 return dest.rotationZYX(angleZ, angleY, angleX); 5765 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5766 double tx = m30, ty = m31, tz = m32; 5767 return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz); 5768 } else if ((properties & PROPERTY_AFFINE) != 0) 5769 return dest.rotateAffineZYX(angleZ, angleY, angleX); 5770 return rotateZYXInternal(angleZ, angleY, angleX, dest); 5771 } 5772 private Matrix4d rotateZYXInternal(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5773 double sinX = Math.sin(angleX); 5774 double cosX = Math.cosFromSin(sinX, angleX); 5775 double sinY = Math.sin(angleY); 5776 double cosY = Math.cosFromSin(sinY, angleY); 5777 double sinZ = Math.sin(angleZ); 5778 double cosZ = Math.cosFromSin(sinZ, angleZ); 5779 double m_sinZ = -sinZ; 5780 double m_sinY = -sinY; 5781 double m_sinX = -sinX; 5782 5783 // rotateZ 5784 double nm00 = m00 * cosZ + m10 * sinZ; 5785 double nm01 = m01 * cosZ + m11 * sinZ; 5786 double nm02 = m02 * cosZ + m12 * sinZ; 5787 double nm03 = m03 * cosZ + m13 * sinZ; 5788 double nm10 = m00 * m_sinZ + m10 * cosZ; 5789 double nm11 = m01 * m_sinZ + m11 * cosZ; 5790 double nm12 = m02 * m_sinZ + m12 * cosZ; 5791 double nm13 = m03 * m_sinZ + m13 * cosZ; 5792 // rotateY 5793 double nm20 = nm00 * sinY + m20 * cosY; 5794 double nm21 = nm01 * sinY + m21 * cosY; 5795 double nm22 = nm02 * sinY + m22 * cosY; 5796 double nm23 = nm03 * sinY + m23 * cosY; 5797 dest._m00(nm00 * cosY + m20 * m_sinY) 5798 ._m01(nm01 * cosY + m21 * m_sinY) 5799 ._m02(nm02 * cosY + m22 * m_sinY) 5800 ._m03(nm03 * cosY + m23 * m_sinY) 5801 // rotateX 5802 ._m10(nm10 * cosX + nm20 * sinX) 5803 ._m11(nm11 * cosX + nm21 * sinX) 5804 ._m12(nm12 * cosX + nm22 * sinX) 5805 ._m13(nm13 * cosX + nm23 * sinX) 5806 ._m20(nm10 * m_sinX + nm20 * cosX) 5807 ._m21(nm11 * m_sinX + nm21 * cosX) 5808 ._m22(nm12 * m_sinX + nm22 * cosX) 5809 ._m23(nm13 * m_sinX + nm23 * cosX) 5810 // copy last column from 'this' 5811 ._m30(m30) 5812 ._m31(m31) 5813 ._m32(m32) 5814 ._m33(m33) 5815 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5816 return dest; 5817 } 5818 5819 /** 5820 * Apply rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation of <code>angleY</code> radians about the Y axis and 5821 * followed by a rotation of <code>angleX</code> radians about the X axis. 5822 * <p> 5823 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5824 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5825 * When used with a left-handed coordinate system, the rotation is clockwise. 5826 * <p> 5827 * This method assumes that <code>this</code> matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to <code>(0, 0, 0, 1)</code>) 5828 * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination). 5829 * <p> 5830 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5831 * then the new matrix will be <code>M * R</code>. So when transforming a 5832 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5833 * rotation will be applied first! 5834 * 5835 * @param angleZ 5836 * the angle to rotate about Z 5837 * @param angleY 5838 * the angle to rotate about Y 5839 * @param angleX 5840 * the angle to rotate about X 5841 * @return this 5842 */ 5843 ref public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX) return { 5844 rotateAffineZYX(angleZ, angleY, angleX, this); 5845 return this; 5846 } 5847 5848 public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5849 double sinX = Math.sin(angleX); 5850 double cosX = Math.cosFromSin(sinX, angleX); 5851 double sinY = Math.sin(angleY); 5852 double cosY = Math.cosFromSin(sinY, angleY); 5853 double sinZ = Math.sin(angleZ); 5854 double cosZ = Math.cosFromSin(sinZ, angleZ); 5855 double m_sinZ = -sinZ; 5856 double m_sinY = -sinY; 5857 double m_sinX = -sinX; 5858 5859 // rotateZ 5860 double nm00 = m00 * cosZ + m10 * sinZ; 5861 double nm01 = m01 * cosZ + m11 * sinZ; 5862 double nm02 = m02 * cosZ + m12 * sinZ; 5863 double nm10 = m00 * m_sinZ + m10 * cosZ; 5864 double nm11 = m01 * m_sinZ + m11 * cosZ; 5865 double nm12 = m02 * m_sinZ + m12 * cosZ; 5866 // rotateY 5867 double nm20 = nm00 * sinY + m20 * cosY; 5868 double nm21 = nm01 * sinY + m21 * cosY; 5869 double nm22 = nm02 * sinY + m22 * cosY; 5870 dest._m00(nm00 * cosY + m20 * m_sinY) 5871 ._m01(nm01 * cosY + m21 * m_sinY) 5872 ._m02(nm02 * cosY + m22 * m_sinY) 5873 ._m03(0.0) 5874 // rotateX 5875 ._m10(nm10 * cosX + nm20 * sinX) 5876 ._m11(nm11 * cosX + nm21 * sinX) 5877 ._m12(nm12 * cosX + nm22 * sinX) 5878 ._m13(0.0) 5879 ._m20(nm10 * m_sinX + nm20 * cosX) 5880 ._m21(nm11 * m_sinX + nm21 * cosX) 5881 ._m22(nm12 * m_sinX + nm22 * cosX) 5882 ._m23(0.0) 5883 // copy last column from 'this' 5884 ._m30(m30) 5885 ._m31(m31) 5886 ._m32(m32) 5887 ._m33(m33) 5888 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5889 return dest; 5890 } 5891 5892 /** 5893 * Apply rotation of <code>angles.y</code> radians about the Y axis, followed by a rotation of <code>angles.x</code> radians about the X axis and 5894 * followed by a rotation of <code>angles.z</code> radians about the Z axis. 5895 * <p> 5896 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5897 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5898 * When used with a left-handed coordinate system, the rotation is clockwise. 5899 * <p> 5900 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5901 * then the new matrix will be <code>M * R</code>. So when transforming a 5902 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5903 * rotation will be applied first! 5904 * <p> 5905 * This method is equivalent to calling: <code>rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)</code> 5906 * 5907 * @param angles 5908 * the Euler angles 5909 * @return this 5910 */ 5911 ref public Matrix4d rotateYXZ(ref Vector3d angles) return { 5912 return rotateYXZ(angles.y, angles.x, angles.z); 5913 } 5914 5915 /** 5916 * Apply rotation of <code>angleY</code> radians about the Y axis, followed by a rotation of <code>angleX</code> radians about the X axis and 5917 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5918 * <p> 5919 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5920 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5921 * When used with a left-handed coordinate system, the rotation is clockwise. 5922 * <p> 5923 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5924 * then the new matrix will be <code>M * R</code>. So when transforming a 5925 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5926 * rotation will be applied first! 5927 * <p> 5928 * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 5929 * 5930 * @param angleY 5931 * the angle to rotate about Y 5932 * @param angleX 5933 * the angle to rotate about X 5934 * @param angleZ 5935 * the angle to rotate about Z 5936 * @return this 5937 */ 5938 ref public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ) return { 5939 rotateYXZ(angleY, angleX, angleZ, this); 5940 return this; 5941 } 5942 5943 public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5944 if ((properties & PROPERTY_IDENTITY) != 0) 5945 return dest.rotationYXZ(angleY, angleX, angleZ); 5946 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5947 double tx = m30, ty = m31, tz = m32; 5948 return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz); 5949 } else if ((properties & PROPERTY_AFFINE) != 0) 5950 return dest.rotateAffineYXZ(angleY, angleX, angleZ); 5951 return rotateYXZInternal(angleY, angleX, angleZ, dest); 5952 } 5953 private Matrix4d rotateYXZInternal(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5954 double sinX = Math.sin(angleX); 5955 double cosX = Math.cosFromSin(sinX, angleX); 5956 double sinY = Math.sin(angleY); 5957 double cosY = Math.cosFromSin(sinY, angleY); 5958 double sinZ = Math.sin(angleZ); 5959 double cosZ = Math.cosFromSin(sinZ, angleZ); 5960 double m_sinY = -sinY; 5961 double m_sinX = -sinX; 5962 double m_sinZ = -sinZ; 5963 5964 // rotateY 5965 double nm20 = m00 * sinY + m20 * cosY; 5966 double nm21 = m01 * sinY + m21 * cosY; 5967 double nm22 = m02 * sinY + m22 * cosY; 5968 double nm23 = m03 * sinY + m23 * cosY; 5969 double nm00 = m00 * cosY + m20 * m_sinY; 5970 double nm01 = m01 * cosY + m21 * m_sinY; 5971 double nm02 = m02 * cosY + m22 * m_sinY; 5972 double nm03 = m03 * cosY + m23 * m_sinY; 5973 // rotateX 5974 double nm10 = m10 * cosX + nm20 * sinX; 5975 double nm11 = m11 * cosX + nm21 * sinX; 5976 double nm12 = m12 * cosX + nm22 * sinX; 5977 double nm13 = m13 * cosX + nm23 * sinX; 5978 dest._m20(m10 * m_sinX + nm20 * cosX) 5979 ._m21(m11 * m_sinX + nm21 * cosX) 5980 ._m22(m12 * m_sinX + nm22 * cosX) 5981 ._m23(m13 * m_sinX + nm23 * cosX) 5982 // rotateZ 5983 ._m00(nm00 * cosZ + nm10 * sinZ) 5984 ._m01(nm01 * cosZ + nm11 * sinZ) 5985 ._m02(nm02 * cosZ + nm12 * sinZ) 5986 ._m03(nm03 * cosZ + nm13 * sinZ) 5987 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5988 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5989 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5990 ._m13(nm03 * m_sinZ + nm13 * cosZ) 5991 // copy last column from 'this' 5992 ._m30(m30) 5993 ._m31(m31) 5994 ._m32(m32) 5995 ._m33(m33) 5996 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5997 return dest; 5998 } 5999 6000 /** 6001 * Apply rotation of <code>angleY</code> radians about the Y axis, followed by a rotation of <code>angleX</code> radians about the X axis and 6002 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 6003 * <p> 6004 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6005 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6006 * When used with a left-handed coordinate system, the rotation is clockwise. 6007 * <p> 6008 * This method assumes that <code>this</code> matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to <code>(0, 0, 0, 1)</code>) 6009 * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination). 6010 * <p> 6011 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 6012 * then the new matrix will be <code>M * R</code>. So when transforming a 6013 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 6014 * rotation will be applied first! 6015 * 6016 * @param angleY 6017 * the angle to rotate about Y 6018 * @param angleX 6019 * the angle to rotate about X 6020 * @param angleZ 6021 * the angle to rotate about Z 6022 * @return this 6023 */ 6024 ref public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ) return { 6025 rotateAffineYXZ(angleY, angleX, angleZ, this); 6026 return this; 6027 } 6028 6029 public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 6030 double sinX = Math.sin(angleX); 6031 double cosX = Math.cosFromSin(sinX, angleX); 6032 double sinY = Math.sin(angleY); 6033 double cosY = Math.cosFromSin(sinY, angleY); 6034 double sinZ = Math.sin(angleZ); 6035 double cosZ = Math.cosFromSin(sinZ, angleZ); 6036 double m_sinY = -sinY; 6037 double m_sinX = -sinX; 6038 double m_sinZ = -sinZ; 6039 6040 // rotateY 6041 double nm20 = m00 * sinY + m20 * cosY; 6042 double nm21 = m01 * sinY + m21 * cosY; 6043 double nm22 = m02 * sinY + m22 * cosY; 6044 double nm00 = m00 * cosY + m20 * m_sinY; 6045 double nm01 = m01 * cosY + m21 * m_sinY; 6046 double nm02 = m02 * cosY + m22 * m_sinY; 6047 // rotateX 6048 double nm10 = m10 * cosX + nm20 * sinX; 6049 double nm11 = m11 * cosX + nm21 * sinX; 6050 double nm12 = m12 * cosX + nm22 * sinX; 6051 dest._m20(m10 * m_sinX + nm20 * cosX) 6052 ._m21(m11 * m_sinX + nm21 * cosX) 6053 ._m22(m12 * m_sinX + nm22 * cosX) 6054 ._m23(0.0) 6055 // rotateZ 6056 ._m00(nm00 * cosZ + nm10 * sinZ) 6057 ._m01(nm01 * cosZ + nm11 * sinZ) 6058 ._m02(nm02 * cosZ + nm12 * sinZ) 6059 ._m03(0.0) 6060 ._m10(nm00 * m_sinZ + nm10 * cosZ) 6061 ._m11(nm01 * m_sinZ + nm11 * cosZ) 6062 ._m12(nm02 * m_sinZ + nm12 * cosZ) 6063 ._m13(0.0) 6064 // copy last column from 'this' 6065 ._m30(m30) 6066 ._m31(m31) 6067 ._m32(m32) 6068 ._m33(m33) 6069 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6070 return dest; 6071 } 6072 6073 /** 6074 * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}. 6075 * <p> 6076 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6077 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6078 * When used with a left-handed coordinate system, the rotation is clockwise. 6079 * <p> 6080 * The resulting matrix can be multiplied against another transformation 6081 * matrix to obtain an additional rotation. 6082 * <p> 6083 * In order to apply the rotation transformation to an existing transformation, 6084 * use {@link #rotate(ref AxisAngle4d) rotate()} instead. 6085 * <p> 6086 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 6087 * 6088 * @see #rotate(ref AxisAngle4d) 6089 * 6090 * @param angleAxis 6091 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 6092 * @return this 6093 */ 6094 ref public Matrix4d rotation(ref AxisAngle4d angleAxis) return { 6095 return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z); 6096 } 6097 6098 /** 6099 * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniond}. 6100 * <p> 6101 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6102 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6103 * When used with a left-handed coordinate system, the rotation is clockwise. 6104 * <p> 6105 * The resulting matrix can be multiplied against another transformation 6106 * matrix to obtain an additional rotation. 6107 * <p> 6108 * In order to apply the rotation transformation to an existing transformation, 6109 * use {@link #rotate(ref Quaterniond) rotate()} instead. 6110 * <p> 6111 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6112 * 6113 * @see #rotate(ref Quaterniond) 6114 * 6115 * @param quat 6116 * the {@link Quaterniond} 6117 * @return this 6118 */ 6119 ref public Matrix4d rotation(ref Quaterniond quat) return { 6120 double w2 = quat.w * quat.w; 6121 double x2 = quat.x * quat.x; 6122 double y2 = quat.y * quat.y; 6123 double z2 = quat.z * quat.z; 6124 double zw = quat.z * quat.w, dzw = zw + zw; 6125 double xy = quat.x * quat.y, dxy = xy + xy; 6126 double xz = quat.x * quat.z, dxz = xz + xz; 6127 double yw = quat.y * quat.w, dyw = yw + yw; 6128 double yz = quat.y * quat.z, dyz = yz + yz; 6129 double xw = quat.x * quat.w, dxw = xw + xw; 6130 if ((properties & PROPERTY_IDENTITY) == 0) 6131 this._identity(); 6132 _m00(w2 + x2 - z2 - y2). 6133 _m01(dxy + dzw). 6134 _m02(dxz - dyw). 6135 _m10(-dzw + dxy). 6136 _m11(y2 - z2 + w2 - x2). 6137 _m12(dyz + dxw). 6138 _m20(dyw + dxz). 6139 _m21(dyz - dxw). 6140 _m22(z2 - y2 - x2 + w2). 6141 _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 6142 return this; 6143 } 6144 6145 6146 /** 6147 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>, 6148 * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, and <code>S</code> is a scaling transformation 6149 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>. 6150 * <p> 6151 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6152 * at last the translation. 6153 * <p> 6154 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6155 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6156 * When used with a left-handed coordinate system, the rotation is clockwise. 6157 * <p> 6158 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)</code> 6159 * 6160 * @see #translation(double, double, double) 6161 * @see #rotate(ref Quaterniond) 6162 * @see #scale(double, double, double) 6163 * 6164 * @param tx 6165 * the number of units by which to translate the x-component 6166 * @param ty 6167 * the number of units by which to translate the y-component 6168 * @param tz 6169 * the number of units by which to translate the z-component 6170 * @param qx 6171 * the x-coordinate of the vector part of the quaternion 6172 * @param qy 6173 * the y-coordinate of the vector part of the quaternion 6174 * @param qz 6175 * the z-coordinate of the vector part of the quaternion 6176 * @param qw 6177 * the scalar part of the quaternion 6178 * @param sx 6179 * the scaling factor for the x-axis 6180 * @param sy 6181 * the scaling factor for the y-axis 6182 * @param sz 6183 * the scaling factor for the z-axis 6184 * @return this 6185 */ 6186 ref public Matrix4d translationRotateScale(double tx, double ty, double tz, 6187 double qx, double qy, double qz, double qw, 6188 double sx, double sy, double sz) return { 6189 double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz; 6190 double q00 = dqx * qx; 6191 double q11 = dqy * qy; 6192 double q22 = dqz * qz; 6193 double q01 = dqx * qy; 6194 double q02 = dqx * qz; 6195 double q03 = dqx * qw; 6196 double q12 = dqy * qz; 6197 double q13 = dqy * qw; 6198 double q23 = dqz * qw; 6199 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6200 _m00(sx - (q11 + q22) * sx). 6201 _m01((q01 + q23) * sx). 6202 _m02((q02 - q13) * sx). 6203 _m03(0.0). 6204 _m10((q01 - q23) * sy). 6205 _m11(sy - (q22 + q00) * sy). 6206 _m12((q12 + q03) * sy). 6207 _m13(0.0). 6208 _m20((q02 + q13) * sz). 6209 _m21((q12 - q03) * sz). 6210 _m22(sz - (q11 + q00) * sz). 6211 _m23(0.0). 6212 _m30(tx). 6213 _m31(ty). 6214 _m32(tz). 6215 _m33(1.0). 6216 properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0); 6217 return this; 6218 } 6219 6220 /** 6221 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>, 6222 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6223 * which scales the axes by <code>scale</code>. 6224 * <p> 6225 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6226 * at last the translation. 6227 * <p> 6228 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6229 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6230 * When used with a left-handed coordinate system, the rotation is clockwise. 6231 * <p> 6232 * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code> 6233 * 6234 * @see #translation(ref Vector3d) 6235 * @see #rotate(ref Quaterniond) 6236 * @see #scale(ref Vector3d) 6237 * 6238 * @param translation 6239 * the translation 6240 * @param quat 6241 * the quaternion representing a rotation 6242 * @param scale 6243 * the scaling factors 6244 * @return this 6245 */ 6246 ref public Matrix4d translationRotateScale(ref Vector3d translation, 6247 Quaterniond quat, 6248 Vector3d scale) return { 6249 return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale.x, scale.y, scale.z); 6250 } 6251 6252 /** 6253 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>, 6254 * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, and <code>S</code> is a scaling transformation 6255 * which scales all three axes by <code>scale</code>. 6256 * <p> 6257 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6258 * at last the translation. 6259 * <p> 6260 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6261 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6262 * When used with a left-handed coordinate system, the rotation is clockwise. 6263 * <p> 6264 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(scale)</code> 6265 * 6266 * @see #translation(double, double, double) 6267 * @see #rotate(ref Quaterniond) 6268 * @see #scale(double) 6269 * 6270 * @param tx 6271 * the number of units by which to translate the x-component 6272 * @param ty 6273 * the number of units by which to translate the y-component 6274 * @param tz 6275 * the number of units by which to translate the z-component 6276 * @param qx 6277 * the x-coordinate of the vector part of the quaternion 6278 * @param qy 6279 * the y-coordinate of the vector part of the quaternion 6280 * @param qz 6281 * the z-coordinate of the vector part of the quaternion 6282 * @param qw 6283 * the scalar part of the quaternion 6284 * @param scale 6285 * the scaling factor for all three axes 6286 * @return this 6287 */ 6288 ref public Matrix4d translationRotateScale(double tx, double ty, double tz, 6289 double qx, double qy, double qz, double qw, 6290 double scale) return { 6291 return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, scale, scale, scale); 6292 } 6293 6294 /** 6295 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>, 6296 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6297 * which scales all three axes by <code>scale</code>. 6298 * <p> 6299 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6300 * at last the translation. 6301 * <p> 6302 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6303 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6304 * When used with a left-handed coordinate system, the rotation is clockwise. 6305 * <p> 6306 * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code> 6307 * 6308 * @see #translation(ref Vector3d) 6309 * @see #rotate(ref Quaterniond) 6310 * @see #scale(double) 6311 * 6312 * @param translation 6313 * the translation 6314 * @param quat 6315 * the quaternion representing a rotation 6316 * @param scale 6317 * the scaling factors 6318 * @return this 6319 */ 6320 ref public Matrix4d translationRotateScale(ref Vector3d translation, 6321 Quaterniond quat, 6322 double scale) return { 6323 return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale, scale, scale); 6324 } 6325 6326 6327 /** 6328 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>, 6329 * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, and <code>S</code> is a scaling transformation 6330 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>. 6331 * <p> 6332 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6333 * 6334 * @see #translationRotateScale(double, double, double, double, double, double, double, double, double, double) 6335 * @see #invert() 6336 * 6337 * @param tx 6338 * the number of units by which to translate the x-component 6339 * @param ty 6340 * the number of units by which to translate the y-component 6341 * @param tz 6342 * the number of units by which to translate the z-component 6343 * @param qx 6344 * the x-coordinate of the vector part of the quaternion 6345 * @param qy 6346 * the y-coordinate of the vector part of the quaternion 6347 * @param qz 6348 * the z-coordinate of the vector part of the quaternion 6349 * @param qw 6350 * the scalar part of the quaternion 6351 * @param sx 6352 * the scaling factor for the x-axis 6353 * @param sy 6354 * the scaling factor for the y-axis 6355 * @param sz 6356 * the scaling factor for the z-axis 6357 * @return this 6358 */ 6359 ref public Matrix4d translationRotateScaleInvert(double tx, double ty, double tz, 6360 double qx, double qy, double qz, double qw, 6361 double sx, double sy, double sz) return { 6362 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6363 if (one) 6364 return translationRotateInvert(tx, ty, tz, qx, qy, qz, qw); 6365 double nqx = -qx, nqy = -qy, nqz = -qz; 6366 double dqx = nqx + nqx; 6367 double dqy = nqy + nqy; 6368 double dqz = nqz + nqz; 6369 double q00 = dqx * nqx; 6370 double q11 = dqy * nqy; 6371 double q22 = dqz * nqz; 6372 double q01 = dqx * nqy; 6373 double q02 = dqx * nqz; 6374 double q03 = dqx * qw; 6375 double q12 = dqy * nqz; 6376 double q13 = dqy * qw; 6377 double q23 = dqz * qw; 6378 double isx = 1/sx, isy = 1/sy, isz = 1/sz; 6379 _m00(isx * (1.0 - q11 - q22)). 6380 _m01(isy * (q01 + q23)). 6381 _m02(isz * (q02 - q13)). 6382 _m03(0.0). 6383 _m10(isx * (q01 - q23)). 6384 _m11(isy * (1.0 - q22 - q00)). 6385 _m12(isz * (q12 + q03)). 6386 _m13(0.0). 6387 _m20(isx * (q02 + q13)). 6388 _m21(isy * (q12 - q03)). 6389 _m22(isz * (1.0 - q11 - q00)). 6390 _m23(0.0). 6391 _m30(-m00 * tx - m10 * ty - m20 * tz). 6392 _m31(-m01 * tx - m11 * ty - m21 * tz). 6393 _m32(-m02 * tx - m12 * ty - m22 * tz). 6394 _m33(1.0). 6395 properties = PROPERTY_AFFINE; 6396 return this; 6397 } 6398 6399 /** 6400 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code>, 6401 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6402 * which scales the axes by <code>scale</code>. 6403 * <p> 6404 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6405 * 6406 * @see #translationRotateScale(ref Vector3d, Quaterniond, Vector3d) 6407 * @see #invert() 6408 * 6409 * @param translation 6410 * the translation 6411 * @param quat 6412 * the quaternion representing a rotation 6413 * @param scale 6414 * the scaling factors 6415 * @return this 6416 */ 6417 ref public Matrix4d translationRotateScaleInvert(ref Vector3d translation, 6418 Quaterniond quat, 6419 Vector3d scale) return { 6420 return translationRotateScaleInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale.x, scale.y, scale.z); 6421 } 6422 6423 6424 /** 6425 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code>, 6426 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6427 * which scales all three axes by <code>scale</code>. 6428 * <p> 6429 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6430 * 6431 * @see #translationRotateScale(ref Vector3d, Quaterniond, double) 6432 * @see #invert() 6433 * 6434 * @param translation 6435 * the translation 6436 * @param quat 6437 * the quaternion representing a rotation 6438 * @param scale 6439 * the scaling factors 6440 * @return this 6441 */ 6442 ref public Matrix4d translationRotateScaleInvert(ref Vector3d translation, 6443 Quaterniond quat, 6444 double scale) return { 6445 return translationRotateScaleInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale, scale, scale); 6446 } 6447 6448 6449 /** 6450 * Set <code>this</code> matrix to <code>T * R * S * M</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>, 6451 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, <code>S</code> is a scaling transformation 6452 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code> and <code>M</code> is an {@link #isAffine() affine} matrix. 6453 * <p> 6454 * When transforming a vector by the resulting matrix the transformation described by <code>M</code> will be applied first, then the scaling, then rotation and 6455 * at last the translation. 6456 * <p> 6457 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6458 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6459 * When used with a left-handed coordinate system, the rotation is clockwise. 6460 * <p> 6461 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mulAffine(m)</code> 6462 * 6463 * @see #translation(double, double, double) 6464 * @see #rotate(ref Quaterniond) 6465 * @see #scale(double, double, double) 6466 * @see #mulAffine(Matrix4d) 6467 * 6468 * @param tx 6469 * the number of units by which to translate the x-component 6470 * @param ty 6471 * the number of units by which to translate the y-component 6472 * @param tz 6473 * the number of units by which to translate the z-component 6474 * @param qx 6475 * the x-coordinate of the vector part of the quaternion 6476 * @param qy 6477 * the y-coordinate of the vector part of the quaternion 6478 * @param qz 6479 * the z-coordinate of the vector part of the quaternion 6480 * @param qw 6481 * the scalar part of the quaternion 6482 * @param sx 6483 * the scaling factor for the x-axis 6484 * @param sy 6485 * the scaling factor for the y-axis 6486 * @param sz 6487 * the scaling factor for the z-axis 6488 * @param m 6489 * the {@link #isAffine() affine} matrix to multiply by 6490 * @return this 6491 */ 6492 ref public Matrix4d translationRotateScaleMulAffine(double tx, double ty, double tz, 6493 double qx, double qy, double qz, double qw, 6494 double sx, double sy, double sz, 6495 Matrix4d m) return { 6496 double w2 = qw * qw; 6497 double x2 = qx * qx; 6498 double y2 = qy * qy; 6499 double z2 = qz * qz; 6500 double zw = qz * qw; 6501 double xy = qx * qy; 6502 double xz = qx * qz; 6503 double yw = qy * qw; 6504 double yz = qy * qz; 6505 double xw = qx * qw; 6506 double nm00 = w2 + x2 - z2 - y2; 6507 double nm01 = xy + zw + zw + xy; 6508 double nm02 = xz - yw + xz - yw; 6509 double nm10 = -zw + xy - zw + xy; 6510 double nm11 = y2 - z2 + w2 - x2; 6511 double nm12 = yz + yz + xw + xw; 6512 double nm20 = yw + xz + xz + yw; 6513 double nm21 = yz + yz - xw - xw; 6514 double nm22 = z2 - y2 - x2 + w2; 6515 double m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02; 6516 double m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02; 6517 setm02(nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02); 6518 setm00(m00); 6519 setm01(m01); 6520 setm03(0.0); 6521 double m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12; 6522 double m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12; 6523 setm12(nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12); 6524 setm10(m10); 6525 setm11(m11); 6526 setm13(0.0); 6527 double m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22; 6528 double m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22; 6529 setm22(nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22); 6530 setm20(m20); 6531 setm21(m21); 6532 setm23(0.0); 6533 double m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx; 6534 double m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty; 6535 setm32(nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz); 6536 setm30(m30); 6537 setm31(m31); 6538 setm33(1.0); 6539 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6540 properties = PROPERTY_AFFINE | (one && (m.properties & PROPERTY_ORTHONORMAL) != 0 ? PROPERTY_ORTHONORMAL : 0); 6541 return this; 6542 } 6543 6544 6545 6546 /** 6547 * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code> and 6548 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>. 6549 * <p> 6550 * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation. 6551 * <p> 6552 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6553 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6554 * When used with a left-handed coordinate system, the rotation is clockwise. 6555 * <p> 6556 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code> 6557 * 6558 * @see #translation(double, double, double) 6559 * @see #rotate(ref Quaterniond) 6560 * 6561 * @param tx 6562 * the number of units by which to translate the x-component 6563 * @param ty 6564 * the number of units by which to translate the y-component 6565 * @param tz 6566 * the number of units by which to translate the z-component 6567 * @param qx 6568 * the x-coordinate of the vector part of the quaternion 6569 * @param qy 6570 * the y-coordinate of the vector part of the quaternion 6571 * @param qz 6572 * the z-coordinate of the vector part of the quaternion 6573 * @param qw 6574 * the scalar part of the quaternion 6575 * @return this 6576 */ 6577 ref public Matrix4d translationRotate(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return { 6578 double w2 = qw * qw; 6579 double x2 = qx * qx; 6580 double y2 = qy * qy; 6581 double z2 = qz * qz; 6582 double zw = qz * qw; 6583 double xy = qx * qy; 6584 double xz = qx * qz; 6585 double yw = qy * qw; 6586 double yz = qy * qz; 6587 double xw = qx * qw; 6588 setm00(w2 + x2 - z2 - y2); 6589 setm01(xy + zw + zw + xy); 6590 setm02(xz - yw + xz - yw); 6591 setm10(-zw + xy - zw + xy); 6592 setm11(y2 - z2 + w2 - x2); 6593 setm12(yz + yz + xw + xw); 6594 setm20(yw + xz + xz + yw); 6595 setm21(yz + yz - xw - xw); 6596 setm22(z2 - y2 - x2 + w2); 6597 setm30(tx); 6598 setm31(ty); 6599 setm32(tz); 6600 setm33(1.0); 6601 this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 6602 return this; 6603 } 6604 6605 /** 6606 * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code> and 6607 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the given quaternion. 6608 * <p> 6609 * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation. 6610 * <p> 6611 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6612 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6613 * When used with a left-handed coordinate system, the rotation is clockwise. 6614 * <p> 6615 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code> 6616 * 6617 * @see #translation(double, double, double) 6618 * @see #rotate(ref Quaterniond) 6619 * 6620 * @param tx 6621 * the number of units by which to translate the x-component 6622 * @param ty 6623 * the number of units by which to translate the y-component 6624 * @param tz 6625 * the number of units by which to translate the z-component 6626 * @param quat 6627 * the quaternion representing a rotation 6628 * @return this 6629 */ 6630 ref public Matrix4d translationRotate(double tx, double ty, double tz, Quaterniond quat) return { 6631 return translationRotate(tx, ty, tz, quat.x, quat.y, quat.z, quat.w); 6632 } 6633 6634 /** 6635 * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is the given <code>translation</code> and 6636 * <code>R</code> is a rotation transformation specified by the given quaternion. 6637 * <p> 6638 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6639 * at last the translation. 6640 * <p> 6641 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6642 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6643 * When used with a left-handed coordinate system, the rotation is clockwise. 6644 * <p> 6645 * This method is equivalent to calling: <code>translation(translation).rotate(quat)</code> 6646 * 6647 * @see #translation(ref Vector3d) 6648 * @see #rotate(ref Quaterniond) 6649 * 6650 * @param translation 6651 * the translation 6652 * @param quat 6653 * the quaternion representing a rotation 6654 * @return this 6655 */ 6656 ref public Matrix4d translationRotate(ref Vector3d translation, 6657 Quaterniond quat) return { 6658 return translationRotate(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w); 6659 } 6660 6661 /** 6662 * Set <code>this</code> matrix to <code>(T * R)<sup>-1</sup></code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code> and 6663 * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>. 6664 * <p> 6665 * This method is equivalent to calling: <code>translationRotate(...).invert()</code> 6666 * 6667 * @see #translationRotate(double, double, double, double, double, double, double) 6668 * @see #invert() 6669 * 6670 * @param tx 6671 * the number of units by which to translate the x-component 6672 * @param ty 6673 * the number of units by which to translate the y-component 6674 * @param tz 6675 * the number of units by which to translate the z-component 6676 * @param qx 6677 * the x-coordinate of the vector part of the quaternion 6678 * @param qy 6679 * the y-coordinate of the vector part of the quaternion 6680 * @param qz 6681 * the z-coordinate of the vector part of the quaternion 6682 * @param qw 6683 * the scalar part of the quaternion 6684 * @return this 6685 */ 6686 ref public Matrix4d translationRotateInvert(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return { 6687 double nqx = -qx, nqy = -qy, nqz = -qz; 6688 double dqx = nqx + nqx; 6689 double dqy = nqy + nqy; 6690 double dqz = nqz + nqz; 6691 double q00 = dqx * nqx; 6692 double q11 = dqy * nqy; 6693 double q22 = dqz * nqz; 6694 double q01 = dqx * nqy; 6695 double q02 = dqx * nqz; 6696 double q03 = dqx * qw; 6697 double q12 = dqy * nqz; 6698 double q13 = dqy * qw; 6699 double q23 = dqz * qw; 6700 return this 6701 ._m00(1.0 - q11 - q22) 6702 ._m01(q01 + q23) 6703 ._m02(q02 - q13) 6704 ._m03(0.0) 6705 ._m10(q01 - q23) 6706 ._m11(1.0 - q22 - q00) 6707 ._m12(q12 + q03) 6708 ._m13(0.0) 6709 ._m20(q02 + q13) 6710 ._m21(q12 - q03) 6711 ._m22(1.0 - q11 - q00) 6712 ._m23(0.0) 6713 ._m30(-m00 * tx - m10 * ty - m20 * tz) 6714 ._m31(-m01 * tx - m11 * ty - m21 * tz) 6715 ._m32(-m02 * tx - m12 * ty - m22 * tz) 6716 ._m33(1.0) 6717 ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 6718 } 6719 6720 6721 6722 /** 6723 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store 6724 * the result in <code>dest</code>. 6725 * <p> 6726 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6727 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6728 * When used with a left-handed coordinate system, the rotation is clockwise. 6729 * <p> 6730 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6731 * then the new matrix will be <code>M * Q</code>. So when transforming a 6732 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6733 * the quaternion rotation will be applied first! 6734 * <p> 6735 * In order to set the matrix to a rotation transformation without post-multiplying, 6736 * use {@link #rotation(ref Quaterniond)}. 6737 * <p> 6738 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6739 * 6740 * @see #rotation(ref Quaterniond) 6741 * 6742 * @param quat 6743 * the {@link Quaterniond} 6744 * @param dest 6745 * will hold the result 6746 * @return dest 6747 */ 6748 public Matrix4d rotate(ref Quaterniond quat, ref Matrix4d dest) { 6749 if ((properties & PROPERTY_IDENTITY) != 0) 6750 return dest.rotation(quat); 6751 else if ((properties & PROPERTY_TRANSLATION) != 0) 6752 return rotateTranslation(quat, dest); 6753 else if ((properties & PROPERTY_AFFINE) != 0) 6754 return rotateAffine(quat, dest); 6755 return rotateGeneric(quat, dest); 6756 } 6757 private Matrix4d rotateGeneric(ref Quaterniond quat, ref Matrix4d dest) { 6758 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6759 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6760 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6761 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6762 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6763 double rm00 = w2 + x2 - z2 - y2; 6764 double rm01 = dxy + dzw; 6765 double rm02 = dxz - dyw; 6766 double rm10 = -dzw + dxy; 6767 double rm11 = y2 - z2 + w2 - x2; 6768 double rm12 = dyz + dxw; 6769 double rm20 = dyw + dxz; 6770 double rm21 = dyz - dxw; 6771 double rm22 = z2 - y2 - x2 + w2; 6772 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 6773 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 6774 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 6775 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 6776 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 6777 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 6778 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 6779 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 6780 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 6781 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 6782 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 6783 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 6784 ._m00(nm00) 6785 ._m01(nm01) 6786 ._m02(nm02) 6787 ._m03(nm03) 6788 ._m10(nm10) 6789 ._m11(nm11) 6790 ._m12(nm12) 6791 ._m13(nm13) 6792 ._m30(m30) 6793 ._m31(m31) 6794 ._m32(m32) 6795 ._m33(m33) 6796 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6797 return dest; 6798 } 6799 6800 6801 /** 6802 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 6803 * <p> 6804 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6805 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6806 * When used with a left-handed coordinate system, the rotation is clockwise. 6807 * <p> 6808 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6809 * then the new matrix will be <code>M * Q</code>. So when transforming a 6810 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6811 * the quaternion rotation will be applied first! 6812 * <p> 6813 * In order to set the matrix to a rotation transformation without post-multiplying, 6814 * use {@link #rotation(ref Quaterniond)}. 6815 * <p> 6816 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6817 * 6818 * @see #rotation(ref Quaterniond) 6819 * 6820 * @param quat 6821 * the {@link Quaterniond} 6822 * @return this 6823 */ 6824 ref public Matrix4d rotate(ref Quaterniond quat) return { 6825 rotate(quat, this); 6826 return this; 6827 } 6828 6829 6830 /** 6831 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this {@link #isAffine() affine} matrix and store 6832 * the result in <code>dest</code>. 6833 * <p> 6834 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 6835 * <p> 6836 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6837 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6838 * When used with a left-handed coordinate system, the rotation is clockwise. 6839 * <p> 6840 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6841 * then the new matrix will be <code>M * Q</code>. So when transforming a 6842 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6843 * the quaternion rotation will be applied first! 6844 * <p> 6845 * In order to set the matrix to a rotation transformation without post-multiplying, 6846 * use {@link #rotation(ref Quaterniond)}. 6847 * <p> 6848 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6849 * 6850 * @see #rotation(ref Quaterniond) 6851 * 6852 * @param quat 6853 * the {@link Quaterniond} 6854 * @param dest 6855 * will hold the result 6856 * @return dest 6857 */ 6858 public Matrix4d rotateAffine(ref Quaterniond quat, ref Matrix4d dest) { 6859 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6860 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6861 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6862 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6863 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6864 double rm00 = w2 + x2 - z2 - y2; 6865 double rm01 = dxy + dzw; 6866 double rm02 = dxz - dyw; 6867 double rm10 = -dzw + dxy; 6868 double rm11 = y2 - z2 + w2 - x2; 6869 double rm12 = dyz + dxw; 6870 double rm20 = dyw + dxz; 6871 double rm21 = dyz - dxw; 6872 double rm22 = z2 - y2 - x2 + w2; 6873 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 6874 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 6875 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 6876 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 6877 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 6878 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 6879 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 6880 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 6881 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 6882 ._m23(0.0) 6883 ._m00(nm00) 6884 ._m01(nm01) 6885 ._m02(nm02) 6886 ._m03(0.0) 6887 ._m10(nm10) 6888 ._m11(nm11) 6889 ._m12(nm12) 6890 ._m13(0.0) 6891 ._m30(m30) 6892 ._m31(m31) 6893 ._m32(m32) 6894 ._m33(m33) 6895 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6896 return dest; 6897 } 6898 6899 /** 6900 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 6901 * <p> 6902 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 6903 * <p> 6904 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6905 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6906 * When used with a left-handed coordinate system, the rotation is clockwise. 6907 * <p> 6908 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6909 * then the new matrix will be <code>M * Q</code>. So when transforming a 6910 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6911 * the quaternion rotation will be applied first! 6912 * <p> 6913 * In order to set the matrix to a rotation transformation without post-multiplying, 6914 * use {@link #rotation(ref Quaterniond)}. 6915 * <p> 6916 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6917 * 6918 * @see #rotation(ref Quaterniond) 6919 * 6920 * @param quat 6921 * the {@link Quaterniond} 6922 * @return this 6923 */ 6924 ref public Matrix4d rotateAffine(ref Quaterniond quat) return { 6925 rotateAffine(quat, this); 6926 return this; 6927 } 6928 6929 /** 6930 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix, which is assumed to only contain a translation, and store 6931 * the result in <code>dest</code>. 6932 * <p> 6933 * This method assumes <code>this</code> to only contain a translation. 6934 * <p> 6935 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6936 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6937 * When used with a left-handed coordinate system, the rotation is clockwise. 6938 * <p> 6939 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6940 * then the new matrix will be <code>M * Q</code>. So when transforming a 6941 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6942 * the quaternion rotation will be applied first! 6943 * <p> 6944 * In order to set the matrix to a rotation transformation without post-multiplying, 6945 * use {@link #rotation(ref Quaterniond)}. 6946 * <p> 6947 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6948 * 6949 * @see #rotation(ref Quaterniond) 6950 * 6951 * @param quat 6952 * the {@link Quaterniond} 6953 * @param dest 6954 * will hold the result 6955 * @return dest 6956 */ 6957 public Matrix4d rotateTranslation(ref Quaterniond quat, ref Matrix4d dest) { 6958 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6959 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6960 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6961 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6962 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6963 double rm00 = w2 + x2 - z2 - y2; 6964 double rm01 = dxy + dzw; 6965 double rm02 = dxz - dyw; 6966 double rm10 = -dzw + dxy; 6967 double rm11 = y2 - z2 + w2 - x2; 6968 double rm12 = dyz + dxw; 6969 double rm20 = dyw + dxz; 6970 double rm21 = dyz - dxw; 6971 double rm22 = z2 - y2 - x2 + w2; 6972 dest._m20(rm20) 6973 ._m21(rm21) 6974 ._m22(rm22) 6975 ._m23(0.0) 6976 ._m00(rm00) 6977 ._m01(rm01) 6978 ._m02(rm02) 6979 ._m03(0.0) 6980 ._m10(rm10) 6981 ._m11(rm11) 6982 ._m12(rm12) 6983 ._m13(0.0) 6984 ._m30(m30) 6985 ._m31(m31) 6986 ._m32(m32) 6987 ._m33(1.0) 6988 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6989 return dest; 6990 } 6991 6992 6993 /** 6994 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store 6995 * the result in <code>dest</code>. 6996 * <p> 6997 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6998 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6999 * When used with a left-handed coordinate system, the rotation is clockwise. 7000 * <p> 7001 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 7002 * then the new matrix will be <code>Q * M</code>. So when transforming a 7003 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 7004 * the quaternion rotation will be applied last! 7005 * <p> 7006 * In order to set the matrix to a rotation transformation without pre-multiplying, 7007 * use {@link #rotation(ref Quaterniond)}. 7008 * <p> 7009 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 7010 * 7011 * @see #rotation(ref Quaterniond) 7012 * 7013 * @param quat 7014 * the {@link Quaterniond} 7015 * @param dest 7016 * will hold the result 7017 * @return dest 7018 */ 7019 public Matrix4d rotateLocal(ref Quaterniond quat, ref Matrix4d dest) { 7020 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 7021 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 7022 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 7023 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 7024 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 7025 double lm00 = w2 + x2 - z2 - y2; 7026 double lm01 = dxy + dzw; 7027 double lm02 = dxz - dyw; 7028 double lm10 = -dzw + dxy; 7029 double lm11 = y2 - z2 + w2 - x2; 7030 double lm12 = dyz + dxw; 7031 double lm20 = dyw + dxz; 7032 double lm21 = dyz - dxw; 7033 double lm22 = z2 - y2 - x2 + w2; 7034 double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; 7035 double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; 7036 double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; 7037 double nm03 = m03; 7038 double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; 7039 double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; 7040 double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; 7041 double nm13 = m13; 7042 double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; 7043 double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; 7044 double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; 7045 double nm23 = m23; 7046 double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32; 7047 double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32; 7048 double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32; 7049 dest._m00(nm00) 7050 ._m01(nm01) 7051 ._m02(nm02) 7052 ._m03(nm03) 7053 ._m10(nm10) 7054 ._m11(nm11) 7055 ._m12(nm12) 7056 ._m13(nm13) 7057 ._m20(nm20) 7058 ._m21(nm21) 7059 ._m22(nm22) 7060 ._m23(nm23) 7061 ._m30(nm30) 7062 ._m31(nm31) 7063 ._m32(nm32) 7064 ._m33(m33) 7065 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7066 return dest; 7067 } 7068 7069 /** 7070 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 7071 * <p> 7072 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7073 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7074 * When used with a left-handed coordinate system, the rotation is clockwise. 7075 * <p> 7076 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 7077 * then the new matrix will be <code>Q * M</code>. So when transforming a 7078 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 7079 * the quaternion rotation will be applied last! 7080 * <p> 7081 * In order to set the matrix to a rotation transformation without pre-multiplying, 7082 * use {@link #rotation(ref Quaterniond)}. 7083 * <p> 7084 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 7085 * 7086 * @see #rotation(ref Quaterniond) 7087 * 7088 * @param quat 7089 * the {@link Quaterniond} 7090 * @return this 7091 */ 7092 ref public Matrix4d rotateLocal(ref Quaterniond quat) return { 7093 rotateLocal(quat, this); 7094 return this; 7095 } 7096 7097 7098 /** 7099 * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix. 7100 * <p> 7101 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7102 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7103 * When used with a left-handed coordinate system, the rotation is clockwise. 7104 * <p> 7105 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d}, 7106 * then the new matrix will be <code>M * A</code>. So when transforming a 7107 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7108 * the {@link AxisAngle4d} rotation will be applied first! 7109 * <p> 7110 * In order to set the matrix to a rotation transformation without post-multiplying, 7111 * use {@link #rotation(ref AxisAngle4d)}. 7112 * <p> 7113 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7114 * 7115 * @see #rotate(double, double, double, double) 7116 * @see #rotation(ref AxisAngle4d) 7117 * 7118 * @param axisAngle 7119 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 7120 * @return this 7121 */ 7122 ref public Matrix4d rotate(ref AxisAngle4d axisAngle) return { 7123 return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z); 7124 } 7125 7126 /** 7127 * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in <code>dest</code>. 7128 * <p> 7129 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7130 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7131 * When used with a left-handed coordinate system, the rotation is clockwise. 7132 * <p> 7133 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d}, 7134 * then the new matrix will be <code>M * A</code>. So when transforming a 7135 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7136 * the {@link AxisAngle4d} rotation will be applied first! 7137 * <p> 7138 * In order to set the matrix to a rotation transformation without post-multiplying, 7139 * use {@link #rotation(ref AxisAngle4d)}. 7140 * <p> 7141 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7142 * 7143 * @see #rotate(double, double, double, double) 7144 * @see #rotation(ref AxisAngle4d) 7145 * 7146 * @param axisAngle 7147 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 7148 * @param dest 7149 * will hold the result 7150 * @return dest 7151 */ 7152 public Matrix4d rotate(ref AxisAngle4d axisAngle, ref Matrix4d dest) { 7153 return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest); 7154 } 7155 7156 /** 7157 * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix. 7158 * <p> 7159 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7160 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7161 * When used with a left-handed coordinate system, the rotation is clockwise. 7162 * <p> 7163 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis, 7164 * then the new matrix will be <code>M * A</code>. So when transforming a 7165 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7166 * the axis-angle rotation will be applied first! 7167 * <p> 7168 * In order to set the matrix to a rotation transformation without post-multiplying, 7169 * use {@link #rotation(double, Vector3d)}. 7170 * <p> 7171 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7172 * 7173 * @see #rotate(double, double, double, double) 7174 * @see #rotation(double, Vector3d) 7175 * 7176 * @param angle 7177 * the angle in radians 7178 * @param axis 7179 * the rotation axis (needs to be {@link Vector3d#normalize() normalized}) 7180 * @return this 7181 */ 7182 ref public Matrix4d rotate(double angle, Vector3d axis) return { 7183 return rotate(angle, axis.x, axis.y, axis.z); 7184 } 7185 7186 /** 7187 * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in <code>dest</code>. 7188 * <p> 7189 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7190 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7191 * When used with a left-handed coordinate system, the rotation is clockwise. 7192 * <p> 7193 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis, 7194 * then the new matrix will be <code>M * A</code>. So when transforming a 7195 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7196 * the axis-angle rotation will be applied first! 7197 * <p> 7198 * In order to set the matrix to a rotation transformation without post-multiplying, 7199 * use {@link #rotation(double, Vector3d)}. 7200 * <p> 7201 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7202 * 7203 * @see #rotate(double, double, double, double) 7204 * @see #rotation(double, Vector3d) 7205 * 7206 * @param angle 7207 * the angle in radians 7208 * @param axis 7209 * the rotation axis (needs to be {@link Vector3d#normalize() normalized}) 7210 * @param dest 7211 * will hold the result 7212 * @return dest 7213 */ 7214 public Matrix4d rotate(double angle, Vector3d axis, ref Matrix4d dest) { 7215 return rotate(angle, axis.x, axis.y, axis.z, dest); 7216 } 7217 7218 public Vector4d getRow(int row, ref Vector4d dest) { 7219 switch (row) { 7220 case 0: 7221 dest.x = m00; 7222 dest.y = m10; 7223 dest.z = m20; 7224 dest.w = m30; 7225 break; 7226 case 1: 7227 dest.x = m01; 7228 dest.y = m11; 7229 dest.z = m21; 7230 dest.w = m31; 7231 break; 7232 case 2: 7233 dest.x = m02; 7234 dest.y = m12; 7235 dest.z = m22; 7236 dest.w = m32; 7237 break; 7238 case 3: 7239 dest.x = m03; 7240 dest.y = m13; 7241 dest.z = m23; 7242 dest.w = m33; 7243 break; 7244 default: {} 7245 } 7246 return dest; 7247 } 7248 7249 public Vector3d getRow(int row, ref Vector3d dest){ 7250 switch (row) { 7251 case 0: 7252 dest.x = m00; 7253 dest.y = m10; 7254 dest.z = m20; 7255 break; 7256 case 1: 7257 dest.x = m01; 7258 dest.y = m11; 7259 dest.z = m21; 7260 break; 7261 case 2: 7262 dest.x = m02; 7263 dest.y = m12; 7264 dest.z = m22; 7265 break; 7266 case 3: 7267 dest.x = m03; 7268 dest.y = m13; 7269 dest.z = m23; 7270 break; 7271 default: {} 7272 } 7273 return dest; 7274 } 7275 7276 /** 7277 * Set the row at the given <code>row</code> index, starting with <code>0</code>. 7278 * 7279 * @param row 7280 * the row index in <code>[0..3]</code> 7281 * @param src 7282 * the row components to set 7283 * @return this 7284 * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..3]</code> 7285 */ 7286 ref public Matrix4d setRow(int row, Vector4d src) return { 7287 switch (row) { 7288 case 0: 7289 return _m00(src.x)._m10(src.y)._m20(src.z)._m30(src.w)._properties(0); 7290 case 1: 7291 return _m01(src.x)._m11(src.y)._m21(src.z)._m31(src.w)._properties(0); 7292 case 2: 7293 return _m02(src.x)._m12(src.y)._m22(src.z)._m32(src.w)._properties(0); 7294 case 3: 7295 return _m03(src.x)._m13(src.y)._m23(src.z)._m33(src.w)._properties(0); 7296 default: 7297 return this; 7298 } 7299 } 7300 7301 public Vector4d getColumn(int column, ref Vector4d dest) { 7302 switch (column) { 7303 case 0: 7304 dest.x = m00; 7305 dest.y = m01; 7306 dest.z = m02; 7307 dest.w = m03; 7308 break; 7309 case 1: 7310 dest.x = m10; 7311 dest.y = m11; 7312 dest.z = m12; 7313 dest.w = m13; 7314 break; 7315 case 2: 7316 dest.x = m20; 7317 dest.y = m21; 7318 dest.z = m22; 7319 dest.w = m23; 7320 break; 7321 case 3: 7322 dest.x = m30; 7323 dest.y = m31; 7324 dest.z = m32; 7325 dest.w = m33; 7326 break; 7327 default: {} 7328 } 7329 return dest; 7330 } 7331 7332 public Vector3d getColumn(int column, ref Vector3d dest) { 7333 switch (column) { 7334 case 0: 7335 dest.x = m00; 7336 dest.y = m01; 7337 dest.z = m02; 7338 break; 7339 case 1: 7340 dest.x = m10; 7341 dest.y = m11; 7342 dest.z = m12; 7343 break; 7344 case 2: 7345 dest.x = m20; 7346 dest.y = m21; 7347 dest.z = m22; 7348 break; 7349 case 3: 7350 dest.x = m30; 7351 dest.y = m31; 7352 dest.z = m32; 7353 break; 7354 default: {} 7355 } 7356 return dest; 7357 } 7358 7359 /** 7360 * Set the column at the given <code>column</code> index, starting with <code>0</code>. 7361 * 7362 * @param column 7363 * the column index in <code>[0..3]</code> 7364 * @param src 7365 * the column components to set 7366 * @return this 7367 * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..3]</code> 7368 */ 7369 ref public Matrix4d setColumn(int column, Vector4d src) return { 7370 switch (column) { 7371 case 0: 7372 return _m00(src.x)._m01(src.y)._m02(src.z)._m03(src.w)._properties(0); 7373 case 1: 7374 return _m10(src.x)._m11(src.y)._m12(src.z)._m13(src.w)._properties(0); 7375 case 2: 7376 return _m20(src.x)._m21(src.y)._m22(src.z)._m23(src.w)._properties(0); 7377 case 3: 7378 return _m30(src.x)._m31(src.y)._m32(src.z)._m33(src.w)._properties(0); 7379 default: 7380 return this; 7381 } 7382 } 7383 7384 public double get(int column, int row) { 7385 return MemUtil.get(this, column, row); 7386 } 7387 7388 /** 7389 * Set the matrix element at the given column and row to the specified value. 7390 * 7391 * @param column 7392 * the colum index in <code>[0..3]</code> 7393 * @param row 7394 * the row index in <code>[0..3]</code> 7395 * @param value 7396 * the value 7397 * @return this 7398 */ 7399 ref public Matrix4d set(int column, int row, double value) return { 7400 MemUtil.set(this, column, row, value); 7401 return this; 7402 } 7403 7404 public double getRowColumn(int row, int column) { 7405 return MemUtil.get(this, column, row); 7406 } 7407 7408 /** 7409 * Set the matrix element at the given row and column to the specified value. 7410 * 7411 * @param row 7412 * the row index in <code>[0..3]</code> 7413 * @param column 7414 * the colum index in <code>[0..3]</code> 7415 * @param value 7416 * the value 7417 * @return this 7418 */ 7419 ref public Matrix4d setRowColumn(int row, int column, double value) return { 7420 MemUtil.set(this, column, row, value); 7421 return this; 7422 } 7423 7424 /** 7425 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7426 * and store it into the upper left 3x3 submatrix of <code>this</code>. 7427 * All other values of <code>this</code> will be set to {@link #identity() identity}. 7428 * <p> 7429 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7430 * <p> 7431 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7432 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7433 * In that case, use {@link #set3x3(Matrix4d)} to set a given Matrix4f to only the upper left 3x3 submatrix 7434 * of this matrix. 7435 * 7436 * @see #set3x3(Matrix4d) 7437 * 7438 * @return this 7439 */ 7440 ref public Matrix4d normal() return { 7441 normal(this); 7442 return this; 7443 } 7444 7445 /** 7446 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7447 * and store it into the upper left 3x3 submatrix of <code>dest</code>. 7448 * All other values of <code>dest</code> will be set to {@link #identity() identity}. 7449 * <p> 7450 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7451 * <p> 7452 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7453 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7454 * In that case, use {@link #set3x3(Matrix4d)} to set a given Matrix4d to only the upper left 3x3 submatrix 7455 * of a given matrix. 7456 * 7457 * @see #set3x3(Matrix4d) 7458 * 7459 * @param dest 7460 * will hold the result 7461 * @return dest 7462 */ 7463 public Matrix4d normal(ref Matrix4d dest) { 7464 if ((properties & PROPERTY_IDENTITY) != 0) 7465 return dest.identity(); 7466 else if ((properties & PROPERTY_ORTHONORMAL) != 0) 7467 return normalOrthonormal(dest); 7468 return normalGeneric(dest); 7469 } 7470 private Matrix4d normalOrthonormal(ref Matrix4d dest) { 7471 if (dest != this) 7472 dest.set(this); 7473 return dest._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 7474 } 7475 private Matrix4d normalGeneric(ref Matrix4d dest) { 7476 double m00m11 = m00 * m11; 7477 double m01m10 = m01 * m10; 7478 double m02m10 = m02 * m10; 7479 double m00m12 = m00 * m12; 7480 double m01m12 = m01 * m12; 7481 double m02m11 = m02 * m11; 7482 double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; 7483 double s = 1.0 / det; 7484 /* Invert and transpose in one go */ 7485 double nm00 = (m11 * m22 - m21 * m12) * s; 7486 double nm01 = (m20 * m12 - m10 * m22) * s; 7487 double nm02 = (m10 * m21 - m20 * m11) * s; 7488 double nm10 = (m21 * m02 - m01 * m22) * s; 7489 double nm11 = (m00 * m22 - m20 * m02) * s; 7490 double nm12 = (m20 * m01 - m00 * m21) * s; 7491 double nm20 = (m01m12 - m02m11) * s; 7492 double nm21 = (m02m10 - m00m12) * s; 7493 double nm22 = (m00m11 - m01m10) * s; 7494 return dest 7495 ._m00(nm00) 7496 ._m01(nm01) 7497 ._m02(nm02) 7498 ._m03(0.0) 7499 ._m10(nm10) 7500 ._m11(nm11) 7501 ._m12(nm12) 7502 ._m13(0.0) 7503 ._m20(nm20) 7504 ._m21(nm21) 7505 ._m22(nm22) 7506 ._m23(0.0) 7507 ._m30(0.0) 7508 ._m31(0.0) 7509 ._m32(0.0) 7510 ._m33(1.0) 7511 ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE)); 7512 } 7513 7514 /** 7515 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7516 * and store it into <code>dest</code>. 7517 * <p> 7518 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7519 * <p> 7520 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7521 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7522 * In that case, use {@link Matrix3d#set(Matrix4d)} to set a given Matrix3d to only the upper left 3x3 submatrix 7523 * of this matrix. 7524 * 7525 * @see Matrix3d#set(Matrix4d) 7526 * @see #get3x3(Matrix3d) 7527 * 7528 * @param dest 7529 * will hold the result 7530 * @return dest 7531 */ 7532 public Matrix3d normal(ref Matrix3d dest) { 7533 if ((properties & PROPERTY_ORTHONORMAL) != 0) 7534 return normalOrthonormal(dest); 7535 return normalGeneric(dest); 7536 } 7537 private Matrix3d normalOrthonormal(ref Matrix3d dest) { 7538 dest.set(this); 7539 return dest; 7540 } 7541 private Matrix3d normalGeneric(ref Matrix3d dest) { 7542 double m00m11 = m00 * m11; 7543 double m01m10 = m01 * m10; 7544 double m02m10 = m02 * m10; 7545 double m00m12 = m00 * m12; 7546 double m01m12 = m01 * m12; 7547 double m02m11 = m02 * m11; 7548 double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; 7549 double s = 1.0 / det; 7550 /* Invert and transpose in one go */ 7551 return dest._m00((m11 * m22 - m21 * m12) * s) 7552 ._m01((m20 * m12 - m10 * m22) * s) 7553 ._m02((m10 * m21 - m20 * m11) * s) 7554 ._m10((m21 * m02 - m01 * m22) * s) 7555 ._m11((m00 * m22 - m20 * m02) * s) 7556 ._m12((m20 * m01 - m00 * m21) * s) 7557 ._m20((m01m12 - m02m11) * s) 7558 ._m21((m02m10 - m00m12) * s) 7559 ._m22((m00m11 - m01m10) * s); 7560 } 7561 7562 /** 7563 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code>. 7564 * <p> 7565 * The cofactor matrix can be used instead of {@link #normal()} to transform normals 7566 * when the orientation of the normals with respect to the surface should be preserved. 7567 * 7568 * @return this 7569 */ 7570 ref public Matrix4d cofactor3x3() return { 7571 cofactor3x3(this); 7572 return this; 7573 } 7574 7575 /** 7576 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code> 7577 * and store it into <code>dest</code>. 7578 * <p> 7579 * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals 7580 * when the orientation of the normals with respect to the surface should be preserved. 7581 * 7582 * @param dest 7583 * will hold the result 7584 * @return dest 7585 */ 7586 public Matrix3d cofactor3x3(ref Matrix3d dest) { 7587 return dest._m00(m11 * m22 - m21 * m12) 7588 ._m01(m20 * m12 - m10 * m22) 7589 ._m02(m10 * m21 - m20 * m11) 7590 ._m10(m21 * m02 - m01 * m22) 7591 ._m11(m00 * m22 - m20 * m02) 7592 ._m12(m20 * m01 - m00 * m21) 7593 ._m20(m01 * m12 - m02 * m11) 7594 ._m21(m02 * m10 - m00 * m12) 7595 ._m22(m00 * m11 - m01 * m10); 7596 } 7597 7598 /** 7599 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code> 7600 * and store it into <code>dest</code>. 7601 * All other values of <code>dest</code> will be set to {@link #identity() identity}. 7602 * <p> 7603 * The cofactor matrix can be used instead of {@link #normal(Matrix4d)} to transform normals 7604 * when the orientation of the normals with respect to the surface should be preserved. 7605 * 7606 * @param dest 7607 * will hold the result 7608 * @return dest 7609 */ 7610 public Matrix4d cofactor3x3(ref Matrix4d dest) { 7611 double nm10 = m21 * m02 - m01 * m22; 7612 double nm11 = m00 * m22 - m20 * m02; 7613 double nm12 = m20 * m01 - m00 * m21; 7614 double nm20 = m01 * m12 - m11 * m02; 7615 double nm21 = m02 * m10 - m12 * m00; 7616 double nm22 = m00 * m11 - m10 * m01; 7617 return dest 7618 ._m00(m11 * m22 - m21 * m12) 7619 ._m01(m20 * m12 - m10 * m22) 7620 ._m02(m10 * m21 - m20 * m11) 7621 ._m03(0.0) 7622 ._m10(nm10) 7623 ._m11(nm11) 7624 ._m12(nm12) 7625 ._m13(0.0) 7626 ._m20(nm20) 7627 ._m21(nm21) 7628 ._m22(nm22) 7629 ._m23(0.0) 7630 ._m30(0.0) 7631 ._m31(0.0) 7632 ._m32(0.0) 7633 ._m33(1.0) 7634 ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE)); 7635 } 7636 7637 /** 7638 * Normalize the upper left 3x3 submatrix of this matrix. 7639 * <p> 7640 * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit 7641 * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself 7642 * (i.e. had <i>skewing</i>). 7643 * 7644 * @return this 7645 */ 7646 ref public Matrix4d normalize3x3() return { 7647 normalize3x3(this); 7648 return this; 7649 } 7650 7651 public Matrix4d normalize3x3(ref Matrix4d dest) { 7652 double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 7653 double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 7654 double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 7655 dest._m00(m00 * invXlen)._m01(m01 * invXlen)._m02(m02 * invXlen) 7656 ._m10(m10 * invYlen)._m11(m11 * invYlen)._m12(m12 * invYlen) 7657 ._m20(m20 * invZlen)._m21(m21 * invZlen)._m22(m22 * invZlen) 7658 ._m30(m30)._m31(m31)._m32(m32)._m33(m33) 7659 ._properties(properties); 7660 return dest; 7661 } 7662 7663 public Matrix3d normalize3x3(ref Matrix3d dest) { 7664 double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 7665 double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 7666 double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 7667 dest.m00 = (m00 * invXlen); 7668 dest.m01 = (m01 * invXlen); 7669 dest.m02 = (m02 * invXlen); 7670 7671 dest.m10 = (m10 * invYlen); 7672 dest.m11 = (m11 * invYlen); 7673 dest.m12 = (m12 * invYlen); 7674 7675 dest.m20 = (m20 * invZlen); 7676 dest.m21 = (m21 * invZlen); 7677 dest.m22 = (m22 * invZlen); 7678 return dest; 7679 } 7680 7681 public Vector4d unproject(double winX, double winY, double winZ, int[] viewport, ref Vector4d dest) { 7682 double a = m00 * m11 - m01 * m10; 7683 double b = m00 * m12 - m02 * m10; 7684 double c = m00 * m13 - m03 * m10; 7685 double d = m01 * m12 - m02 * m11; 7686 double e = m01 * m13 - m03 * m11; 7687 double f = m02 * m13 - m03 * m12; 7688 double g = m20 * m31 - m21 * m30; 7689 double h = m20 * m32 - m22 * m30; 7690 double i = m20 * m33 - m23 * m30; 7691 double j = m21 * m32 - m22 * m31; 7692 double k = m21 * m33 - m23 * m31; 7693 double l = m22 * m33 - m23 * m32; 7694 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7695 det = 1.0 / det; 7696 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7697 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7698 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7699 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7700 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7701 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7702 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7703 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7704 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7705 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7706 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7707 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7708 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7709 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7710 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7711 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7712 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7713 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7714 double ndcZ = winZ+winZ-1.0; 7715 double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); 7716 dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW; 7717 dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW; 7718 dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW; 7719 dest.w = 1.0; 7720 return dest; 7721 } 7722 7723 public Vector3d unproject(double winX, double winY, double winZ, int[] viewport, ref Vector3d dest) { 7724 double a = m00 * m11 - m01 * m10; 7725 double b = m00 * m12 - m02 * m10; 7726 double c = m00 * m13 - m03 * m10; 7727 double d = m01 * m12 - m02 * m11; 7728 double e = m01 * m13 - m03 * m11; 7729 double f = m02 * m13 - m03 * m12; 7730 double g = m20 * m31 - m21 * m30; 7731 double h = m20 * m32 - m22 * m30; 7732 double i = m20 * m33 - m23 * m30; 7733 double j = m21 * m32 - m22 * m31; 7734 double k = m21 * m33 - m23 * m31; 7735 double l = m22 * m33 - m23 * m32; 7736 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7737 det = 1.0 / det; 7738 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7739 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7740 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7741 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7742 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7743 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7744 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7745 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7746 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7747 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7748 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7749 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7750 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7751 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7752 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7753 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7754 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7755 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7756 double ndcZ = winZ+winZ-1.0; 7757 double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); 7758 dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW; 7759 dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW; 7760 dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW; 7761 return dest; 7762 } 7763 7764 public Vector4d unproject(ref Vector3d winCoords, int[] viewport, ref Vector4d dest) { 7765 return unproject(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7766 } 7767 7768 public Vector3d unproject(ref Vector3d winCoords, int[] viewport, ref Vector3d dest) { 7769 return unproject(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7770 } 7771 7772 ref public Matrix4d unprojectRay(double winX, double winY, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) return { 7773 double a = m00 * m11 - m01 * m10; 7774 double b = m00 * m12 - m02 * m10; 7775 double c = m00 * m13 - m03 * m10; 7776 double d = m01 * m12 - m02 * m11; 7777 double e = m01 * m13 - m03 * m11; 7778 double f = m02 * m13 - m03 * m12; 7779 double g = m20 * m31 - m21 * m30; 7780 double h = m20 * m32 - m22 * m30; 7781 double i = m20 * m33 - m23 * m30; 7782 double j = m21 * m32 - m22 * m31; 7783 double k = m21 * m33 - m23 * m31; 7784 double l = m22 * m33 - m23 * m32; 7785 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7786 det = 1.0 / det; 7787 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7788 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7789 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7790 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7791 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7792 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7793 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7794 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7795 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7796 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7797 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7798 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7799 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7800 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7801 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7802 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7803 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7804 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7805 double px = im00 * ndcX + im10 * ndcY + im30; 7806 double py = im01 * ndcX + im11 * ndcY + im31; 7807 double pz = im02 * ndcX + im12 * ndcY + im32; 7808 double invNearW = 1.0 / (im03 * ndcX + im13 * ndcY - im23 + im33); 7809 double nearX = (px - im20) * invNearW; 7810 double nearY = (py - im21) * invNearW; 7811 double nearZ = (pz - im22) * invNearW; 7812 double invW0 = 1.0 / (im03 * ndcX + im13 * ndcY + im33); 7813 double x0 = px * invW0; 7814 double y0 = py * invW0; 7815 double z0 = pz * invW0; 7816 originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ; 7817 dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ; 7818 return this; 7819 } 7820 7821 public Matrix4d unprojectRay(ref Vector2d winCoords, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) { 7822 return unprojectRay(winCoords.x, winCoords.y, viewport, originDest, dirDest); 7823 } 7824 7825 public Vector4d unprojectInv(ref Vector3d winCoords, int[] viewport, ref Vector4d dest) { 7826 return unprojectInv(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7827 } 7828 7829 public Vector4d unprojectInv(double winX, double winY, double winZ, int[] viewport, ref Vector4d dest) { 7830 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7831 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7832 double ndcZ = winZ+winZ-1.0; 7833 double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33); 7834 dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW; 7835 dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW; 7836 dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW; 7837 dest.w = 1.0; 7838 return dest; 7839 } 7840 7841 public Vector3d unprojectInv(ref Vector3d winCoords, int[] viewport, ref Vector3d dest) { 7842 return unprojectInv(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7843 } 7844 7845 public Vector3d unprojectInv(double winX, double winY, double winZ, int[] viewport, ref Vector3d dest) { 7846 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7847 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7848 double ndcZ = winZ+winZ-1.0; 7849 double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33); 7850 dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW; 7851 dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW; 7852 dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW; 7853 return dest; 7854 } 7855 7856 public Matrix4d unprojectInvRay(ref Vector2d winCoords, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) { 7857 return unprojectInvRay(winCoords.x, winCoords.y, viewport, originDest, dirDest); 7858 } 7859 7860 ref public Matrix4d unprojectInvRay(double winX, double winY, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) return { 7861 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7862 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7863 double px = m00 * ndcX + m10 * ndcY + m30; 7864 double py = m01 * ndcX + m11 * ndcY + m31; 7865 double pz = m02 * ndcX + m12 * ndcY + m32; 7866 double invNearW = 1.0 / (m03 * ndcX + m13 * ndcY - m23 + m33); 7867 double nearX = (px - m20) * invNearW; 7868 double nearY = (py - m21) * invNearW; 7869 double nearZ = (pz - m22) * invNearW; 7870 double invW0 = 1.0 / (m03 * ndcX + m13 * ndcY + m33); 7871 double x0 = px * invW0; 7872 double y0 = py * invW0; 7873 double z0 = pz * invW0; 7874 originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ; 7875 dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ; 7876 return this; 7877 } 7878 7879 public Vector4d project(double x, double y, double z, int[] viewport, ref Vector4d winCoordsDest) { 7880 double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))); 7881 double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW; 7882 double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW; 7883 double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW; 7884 return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]), 7885 Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]), 7886 Math.fma(0.5, nz, 0.5), 7887 1.0); 7888 } 7889 7890 public Vector3d project(double x, double y, double z, int[] viewport, ref Vector3d winCoordsDest) { 7891 double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))); 7892 double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW; 7893 double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW; 7894 double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW; 7895 winCoordsDest.x = Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]); 7896 winCoordsDest.y = Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]); 7897 winCoordsDest.z = Math.fma(0.5, nz, 0.5); 7898 return winCoordsDest; 7899 } 7900 7901 public Vector4d project(ref Vector3d position, int[] viewport, ref Vector4d dest) { 7902 return project(position.x, position.y, position.z, viewport, dest); 7903 } 7904 7905 public Vector3d project(ref Vector3d position, int[] viewport, ref Vector3d dest) { 7906 return project(position.x, position.y, position.z, viewport, dest); 7907 } 7908 7909 public Matrix4d reflect(double a, double b, double c, double d, ref Matrix4d dest) { 7910 if ((properties & PROPERTY_IDENTITY) != 0) 7911 return dest.reflection(a, b, c, d); 7912 if ((properties & PROPERTY_IDENTITY) != 0) 7913 return dest.reflection(a, b, c, d); 7914 else if ((properties & PROPERTY_AFFINE) != 0) 7915 return reflectAffine(a, b, c, d, dest); 7916 return reflectGeneric(a, b, c, d, dest); 7917 } 7918 private Matrix4d reflectAffine(double a, double b, double c, double d, ref Matrix4d dest) { 7919 double da = a + a, db = b + b, dc = c + c, dd = d + d; 7920 double rm00 = 1.0 - da * a; 7921 double rm01 = -da * b; 7922 double rm02 = -da * c; 7923 double rm10 = -db * a; 7924 double rm11 = 1.0 - db * b; 7925 double rm12 = -db * c; 7926 double rm20 = -dc * a; 7927 double rm21 = -dc * b; 7928 double rm22 = 1.0 - dc * c; 7929 double rm30 = -dd * a; 7930 double rm31 = -dd * b; 7931 double rm32 = -dd * c; 7932 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 7933 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 7934 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 7935 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 7936 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 7937 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 7938 // matrix multiplication 7939 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 7940 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 7941 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 7942 ._m33(m33) 7943 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 7944 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 7945 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 7946 ._m23(0.0) 7947 ._m00(nm00) 7948 ._m01(nm01) 7949 ._m02(nm02) 7950 ._m03(0.0) 7951 ._m10(nm10) 7952 ._m11(nm11) 7953 ._m12(nm12) 7954 ._m13(0.0) 7955 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7956 return dest; 7957 } 7958 private Matrix4d reflectGeneric(double a, double b, double c, double d, ref Matrix4d dest) { 7959 double da = a + a, db = b + b, dc = c + c, dd = d + d; 7960 double rm00 = 1.0 - da * a; 7961 double rm01 = -da * b; 7962 double rm02 = -da * c; 7963 double rm10 = -db * a; 7964 double rm11 = 1.0 - db * b; 7965 double rm12 = -db * c; 7966 double rm20 = -dc * a; 7967 double rm21 = -dc * b; 7968 double rm22 = 1.0 - dc * c; 7969 double rm30 = -dd * a; 7970 double rm31 = -dd * b; 7971 double rm32 = -dd * c; 7972 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 7973 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 7974 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 7975 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 7976 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 7977 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 7978 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 7979 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 7980 // matrix multiplication 7981 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 7982 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 7983 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 7984 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 7985 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 7986 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 7987 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 7988 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 7989 ._m00(nm00) 7990 ._m01(nm01) 7991 ._m02(nm02) 7992 ._m03(nm03) 7993 ._m10(nm10) 7994 ._m11(nm11) 7995 ._m12(nm12) 7996 ._m13(nm13) 7997 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7998 return dest; 7999 } 8000 8001 /** 8002 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 8003 * specified via the equation <code>x*a + y*b + z*c + d = 0</code>. 8004 * <p> 8005 * The vector <code>(a, b, c)</code> must be a unit vector. 8006 * <p> 8007 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8008 * then the new matrix will be <code>M * R</code>. So when transforming a 8009 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8010 * reflection will be applied first! 8011 * <p> 8012 * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a> 8013 * 8014 * @param a 8015 * the x factor in the plane equation 8016 * @param b 8017 * the y factor in the plane equation 8018 * @param c 8019 * the z factor in the plane equation 8020 * @param d 8021 * the constant in the plane equation 8022 * @return this 8023 */ 8024 ref public Matrix4d reflect(double a, double b, double c, double d) return { 8025 reflect(a, b, c, d, this); 8026 return this; 8027 } 8028 8029 /** 8030 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 8031 * specified via the plane normal and a point on the plane. 8032 * <p> 8033 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8034 * then the new matrix will be <code>M * R</code>. So when transforming a 8035 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8036 * reflection will be applied first! 8037 * 8038 * @param nx 8039 * the x-coordinate of the plane normal 8040 * @param ny 8041 * the y-coordinate of the plane normal 8042 * @param nz 8043 * the z-coordinate of the plane normal 8044 * @param px 8045 * the x-coordinate of a point on the plane 8046 * @param py 8047 * the y-coordinate of a point on the plane 8048 * @param pz 8049 * the z-coordinate of a point on the plane 8050 * @return this 8051 */ 8052 ref public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz) return { 8053 reflect(nx, ny, nz, px, py, pz, this); 8054 return this; 8055 } 8056 8057 public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz, ref Matrix4d dest) { 8058 double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz); 8059 double nnx = nx * invLength; 8060 double nny = ny * invLength; 8061 double nnz = nz * invLength; 8062 /* See: http://mathworld.wolfram.com/Plane.html */ 8063 return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest); 8064 } 8065 8066 /** 8067 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 8068 * specified via the plane normal and a point on the plane. 8069 * <p> 8070 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8071 * then the new matrix will be <code>M * R</code>. So when transforming a 8072 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8073 * reflection will be applied first! 8074 * 8075 * @param normal 8076 * the plane normal 8077 * @param point 8078 * a point on the plane 8079 * @return this 8080 */ 8081 ref public Matrix4d reflect(ref Vector3d normal, Vector3d point) return { 8082 return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z); 8083 } 8084 8085 /** 8086 * Apply a mirror/reflection transformation to this matrix that reflects about a plane 8087 * specified via the plane orientation and a point on the plane. 8088 * <p> 8089 * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. 8090 * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is 8091 * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>. 8092 * <p> 8093 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8094 * then the new matrix will be <code>M * R</code>. So when transforming a 8095 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8096 * reflection will be applied first! 8097 * 8098 * @param orientation 8099 * the plane orientation relative to an implied normal vector of <code>(0, 0, 1)</code> 8100 * @param point 8101 * a point on the plane 8102 * @return this 8103 */ 8104 ref public Matrix4d reflect(ref Quaterniond orientation, Vector3d point) return { 8105 reflect(orientation, point, this); 8106 return this; 8107 } 8108 8109 public Matrix4d reflect(ref Quaterniond orientation, Vector3d point, ref Matrix4d dest) { 8110 double num1 = orientation.x + orientation.x; 8111 double num2 = orientation.y + orientation.y; 8112 double num3 = orientation.z + orientation.z; 8113 double normalX = orientation.x * num3 + orientation.w * num2; 8114 double normalY = orientation.y * num3 - orientation.w * num1; 8115 double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2); 8116 return reflect(normalX, normalY, normalZ, point.x, point.y, point.z, dest); 8117 } 8118 8119 public Matrix4d reflect(ref Vector3d normal, Vector3d point, ref Matrix4d dest) { 8120 return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z, dest); 8121 } 8122 8123 /** 8124 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8125 * specified via the equation <code>x*a + y*b + z*c + d = 0</code>. 8126 * <p> 8127 * The vector <code>(a, b, c)</code> must be a unit vector. 8128 * <p> 8129 * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a> 8130 * 8131 * @param a 8132 * the x factor in the plane equation 8133 * @param b 8134 * the y factor in the plane equation 8135 * @param c 8136 * the z factor in the plane equation 8137 * @param d 8138 * the constant in the plane equation 8139 * @return this 8140 */ 8141 ref public Matrix4d reflection(double a, double b, double c, double d) return { 8142 double da = a + a, db = b + b, dc = c + c, dd = d + d; 8143 _m00(1.0 - da * a). 8144 _m01(-da * b). 8145 _m02(-da * c). 8146 _m03(0.0). 8147 _m10(-db * a). 8148 _m11(1.0 - db * b). 8149 _m12(-db * c). 8150 _m13(0.0). 8151 _m20(-dc * a). 8152 _m21(-dc * b). 8153 _m22(1.0 - dc * c). 8154 _m23(0.0). 8155 _m30(-dd * a). 8156 _m31(-dd * b). 8157 _m32(-dd * c). 8158 _m33(1.0). 8159 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 8160 return this; 8161 } 8162 8163 /** 8164 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8165 * specified via the plane normal and a point on the plane. 8166 * 8167 * @param nx 8168 * the x-coordinate of the plane normal 8169 * @param ny 8170 * the y-coordinate of the plane normal 8171 * @param nz 8172 * the z-coordinate of the plane normal 8173 * @param px 8174 * the x-coordinate of a point on the plane 8175 * @param py 8176 * the y-coordinate of a point on the plane 8177 * @param pz 8178 * the z-coordinate of a point on the plane 8179 * @return this 8180 */ 8181 ref public Matrix4d reflection(double nx, double ny, double nz, double px, double py, double pz) return { 8182 double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz); 8183 double nnx = nx * invLength; 8184 double nny = ny * invLength; 8185 double nnz = nz * invLength; 8186 /* See: http://mathworld.wolfram.com/Plane.html */ 8187 return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz); 8188 } 8189 8190 /** 8191 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8192 * specified via the plane normal and a point on the plane. 8193 * 8194 * @param normal 8195 * the plane normal 8196 * @param point 8197 * a point on the plane 8198 * @return this 8199 */ 8200 ref public Matrix4d reflection(ref Vector3d normal, Vector3d point) return { 8201 return reflection(normal.x, normal.y, normal.z, point.x, point.y, point.z); 8202 } 8203 8204 /** 8205 * Set this matrix to a mirror/reflection transformation that reflects about a plane 8206 * specified via the plane orientation and a point on the plane. 8207 * <p> 8208 * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. 8209 * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is 8210 * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>. 8211 * 8212 * @param orientation 8213 * the plane orientation 8214 * @param point 8215 * a point on the plane 8216 * @return this 8217 */ 8218 ref public Matrix4d reflection(ref Quaterniond orientation, Vector3d point) return { 8219 double num1 = orientation.x + orientation.x; 8220 double num2 = orientation.y + orientation.y; 8221 double num3 = orientation.z + orientation.z; 8222 double normalX = orientation.x * num3 + orientation.w * num2; 8223 double normalY = orientation.y * num3 - orientation.w * num1; 8224 double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2); 8225 return reflection(normalX, normalY, normalZ, point.x, point.y, point.z); 8226 } 8227 8228 /** 8229 * Apply an orthographic projection transformation for a right-handed coordinate system 8230 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8231 * <p> 8232 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8233 * then the new matrix will be <code>M * O</code>. So when transforming a 8234 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8235 * orthographic projection transformation will be applied first! 8236 * <p> 8237 * In order to set the matrix to an orthographic projection without post-multiplying it, 8238 * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}. 8239 * <p> 8240 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8241 * 8242 * @see #setOrtho(double, double, double, double, double, double, bool) 8243 * 8244 * @param left 8245 * the distance from the center to the left frustum edge 8246 * @param right 8247 * the distance from the center to the right frustum edge 8248 * @param bottom 8249 * the distance from the center to the bottom frustum edge 8250 * @param top 8251 * the distance from the center to the top frustum edge 8252 * @param zNear 8253 * near clipping plane distance 8254 * @param zFar 8255 * far clipping plane distance 8256 * @param zZeroToOne 8257 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8258 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8259 * @param dest 8260 * will hold the result 8261 * @return dest 8262 */ 8263 public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8264 if ((properties & PROPERTY_IDENTITY) != 0) 8265 return dest.setOrtho(left, right, bottom, top, zNear, zFar, zZeroToOne); 8266 return orthoGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 8267 } 8268 private Matrix4d orthoGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8269 // calculate right matrix elements 8270 double rm00 = 2.0 / (right - left); 8271 double rm11 = 2.0 / (top - bottom); 8272 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar); 8273 double rm30 = (left + right) / (left - right); 8274 double rm31 = (top + bottom) / (bottom - top); 8275 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8276 // perform optimized multiplication 8277 // compute the last column first, because other columns do not depend on it 8278 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 8279 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 8280 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 8281 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 8282 ._m00(m00 * rm00) 8283 ._m01(m01 * rm00) 8284 ._m02(m02 * rm00) 8285 ._m03(m03 * rm00) 8286 ._m10(m10 * rm11) 8287 ._m11(m11 * rm11) 8288 ._m12(m12 * rm11) 8289 ._m13(m13 * rm11) 8290 ._m20(m20 * rm22) 8291 ._m21(m21 * rm22) 8292 ._m22(m22 * rm22) 8293 ._m23(m23 * rm22) 8294 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8295 return dest; 8296 } 8297 8298 /** 8299 * Apply an orthographic projection transformation for a right-handed coordinate system 8300 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8301 * <p> 8302 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8303 * then the new matrix will be <code>M * O</code>. So when transforming a 8304 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8305 * orthographic projection transformation will be applied first! 8306 * <p> 8307 * In order to set the matrix to an orthographic projection without post-multiplying it, 8308 * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}. 8309 * <p> 8310 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8311 * 8312 * @see #setOrtho(double, double, double, double, double, double) 8313 * 8314 * @param left 8315 * the distance from the center to the left frustum edge 8316 * @param right 8317 * the distance from the center to the right frustum edge 8318 * @param bottom 8319 * the distance from the center to the bottom frustum edge 8320 * @param top 8321 * the distance from the center to the top frustum edge 8322 * @param zNear 8323 * near clipping plane distance 8324 * @param zFar 8325 * far clipping plane distance 8326 * @param dest 8327 * will hold the result 8328 * @return dest 8329 */ 8330 public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 8331 return ortho(left, right, bottom, top, zNear, zFar, false, dest); 8332 } 8333 8334 /** 8335 * Apply an orthographic projection transformation for a right-handed coordinate system 8336 * using the given NDC z range to this matrix. 8337 * <p> 8338 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8339 * then the new matrix will be <code>M * O</code>. So when transforming a 8340 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8341 * orthographic projection transformation will be applied first! 8342 * <p> 8343 * In order to set the matrix to an orthographic projection without post-multiplying it, 8344 * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}. 8345 * <p> 8346 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8347 * 8348 * @see #setOrtho(double, double, double, double, double, double, bool) 8349 * 8350 * @param left 8351 * the distance from the center to the left frustum edge 8352 * @param right 8353 * the distance from the center to the right frustum edge 8354 * @param bottom 8355 * the distance from the center to the bottom frustum edge 8356 * @param top 8357 * the distance from the center to the top frustum edge 8358 * @param zNear 8359 * near clipping plane distance 8360 * @param zFar 8361 * far clipping plane distance 8362 * @param zZeroToOne 8363 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8364 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8365 * @return this 8366 */ 8367 ref public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8368 ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 8369 return this; 8370 } 8371 8372 /** 8373 * Apply an orthographic projection transformation for a right-handed coordinate system 8374 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8375 * <p> 8376 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8377 * then the new matrix will be <code>M * O</code>. So when transforming a 8378 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8379 * orthographic projection transformation will be applied first! 8380 * <p> 8381 * In order to set the matrix to an orthographic projection without post-multiplying it, 8382 * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}. 8383 * <p> 8384 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8385 * 8386 * @see #setOrtho(double, double, double, double, double, double) 8387 * 8388 * @param left 8389 * the distance from the center to the left frustum edge 8390 * @param right 8391 * the distance from the center to the right frustum edge 8392 * @param bottom 8393 * the distance from the center to the bottom frustum edge 8394 * @param top 8395 * the distance from the center to the top frustum edge 8396 * @param zNear 8397 * near clipping plane distance 8398 * @param zFar 8399 * far clipping plane distance 8400 * @return this 8401 */ 8402 ref public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar) return { 8403 return ortho(left, right, bottom, top, zNear, zFar, false); 8404 } 8405 8406 /** 8407 * Apply an orthographic projection transformation for a left-handed coordiante system 8408 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8409 * <p> 8410 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8411 * then the new matrix will be <code>M * O</code>. So when transforming a 8412 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8413 * orthographic projection transformation will be applied first! 8414 * <p> 8415 * In order to set the matrix to an orthographic projection without post-multiplying it, 8416 * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}. 8417 * <p> 8418 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8419 * 8420 * @see #setOrthoLH(double, double, double, double, double, double, bool) 8421 * 8422 * @param left 8423 * the distance from the center to the left frustum edge 8424 * @param right 8425 * the distance from the center to the right frustum edge 8426 * @param bottom 8427 * the distance from the center to the bottom frustum edge 8428 * @param top 8429 * the distance from the center to the top frustum edge 8430 * @param zNear 8431 * near clipping plane distance 8432 * @param zFar 8433 * far clipping plane distance 8434 * @param zZeroToOne 8435 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8436 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8437 * @param dest 8438 * will hold the result 8439 * @return dest 8440 */ 8441 public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8442 if ((properties & PROPERTY_IDENTITY) != 0) 8443 return dest.setOrthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne); 8444 return orthoLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 8445 } 8446 private Matrix4d orthoLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8447 // calculate right matrix elements 8448 double rm00 = 2.0 / (right - left); 8449 double rm11 = 2.0 / (top - bottom); 8450 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear); 8451 double rm30 = (left + right) / (left - right); 8452 double rm31 = (top + bottom) / (bottom - top); 8453 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8454 // perform optimized multiplication 8455 // compute the last column first, because other columns do not depend on it 8456 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 8457 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 8458 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 8459 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 8460 ._m00(m00 * rm00) 8461 ._m01(m01 * rm00) 8462 ._m02(m02 * rm00) 8463 ._m03(m03 * rm00) 8464 ._m10(m10 * rm11) 8465 ._m11(m11 * rm11) 8466 ._m12(m12 * rm11) 8467 ._m13(m13 * rm11) 8468 ._m20(m20 * rm22) 8469 ._m21(m21 * rm22) 8470 ._m22(m22 * rm22) 8471 ._m23(m23 * rm22) 8472 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8473 return dest; 8474 } 8475 8476 /** 8477 * Apply an orthographic projection transformation for a left-handed coordiante system 8478 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8479 * <p> 8480 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8481 * then the new matrix will be <code>M * O</code>. So when transforming a 8482 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8483 * orthographic projection transformation will be applied first! 8484 * <p> 8485 * In order to set the matrix to an orthographic projection without post-multiplying it, 8486 * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}. 8487 * <p> 8488 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8489 * 8490 * @see #setOrthoLH(double, double, double, double, double, double) 8491 * 8492 * @param left 8493 * the distance from the center to the left frustum edge 8494 * @param right 8495 * the distance from the center to the right frustum edge 8496 * @param bottom 8497 * the distance from the center to the bottom frustum edge 8498 * @param top 8499 * the distance from the center to the top frustum edge 8500 * @param zNear 8501 * near clipping plane distance 8502 * @param zFar 8503 * far clipping plane distance 8504 * @param dest 8505 * will hold the result 8506 * @return dest 8507 */ 8508 public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 8509 return orthoLH(left, right, bottom, top, zNear, zFar, false, dest); 8510 } 8511 8512 /** 8513 * Apply an orthographic projection transformation for a left-handed coordiante system 8514 * using the given NDC z range to this matrix. 8515 * <p> 8516 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8517 * then the new matrix will be <code>M * O</code>. So when transforming a 8518 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8519 * orthographic projection transformation will be applied first! 8520 * <p> 8521 * In order to set the matrix to an orthographic projection without post-multiplying it, 8522 * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}. 8523 * <p> 8524 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8525 * 8526 * @see #setOrthoLH(double, double, double, double, double, double, bool) 8527 * 8528 * @param left 8529 * the distance from the center to the left frustum edge 8530 * @param right 8531 * the distance from the center to the right frustum edge 8532 * @param bottom 8533 * the distance from the center to the bottom frustum edge 8534 * @param top 8535 * the distance from the center to the top frustum edge 8536 * @param zNear 8537 * near clipping plane distance 8538 * @param zFar 8539 * far clipping plane distance 8540 * @param zZeroToOne 8541 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8542 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8543 * @return this 8544 */ 8545 ref public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8546 orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 8547 return this; 8548 } 8549 8550 /** 8551 * Apply an orthographic projection transformation for a left-handed coordiante system 8552 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8553 * <p> 8554 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8555 * then the new matrix will be <code>M * O</code>. So when transforming a 8556 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8557 * orthographic projection transformation will be applied first! 8558 * <p> 8559 * In order to set the matrix to an orthographic projection without post-multiplying it, 8560 * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}. 8561 * <p> 8562 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8563 * 8564 * @see #setOrthoLH(double, double, double, double, double, double) 8565 * 8566 * @param left 8567 * the distance from the center to the left frustum edge 8568 * @param right 8569 * the distance from the center to the right frustum edge 8570 * @param bottom 8571 * the distance from the center to the bottom frustum edge 8572 * @param top 8573 * the distance from the center to the top frustum edge 8574 * @param zNear 8575 * near clipping plane distance 8576 * @param zFar 8577 * far clipping plane distance 8578 * @return this 8579 */ 8580 ref public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 8581 return orthoLH(left, right, bottom, top, zNear, zFar, false); 8582 } 8583 8584 /** 8585 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system 8586 * using the given NDC z range. 8587 * <p> 8588 * In order to apply the orthographic projection to an already existing transformation, 8589 * use {@link #ortho(double, double, double, double, double, double, bool) ortho()}. 8590 * <p> 8591 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8592 * 8593 * @see #ortho(double, double, double, double, double, double, bool) 8594 * 8595 * @param left 8596 * the distance from the center to the left frustum edge 8597 * @param right 8598 * the distance from the center to the right frustum edge 8599 * @param bottom 8600 * the distance from the center to the bottom frustum edge 8601 * @param top 8602 * the distance from the center to the top frustum edge 8603 * @param zNear 8604 * near clipping plane distance 8605 * @param zFar 8606 * far clipping plane distance 8607 * @param zZeroToOne 8608 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8609 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8610 * @return this 8611 */ 8612 ref public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8613 if ((properties & PROPERTY_IDENTITY) == 0) 8614 _identity(); 8615 _m00(2.0 / (right - left)). 8616 _m11(2.0 / (top - bottom)). 8617 _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)). 8618 _m30((right + left) / (left - right)). 8619 _m31((top + bottom) / (bottom - top)). 8620 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 8621 properties = PROPERTY_AFFINE; 8622 return this; 8623 } 8624 8625 /** 8626 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system 8627 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 8628 * <p> 8629 * In order to apply the orthographic projection to an already existing transformation, 8630 * use {@link #ortho(double, double, double, double, double, double) ortho()}. 8631 * <p> 8632 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8633 * 8634 * @see #ortho(double, double, double, double, double, double) 8635 * 8636 * @param left 8637 * the distance from the center to the left frustum edge 8638 * @param right 8639 * the distance from the center to the right frustum edge 8640 * @param bottom 8641 * the distance from the center to the bottom frustum edge 8642 * @param top 8643 * the distance from the center to the top frustum edge 8644 * @param zNear 8645 * near clipping plane distance 8646 * @param zFar 8647 * far clipping plane distance 8648 * @return this 8649 */ 8650 ref public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) return { 8651 return setOrtho(left, right, bottom, top, zNear, zFar, false); 8652 } 8653 8654 /** 8655 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system 8656 * using the given NDC z range. 8657 * <p> 8658 * In order to apply the orthographic projection to an already existing transformation, 8659 * use {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()}. 8660 * <p> 8661 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8662 * 8663 * @see #orthoLH(double, double, double, double, double, double, bool) 8664 * 8665 * @param left 8666 * the distance from the center to the left frustum edge 8667 * @param right 8668 * the distance from the center to the right frustum edge 8669 * @param bottom 8670 * the distance from the center to the bottom frustum edge 8671 * @param top 8672 * the distance from the center to the top frustum edge 8673 * @param zNear 8674 * near clipping plane distance 8675 * @param zFar 8676 * far clipping plane distance 8677 * @param zZeroToOne 8678 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8679 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8680 * @return this 8681 */ 8682 ref public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8683 if ((properties & PROPERTY_IDENTITY) == 0) 8684 _identity(); 8685 _m00(2.0 / (right - left)). 8686 _m11(2.0 / (top - bottom)). 8687 _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)). 8688 _m30((right + left) / (left - right)). 8689 _m31((top + bottom) / (bottom - top)). 8690 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 8691 properties = PROPERTY_AFFINE; 8692 return this; 8693 } 8694 8695 /** 8696 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system 8697 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 8698 * <p> 8699 * In order to apply the orthographic projection to an already existing transformation, 8700 * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}. 8701 * <p> 8702 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8703 * 8704 * @see #orthoLH(double, double, double, double, double, double) 8705 * 8706 * @param left 8707 * the distance from the center to the left frustum edge 8708 * @param right 8709 * the distance from the center to the right frustum edge 8710 * @param bottom 8711 * the distance from the center to the bottom frustum edge 8712 * @param top 8713 * the distance from the center to the top frustum edge 8714 * @param zNear 8715 * near clipping plane distance 8716 * @param zFar 8717 * far clipping plane distance 8718 * @return this 8719 */ 8720 ref public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 8721 return setOrthoLH(left, right, bottom, top, zNear, zFar, false); 8722 } 8723 8724 /** 8725 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8726 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8727 * <p> 8728 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool, Matrix4d) ortho()} with 8729 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8730 * <p> 8731 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8732 * then the new matrix will be <code>M * O</code>. So when transforming a 8733 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8734 * orthographic projection transformation will be applied first! 8735 * <p> 8736 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8737 * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}. 8738 * <p> 8739 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8740 * 8741 * @see #setOrthoSymmetric(double, double, double, double, bool) 8742 * 8743 * @param width 8744 * the distance between the right and left frustum edges 8745 * @param height 8746 * the distance between the top and bottom frustum edges 8747 * @param zNear 8748 * near clipping plane distance 8749 * @param zFar 8750 * far clipping plane distance 8751 * @param dest 8752 * will hold the result 8753 * @param zZeroToOne 8754 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8755 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8756 * @return dest 8757 */ 8758 public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8759 if ((properties & PROPERTY_IDENTITY) != 0) 8760 return dest.setOrthoSymmetric(width, height, zNear, zFar, zZeroToOne); 8761 return orthoSymmetricGeneric(width, height, zNear, zFar, zZeroToOne, dest); 8762 } 8763 private Matrix4d orthoSymmetricGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8764 // calculate right matrix elements 8765 double rm00 = 2.0 / width; 8766 double rm11 = 2.0 / height; 8767 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar); 8768 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8769 // perform optimized multiplication 8770 // compute the last column first, because other columns do not depend on it 8771 dest._m30(m20 * rm32 + m30) 8772 ._m31(m21 * rm32 + m31) 8773 ._m32(m22 * rm32 + m32) 8774 ._m33(m23 * rm32 + m33) 8775 ._m00(m00 * rm00) 8776 ._m01(m01 * rm00) 8777 ._m02(m02 * rm00) 8778 ._m03(m03 * rm00) 8779 ._m10(m10 * rm11) 8780 ._m11(m11 * rm11) 8781 ._m12(m12 * rm11) 8782 ._m13(m13 * rm11) 8783 ._m20(m20 * rm22) 8784 ._m21(m21 * rm22) 8785 ._m22(m22 * rm22) 8786 ._m23(m23 * rm22) 8787 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8788 return dest; 8789 } 8790 8791 /** 8792 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8793 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8794 * <p> 8795 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with 8796 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8797 * <p> 8798 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8799 * then the new matrix will be <code>M * O</code>. So when transforming a 8800 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8801 * orthographic projection transformation will be applied first! 8802 * <p> 8803 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8804 * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}. 8805 * <p> 8806 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8807 * 8808 * @see #setOrthoSymmetric(double, double, double, double) 8809 * 8810 * @param width 8811 * the distance between the right and left frustum edges 8812 * @param height 8813 * the distance between the top and bottom frustum edges 8814 * @param zNear 8815 * near clipping plane distance 8816 * @param zFar 8817 * far clipping plane distance 8818 * @param dest 8819 * will hold the result 8820 * @return dest 8821 */ 8822 public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 8823 return orthoSymmetric(width, height, zNear, zFar, false, dest); 8824 } 8825 8826 /** 8827 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8828 * using the given NDC z range to this matrix. 8829 * <p> 8830 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool) ortho()} with 8831 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8832 * <p> 8833 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8834 * then the new matrix will be <code>M * O</code>. So when transforming a 8835 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8836 * orthographic projection transformation will be applied first! 8837 * <p> 8838 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8839 * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}. 8840 * <p> 8841 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8842 * 8843 * @see #setOrthoSymmetric(double, double, double, double, bool) 8844 * 8845 * @param width 8846 * the distance between the right and left frustum edges 8847 * @param height 8848 * the distance between the top and bottom frustum edges 8849 * @param zNear 8850 * near clipping plane distance 8851 * @param zFar 8852 * far clipping plane distance 8853 * @param zZeroToOne 8854 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8855 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8856 * @return this 8857 */ 8858 ref public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 8859 orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this); 8860 return this; 8861 } 8862 8863 /** 8864 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8865 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8866 * <p> 8867 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with 8868 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8869 * <p> 8870 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8871 * then the new matrix will be <code>M * O</code>. So when transforming a 8872 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8873 * orthographic projection transformation will be applied first! 8874 * <p> 8875 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8876 * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}. 8877 * <p> 8878 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8879 * 8880 * @see #setOrthoSymmetric(double, double, double, double) 8881 * 8882 * @param width 8883 * the distance between the right and left frustum edges 8884 * @param height 8885 * the distance between the top and bottom frustum edges 8886 * @param zNear 8887 * near clipping plane distance 8888 * @param zFar 8889 * far clipping plane distance 8890 * @return this 8891 */ 8892 ref public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar) return { 8893 orthoSymmetric(width, height, zNear, zFar, false, this); 8894 return this; 8895 } 8896 8897 /** 8898 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8899 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8900 * <p> 8901 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool, Matrix4d) orthoLH()} with 8902 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8903 * <p> 8904 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8905 * then the new matrix will be <code>M * O</code>. So when transforming a 8906 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8907 * orthographic projection transformation will be applied first! 8908 * <p> 8909 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8910 * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}. 8911 * <p> 8912 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8913 * 8914 * @see #setOrthoSymmetricLH(double, double, double, double, bool) 8915 * 8916 * @param width 8917 * the distance between the right and left frustum edges 8918 * @param height 8919 * the distance between the top and bottom frustum edges 8920 * @param zNear 8921 * near clipping plane distance 8922 * @param zFar 8923 * far clipping plane distance 8924 * @param dest 8925 * will hold the result 8926 * @param zZeroToOne 8927 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8928 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8929 * @return dest 8930 */ 8931 public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8932 if ((properties & PROPERTY_IDENTITY) != 0) 8933 return dest.setOrthoSymmetricLH(width, height, zNear, zFar, zZeroToOne); 8934 return orthoSymmetricLHGeneric(width, height, zNear, zFar, zZeroToOne, dest); 8935 } 8936 private Matrix4d orthoSymmetricLHGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8937 // calculate right matrix elements 8938 double rm00 = 2.0 / width; 8939 double rm11 = 2.0 / height; 8940 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear); 8941 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8942 // perform optimized multiplication 8943 // compute the last column first, because other columns do not depend on it 8944 dest._m30(m20 * rm32 + m30) 8945 ._m31(m21 * rm32 + m31) 8946 ._m32(m22 * rm32 + m32) 8947 ._m33(m23 * rm32 + m33) 8948 ._m00(m00 * rm00) 8949 ._m01(m01 * rm00) 8950 ._m02(m02 * rm00) 8951 ._m03(m03 * rm00) 8952 ._m10(m10 * rm11) 8953 ._m11(m11 * rm11) 8954 ._m12(m12 * rm11) 8955 ._m13(m13 * rm11) 8956 ._m20(m20 * rm22) 8957 ._m21(m21 * rm22) 8958 ._m22(m22 * rm22) 8959 ._m23(m23 * rm22) 8960 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8961 return dest; 8962 } 8963 8964 /** 8965 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8966 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8967 * <p> 8968 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with 8969 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8970 * <p> 8971 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8972 * then the new matrix will be <code>M * O</code>. So when transforming a 8973 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8974 * orthographic projection transformation will be applied first! 8975 * <p> 8976 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8977 * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}. 8978 * <p> 8979 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8980 * 8981 * @see #setOrthoSymmetricLH(double, double, double, double) 8982 * 8983 * @param width 8984 * the distance between the right and left frustum edges 8985 * @param height 8986 * the distance between the top and bottom frustum edges 8987 * @param zNear 8988 * near clipping plane distance 8989 * @param zFar 8990 * far clipping plane distance 8991 * @param dest 8992 * will hold the result 8993 * @return dest 8994 */ 8995 public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 8996 return orthoSymmetricLH(width, height, zNear, zFar, false, dest); 8997 } 8998 8999 /** 9000 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 9001 * using the given NDC z range to this matrix. 9002 * <p> 9003 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()} with 9004 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9005 * <p> 9006 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9007 * then the new matrix will be <code>M * O</code>. So when transforming a 9008 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9009 * orthographic projection transformation will be applied first! 9010 * <p> 9011 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 9012 * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}. 9013 * <p> 9014 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9015 * 9016 * @see #setOrthoSymmetricLH(double, double, double, double, bool) 9017 * 9018 * @param width 9019 * the distance between the right and left frustum edges 9020 * @param height 9021 * the distance between the top and bottom frustum edges 9022 * @param zNear 9023 * near clipping plane distance 9024 * @param zFar 9025 * far clipping plane distance 9026 * @param zZeroToOne 9027 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9028 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9029 * @return this 9030 */ 9031 ref public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9032 orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this); 9033 return this; 9034 } 9035 9036 /** 9037 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 9038 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 9039 * <p> 9040 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with 9041 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9042 * <p> 9043 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9044 * then the new matrix will be <code>M * O</code>. So when transforming a 9045 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9046 * orthographic projection transformation will be applied first! 9047 * <p> 9048 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 9049 * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}. 9050 * <p> 9051 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9052 * 9053 * @see #setOrthoSymmetricLH(double, double, double, double) 9054 * 9055 * @param width 9056 * the distance between the right and left frustum edges 9057 * @param height 9058 * the distance between the top and bottom frustum edges 9059 * @param zNear 9060 * near clipping plane distance 9061 * @param zFar 9062 * far clipping plane distance 9063 * @return this 9064 */ 9065 ref public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar) return { 9066 orthoSymmetricLH(width, height, zNear, zFar, false, this); 9067 return this; 9068 } 9069 9070 /** 9071 * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system 9072 * using the given NDC z range. 9073 * <p> 9074 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with 9075 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9076 * <p> 9077 * In order to apply the symmetric orthographic projection to an already existing transformation, 9078 * use {@link #orthoSymmetric(double, double, double, double, bool) orthoSymmetric()}. 9079 * <p> 9080 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9081 * 9082 * @see #orthoSymmetric(double, double, double, double, bool) 9083 * 9084 * @param width 9085 * the distance between the right and left frustum edges 9086 * @param height 9087 * the distance between the top and bottom frustum edges 9088 * @param zNear 9089 * near clipping plane distance 9090 * @param zFar 9091 * far clipping plane distance 9092 * @param zZeroToOne 9093 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9094 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9095 * @return this 9096 */ 9097 ref public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9098 if ((properties & PROPERTY_IDENTITY) == 0) 9099 _identity(); 9100 _m00(2.0 / width). 9101 _m11(2.0 / height). 9102 _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)). 9103 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 9104 properties = PROPERTY_AFFINE; 9105 return this; 9106 } 9107 9108 /** 9109 * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system 9110 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 9111 * <p> 9112 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with 9113 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9114 * <p> 9115 * In order to apply the symmetric orthographic projection to an already existing transformation, 9116 * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}. 9117 * <p> 9118 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9119 * 9120 * @see #orthoSymmetric(double, double, double, double) 9121 * 9122 * @param width 9123 * the distance between the right and left frustum edges 9124 * @param height 9125 * the distance between the top and bottom frustum edges 9126 * @param zNear 9127 * near clipping plane distance 9128 * @param zFar 9129 * far clipping plane distance 9130 * @return this 9131 */ 9132 ref public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar) return { 9133 return setOrthoSymmetric(width, height, zNear, zFar, false); 9134 } 9135 9136 /** 9137 * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range. 9138 * <p> 9139 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with 9140 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9141 * <p> 9142 * In order to apply the symmetric orthographic projection to an already existing transformation, 9143 * use {@link #orthoSymmetricLH(double, double, double, double, bool) orthoSymmetricLH()}. 9144 * <p> 9145 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9146 * 9147 * @see #orthoSymmetricLH(double, double, double, double, bool) 9148 * 9149 * @param width 9150 * the distance between the right and left frustum edges 9151 * @param height 9152 * the distance between the top and bottom frustum edges 9153 * @param zNear 9154 * near clipping plane distance 9155 * @param zFar 9156 * far clipping plane distance 9157 * @param zZeroToOne 9158 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9159 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9160 * @return this 9161 */ 9162 ref public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9163 if ((properties & PROPERTY_IDENTITY) == 0) 9164 _identity(); 9165 _m00(2.0 / width). 9166 _m11(2.0 / height). 9167 _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)). 9168 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 9169 properties = PROPERTY_AFFINE; 9170 return this; 9171 } 9172 9173 /** 9174 * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system 9175 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 9176 * <p> 9177 * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with 9178 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9179 * <p> 9180 * In order to apply the symmetric orthographic projection to an already existing transformation, 9181 * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}. 9182 * <p> 9183 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9184 * 9185 * @see #orthoSymmetricLH(double, double, double, double) 9186 * 9187 * @param width 9188 * the distance between the right and left frustum edges 9189 * @param height 9190 * the distance between the top and bottom frustum edges 9191 * @param zNear 9192 * near clipping plane distance 9193 * @param zFar 9194 * far clipping plane distance 9195 * @return this 9196 */ 9197 ref public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) return { 9198 return setOrthoSymmetricLH(width, height, zNear, zFar, false); 9199 } 9200 9201 /** 9202 * Apply an orthographic projection transformation for a right-handed coordinate system 9203 * to this matrix and store the result in <code>dest</code>. 9204 * <p> 9205 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with 9206 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9207 * <p> 9208 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9209 * then the new matrix will be <code>M * O</code>. So when transforming a 9210 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9211 * orthographic projection transformation will be applied first! 9212 * <p> 9213 * In order to set the matrix to an orthographic projection without post-multiplying it, 9214 * use {@link #setOrtho2D(double, double, double, double) setOrtho()}. 9215 * <p> 9216 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9217 * 9218 * @see #ortho(double, double, double, double, double, double, Matrix4d) 9219 * @see #setOrtho2D(double, double, double, double) 9220 * 9221 * @param left 9222 * the distance from the center to the left frustum edge 9223 * @param right 9224 * the distance from the center to the right frustum edge 9225 * @param bottom 9226 * the distance from the center to the bottom frustum edge 9227 * @param top 9228 * the distance from the center to the top frustum edge 9229 * @param dest 9230 * will hold the result 9231 * @return dest 9232 */ 9233 public Matrix4d ortho2D(double left, double right, double bottom, double top, ref Matrix4d dest) { 9234 if ((properties & PROPERTY_IDENTITY) != 0) 9235 return dest.setOrtho2D(left, right, bottom, top); 9236 return ortho2DGeneric(left, right, bottom, top, dest); 9237 } 9238 private Matrix4d ortho2DGeneric(double left, double right, double bottom, double top, ref Matrix4d dest) { 9239 // calculate right matrix elements 9240 double rm00 = 2.0 / (right - left); 9241 double rm11 = 2.0 / (top - bottom); 9242 double rm30 = (right + left) / (left - right); 9243 double rm31 = (top + bottom) / (bottom - top); 9244 // perform optimized multiplication 9245 // compute the last column first, because other columns do not depend on it 9246 dest._m30(m00 * rm30 + m10 * rm31 + m30) 9247 ._m31(m01 * rm30 + m11 * rm31 + m31) 9248 ._m32(m02 * rm30 + m12 * rm31 + m32) 9249 ._m33(m03 * rm30 + m13 * rm31 + m33) 9250 ._m00(m00 * rm00) 9251 ._m01(m01 * rm00) 9252 ._m02(m02 * rm00) 9253 ._m03(m03 * rm00) 9254 ._m10(m10 * rm11) 9255 ._m11(m11 * rm11) 9256 ._m12(m12 * rm11) 9257 ._m13(m13 * rm11) 9258 ._m20(-m20) 9259 ._m21(-m21) 9260 ._m22(-m22) 9261 ._m23(-m23) 9262 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 9263 return dest; 9264 } 9265 9266 /** 9267 * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix. 9268 * <p> 9269 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with 9270 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9271 * <p> 9272 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9273 * then the new matrix will be <code>M * O</code>. So when transforming a 9274 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9275 * orthographic projection transformation will be applied first! 9276 * <p> 9277 * In order to set the matrix to an orthographic projection without post-multiplying it, 9278 * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}. 9279 * <p> 9280 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9281 * 9282 * @see #ortho(double, double, double, double, double, double) 9283 * @see #setOrtho2D(double, double, double, double) 9284 * 9285 * @param left 9286 * the distance from the center to the left frustum edge 9287 * @param right 9288 * the distance from the center to the right frustum edge 9289 * @param bottom 9290 * the distance from the center to the bottom frustum edge 9291 * @param top 9292 * the distance from the center to the top frustum edge 9293 * @return this 9294 */ 9295 ref public Matrix4d ortho2D(double left, double right, double bottom, double top) return { 9296 ortho2D(left, right, bottom, top, this); 9297 return this; 9298 } 9299 9300 /** 9301 * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in <code>dest</code>. 9302 * <p> 9303 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with 9304 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9305 * <p> 9306 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9307 * then the new matrix will be <code>M * O</code>. So when transforming a 9308 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9309 * orthographic projection transformation will be applied first! 9310 * <p> 9311 * In order to set the matrix to an orthographic projection without post-multiplying it, 9312 * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}. 9313 * <p> 9314 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9315 * 9316 * @see #orthoLH(double, double, double, double, double, double, Matrix4d) 9317 * @see #setOrtho2DLH(double, double, double, double) 9318 * 9319 * @param left 9320 * the distance from the center to the left frustum edge 9321 * @param right 9322 * the distance from the center to the right frustum edge 9323 * @param bottom 9324 * the distance from the center to the bottom frustum edge 9325 * @param top 9326 * the distance from the center to the top frustum edge 9327 * @param dest 9328 * will hold the result 9329 * @return dest 9330 */ 9331 public Matrix4d ortho2DLH(double left, double right, double bottom, double top, ref Matrix4d dest) { 9332 if ((properties & PROPERTY_IDENTITY) != 0) 9333 return dest.setOrtho2DLH(left, right, bottom, top); 9334 return ortho2DLHGeneric(left, right, bottom, top, dest); 9335 } 9336 private Matrix4d ortho2DLHGeneric(double left, double right, double bottom, double top, ref Matrix4d dest) { 9337 // calculate right matrix elements 9338 double rm00 = 2.0 / (right - left); 9339 double rm11 = 2.0 / (top - bottom); 9340 double rm30 = (right + left) / (left - right); 9341 double rm31 = (top + bottom) / (bottom - top); 9342 // perform optimized multiplication 9343 // compute the last column first, because other columns do not depend on it 9344 dest._m30(m00 * rm30 + m10 * rm31 + m30) 9345 ._m31(m01 * rm30 + m11 * rm31 + m31) 9346 ._m32(m02 * rm30 + m12 * rm31 + m32) 9347 ._m33(m03 * rm30 + m13 * rm31 + m33) 9348 ._m00(m00 * rm00) 9349 ._m01(m01 * rm00) 9350 ._m02(m02 * rm00) 9351 ._m03(m03 * rm00) 9352 ._m10(m10 * rm11) 9353 ._m11(m11 * rm11) 9354 ._m12(m12 * rm11) 9355 ._m13(m13 * rm11) 9356 ._m20(m20) 9357 ._m21(m21) 9358 ._m22(m22) 9359 ._m23(m23) 9360 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 9361 return dest; 9362 } 9363 9364 /** 9365 * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix. 9366 * <p> 9367 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with 9368 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9369 * <p> 9370 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9371 * then the new matrix will be <code>M * O</code>. So when transforming a 9372 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9373 * orthographic projection transformation will be applied first! 9374 * <p> 9375 * In order to set the matrix to an orthographic projection without post-multiplying it, 9376 * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}. 9377 * <p> 9378 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9379 * 9380 * @see #orthoLH(double, double, double, double, double, double) 9381 * @see #setOrtho2DLH(double, double, double, double) 9382 * 9383 * @param left 9384 * the distance from the center to the left frustum edge 9385 * @param right 9386 * the distance from the center to the right frustum edge 9387 * @param bottom 9388 * the distance from the center to the bottom frustum edge 9389 * @param top 9390 * the distance from the center to the top frustum edge 9391 * @return this 9392 */ 9393 ref public Matrix4d ortho2DLH(double left, double right, double bottom, double top) return { 9394 ortho2DLH(left, right, bottom, top, this); 9395 return this; 9396 } 9397 9398 /** 9399 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system. 9400 * <p> 9401 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with 9402 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9403 * <p> 9404 * In order to apply the orthographic projection to an already existing transformation, 9405 * use {@link #ortho2D(double, double, double, double) ortho2D()}. 9406 * <p> 9407 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9408 * 9409 * @see #setOrtho(double, double, double, double, double, double) 9410 * @see #ortho2D(double, double, double, double) 9411 * 9412 * @param left 9413 * the distance from the center to the left frustum edge 9414 * @param right 9415 * the distance from the center to the right frustum edge 9416 * @param bottom 9417 * the distance from the center to the bottom frustum edge 9418 * @param top 9419 * the distance from the center to the top frustum edge 9420 * @return this 9421 */ 9422 ref public Matrix4d setOrtho2D(double left, double right, double bottom, double top) return { 9423 if ((properties & PROPERTY_IDENTITY) == 0) 9424 _identity(); 9425 _m00(2.0 / (right - left)). 9426 _m11(2.0 / (top - bottom)). 9427 _m22(-1.0). 9428 _m30((right + left) / (left - right)). 9429 _m31((top + bottom) / (bottom - top)). 9430 properties = PROPERTY_AFFINE; 9431 return this; 9432 } 9433 9434 /** 9435 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system. 9436 * <p> 9437 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with 9438 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9439 * <p> 9440 * In order to apply the orthographic projection to an already existing transformation, 9441 * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}. 9442 * <p> 9443 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9444 * 9445 * @see #setOrthoLH(double, double, double, double, double, double) 9446 * @see #ortho2DLH(double, double, double, double) 9447 * 9448 * @param left 9449 * the distance from the center to the left frustum edge 9450 * @param right 9451 * the distance from the center to the right frustum edge 9452 * @param bottom 9453 * the distance from the center to the bottom frustum edge 9454 * @param top 9455 * the distance from the center to the top frustum edge 9456 * @return this 9457 */ 9458 ref public Matrix4d setOrtho2DLH(double left, double right, double bottom, double top) return { 9459 if ((properties & PROPERTY_IDENTITY) == 0) 9460 _identity(); 9461 _m00(2.0 / (right - left)). 9462 _m11(2.0 / (top - bottom)). 9463 _m30((right + left) / (left - right)). 9464 _m31((top + bottom) / (bottom - top)). 9465 properties = PROPERTY_AFFINE; 9466 return this; 9467 } 9468 9469 /** 9470 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 9471 * <p> 9472 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9473 * then the new matrix will be <code>M * L</code>. So when transforming a 9474 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9475 * lookalong rotation transformation will be applied first! 9476 * <p> 9477 * This is equivalent to calling 9478 * {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt} 9479 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9480 * <p> 9481 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9482 * use {@link #setLookAlong(ref Vector3d, Vector3d) setLookAlong()}. 9483 * 9484 * @see #lookAlong(double, double, double, double, double, double) 9485 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9486 * @see #setLookAlong(ref Vector3d, Vector3d) 9487 * 9488 * @param dir 9489 * the direction in space to look along 9490 * @param up 9491 * the direction of 'up' 9492 * @return this 9493 */ 9494 ref public Matrix4d lookAlong(ref Vector3d dir, Vector3d up) return { 9495 lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this); 9496 return this; 9497 } 9498 9499 /** 9500 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code> 9501 * and store the result in <code>dest</code>. 9502 * <p> 9503 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9504 * then the new matrix will be <code>M * L</code>. So when transforming a 9505 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9506 * lookalong rotation transformation will be applied first! 9507 * <p> 9508 * This is equivalent to calling 9509 * {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt} 9510 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9511 * <p> 9512 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9513 * use {@link #setLookAlong(ref Vector3d, Vector3d) setLookAlong()}. 9514 * 9515 * @see #lookAlong(double, double, double, double, double, double) 9516 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9517 * @see #setLookAlong(ref Vector3d, Vector3d) 9518 * 9519 * @param dir 9520 * the direction in space to look along 9521 * @param up 9522 * the direction of 'up' 9523 * @param dest 9524 * will hold the result 9525 * @return dest 9526 */ 9527 public Matrix4d lookAlong(ref Vector3d dir, Vector3d up, ref Matrix4d dest) { 9528 return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest); 9529 } 9530 9531 /** 9532 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code> 9533 * and store the result in <code>dest</code>. 9534 * <p> 9535 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9536 * then the new matrix will be <code>M * L</code>. So when transforming a 9537 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9538 * lookalong rotation transformation will be applied first! 9539 * <p> 9540 * This is equivalent to calling 9541 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()} 9542 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9543 * <p> 9544 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9545 * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()} 9546 * 9547 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9548 * @see #setLookAlong(double, double, double, double, double, double) 9549 * 9550 * @param dirX 9551 * the x-coordinate of the direction to look along 9552 * @param dirY 9553 * the y-coordinate of the direction to look along 9554 * @param dirZ 9555 * the z-coordinate of the direction to look along 9556 * @param upX 9557 * the x-coordinate of the up vector 9558 * @param upY 9559 * the y-coordinate of the up vector 9560 * @param upZ 9561 * the z-coordinate of the up vector 9562 * @param dest 9563 * will hold the result 9564 * @return dest 9565 */ 9566 public Matrix4d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 9567 if ((properties & PROPERTY_IDENTITY) != 0) 9568 return dest.setLookAlong(dirX, dirY, dirZ, upX, upY, upZ); 9569 return lookAlongGeneric(dirX, dirY, dirZ, upX, upY, upZ, dest); 9570 } 9571 9572 private Matrix4d lookAlongGeneric(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 9573 // Normalize direction 9574 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9575 dirX *= -invDirLength; 9576 dirY *= -invDirLength; 9577 dirZ *= -invDirLength; 9578 // left = up x direction 9579 double leftX, leftY, leftZ; 9580 leftX = upY * dirZ - upZ * dirY; 9581 leftY = upZ * dirX - upX * dirZ; 9582 leftZ = upX * dirY - upY * dirX; 9583 // normalize left 9584 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9585 leftX *= invLeftLength; 9586 leftY *= invLeftLength; 9587 leftZ *= invLeftLength; 9588 // up = direction x left 9589 double upnX = dirY * leftZ - dirZ * leftY; 9590 double upnY = dirZ * leftX - dirX * leftZ; 9591 double upnZ = dirX * leftY - dirY * leftX; 9592 // calculate right matrix elements 9593 double rm00 = leftX; 9594 double rm01 = upnX; 9595 double rm02 = dirX; 9596 double rm10 = leftY; 9597 double rm11 = upnY; 9598 double rm12 = dirY; 9599 double rm20 = leftZ; 9600 double rm21 = upnZ; 9601 double rm22 = dirZ; 9602 // perform optimized matrix multiplication 9603 // introduce temporaries for dependent results 9604 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 9605 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 9606 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 9607 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 9608 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 9609 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 9610 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 9611 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 9612 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 9613 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 9614 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 9615 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 9616 // set the rest of the matrix elements 9617 ._m00(nm00) 9618 ._m01(nm01) 9619 ._m02(nm02) 9620 ._m03(nm03) 9621 ._m10(nm10) 9622 ._m11(nm11) 9623 ._m12(nm12) 9624 ._m13(nm13) 9625 ._m30(m30) 9626 ._m31(m31) 9627 ._m32(m32) 9628 ._m33(m33) 9629 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 9630 return dest; 9631 } 9632 9633 /** 9634 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 9635 * <p> 9636 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9637 * then the new matrix will be <code>M * L</code>. So when transforming a 9638 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9639 * lookalong rotation transformation will be applied first! 9640 * <p> 9641 * This is equivalent to calling 9642 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()} 9643 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9644 * <p> 9645 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9646 * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()} 9647 * 9648 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9649 * @see #setLookAlong(double, double, double, double, double, double) 9650 * 9651 * @param dirX 9652 * the x-coordinate of the direction to look along 9653 * @param dirY 9654 * the y-coordinate of the direction to look along 9655 * @param dirZ 9656 * the z-coordinate of the direction to look along 9657 * @param upX 9658 * the x-coordinate of the up vector 9659 * @param upY 9660 * the y-coordinate of the up vector 9661 * @param upZ 9662 * the z-coordinate of the up vector 9663 * @return this 9664 */ 9665 ref public Matrix4d lookAlong(double dirX, double dirY, double dirZ, 9666 double upX, double upY, double upZ) return { 9667 lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this); 9668 return this; 9669 } 9670 9671 /** 9672 * Set this matrix to a rotation transformation to make <code>-z</code> 9673 * point along <code>dir</code>. 9674 * <p> 9675 * This is equivalent to calling 9676 * {@link #setLookAt(ref Vector3d, Vector3d, Vector3d) setLookAt()} 9677 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9678 * <p> 9679 * In order to apply the lookalong transformation to any previous existing transformation, 9680 * use {@link #lookAlong(ref Vector3d, Vector3d)}. 9681 * 9682 * @see #setLookAlong(ref Vector3d, Vector3d) 9683 * @see #lookAlong(ref Vector3d, Vector3d) 9684 * 9685 * @param dir 9686 * the direction in space to look along 9687 * @param up 9688 * the direction of 'up' 9689 * @return this 9690 */ 9691 ref public Matrix4d setLookAlong(ref Vector3d dir, Vector3d up) return { 9692 return setLookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z); 9693 } 9694 9695 /** 9696 * Set this matrix to a rotation transformation to make <code>-z</code> 9697 * point along <code>dir</code>. 9698 * <p> 9699 * This is equivalent to calling 9700 * {@link #setLookAt(double, double, double, double, double, double, double, double, double) 9701 * setLookAt()} with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9702 * <p> 9703 * In order to apply the lookalong transformation to any previous existing transformation, 9704 * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()} 9705 * 9706 * @see #setLookAlong(double, double, double, double, double, double) 9707 * @see #lookAlong(double, double, double, double, double, double) 9708 * 9709 * @param dirX 9710 * the x-coordinate of the direction to look along 9711 * @param dirY 9712 * the y-coordinate of the direction to look along 9713 * @param dirZ 9714 * the z-coordinate of the direction to look along 9715 * @param upX 9716 * the x-coordinate of the up vector 9717 * @param upY 9718 * the y-coordinate of the up vector 9719 * @param upZ 9720 * the z-coordinate of the up vector 9721 * @return this 9722 */ 9723 ref public Matrix4d setLookAlong(double dirX, double dirY, double dirZ, 9724 double upX, double upY, double upZ) return { 9725 // Normalize direction 9726 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9727 dirX *= -invDirLength; 9728 dirY *= -invDirLength; 9729 dirZ *= -invDirLength; 9730 // left = up x direction 9731 double leftX, leftY, leftZ; 9732 leftX = upY * dirZ - upZ * dirY; 9733 leftY = upZ * dirX - upX * dirZ; 9734 leftZ = upX * dirY - upY * dirX; 9735 // normalize left 9736 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9737 leftX *= invLeftLength; 9738 leftY *= invLeftLength; 9739 leftZ *= invLeftLength; 9740 // up = direction x left 9741 double upnX = dirY * leftZ - dirZ * leftY; 9742 double upnY = dirZ * leftX - dirX * leftZ; 9743 double upnZ = dirX * leftY - dirY * leftX; 9744 _m00(leftX). 9745 _m01(upnX). 9746 _m02(dirX). 9747 _m03(0.0). 9748 _m10(leftY). 9749 _m11(upnY). 9750 _m12(dirY). 9751 _m13(0.0). 9752 _m20(leftZ). 9753 _m21(upnZ). 9754 _m22(dirZ). 9755 _m23(0.0). 9756 _m30(0.0). 9757 _m31(0.0). 9758 _m32(0.0). 9759 _m33(1.0). 9760 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 9761 return this; 9762 } 9763 9764 /** 9765 * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns 9766 * <code>-z</code> with <code>center - eye</code>. 9767 * <p> 9768 * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives, 9769 * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()} 9770 * instead. 9771 * <p> 9772 * In order to apply the lookat transformation to a previous existing transformation, 9773 * use {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt()}. 9774 * 9775 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 9776 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9777 * 9778 * @param eye 9779 * the position of the camera 9780 * @param center 9781 * the point in space to look at 9782 * @param up 9783 * the direction of 'up' 9784 * @return this 9785 */ 9786 ref public Matrix4d setLookAt(ref Vector3d eye, Vector3d center, Vector3d up) return { 9787 return setLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z); 9788 } 9789 9790 /** 9791 * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, 9792 * that aligns <code>-z</code> with <code>center - eye</code>. 9793 * <p> 9794 * In order to apply the lookat transformation to a previous existing transformation, 9795 * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}. 9796 * 9797 * @see #setLookAt(ref Vector3d, Vector3d, Vector3d) 9798 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9799 * 9800 * @param eyeX 9801 * the x-coordinate of the eye/camera location 9802 * @param eyeY 9803 * the y-coordinate of the eye/camera location 9804 * @param eyeZ 9805 * the z-coordinate of the eye/camera location 9806 * @param centerX 9807 * the x-coordinate of the point to look at 9808 * @param centerY 9809 * the y-coordinate of the point to look at 9810 * @param centerZ 9811 * the z-coordinate of the point to look at 9812 * @param upX 9813 * the x-coordinate of the up vector 9814 * @param upY 9815 * the y-coordinate of the up vector 9816 * @param upZ 9817 * the z-coordinate of the up vector 9818 * @return this 9819 */ 9820 ref public Matrix4d setLookAt(double eyeX, double eyeY, double eyeZ, 9821 double centerX, double centerY, double centerZ, 9822 double upX, double upY, double upZ) return { 9823 // Compute direction from position to lookAt 9824 double dirX, dirY, dirZ; 9825 dirX = eyeX - centerX; 9826 dirY = eyeY - centerY; 9827 dirZ = eyeZ - centerZ; 9828 // Normalize direction 9829 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9830 dirX *= invDirLength; 9831 dirY *= invDirLength; 9832 dirZ *= invDirLength; 9833 // left = up x direction 9834 double leftX, leftY, leftZ; 9835 leftX = upY * dirZ - upZ * dirY; 9836 leftY = upZ * dirX - upX * dirZ; 9837 leftZ = upX * dirY - upY * dirX; 9838 // normalize left 9839 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9840 leftX *= invLeftLength; 9841 leftY *= invLeftLength; 9842 leftZ *= invLeftLength; 9843 // up = direction x left 9844 double upnX = dirY * leftZ - dirZ * leftY; 9845 double upnY = dirZ * leftX - dirX * leftZ; 9846 double upnZ = dirX * leftY - dirY * leftX; 9847 return this. 9848 _m00(leftX). 9849 _m01(upnX). 9850 _m02(dirX). 9851 _m03(0.0). 9852 _m10(leftY). 9853 _m11(upnY). 9854 _m12(dirY). 9855 _m13(0.0). 9856 _m20(leftZ). 9857 _m21(upnZ). 9858 _m22(dirZ). 9859 _m23(0.0). 9860 _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)). 9861 _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)). 9862 _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)). 9863 _m33(1.0). 9864 _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 9865 } 9866 9867 /** 9868 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9869 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 9870 * <p> 9871 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9872 * then the new matrix will be <code>M * L</code>. So when transforming a 9873 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9874 * the lookat transformation will be applied first! 9875 * <p> 9876 * In order to set the matrix to a lookat transformation without post-multiplying it, 9877 * use {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)}. 9878 * 9879 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9880 * @see #setLookAlong(ref Vector3d, Vector3d) 9881 * 9882 * @param eye 9883 * the position of the camera 9884 * @param center 9885 * the point in space to look at 9886 * @param up 9887 * the direction of 'up' 9888 * @param dest 9889 * will hold the result 9890 * @return dest 9891 */ 9892 public Matrix4d lookAt(ref Vector3d eye, Vector3d center, Vector3d up, ref Matrix4d dest) { 9893 return lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest); 9894 } 9895 9896 /** 9897 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9898 * that aligns <code>-z</code> with <code>center - eye</code>. 9899 * <p> 9900 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9901 * then the new matrix will be <code>M * L</code>. So when transforming a 9902 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9903 * the lookat transformation will be applied first! 9904 * <p> 9905 * In order to set the matrix to a lookat transformation without post-multiplying it, 9906 * use {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)}. 9907 * 9908 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9909 * @see #setLookAlong(ref Vector3d, Vector3d) 9910 * 9911 * @param eye 9912 * the position of the camera 9913 * @param center 9914 * the point in space to look at 9915 * @param up 9916 * the direction of 'up' 9917 * @return this 9918 */ 9919 ref public Matrix4d lookAt(ref Vector3d eye, Vector3d center, Vector3d up) return { 9920 lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this); 9921 return this; 9922 } 9923 9924 /** 9925 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9926 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 9927 * <p> 9928 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9929 * then the new matrix will be <code>M * L</code>. So when transforming a 9930 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9931 * the lookat transformation will be applied first! 9932 * <p> 9933 * In order to set the matrix to a lookat transformation without post-multiplying it, 9934 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 9935 * 9936 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9937 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 9938 * 9939 * @param eyeX 9940 * the x-coordinate of the eye/camera location 9941 * @param eyeY 9942 * the y-coordinate of the eye/camera location 9943 * @param eyeZ 9944 * the z-coordinate of the eye/camera location 9945 * @param centerX 9946 * the x-coordinate of the point to look at 9947 * @param centerY 9948 * the y-coordinate of the point to look at 9949 * @param centerZ 9950 * the z-coordinate of the point to look at 9951 * @param upX 9952 * the x-coordinate of the up vector 9953 * @param upY 9954 * the y-coordinate of the up vector 9955 * @param upZ 9956 * the z-coordinate of the up vector 9957 * @param dest 9958 * will hold the result 9959 * @return dest 9960 */ 9961 public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, 9962 double centerX, double centerY, double centerZ, 9963 double upX, double upY, double upZ, ref Matrix4d dest) { 9964 if ((properties & PROPERTY_IDENTITY) != 0) 9965 return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 9966 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 9967 return lookAtPerspective(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 9968 return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 9969 } 9970 private Matrix4d lookAtGeneric(double eyeX, double eyeY, double eyeZ, 9971 double centerX, double centerY, double centerZ, 9972 double upX, double upY, double upZ, ref Matrix4d dest) { 9973 // Compute direction from position to lookAt 9974 double dirX, dirY, dirZ; 9975 dirX = eyeX - centerX; 9976 dirY = eyeY - centerY; 9977 dirZ = eyeZ - centerZ; 9978 // Normalize direction 9979 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9980 dirX *= invDirLength; 9981 dirY *= invDirLength; 9982 dirZ *= invDirLength; 9983 // left = up x direction 9984 double leftX, leftY, leftZ; 9985 leftX = upY * dirZ - upZ * dirY; 9986 leftY = upZ * dirX - upX * dirZ; 9987 leftZ = upX * dirY - upY * dirX; 9988 // normalize left 9989 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9990 leftX *= invLeftLength; 9991 leftY *= invLeftLength; 9992 leftZ *= invLeftLength; 9993 // up = direction x left 9994 double upnX = dirY * leftZ - dirZ * leftY; 9995 double upnY = dirZ * leftX - dirX * leftZ; 9996 double upnZ = dirX * leftY - dirY * leftX; 9997 // calculate right matrix elements 9998 double rm00 = leftX; 9999 double rm01 = upnX; 10000 double rm02 = dirX; 10001 double rm10 = leftY; 10002 double rm11 = upnY; 10003 double rm12 = dirY; 10004 double rm20 = leftZ; 10005 double rm21 = upnZ; 10006 double rm22 = dirZ; 10007 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10008 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10009 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10010 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 10011 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 10012 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 10013 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 10014 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 10015 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 10016 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 10017 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 10018 // perform optimized matrix multiplication 10019 // compute last column first, because others do not depend on it 10020 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 10021 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 10022 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 10023 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 10024 // introduce temporaries for dependent results 10025 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 10026 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 10027 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 10028 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 10029 // set the rest of the matrix elements 10030 ._m00(nm00) 10031 ._m01(nm01) 10032 ._m02(nm02) 10033 ._m03(nm03) 10034 ._m10(nm10) 10035 ._m11(nm11) 10036 ._m12(nm12) 10037 ._m13(nm13) 10038 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 10039 return dest; 10040 } 10041 10042 /** 10043 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 10044 * that aligns <code>-z</code> with <code>center - eye</code>. 10045 * <p> 10046 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10047 * then the new matrix will be <code>M * L</code>. So when transforming a 10048 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10049 * the lookat transformation will be applied first! 10050 * <p> 10051 * In order to set the matrix to a lookat transformation without post-multiplying it, 10052 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 10053 * 10054 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 10055 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 10056 * 10057 * @param eyeX 10058 * the x-coordinate of the eye/camera location 10059 * @param eyeY 10060 * the y-coordinate of the eye/camera location 10061 * @param eyeZ 10062 * the z-coordinate of the eye/camera location 10063 * @param centerX 10064 * the x-coordinate of the point to look at 10065 * @param centerY 10066 * the y-coordinate of the point to look at 10067 * @param centerZ 10068 * the z-coordinate of the point to look at 10069 * @param upX 10070 * the x-coordinate of the up vector 10071 * @param upY 10072 * the y-coordinate of the up vector 10073 * @param upZ 10074 * the z-coordinate of the up vector 10075 * @return this 10076 */ 10077 ref public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, 10078 double centerX, double centerY, double centerZ, 10079 double upX, double upY, double upZ) return { 10080 lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this); 10081 return this; 10082 } 10083 10084 /** 10085 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 10086 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10087 * <p> 10088 * This method assumes <code>this</code> to be a perspective transformation, obtained via 10089 * {@link #frustum(double, double, double, double, double, double) frustum()} or {@link #perspective(double, double, double, double) perspective()} or 10090 * one of their overloads. 10091 * <p> 10092 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10093 * then the new matrix will be <code>M * L</code>. So when transforming a 10094 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10095 * the lookat transformation will be applied first! 10096 * <p> 10097 * In order to set the matrix to a lookat transformation without post-multiplying it, 10098 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 10099 * 10100 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 10101 * 10102 * @param eyeX 10103 * the x-coordinate of the eye/camera location 10104 * @param eyeY 10105 * the y-coordinate of the eye/camera location 10106 * @param eyeZ 10107 * the z-coordinate of the eye/camera location 10108 * @param centerX 10109 * the x-coordinate of the point to look at 10110 * @param centerY 10111 * the y-coordinate of the point to look at 10112 * @param centerZ 10113 * the z-coordinate of the point to look at 10114 * @param upX 10115 * the x-coordinate of the up vector 10116 * @param upY 10117 * the y-coordinate of the up vector 10118 * @param upZ 10119 * the z-coordinate of the up vector 10120 * @param dest 10121 * will hold the result 10122 * @return dest 10123 */ 10124 public Matrix4d lookAtPerspective(double eyeX, double eyeY, double eyeZ, 10125 double centerX, double centerY, double centerZ, 10126 double upX, double upY, double upZ, ref Matrix4d dest) { 10127 // Compute direction from position to lookAt 10128 double dirX, dirY, dirZ; 10129 dirX = eyeX - centerX; 10130 dirY = eyeY - centerY; 10131 dirZ = eyeZ - centerZ; 10132 // Normalize direction 10133 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10134 dirX *= invDirLength; 10135 dirY *= invDirLength; 10136 dirZ *= invDirLength; 10137 // left = up x direction 10138 double leftX, leftY, leftZ; 10139 leftX = upY * dirZ - upZ * dirY; 10140 leftY = upZ * dirX - upX * dirZ; 10141 leftZ = upX * dirY - upY * dirX; 10142 // normalize left 10143 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10144 leftX *= invLeftLength; 10145 leftY *= invLeftLength; 10146 leftZ *= invLeftLength; 10147 // up = direction x left 10148 double upnX = dirY * leftZ - dirZ * leftY; 10149 double upnY = dirZ * leftX - dirX * leftZ; 10150 double upnZ = dirX * leftY - dirY * leftX; 10151 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10152 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10153 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10154 double nm10 = m00 * leftY; 10155 double nm20 = m00 * leftZ; 10156 double nm21 = m11 * upnZ; 10157 double nm30 = m00 * rm30; 10158 double nm31 = m11 * rm31; 10159 double nm32 = m22 * rm32 + m32; 10160 double nm33 = m23 * rm32; 10161 return dest 10162 ._m00(m00 * leftX) 10163 ._m01(m11 * upnX) 10164 ._m02(m22 * dirX) 10165 ._m03(m23 * dirX) 10166 ._m10(nm10) 10167 ._m11(m11 * upnY) 10168 ._m12(m22 * dirY) 10169 ._m13(m23 * dirY) 10170 ._m20(nm20) 10171 ._m21(nm21) 10172 ._m22(m22 * dirZ) 10173 ._m23(m23 * dirZ) 10174 ._m30(nm30) 10175 ._m31(nm31) 10176 ._m32(nm32) 10177 ._m33(nm33) 10178 ._properties(0); 10179 } 10180 10181 /** 10182 * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns 10183 * <code>+z</code> with <code>center - eye</code>. 10184 * <p> 10185 * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives, 10186 * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()} 10187 * instead. 10188 * <p> 10189 * In order to apply the lookat transformation to a previous existing transformation, 10190 * use {@link #lookAtLH(ref Vector3d, Vector3d, Vector3d) lookAt()}. 10191 * 10192 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10193 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10194 * 10195 * @param eye 10196 * the position of the camera 10197 * @param center 10198 * the point in space to look at 10199 * @param up 10200 * the direction of 'up' 10201 * @return this 10202 */ 10203 ref public Matrix4d setLookAtLH(ref Vector3d eye, Vector3d center, Vector3d up) return { 10204 return setLookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z); 10205 } 10206 10207 /** 10208 * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, 10209 * that aligns <code>+z</code> with <code>center - eye</code>. 10210 * <p> 10211 * In order to apply the lookat transformation to a previous existing transformation, 10212 * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}. 10213 * 10214 * @see #setLookAtLH(ref Vector3d, Vector3d, Vector3d) 10215 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10216 * 10217 * @param eyeX 10218 * the x-coordinate of the eye/camera location 10219 * @param eyeY 10220 * the y-coordinate of the eye/camera location 10221 * @param eyeZ 10222 * the z-coordinate of the eye/camera location 10223 * @param centerX 10224 * the x-coordinate of the point to look at 10225 * @param centerY 10226 * the y-coordinate of the point to look at 10227 * @param centerZ 10228 * the z-coordinate of the point to look at 10229 * @param upX 10230 * the x-coordinate of the up vector 10231 * @param upY 10232 * the y-coordinate of the up vector 10233 * @param upZ 10234 * the z-coordinate of the up vector 10235 * @return this 10236 */ 10237 ref public Matrix4d setLookAtLH(double eyeX, double eyeY, double eyeZ, 10238 double centerX, double centerY, double centerZ, 10239 double upX, double upY, double upZ) return { 10240 // Compute direction from position to lookAt 10241 double dirX, dirY, dirZ; 10242 dirX = centerX - eyeX; 10243 dirY = centerY - eyeY; 10244 dirZ = centerZ - eyeZ; 10245 // Normalize direction 10246 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10247 dirX *= invDirLength; 10248 dirY *= invDirLength; 10249 dirZ *= invDirLength; 10250 // left = up x direction 10251 double leftX, leftY, leftZ; 10252 leftX = upY * dirZ - upZ * dirY; 10253 leftY = upZ * dirX - upX * dirZ; 10254 leftZ = upX * dirY - upY * dirX; 10255 // normalize left 10256 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10257 leftX *= invLeftLength; 10258 leftY *= invLeftLength; 10259 leftZ *= invLeftLength; 10260 // up = direction x left 10261 double upnX = dirY * leftZ - dirZ * leftY; 10262 double upnY = dirZ * leftX - dirX * leftZ; 10263 double upnZ = dirX * leftY - dirY * leftX; 10264 _m00(leftX). 10265 _m01(upnX). 10266 _m02(dirX). 10267 _m03(0.0). 10268 _m10(leftY). 10269 _m11(upnY). 10270 _m12(dirY). 10271 _m13(0.0). 10272 _m20(leftZ). 10273 _m21(upnZ). 10274 _m22(dirZ). 10275 _m23(0.0). 10276 _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)). 10277 _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)). 10278 _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)). 10279 _m33(1.0). 10280 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 10281 return this; 10282 } 10283 10284 /** 10285 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10286 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10287 * <p> 10288 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10289 * then the new matrix will be <code>M * L</code>. So when transforming a 10290 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10291 * the lookat transformation will be applied first! 10292 * <p> 10293 * In order to set the matrix to a lookat transformation without post-multiplying it, 10294 * use {@link #setLookAtLH(ref Vector3d, Vector3d, Vector3d)}. 10295 * 10296 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10297 * @see #setLookAtLH(ref Vector3d, Vector3d, Vector3d) 10298 * 10299 * @param eye 10300 * the position of the camera 10301 * @param center 10302 * the point in space to look at 10303 * @param up 10304 * the direction of 'up' 10305 * @param dest 10306 * will hold the result 10307 * @return dest 10308 */ 10309 public Matrix4d lookAtLH(ref Vector3d eye, Vector3d center, Vector3d up, ref Matrix4d dest) { 10310 return lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest); 10311 } 10312 10313 /** 10314 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10315 * that aligns <code>+z</code> with <code>center - eye</code>. 10316 * <p> 10317 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10318 * then the new matrix will be <code>M * L</code>. So when transforming a 10319 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10320 * the lookat transformation will be applied first! 10321 * <p> 10322 * In order to set the matrix to a lookat transformation without post-multiplying it, 10323 * use {@link #setLookAtLH(ref Vector3d, Vector3d, Vector3d)}. 10324 * 10325 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10326 * 10327 * @param eye 10328 * the position of the camera 10329 * @param center 10330 * the point in space to look at 10331 * @param up 10332 * the direction of 'up' 10333 * @return this 10334 */ 10335 ref public Matrix4d lookAtLH(ref Vector3d eye, Vector3d center, Vector3d up) return { 10336 lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this); 10337 return this; 10338 } 10339 10340 /** 10341 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10342 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10343 * <p> 10344 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10345 * then the new matrix will be <code>M * L</code>. So when transforming a 10346 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10347 * the lookat transformation will be applied first! 10348 * <p> 10349 * In order to set the matrix to a lookat transformation without post-multiplying it, 10350 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10351 * 10352 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10353 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10354 * 10355 * @param eyeX 10356 * the x-coordinate of the eye/camera location 10357 * @param eyeY 10358 * the y-coordinate of the eye/camera location 10359 * @param eyeZ 10360 * the z-coordinate of the eye/camera location 10361 * @param centerX 10362 * the x-coordinate of the point to look at 10363 * @param centerY 10364 * the y-coordinate of the point to look at 10365 * @param centerZ 10366 * the z-coordinate of the point to look at 10367 * @param upX 10368 * the x-coordinate of the up vector 10369 * @param upY 10370 * the y-coordinate of the up vector 10371 * @param upZ 10372 * the z-coordinate of the up vector 10373 * @param dest 10374 * will hold the result 10375 * @return dest 10376 */ 10377 public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, 10378 double centerX, double centerY, double centerZ, 10379 double upX, double upY, double upZ, ref Matrix4d dest) { 10380 if ((properties & PROPERTY_IDENTITY) != 0) 10381 return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 10382 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 10383 return lookAtPerspectiveLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 10384 return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 10385 } 10386 private Matrix4d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ, 10387 double centerX, double centerY, double centerZ, 10388 double upX, double upY, double upZ, ref Matrix4d dest) { 10389 // Compute direction from position to lookAt 10390 double dirX, dirY, dirZ; 10391 dirX = centerX - eyeX; 10392 dirY = centerY - eyeY; 10393 dirZ = centerZ - eyeZ; 10394 // Normalize direction 10395 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10396 dirX *= invDirLength; 10397 dirY *= invDirLength; 10398 dirZ *= invDirLength; 10399 // left = up x direction 10400 double leftX, leftY, leftZ; 10401 leftX = upY * dirZ - upZ * dirY; 10402 leftY = upZ * dirX - upX * dirZ; 10403 leftZ = upX * dirY - upY * dirX; 10404 // normalize left 10405 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10406 leftX *= invLeftLength; 10407 leftY *= invLeftLength; 10408 leftZ *= invLeftLength; 10409 // up = direction x left 10410 double upnX = dirY * leftZ - dirZ * leftY; 10411 double upnY = dirZ * leftX - dirX * leftZ; 10412 double upnZ = dirX * leftY - dirY * leftX; 10413 // calculate right matrix elements 10414 double rm00 = leftX; 10415 double rm01 = upnX; 10416 double rm02 = dirX; 10417 double rm10 = leftY; 10418 double rm11 = upnY; 10419 double rm12 = dirY; 10420 double rm20 = leftZ; 10421 double rm21 = upnZ; 10422 double rm22 = dirZ; 10423 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10424 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10425 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10426 // introduce temporaries for dependent results 10427 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 10428 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 10429 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 10430 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 10431 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 10432 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 10433 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 10434 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 10435 // perform optimized matrix multiplication 10436 // compute last column first, because others do not depend on it 10437 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 10438 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 10439 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 10440 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 10441 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 10442 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 10443 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 10444 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 10445 // set the rest of the matrix elements 10446 ._m00(nm00) 10447 ._m01(nm01) 10448 ._m02(nm02) 10449 ._m03(nm03) 10450 ._m10(nm10) 10451 ._m11(nm11) 10452 ._m12(nm12) 10453 ._m13(nm13) 10454 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 10455 return dest; 10456 } 10457 10458 /** 10459 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10460 * that aligns <code>+z</code> with <code>center - eye</code>. 10461 * <p> 10462 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10463 * then the new matrix will be <code>M * L</code>. So when transforming a 10464 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10465 * the lookat transformation will be applied first! 10466 * <p> 10467 * In order to set the matrix to a lookat transformation without post-multiplying it, 10468 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10469 * 10470 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10471 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10472 * 10473 * @param eyeX 10474 * the x-coordinate of the eye/camera location 10475 * @param eyeY 10476 * the y-coordinate of the eye/camera location 10477 * @param eyeZ 10478 * the z-coordinate of the eye/camera location 10479 * @param centerX 10480 * the x-coordinate of the point to look at 10481 * @param centerY 10482 * the y-coordinate of the point to look at 10483 * @param centerZ 10484 * the z-coordinate of the point to look at 10485 * @param upX 10486 * the x-coordinate of the up vector 10487 * @param upY 10488 * the y-coordinate of the up vector 10489 * @param upZ 10490 * the z-coordinate of the up vector 10491 * @return this 10492 */ 10493 ref public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, 10494 double centerX, double centerY, double centerZ, 10495 double upX, double upY, double upZ) return { 10496 lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this); 10497 return this; 10498 } 10499 10500 /** 10501 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10502 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10503 * <p> 10504 * This method assumes <code>this</code> to be a perspective transformation, obtained via 10505 * {@link #frustumLH(double, double, double, double, double, double) frustumLH()} or {@link #perspectiveLH(double, double, double, double) perspectiveLH()} or 10506 * one of their overloads. 10507 * <p> 10508 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10509 * then the new matrix will be <code>M * L</code>. So when transforming a 10510 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10511 * the lookat transformation will be applied first! 10512 * <p> 10513 * In order to set the matrix to a lookat transformation without post-multiplying it, 10514 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10515 * 10516 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10517 * 10518 * @param eyeX 10519 * the x-coordinate of the eye/camera location 10520 * @param eyeY 10521 * the y-coordinate of the eye/camera location 10522 * @param eyeZ 10523 * the z-coordinate of the eye/camera location 10524 * @param centerX 10525 * the x-coordinate of the point to look at 10526 * @param centerY 10527 * the y-coordinate of the point to look at 10528 * @param centerZ 10529 * the z-coordinate of the point to look at 10530 * @param upX 10531 * the x-coordinate of the up vector 10532 * @param upY 10533 * the y-coordinate of the up vector 10534 * @param upZ 10535 * the z-coordinate of the up vector 10536 * @param dest 10537 * will hold the result 10538 * @return dest 10539 */ 10540 public Matrix4d lookAtPerspectiveLH(double eyeX, double eyeY, double eyeZ, 10541 double centerX, double centerY, double centerZ, 10542 double upX, double upY, double upZ, ref Matrix4d dest) { 10543 // Compute direction from position to lookAt 10544 double dirX, dirY, dirZ; 10545 dirX = centerX - eyeX; 10546 dirY = centerY - eyeY; 10547 dirZ = centerZ - eyeZ; 10548 // Normalize direction 10549 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10550 dirX *= invDirLength; 10551 dirY *= invDirLength; 10552 dirZ *= invDirLength; 10553 // left = up x direction 10554 double leftX, leftY, leftZ; 10555 leftX = upY * dirZ - upZ * dirY; 10556 leftY = upZ * dirX - upX * dirZ; 10557 leftZ = upX * dirY - upY * dirX; 10558 // normalize left 10559 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10560 leftX *= invLeftLength; 10561 leftY *= invLeftLength; 10562 leftZ *= invLeftLength; 10563 // up = direction x left 10564 double upnX = dirY * leftZ - dirZ * leftY; 10565 double upnY = dirZ * leftX - dirX * leftZ; 10566 double upnZ = dirX * leftY - dirY * leftX; 10567 10568 // calculate right matrix elements 10569 double rm00 = leftX; 10570 double rm01 = upnX; 10571 double rm02 = dirX; 10572 double rm10 = leftY; 10573 double rm11 = upnY; 10574 double rm12 = dirY; 10575 double rm20 = leftZ; 10576 double rm21 = upnZ; 10577 double rm22 = dirZ; 10578 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10579 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10580 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10581 10582 double nm00 = m00 * rm00; 10583 double nm01 = m11 * rm01; 10584 double nm02 = m22 * rm02; 10585 double nm03 = m23 * rm02; 10586 double nm10 = m00 * rm10; 10587 double nm11 = m11 * rm11; 10588 double nm12 = m22 * rm12; 10589 double nm13 = m23 * rm12; 10590 double nm20 = m00 * rm20; 10591 double nm21 = m11 * rm21; 10592 double nm22 = m22 * rm22; 10593 double nm23 = m23 * rm22; 10594 double nm30 = m00 * rm30; 10595 double nm31 = m11 * rm31; 10596 double nm32 = m22 * rm32 + m32; 10597 double nm33 = m23 * rm32; 10598 dest._m00(nm00) 10599 ._m01(nm01) 10600 ._m02(nm02) 10601 ._m03(nm03) 10602 ._m10(nm10) 10603 ._m11(nm11) 10604 ._m12(nm12) 10605 ._m13(nm13) 10606 ._m20(nm20) 10607 ._m21(nm21) 10608 ._m22(nm22) 10609 ._m23(nm23) 10610 ._m30(nm30) 10611 ._m31(nm31) 10612 ._m32(nm32) 10613 ._m33(nm33) 10614 ._properties(0); 10615 10616 return dest; 10617 } 10618 10619 /** 10620 * This method is equivalent to calling: <code>translate(w-1-2*x, h-1-2*y, 0).scale(w, h, 1)</code> 10621 * <p> 10622 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the created transformation matrix, 10623 * then the new matrix will be <code>M * T</code>. So when transforming a 10624 * vector <code>v</code> with the new matrix by using <code>M * T * v</code>, the 10625 * created transformation will be applied first! 10626 * 10627 * @param x 10628 * the tile's x coordinate/index (should be in <code>[0..w)</code>) 10629 * @param y 10630 * the tile's y coordinate/index (should be in <code>[0..h)</code>) 10631 * @param w 10632 * the number of tiles along the x axis 10633 * @param h 10634 * the number of tiles along the y axis 10635 * @return this 10636 */ 10637 ref public Matrix4d tile(int x, int y, int w, int h) return { 10638 tile(x, y, w, h, this); 10639 return this; 10640 } 10641 public Matrix4d tile(int x, int y, int w, int h, ref Matrix4d dest) { 10642 float tx = w - 1 - (x<<1), ty = h - 1 - (y<<1); 10643 return dest 10644 ._m30(Math.fma(m00, tx, Math.fma(m10, ty, m30))) 10645 ._m31(Math.fma(m01, tx, Math.fma(m11, ty, m31))) 10646 ._m32(Math.fma(m02, tx, Math.fma(m12, ty, m32))) 10647 ._m33(Math.fma(m03, tx, Math.fma(m13, ty, m33))) 10648 ._m00(m00 * w) 10649 ._m01(m01 * w) 10650 ._m02(m02 * w) 10651 ._m03(m03 * w) 10652 ._m10(m10 * h) 10653 ._m11(m11 * h) 10654 ._m12(m12 * h) 10655 ._m13(m13 * h) 10656 ._m20(m20) 10657 ._m21(m21) 10658 ._m22(m22) 10659 ._m23(m23) 10660 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10661 } 10662 10663 /** 10664 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10665 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10666 * <p> 10667 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10668 * then the new matrix will be <code>M * P</code>. So when transforming a 10669 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10670 * the perspective projection will be applied first! 10671 * <p> 10672 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10673 * use {@link #setPerspective(double, double, double, double, bool) setPerspective}. 10674 * 10675 * @see #setPerspective(double, double, double, double, bool) 10676 * 10677 * @param fovy 10678 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10679 * @param aspect 10680 * the aspect ratio (i.e. width / height; must be greater than zero) 10681 * @param zNear 10682 * near clipping plane distance. This value must be greater than zero. 10683 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10684 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10685 * @param zFar 10686 * far clipping plane distance. This value must be greater than zero. 10687 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10688 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10689 * @param dest 10690 * will hold the result 10691 * @param zZeroToOne 10692 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10693 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10694 * @return dest 10695 */ 10696 public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10697 if ((properties & PROPERTY_IDENTITY) != 0) 10698 return dest.setPerspective(fovy, aspect, zNear, zFar, zZeroToOne); 10699 return perspectiveGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest); 10700 } 10701 private Matrix4d perspectiveGeneric(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10702 double h = Math.tan(fovy * 0.5); 10703 // calculate right matrix elements 10704 double rm00 = 1.0 / (h * aspect); 10705 double rm11 = 1.0 / h; 10706 double rm22; 10707 double rm32; 10708 bool farInf = zFar > 0 && Math.isInfinite(zFar); 10709 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 10710 if (farInf) { 10711 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 10712 double e = 1E-6; 10713 rm22 = e - 1.0; 10714 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 10715 } else if (nearInf) { 10716 double e = 1E-6; 10717 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 10718 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 10719 } else { 10720 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 10721 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 10722 } 10723 // perform optimized matrix multiplication 10724 double nm20 = m20 * rm22 - m30; 10725 double nm21 = m21 * rm22 - m31; 10726 double nm22 = m22 * rm22 - m32; 10727 double nm23 = m23 * rm22 - m33; 10728 dest._m00(m00 * rm00) 10729 ._m01(m01 * rm00) 10730 ._m02(m02 * rm00) 10731 ._m03(m03 * rm00) 10732 ._m10(m10 * rm11) 10733 ._m11(m11 * rm11) 10734 ._m12(m12 * rm11) 10735 ._m13(m13 * rm11) 10736 ._m30(m20 * rm32) 10737 ._m31(m21 * rm32) 10738 ._m32(m22 * rm32) 10739 ._m33(m23 * rm32) 10740 ._m20(nm20) 10741 ._m21(nm21) 10742 ._m22(nm22) 10743 ._m23(nm23) 10744 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10745 return dest; 10746 } 10747 10748 /** 10749 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10750 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 10751 * <p> 10752 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10753 * then the new matrix will be <code>M * P</code>. So when transforming a 10754 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10755 * the perspective projection will be applied first! 10756 * <p> 10757 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10758 * use {@link #setPerspective(double, double, double, double) setPerspective}. 10759 * 10760 * @see #setPerspective(double, double, double, double) 10761 * 10762 * @param fovy 10763 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10764 * @param aspect 10765 * the aspect ratio (i.e. width / height; must be greater than zero) 10766 * @param zNear 10767 * near clipping plane distance. This value must be greater than zero. 10768 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10769 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10770 * @param zFar 10771 * far clipping plane distance. This value must be greater than zero. 10772 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10773 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10774 * @param dest 10775 * will hold the result 10776 * @return dest 10777 */ 10778 public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, ref Matrix4d dest) { 10779 return perspective(fovy, aspect, zNear, zFar, false, dest); 10780 } 10781 10782 /** 10783 * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system 10784 * using the given NDC z range to this matrix. 10785 * <p> 10786 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10787 * then the new matrix will be <code>M * P</code>. So when transforming a 10788 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10789 * the perspective projection will be applied first! 10790 * <p> 10791 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10792 * use {@link #setPerspective(double, double, double, double, bool) setPerspective}. 10793 * 10794 * @see #setPerspective(double, double, double, double, bool) 10795 * 10796 * @param fovy 10797 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10798 * @param aspect 10799 * the aspect ratio (i.e. width / height; must be greater than zero) 10800 * @param zNear 10801 * near clipping plane distance. This value must be greater than zero. 10802 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10803 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10804 * @param zFar 10805 * far clipping plane distance. This value must be greater than zero. 10806 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10807 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10808 * @param zZeroToOne 10809 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10810 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10811 * @return this 10812 */ 10813 ref public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 10814 perspective(fovy, aspect, zNear, zFar, zZeroToOne, this); 10815 return this; 10816 } 10817 10818 /** 10819 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10820 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 10821 * <p> 10822 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10823 * then the new matrix will be <code>M * P</code>. So when transforming a 10824 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10825 * the perspective projection will be applied first! 10826 * <p> 10827 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10828 * use {@link #setPerspective(double, double, double, double) setPerspective}. 10829 * 10830 * @see #setPerspective(double, double, double, double) 10831 * 10832 * @param fovy 10833 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10834 * @param aspect 10835 * the aspect ratio (i.e. width / height; must be greater than zero) 10836 * @param zNear 10837 * near clipping plane distance. This value must be greater than zero. 10838 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10839 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10840 * @param zFar 10841 * far clipping plane distance. This value must be greater than zero. 10842 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10843 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10844 * @return this 10845 */ 10846 ref public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar) return { 10847 perspective(fovy, aspect, zNear, zFar, this); 10848 return this; 10849 } 10850 10851 /** 10852 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10853 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10854 * <p> 10855 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10856 * then the new matrix will be <code>M * P</code>. So when transforming a 10857 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10858 * the perspective projection will be applied first! 10859 * <p> 10860 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10861 * use {@link #setPerspectiveRect(double, double, double, double, bool) setPerspectiveRect}. 10862 * 10863 * @see #setPerspectiveRect(double, double, double, double, bool) 10864 * 10865 * @param width 10866 * the width of the near frustum plane 10867 * @param height 10868 * the height of the near frustum plane 10869 * @param zNear 10870 * near clipping plane distance. This value must be greater than zero. 10871 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10872 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10873 * @param zFar 10874 * far clipping plane distance. This value must be greater than zero. 10875 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10876 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10877 * @param dest 10878 * will hold the result 10879 * @param zZeroToOne 10880 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10881 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10882 * @return dest 10883 */ 10884 public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10885 if ((properties & PROPERTY_IDENTITY) != 0) 10886 return dest.setPerspectiveRect(width, height, zNear, zFar, zZeroToOne); 10887 return perspectiveRectGeneric(width, height, zNear, zFar, zZeroToOne, dest); 10888 } 10889 private Matrix4d perspectiveRectGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10890 double rm00 = (zNear + zNear) / width; 10891 double rm11 = (zNear + zNear) / height; 10892 double rm22, rm32; 10893 bool farInf = zFar > 0 && Math.isInfinite(zFar); 10894 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 10895 if (farInf) { 10896 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 10897 double e = 1E-6f; 10898 rm22 = e - 1.0; 10899 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 10900 } else if (nearInf) { 10901 double e = 1E-6f; 10902 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 10903 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 10904 } else { 10905 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 10906 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 10907 } 10908 // perform optimized matrix multiplication 10909 double nm20 = m20 * rm22 - m30; 10910 double nm21 = m21 * rm22 - m31; 10911 double nm22 = m22 * rm22 - m32; 10912 double nm23 = m23 * rm22 - m33; 10913 dest._m00(m00 * rm00) 10914 ._m01(m01 * rm00) 10915 ._m02(m02 * rm00) 10916 ._m03(m03 * rm00) 10917 ._m10(m10 * rm11) 10918 ._m11(m11 * rm11) 10919 ._m12(m12 * rm11) 10920 ._m13(m13 * rm11) 10921 ._m30(m20 * rm32) 10922 ._m31(m21 * rm32) 10923 ._m32(m22 * rm32) 10924 ._m33(m23 * rm32) 10925 ._m20(nm20) 10926 ._m21(nm21) 10927 ._m22(nm22) 10928 ._m23(nm23) 10929 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10930 return dest; 10931 } 10932 10933 /** 10934 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10935 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 10936 * <p> 10937 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10938 * then the new matrix will be <code>M * P</code>. So when transforming a 10939 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10940 * the perspective projection will be applied first! 10941 * <p> 10942 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10943 * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}. 10944 * 10945 * @see #setPerspectiveRect(double, double, double, double) 10946 * 10947 * @param width 10948 * the width of the near frustum plane 10949 * @param height 10950 * the height of the near frustum plane 10951 * @param zNear 10952 * near clipping plane distance. This value must be greater than zero. 10953 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10954 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10955 * @param zFar 10956 * far clipping plane distance. This value must be greater than zero. 10957 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10958 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10959 * @param dest 10960 * will hold the result 10961 * @return dest 10962 */ 10963 public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 10964 return perspectiveRect(width, height, zNear, zFar, false, dest); 10965 } 10966 10967 /** 10968 * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system 10969 * using the given NDC z range to this matrix. 10970 * <p> 10971 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10972 * then the new matrix will be <code>M * P</code>. So when transforming a 10973 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10974 * the perspective projection will be applied first! 10975 * <p> 10976 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10977 * use {@link #setPerspectiveRect(double, double, double, double, bool) setPerspectiveRect}. 10978 * 10979 * @see #setPerspectiveRect(double, double, double, double, bool) 10980 * 10981 * @param width 10982 * the width of the near frustum plane 10983 * @param height 10984 * the height of the near frustum plane 10985 * @param zNear 10986 * near clipping plane distance. This value must be greater than zero. 10987 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10988 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10989 * @param zFar 10990 * far clipping plane distance. This value must be greater than zero. 10991 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10992 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10993 * @param zZeroToOne 10994 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10995 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10996 * @return this 10997 */ 10998 ref public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 10999 perspectiveRect(width, height, zNear, zFar, zZeroToOne, this); 11000 return this; 11001 } 11002 11003 /** 11004 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 11005 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11006 * <p> 11007 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11008 * then the new matrix will be <code>M * P</code>. So when transforming a 11009 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11010 * the perspective projection will be applied first! 11011 * <p> 11012 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11013 * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}. 11014 * 11015 * @see #setPerspectiveRect(double, double, double, double) 11016 * 11017 * @param width 11018 * the width of the near frustum plane 11019 * @param height 11020 * the height of the near frustum plane 11021 * @param zNear 11022 * near clipping plane distance. This value must be greater than zero. 11023 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11024 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11025 * @param zFar 11026 * far clipping plane distance. This value must be greater than zero. 11027 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11028 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11029 * @return this 11030 */ 11031 ref public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar) return { 11032 perspectiveRect(width, height, zNear, zFar, this); 11033 return this; 11034 } 11035 11036 /** 11037 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11038 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 11039 * <p> 11040 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11041 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11042 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11043 * is parallel to the XZ-plane. 11044 * <p> 11045 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11046 * then the new matrix will be <code>M * P</code>. So when transforming a 11047 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11048 * the perspective projection will be applied first! 11049 * <p> 11050 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11051 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, bool) setPerspectiveOffCenter}. 11052 * 11053 * @see #setPerspectiveOffCenter(double, double, double, double, double, double, bool) 11054 * 11055 * @param fovy 11056 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11057 * @param offAngleX 11058 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11059 * @param offAngleY 11060 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11061 * @param aspect 11062 * the aspect ratio (i.e. width / height; must be greater than zero) 11063 * @param zNear 11064 * near clipping plane distance. This value must be greater than zero. 11065 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11066 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11067 * @param zFar 11068 * far clipping plane distance. This value must be greater than zero. 11069 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11070 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11071 * @param dest 11072 * will hold the result 11073 * @param zZeroToOne 11074 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11075 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11076 * @return dest 11077 */ 11078 public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11079 if ((properties & PROPERTY_IDENTITY) != 0) 11080 return dest.setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne); 11081 return perspectiveOffCenterGeneric(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, dest); 11082 } 11083 private Matrix4d perspectiveOffCenterGeneric(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11084 double h = Math.tan(fovy * 0.5); 11085 // calculate right matrix elements 11086 double xScale = 1.0 / (h * aspect); 11087 double yScale = 1.0 / h; 11088 double rm00 = xScale; 11089 double rm11 = yScale; 11090 double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY); 11091 double rm20 = offX * xScale; 11092 double rm21 = offY * yScale; 11093 double rm22; 11094 double rm32; 11095 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11096 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11097 if (farInf) { 11098 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11099 double e = 1E-6; 11100 rm22 = e - 1.0; 11101 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 11102 } else if (nearInf) { 11103 double e = 1E-6; 11104 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 11105 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 11106 } else { 11107 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 11108 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 11109 } 11110 // perform optimized matrix multiplication 11111 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30; 11112 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31; 11113 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32; 11114 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33; 11115 dest._m00(m00 * rm00) 11116 ._m01(m01 * rm00) 11117 ._m02(m02 * rm00) 11118 ._m03(m03 * rm00) 11119 ._m10(m10 * rm11) 11120 ._m11(m11 * rm11) 11121 ._m12(m12 * rm11) 11122 ._m13(m13 * rm11) 11123 ._m30(m20 * rm32) 11124 ._m31(m21 * rm32) 11125 ._m32(m22 * rm32) 11126 ._m33(m23 * rm32) 11127 ._m20(nm20) 11128 ._m21(nm21) 11129 ._m22(nm22) 11130 ._m23(nm23) 11131 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 11132 | PROPERTY_ORTHONORMAL | (rm20 == 0.0 && rm21 == 0.0 ? 0 : PROPERTY_PERSPECTIVE))); 11133 return dest; 11134 } 11135 11136 /** 11137 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11138 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 11139 * <p> 11140 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11141 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11142 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11143 * is parallel to the XZ-plane. 11144 * <p> 11145 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11146 * then the new matrix will be <code>M * P</code>. So when transforming a 11147 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11148 * the perspective projection will be applied first! 11149 * <p> 11150 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11151 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}. 11152 * 11153 * @see #setPerspectiveOffCenter(double, double, double, double, double, double) 11154 * 11155 * @param fovy 11156 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11157 * @param offAngleX 11158 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11159 * @param offAngleY 11160 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11161 * @param aspect 11162 * the aspect ratio (i.e. width / height; must be greater than zero) 11163 * @param zNear 11164 * near clipping plane distance. This value must be greater than zero. 11165 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11166 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11167 * @param zFar 11168 * far clipping plane distance. This value must be greater than zero. 11169 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11170 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11171 * @param dest 11172 * will hold the result 11173 * @return dest 11174 */ 11175 public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, ref Matrix4d dest) { 11176 return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false, dest); 11177 } 11178 11179 /** 11180 * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system 11181 * using the given NDC z range to this matrix. 11182 * <p> 11183 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11184 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11185 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11186 * is parallel to the XZ-plane. 11187 * <p> 11188 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11189 * then the new matrix will be <code>M * P</code>. So when transforming a 11190 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11191 * the perspective projection will be applied first! 11192 * <p> 11193 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11194 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, bool) setPerspectiveOffCenter}. 11195 * 11196 * @see #setPerspectiveOffCenter(double, double, double, double, double, double, bool) 11197 * 11198 * @param fovy 11199 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11200 * @param offAngleX 11201 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11202 * @param offAngleY 11203 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11204 * @param aspect 11205 * the aspect ratio (i.e. width / height; must be greater than zero) 11206 * @param zNear 11207 * near clipping plane distance. This value must be greater than zero. 11208 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11209 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11210 * @param zFar 11211 * far clipping plane distance. This value must be greater than zero. 11212 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11213 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11214 * @param zZeroToOne 11215 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11216 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11217 * @return this 11218 */ 11219 ref public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11220 perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, this); 11221 return this; 11222 } 11223 11224 /** 11225 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11226 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11227 * <p> 11228 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11229 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11230 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11231 * is parallel to the XZ-plane. 11232 * <p> 11233 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11234 * then the new matrix will be <code>M * P</code>. So when transforming a 11235 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11236 * the perspective projection will be applied first! 11237 * <p> 11238 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11239 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}. 11240 * 11241 * @see #setPerspectiveOffCenter(double, double, double, double, double, double) 11242 * 11243 * @param fovy 11244 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11245 * @param offAngleX 11246 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11247 * @param offAngleY 11248 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11249 * @param aspect 11250 * the aspect ratio (i.e. width / height; must be greater than zero) 11251 * @param zNear 11252 * near clipping plane distance. This value must be greater than zero. 11253 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11254 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11255 * @param zFar 11256 * far clipping plane distance. This value must be greater than zero. 11257 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11258 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11259 * @return this 11260 */ 11261 ref public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar) return { 11262 perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, this); 11263 return this; 11264 } 11265 11266 /** 11267 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11268 * using the given NDC z range to this matrix. 11269 * <p> 11270 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11271 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11272 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11273 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11274 * <p> 11275 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11276 * then the new matrix will be <code>M * P</code>. So when transforming a 11277 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11278 * the perspective projection will be applied first! 11279 * <p> 11280 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11281 * use {@link #setPerspectiveOffCenterFov(double, double, double, double, double, double, bool) setPerspectiveOffCenterFov}. 11282 * 11283 * @see #setPerspectiveOffCenterFov(double, double, double, double, double, double, bool) 11284 * 11285 * @param angleLeft 11286 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11287 * For a symmetric frustum, this value is negative. 11288 * @param angleRight 11289 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11290 * @param angleDown 11291 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11292 * For a symmetric frustum, this value is negative. 11293 * @param angleUp 11294 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11295 * @param zNear 11296 * near clipping plane distance. This value must be greater than zero. 11297 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11298 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11299 * @param zFar 11300 * far clipping plane distance. This value must be greater than zero. 11301 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11302 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11303 * @param zZeroToOne 11304 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11305 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11306 * @return this 11307 */ 11308 ref public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11309 perspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, zZeroToOne, this); 11310 return this; 11311 } 11312 public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11313 return frustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne, dest); 11314 } 11315 11316 /** 11317 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11318 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11319 * <p> 11320 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11321 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11322 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11323 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11324 * <p> 11325 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11326 * then the new matrix will be <code>M * P</code>. So when transforming a 11327 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11328 * the perspective projection will be applied first! 11329 * <p> 11330 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11331 * use {@link #setPerspectiveOffCenterFov(double, double, double, double, double, double) setPerspectiveOffCenterFov}. 11332 * 11333 * @see #setPerspectiveOffCenterFov(double, double, double, double, double, double) 11334 * 11335 * @param angleLeft 11336 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11337 * For a symmetric frustum, this value is negative. 11338 * @param angleRight 11339 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11340 * @param angleDown 11341 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11342 * For a symmetric frustum, this value is negative. 11343 * @param angleUp 11344 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11345 * @param zNear 11346 * near clipping plane distance. This value must be greater than zero. 11347 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11348 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11349 * @param zFar 11350 * far clipping plane distance. This value must be greater than zero. 11351 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11352 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11353 * @return this 11354 */ 11355 ref public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11356 perspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, this); 11357 return this; 11358 } 11359 public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, ref Matrix4d dest) { 11360 return frustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, dest); 11361 } 11362 11363 /** 11364 * Apply an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11365 * using the given NDC z range to this matrix. 11366 * <p> 11367 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11368 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11369 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11370 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11371 * <p> 11372 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11373 * then the new matrix will be <code>M * P</code>. So when transforming a 11374 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11375 * the perspective projection will be applied first! 11376 * <p> 11377 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11378 * use {@link #setPerspectiveOffCenterFovLH(double, double, double, double, double, double, bool) setPerspectiveOffCenterFovLH}. 11379 * 11380 * @see #setPerspectiveOffCenterFovLH(double, double, double, double, double, double, bool) 11381 * 11382 * @param angleLeft 11383 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11384 * For a symmetric frustum, this value is negative. 11385 * @param angleRight 11386 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11387 * @param angleDown 11388 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11389 * For a symmetric frustum, this value is negative. 11390 * @param angleUp 11391 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11392 * @param zNear 11393 * near clipping plane distance. This value must be greater than zero. 11394 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11395 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11396 * @param zFar 11397 * far clipping plane distance. This value must be greater than zero. 11398 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11399 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11400 * @param zZeroToOne 11401 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11402 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11403 * @return this 11404 */ 11405 ref public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11406 perspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, zZeroToOne, this); 11407 return this; 11408 } 11409 public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11410 return frustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne, dest); 11411 } 11412 11413 /** 11414 * Apply an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11415 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11416 * <p> 11417 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11418 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11419 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11420 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11421 * <p> 11422 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11423 * then the new matrix will be <code>M * P</code>. So when transforming a 11424 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11425 * the perspective projection will be applied first! 11426 * <p> 11427 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11428 * use {@link #setPerspectiveOffCenterFovLH(double, double, double, double, double, double) setPerspectiveOffCenterFovLH}. 11429 * 11430 * @see #setPerspectiveOffCenterFovLH(double, double, double, double, double, double) 11431 * 11432 * @param angleLeft 11433 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11434 * For a symmetric frustum, this value is negative. 11435 * @param angleRight 11436 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11437 * @param angleDown 11438 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11439 * For a symmetric frustum, this value is negative. 11440 * @param angleUp 11441 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11442 * @param zNear 11443 * near clipping plane distance. This value must be greater than zero. 11444 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11445 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11446 * @param zFar 11447 * far clipping plane distance. This value must be greater than zero. 11448 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11449 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11450 * @return this 11451 */ 11452 ref public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11453 perspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, this); 11454 return this; 11455 } 11456 public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, ref Matrix4d dest) { 11457 return frustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, dest); 11458 } 11459 11460 /** 11461 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11462 * using the given NDC z range. 11463 * <p> 11464 * In order to apply the perspective projection transformation to an existing transformation, 11465 * use {@link #perspective(double, double, double, double, bool) perspective()}. 11466 * 11467 * @see #perspective(double, double, double, double, bool) 11468 * 11469 * @param fovy 11470 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11471 * @param aspect 11472 * the aspect ratio (i.e. width / height; must be greater than zero) 11473 * @param zNear 11474 * near clipping plane distance. This value must be greater than zero. 11475 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11476 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11477 * @param zFar 11478 * far clipping plane distance. This value must be greater than zero. 11479 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11480 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11481 * @param zZeroToOne 11482 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11483 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11484 * @return this 11485 */ 11486 ref public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11487 double h = Math.tan(fovy * 0.5); 11488 _m00(1.0 / (h * aspect)). 11489 _m01(0.0). 11490 _m02(0.0). 11491 _m03(0.0). 11492 _m10(0.0). 11493 _m11(1.0 / h). 11494 _m12(0.0). 11495 _m13(0.0). 11496 _m20(0.0). 11497 _m21(0.0); 11498 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11499 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11500 if (farInf) { 11501 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11502 double e = 1E-6; 11503 _m22(e - 1.0). 11504 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11505 } else if (nearInf) { 11506 double e = 1E-6; 11507 _m22((zZeroToOne ? 0.0 : 1.0) - e). 11508 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11509 } else { 11510 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 11511 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11512 } 11513 _m23(-1.0). 11514 _m30(0.0). 11515 _m31(0.0). 11516 _m33(0.0). 11517 properties = PROPERTY_PERSPECTIVE; 11518 return this; 11519 } 11520 11521 /** 11522 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11523 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 11524 * <p> 11525 * In order to apply the perspective projection transformation to an existing transformation, 11526 * use {@link #perspective(double, double, double, double) perspective()}. 11527 * 11528 * @see #perspective(double, double, double, double) 11529 * 11530 * @param fovy 11531 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11532 * @param aspect 11533 * the aspect ratio (i.e. width / height; must be greater than zero) 11534 * @param zNear 11535 * near clipping plane distance. This value must be greater than zero. 11536 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11537 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11538 * @param zFar 11539 * far clipping plane distance. This value must be greater than zero. 11540 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11541 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11542 * @return this 11543 */ 11544 ref public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar) return { 11545 return setPerspective(fovy, aspect, zNear, zFar, false); 11546 } 11547 11548 /** 11549 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11550 * using the given NDC z range. 11551 * <p> 11552 * In order to apply the perspective projection transformation to an existing transformation, 11553 * use {@link #perspectiveRect(double, double, double, double, bool) perspectiveRect()}. 11554 * 11555 * @see #perspectiveRect(double, double, double, double, bool) 11556 * 11557 * @param width 11558 * the width of the near frustum plane 11559 * @param height 11560 * the height of the near frustum plane 11561 * @param zNear 11562 * near clipping plane distance. This value must be greater than zero. 11563 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11564 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11565 * @param zFar 11566 * far clipping plane distance. This value must be greater than zero. 11567 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11568 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11569 * @param zZeroToOne 11570 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11571 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11572 * @return this 11573 */ 11574 ref public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 11575 this.zero(); 11576 this._m00((zNear + zNear) / width); 11577 this._m11((zNear + zNear) / height); 11578 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11579 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11580 if (farInf) { 11581 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11582 double e = 1E-6; 11583 this._m22(e - 1.0); 11584 this._m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11585 } else if (nearInf) { 11586 double e = 1E-6f; 11587 this._m22((zZeroToOne ? 0.0 : 1.0) - e); 11588 this._m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11589 } else { 11590 this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)); 11591 this._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11592 } 11593 this._m23(-1.0); 11594 properties = PROPERTY_PERSPECTIVE; 11595 return this; 11596 } 11597 11598 /** 11599 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11600 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 11601 * <p> 11602 * In order to apply the perspective projection transformation to an existing transformation, 11603 * use {@link #perspectiveRect(double, double, double, double) perspectiveRect()}. 11604 * 11605 * @see #perspectiveRect(double, double, double, double) 11606 * 11607 * @param width 11608 * the width of the near frustum plane 11609 * @param height 11610 * the height of the near frustum plane 11611 * @param zNear 11612 * near clipping plane distance. This value must be greater than zero. 11613 * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11614 * In that case, <code>zFar</code> may not also be {@link Float#POSITIVE_INFINITY}. 11615 * @param zFar 11616 * far clipping plane distance. This value must be greater than zero. 11617 * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11618 * In that case, <code>zNear</code> may not also be {@link Float#POSITIVE_INFINITY}. 11619 * @return this 11620 */ 11621 ref public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar) return { 11622 return setPerspectiveRect(width, height, zNear, zFar, false); 11623 } 11624 11625 /** 11626 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed 11627 * coordinate system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11628 * <p> 11629 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11630 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11631 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11632 * is parallel to the XZ-plane. 11633 * <p> 11634 * In order to apply the perspective projection transformation to an existing transformation, 11635 * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}. 11636 * 11637 * @see #perspectiveOffCenter(double, double, double, double, double, double) 11638 * 11639 * @param fovy 11640 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11641 * @param offAngleX 11642 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11643 * @param offAngleY 11644 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11645 * @param aspect 11646 * the aspect ratio (i.e. width / height; must be greater than zero) 11647 * @param zNear 11648 * near clipping plane distance. This value must be greater than zero. 11649 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11650 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11651 * @param zFar 11652 * far clipping plane distance. This value must be greater than zero. 11653 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11654 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11655 * @return this 11656 */ 11657 ref public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY, 11658 double aspect, double zNear, double zFar) return { 11659 return setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false); 11660 } 11661 /** 11662 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed 11663 * coordinate system using the given NDC z range. 11664 * <p> 11665 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11666 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11667 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11668 * is parallel to the XZ-plane. 11669 * <p> 11670 * In order to apply the perspective projection transformation to an existing transformation, 11671 * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}. 11672 * 11673 * @see #perspectiveOffCenter(double, double, double, double, double, double) 11674 * 11675 * @param fovy 11676 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11677 * @param offAngleX 11678 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11679 * @param offAngleY 11680 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11681 * @param aspect 11682 * the aspect ratio (i.e. width / height; must be greater than zero) 11683 * @param zNear 11684 * near clipping plane distance. This value must be greater than zero. 11685 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11686 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11687 * @param zFar 11688 * far clipping plane distance. This value must be greater than zero. 11689 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11690 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11691 * @param zZeroToOne 11692 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11693 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11694 * @return this 11695 */ 11696 ref public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY, 11697 double aspect, double zNear, double zFar, bool zZeroToOne) return { 11698 this.zero(); 11699 double h = Math.tan(fovy * 0.5); 11700 double xScale = 1.0 / (h * aspect), yScale = 1.0 / h; 11701 _m00(xScale). 11702 _m11(yScale); 11703 double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY); 11704 _m20(offX * xScale). 11705 _m21(offY * yScale); 11706 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11707 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11708 if (farInf) { 11709 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11710 double e = 1E-6; 11711 _m22(e - 1.0). 11712 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11713 } else if (nearInf) { 11714 double e = 1E-6; 11715 _m22((zZeroToOne ? 0.0 : 1.0) - e). 11716 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11717 } else { 11718 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 11719 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11720 } 11721 _m23(-1.0). 11722 _m30(0.0). 11723 _m31(0.0). 11724 _m33(0.0). 11725 properties = offAngleX == 0.0 && offAngleY == 0.0 ? PROPERTY_PERSPECTIVE : 0; 11726 return this; 11727 } 11728 11729 /** 11730 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate 11731 * system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11732 * <p> 11733 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11734 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11735 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11736 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11737 * <p> 11738 * In order to apply the perspective projection transformation to an existing transformation, 11739 * use {@link #perspectiveOffCenterFov(double, double, double, double, double, double) perspectiveOffCenterFov()}. 11740 * 11741 * @see #perspectiveOffCenterFov(double, double, double, double, double, double) 11742 * 11743 * @param angleLeft 11744 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11745 * For a symmetric frustum, this value is negative. 11746 * @param angleRight 11747 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11748 * @param angleDown 11749 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11750 * For a symmetric frustum, this value is negative. 11751 * @param angleUp 11752 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11753 * @param zNear 11754 * near clipping plane distance. This value must be greater than zero. 11755 * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11756 * In that case, <code>zFar</code> may not also be {@link Float#POSITIVE_INFINITY}. 11757 * @param zFar 11758 * far clipping plane distance. This value must be greater than zero. 11759 * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11760 * In that case, <code>zNear</code> may not also be {@link Float#POSITIVE_INFINITY}. 11761 * @return this 11762 */ 11763 ref public Matrix4d setPerspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11764 return setPerspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, false); 11765 } 11766 /** 11767 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11768 * using the given NDC z range. 11769 * <p> 11770 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11771 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11772 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11773 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11774 * <p> 11775 * In order to apply the perspective projection transformation to an existing transformation, 11776 * use {@link #perspectiveOffCenterFov(double, double, double, double, double, double, bool) perspectiveOffCenterFov()}. 11777 * 11778 * @see #perspectiveOffCenterFov(double, double, double, double, double, double, bool) 11779 * 11780 * @param angleLeft 11781 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11782 * For a symmetric frustum, this value is negative. 11783 * @param angleRight 11784 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11785 * @param angleDown 11786 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11787 * For a symmetric frustum, this value is negative. 11788 * @param angleUp 11789 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11790 * @param zNear 11791 * near clipping plane distance. This value must be greater than zero. 11792 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11793 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11794 * @param zFar 11795 * far clipping plane distance. This value must be greater than zero. 11796 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11797 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11798 * @param zZeroToOne 11799 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11800 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11801 * @return this 11802 */ 11803 ref public Matrix4d setPerspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11804 return setFrustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne); 11805 } 11806 11807 /** 11808 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate 11809 * system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11810 * <p> 11811 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11812 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11813 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11814 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11815 * <p> 11816 * In order to apply the perspective projection transformation to an existing transformation, 11817 * use {@link #perspectiveOffCenterFovLH(double, double, double, double, double, double) perspectiveOffCenterFovLH()}. 11818 * 11819 * @see #perspectiveOffCenterFovLH(double, double, double, double, double, double) 11820 * 11821 * @param angleLeft 11822 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11823 * For a symmetric frustum, this value is negative. 11824 * @param angleRight 11825 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11826 * @param angleDown 11827 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11828 * For a symmetric frustum, this value is negative. 11829 * @param angleUp 11830 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11831 * @param zNear 11832 * near clipping plane distance. This value must be greater than zero. 11833 * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11834 * In that case, <code>zFar</code> may not also be {@link Float#POSITIVE_INFINITY}. 11835 * @param zFar 11836 * far clipping plane distance. This value must be greater than zero. 11837 * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11838 * In that case, <code>zNear</code> may not also be {@link Float#POSITIVE_INFINITY}. 11839 * @return this 11840 */ 11841 ref public Matrix4d setPerspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11842 return setPerspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, false); 11843 } 11844 /** 11845 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11846 * using the given NDC z range. 11847 * <p> 11848 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11849 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11850 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11851 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11852 * <p> 11853 * In order to apply the perspective projection transformation to an existing transformation, 11854 * use {@link #perspectiveOffCenterFovLH(double, double, double, double, double, double, bool) perspectiveOffCenterFovLH()}. 11855 * 11856 * @see #perspectiveOffCenterFovLH(double, double, double, double, double, double, bool) 11857 * 11858 * @param angleLeft 11859 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11860 * For a symmetric frustum, this value is negative. 11861 * @param angleRight 11862 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11863 * @param angleDown 11864 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11865 * For a symmetric frustum, this value is negative. 11866 * @param angleUp 11867 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11868 * @param zNear 11869 * near clipping plane distance. This value must be greater than zero. 11870 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11871 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11872 * @param zFar 11873 * far clipping plane distance. This value must be greater than zero. 11874 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11875 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11876 * @param zZeroToOne 11877 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11878 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11879 * @return this 11880 */ 11881 ref public Matrix4d setPerspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11882 return setFrustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne); 11883 } 11884 11885 /** 11886 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11887 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 11888 * <p> 11889 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11890 * then the new matrix will be <code>M * P</code>. So when transforming a 11891 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11892 * the perspective projection will be applied first! 11893 * <p> 11894 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11895 * use {@link #setPerspectiveLH(double, double, double, double, bool) setPerspectiveLH}. 11896 * 11897 * @see #setPerspectiveLH(double, double, double, double, bool) 11898 * 11899 * @param fovy 11900 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11901 * @param aspect 11902 * the aspect ratio (i.e. width / height; must be greater than zero) 11903 * @param zNear 11904 * near clipping plane distance. This value must be greater than zero. 11905 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11906 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11907 * @param zFar 11908 * far clipping plane distance. This value must be greater than zero. 11909 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11910 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11911 * @param zZeroToOne 11912 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11913 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11914 * @param dest 11915 * will hold the result 11916 * @return dest 11917 */ 11918 public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11919 if ((properties & PROPERTY_IDENTITY) != 0) 11920 return dest.setPerspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne); 11921 return perspectiveLHGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest); 11922 } 11923 private Matrix4d perspectiveLHGeneric(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11924 double h = Math.tan(fovy * 0.5); 11925 // calculate right matrix elements 11926 double rm00 = 1.0 / (h * aspect); 11927 double rm11 = 1.0 / h; 11928 double rm22; 11929 double rm32; 11930 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11931 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11932 if (farInf) { 11933 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11934 double e = 1E-6; 11935 rm22 = 1.0 - e; 11936 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 11937 } else if (nearInf) { 11938 double e = 1E-6; 11939 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 11940 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 11941 } else { 11942 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear); 11943 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 11944 } 11945 // perform optimized matrix multiplication 11946 double nm20 = m20 * rm22 + m30; 11947 double nm21 = m21 * rm22 + m31; 11948 double nm22 = m22 * rm22 + m32; 11949 double nm23 = m23 * rm22 + m33; 11950 dest._m00(m00 * rm00) 11951 ._m01(m01 * rm00) 11952 ._m02(m02 * rm00) 11953 ._m03(m03 * rm00) 11954 ._m10(m10 * rm11) 11955 ._m11(m11 * rm11) 11956 ._m12(m12 * rm11) 11957 ._m13(m13 * rm11) 11958 ._m30(m20 * rm32) 11959 ._m31(m21 * rm32) 11960 ._m32(m22 * rm32) 11961 ._m33(m23 * rm32) 11962 ._m20(nm20) 11963 ._m21(nm21) 11964 ._m22(nm22) 11965 ._m23(nm23) 11966 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 11967 return dest; 11968 } 11969 11970 /** 11971 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11972 * using the given NDC z range to this matrix. 11973 * <p> 11974 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11975 * then the new matrix will be <code>M * P</code>. So when transforming a 11976 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11977 * the perspective projection will be applied first! 11978 * <p> 11979 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11980 * use {@link #setPerspectiveLH(double, double, double, double, bool) setPerspectiveLH}. 11981 * 11982 * @see #setPerspectiveLH(double, double, double, double, bool) 11983 * 11984 * @param fovy 11985 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11986 * @param aspect 11987 * the aspect ratio (i.e. width / height; must be greater than zero) 11988 * @param zNear 11989 * near clipping plane distance. This value must be greater than zero. 11990 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11991 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11992 * @param zFar 11993 * far clipping plane distance. This value must be greater than zero. 11994 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11995 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11996 * @param zZeroToOne 11997 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11998 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11999 * @return this 12000 */ 12001 ref public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 12002 perspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne, this); 12003 return this; 12004 } 12005 12006 /** 12007 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 12008 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12009 * <p> 12010 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 12011 * then the new matrix will be <code>M * P</code>. So when transforming a 12012 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 12013 * the perspective projection will be applied first! 12014 * <p> 12015 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12016 * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}. 12017 * 12018 * @see #setPerspectiveLH(double, double, double, double) 12019 * 12020 * @param fovy 12021 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12022 * @param aspect 12023 * the aspect ratio (i.e. width / height; must be greater than zero) 12024 * @param zNear 12025 * near clipping plane distance. This value must be greater than zero. 12026 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12027 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12028 * @param zFar 12029 * far clipping plane distance. This value must be greater than zero. 12030 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12031 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12032 * @param dest 12033 * will hold the result 12034 * @return dest 12035 */ 12036 public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, ref Matrix4d dest) { 12037 return perspectiveLH(fovy, aspect, zNear, zFar, false, dest); 12038 } 12039 12040 /** 12041 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 12042 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 12043 * <p> 12044 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 12045 * then the new matrix will be <code>M * P</code>. So when transforming a 12046 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 12047 * the perspective projection will be applied first! 12048 * <p> 12049 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12050 * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}. 12051 * 12052 * @see #setPerspectiveLH(double, double, double, double) 12053 * 12054 * @param fovy 12055 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12056 * @param aspect 12057 * the aspect ratio (i.e. width / height; must be greater than zero) 12058 * @param zNear 12059 * near clipping plane distance. This value must be greater than zero. 12060 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12061 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12062 * @param zFar 12063 * far clipping plane distance. This value must be greater than zero. 12064 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12065 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12066 * @return this 12067 */ 12068 ref public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar) return { 12069 perspectiveLH(fovy, aspect, zNear, zFar, this); 12070 return this; 12071 } 12072 12073 /** 12074 * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system 12075 * using the given NDC z range of <code>[-1..+1]</code>. 12076 * <p> 12077 * In order to apply the perspective projection transformation to an existing transformation, 12078 * use {@link #perspectiveLH(double, double, double, double, bool) perspectiveLH()}. 12079 * 12080 * @see #perspectiveLH(double, double, double, double, bool) 12081 * 12082 * @param fovy 12083 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12084 * @param aspect 12085 * the aspect ratio (i.e. width / height; must be greater than zero) 12086 * @param zNear 12087 * near clipping plane distance. This value must be greater than zero. 12088 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12089 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12090 * @param zFar 12091 * far clipping plane distance. This value must be greater than zero. 12092 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12093 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12094 * @param zZeroToOne 12095 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12096 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12097 * @return this 12098 */ 12099 ref public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 12100 double h = Math.tan(fovy * 0.5); 12101 _m00(1.0 / (h * aspect)). 12102 _m01(0.0). 12103 _m02(0.0). 12104 _m03(0.0). 12105 _m10(0.0). 12106 _m11(1.0 / h). 12107 _m12(0.0). 12108 _m13(0.0). 12109 _m20(0.0). 12110 _m21(0.0); 12111 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12112 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12113 if (farInf) { 12114 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12115 double e = 1E-6; 12116 _m22(1.0 - e). 12117 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12118 } else if (nearInf) { 12119 double e = 1E-6; 12120 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12121 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12122 } else { 12123 _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)). 12124 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12125 } 12126 _m23(1.0). 12127 _m30(0.0). 12128 _m31(0.0). 12129 _m33(0.0). 12130 properties = PROPERTY_PERSPECTIVE; 12131 return this; 12132 } 12133 12134 /** 12135 * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system 12136 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12137 * <p> 12138 * In order to apply the perspective projection transformation to an existing transformation, 12139 * use {@link #perspectiveLH(double, double, double, double) perspectiveLH()}. 12140 * 12141 * @see #perspectiveLH(double, double, double, double) 12142 * 12143 * @param fovy 12144 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12145 * @param aspect 12146 * the aspect ratio (i.e. width / height; must be greater than zero) 12147 * @param zNear 12148 * near clipping plane distance. This value must be greater than zero. 12149 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12150 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12151 * @param zFar 12152 * far clipping plane distance. This value must be greater than zero. 12153 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12154 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12155 * @return this 12156 */ 12157 ref public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar) return { 12158 return setPerspectiveLH(fovy, aspect, zNear, zFar, false); 12159 } 12160 12161 /** 12162 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12163 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 12164 * <p> 12165 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12166 * then the new matrix will be <code>M * F</code>. So when transforming a 12167 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12168 * the frustum transformation will be applied first! 12169 * <p> 12170 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12171 * use {@link #setFrustum(double, double, double, double, double, double, bool) setFrustum()}. 12172 * <p> 12173 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12174 * 12175 * @see #setFrustum(double, double, double, double, double, double, bool) 12176 * 12177 * @param left 12178 * the distance along the x-axis to the left frustum edge 12179 * @param right 12180 * the distance along the x-axis to the right frustum edge 12181 * @param bottom 12182 * the distance along the y-axis to the bottom frustum edge 12183 * @param top 12184 * the distance along the y-axis to the top frustum edge 12185 * @param zNear 12186 * near clipping plane distance. This value must be greater than zero. 12187 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12188 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12189 * @param zFar 12190 * far clipping plane distance. This value must be greater than zero. 12191 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12192 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12193 * @param zZeroToOne 12194 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12195 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12196 * @param dest 12197 * will hold the result 12198 * @return dest 12199 */ 12200 public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12201 if ((properties & PROPERTY_IDENTITY) != 0) 12202 return dest.setFrustum(left, right, bottom, top, zNear, zFar, zZeroToOne); 12203 return frustumGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 12204 } 12205 private Matrix4d frustumGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12206 // calculate right matrix elements 12207 double rm00 = (zNear + zNear) / (right - left); 12208 double rm11 = (zNear + zNear) / (top - bottom); 12209 double rm20 = (right + left) / (right - left); 12210 double rm21 = (top + bottom) / (top - bottom); 12211 double rm22; 12212 double rm32; 12213 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12214 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12215 if (farInf) { 12216 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12217 double e = 1E-6; 12218 rm22 = e - 1.0; 12219 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 12220 } else if (nearInf) { 12221 double e = 1E-6; 12222 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 12223 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 12224 } else { 12225 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 12226 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 12227 } 12228 // perform optimized matrix multiplication 12229 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30; 12230 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31; 12231 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32; 12232 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33; 12233 dest._m00(m00 * rm00) 12234 ._m01(m01 * rm00) 12235 ._m02(m02 * rm00) 12236 ._m03(m03 * rm00) 12237 ._m10(m10 * rm11) 12238 ._m11(m11 * rm11) 12239 ._m12(m12 * rm11) 12240 ._m13(m13 * rm11) 12241 ._m30(m20 * rm32) 12242 ._m31(m21 * rm32) 12243 ._m32(m22 * rm32) 12244 ._m33(m23 * rm32) 12245 ._m20(nm20) 12246 ._m21(nm21) 12247 ._m22(nm22) 12248 ._m23(nm23) 12249 ._properties(0); 12250 return dest; 12251 } 12252 12253 /** 12254 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12255 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12256 * <p> 12257 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12258 * then the new matrix will be <code>M * F</code>. So when transforming a 12259 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12260 * the frustum transformation will be applied first! 12261 * <p> 12262 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12263 * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}. 12264 * <p> 12265 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12266 * 12267 * @see #setFrustum(double, double, double, double, double, double) 12268 * 12269 * @param left 12270 * the distance along the x-axis to the left frustum edge 12271 * @param right 12272 * the distance along the x-axis to the right frustum edge 12273 * @param bottom 12274 * the distance along the y-axis to the bottom frustum edge 12275 * @param top 12276 * the distance along the y-axis to the top frustum edge 12277 * @param zNear 12278 * near clipping plane distance. This value must be greater than zero. 12279 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12280 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12281 * @param zFar 12282 * far clipping plane distance. This value must be greater than zero. 12283 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12284 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12285 * @param dest 12286 * will hold the result 12287 * @return dest 12288 */ 12289 public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 12290 return frustum(left, right, bottom, top, zNear, zFar, false, dest); 12291 } 12292 12293 /** 12294 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12295 * using the given NDC z range to this matrix. 12296 * <p> 12297 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12298 * then the new matrix will be <code>M * F</code>. So when transforming a 12299 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12300 * the frustum transformation will be applied first! 12301 * <p> 12302 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12303 * use {@link #setFrustum(double, double, double, double, double, double, bool) setFrustum()}. 12304 * <p> 12305 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12306 * 12307 * @see #setFrustum(double, double, double, double, double, double, bool) 12308 * 12309 * @param left 12310 * the distance along the x-axis to the left frustum edge 12311 * @param right 12312 * the distance along the x-axis to the right frustum edge 12313 * @param bottom 12314 * the distance along the y-axis to the bottom frustum edge 12315 * @param top 12316 * the distance along the y-axis to the top frustum edge 12317 * @param zNear 12318 * near clipping plane distance. This value must be greater than zero. 12319 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12320 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12321 * @param zFar 12322 * far clipping plane distance. This value must be greater than zero. 12323 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12324 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12325 * @param zZeroToOne 12326 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12327 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12328 * @return this 12329 */ 12330 ref public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12331 frustum(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 12332 return this; 12333 } 12334 12335 /** 12336 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12337 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 12338 * <p> 12339 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12340 * then the new matrix will be <code>M * F</code>. So when transforming a 12341 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12342 * the frustum transformation will be applied first! 12343 * <p> 12344 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12345 * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}. 12346 * <p> 12347 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12348 * 12349 * @see #setFrustum(double, double, double, double, double, double) 12350 * 12351 * @param left 12352 * the distance along the x-axis to the left frustum edge 12353 * @param right 12354 * the distance along the x-axis to the right frustum edge 12355 * @param bottom 12356 * the distance along the y-axis to the bottom frustum edge 12357 * @param top 12358 * the distance along the y-axis to the top frustum edge 12359 * @param zNear 12360 * near clipping plane distance. This value must be greater than zero. 12361 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12362 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12363 * @param zFar 12364 * far clipping plane distance. This value must be greater than zero. 12365 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12366 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12367 * @return this 12368 */ 12369 ref public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar) return { 12370 frustum(left, right, bottom, top, zNear, zFar, this); 12371 return this; 12372 } 12373 12374 /** 12375 * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12376 * using the given NDC z range. 12377 * <p> 12378 * In order to apply the perspective frustum transformation to an existing transformation, 12379 * use {@link #frustum(double, double, double, double, double, double, bool) frustum()}. 12380 * <p> 12381 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12382 * 12383 * @see #frustum(double, double, double, double, double, double, bool) 12384 * 12385 * @param left 12386 * the distance along the x-axis to the left frustum edge 12387 * @param right 12388 * the distance along the x-axis to the right frustum edge 12389 * @param bottom 12390 * the distance along the y-axis to the bottom frustum edge 12391 * @param top 12392 * the distance along the y-axis to the top frustum edge 12393 * @param zNear 12394 * near clipping plane distance. This value must be greater than zero. 12395 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12396 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12397 * @param zFar 12398 * far clipping plane distance. This value must be greater than zero. 12399 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12400 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12401 * @param zZeroToOne 12402 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12403 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12404 * @return this 12405 */ 12406 ref public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12407 if ((properties & PROPERTY_IDENTITY) == 0) 12408 _identity(); 12409 _m00((zNear + zNear) / (right - left)). 12410 _m11((zNear + zNear) / (top - bottom)). 12411 _m20((right + left) / (right - left)). 12412 _m21((top + bottom) / (top - bottom)); 12413 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12414 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12415 if (farInf) { 12416 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12417 double e = 1E-6; 12418 _m22(e - 1.0). 12419 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12420 } else if (nearInf) { 12421 double e = 1E-6; 12422 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12423 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12424 } else { 12425 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 12426 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12427 } 12428 _m23(-1.0). 12429 _m33(0.0). 12430 properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0; 12431 return this; 12432 } 12433 12434 /** 12435 * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12436 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12437 * <p> 12438 * In order to apply the perspective frustum transformation to an existing transformation, 12439 * use {@link #frustum(double, double, double, double, double, double) frustum()}. 12440 * <p> 12441 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12442 * 12443 * @see #frustum(double, double, double, double, double, double) 12444 * 12445 * @param left 12446 * the distance along the x-axis to the left frustum edge 12447 * @param right 12448 * the distance along the x-axis to the right frustum edge 12449 * @param bottom 12450 * the distance along the y-axis to the bottom frustum edge 12451 * @param top 12452 * the distance along the y-axis to the top frustum edge 12453 * @param zNear 12454 * near clipping plane distance. This value must be greater than zero. 12455 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12456 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12457 * @param zFar 12458 * far clipping plane distance. This value must be greater than zero. 12459 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12460 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12461 * @return this 12462 */ 12463 ref public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar) return { 12464 return setFrustum(left, right, bottom, top, zNear, zFar, false); 12465 } 12466 12467 /** 12468 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12469 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 12470 * <p> 12471 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12472 * then the new matrix will be <code>M * F</code>. So when transforming a 12473 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12474 * the frustum transformation will be applied first! 12475 * <p> 12476 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12477 * use {@link #setFrustumLH(double, double, double, double, double, double, bool) setFrustumLH()}. 12478 * <p> 12479 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12480 * 12481 * @see #setFrustumLH(double, double, double, double, double, double, bool) 12482 * 12483 * @param left 12484 * the distance along the x-axis to the left frustum edge 12485 * @param right 12486 * the distance along the x-axis to the right frustum edge 12487 * @param bottom 12488 * the distance along the y-axis to the bottom frustum edge 12489 * @param top 12490 * the distance along the y-axis to the top frustum edge 12491 * @param zNear 12492 * near clipping plane distance. This value must be greater than zero. 12493 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12494 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12495 * @param zFar 12496 * far clipping plane distance. This value must be greater than zero. 12497 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12498 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12499 * @param zZeroToOne 12500 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12501 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12502 * @param dest 12503 * will hold the result 12504 * @return dest 12505 */ 12506 public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12507 if ((properties & PROPERTY_IDENTITY) != 0) 12508 return dest.setFrustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne); 12509 return frustumLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 12510 } 12511 private Matrix4d frustumLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12512 // calculate right matrix elements 12513 double rm00 = (zNear + zNear) / (right - left); 12514 double rm11 = (zNear + zNear) / (top - bottom); 12515 double rm20 = (right + left) / (right - left); 12516 double rm21 = (top + bottom) / (top - bottom); 12517 double rm22; 12518 double rm32; 12519 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12520 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12521 if (farInf) { 12522 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12523 double e = 1E-6; 12524 rm22 = 1.0 - e; 12525 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 12526 } else if (nearInf) { 12527 double e = 1E-6; 12528 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 12529 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 12530 } else { 12531 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear); 12532 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 12533 } 12534 // perform optimized matrix multiplication 12535 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30; 12536 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31; 12537 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32; 12538 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33; 12539 dest._m00(m00 * rm00) 12540 ._m01(m01 * rm00) 12541 ._m02(m02 * rm00) 12542 ._m03(m03 * rm00) 12543 ._m10(m10 * rm11) 12544 ._m11(m11 * rm11) 12545 ._m12(m12 * rm11) 12546 ._m13(m13 * rm11) 12547 ._m30(m20 * rm32) 12548 ._m31(m21 * rm32) 12549 ._m32(m22 * rm32) 12550 ._m33(m23 * rm32) 12551 ._m20(nm20) 12552 ._m21(nm21) 12553 ._m22(nm22) 12554 ._m23(nm23) 12555 ._properties(0); 12556 return dest; 12557 } 12558 12559 /** 12560 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12561 * using the given NDC z range to this matrix. 12562 * <p> 12563 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12564 * then the new matrix will be <code>M * F</code>. So when transforming a 12565 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12566 * the frustum transformation will be applied first! 12567 * <p> 12568 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12569 * use {@link #setFrustumLH(double, double, double, double, double, double, bool) setFrustumLH()}. 12570 * <p> 12571 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12572 * 12573 * @see #setFrustumLH(double, double, double, double, double, double, bool) 12574 * 12575 * @param left 12576 * the distance along the x-axis to the left frustum edge 12577 * @param right 12578 * the distance along the x-axis to the right frustum edge 12579 * @param bottom 12580 * the distance along the y-axis to the bottom frustum edge 12581 * @param top 12582 * the distance along the y-axis to the top frustum edge 12583 * @param zNear 12584 * near clipping plane distance. This value must be greater than zero. 12585 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12586 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12587 * @param zFar 12588 * far clipping plane distance. This value must be greater than zero. 12589 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12590 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12591 * @param zZeroToOne 12592 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12593 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12594 * @return this 12595 */ 12596 ref public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12597 frustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 12598 return this; 12599 } 12600 12601 /** 12602 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12603 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12604 * <p> 12605 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12606 * then the new matrix will be <code>M * F</code>. So when transforming a 12607 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12608 * the frustum transformation will be applied first! 12609 * <p> 12610 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12611 * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}. 12612 * <p> 12613 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12614 * 12615 * @see #setFrustumLH(double, double, double, double, double, double) 12616 * 12617 * @param left 12618 * the distance along the x-axis to the left frustum edge 12619 * @param right 12620 * the distance along the x-axis to the right frustum edge 12621 * @param bottom 12622 * the distance along the y-axis to the bottom frustum edge 12623 * @param top 12624 * the distance along the y-axis to the top frustum edge 12625 * @param zNear 12626 * near clipping plane distance. This value must be greater than zero. 12627 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12628 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12629 * @param zFar 12630 * far clipping plane distance. This value must be greater than zero. 12631 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12632 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12633 * @param dest 12634 * will hold the result 12635 * @return dest 12636 */ 12637 public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 12638 return frustumLH(left, right, bottom, top, zNear, zFar, false, dest); 12639 } 12640 12641 /** 12642 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12643 * using the given NDC z range to this matrix. 12644 * <p> 12645 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12646 * then the new matrix will be <code>M * F</code>. So when transforming a 12647 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12648 * the frustum transformation will be applied first! 12649 * <p> 12650 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12651 * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}. 12652 * <p> 12653 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12654 * 12655 * @see #setFrustumLH(double, double, double, double, double, double) 12656 * 12657 * @param left 12658 * the distance along the x-axis to the left frustum edge 12659 * @param right 12660 * the distance along the x-axis to the right frustum edge 12661 * @param bottom 12662 * the distance along the y-axis to the bottom frustum edge 12663 * @param top 12664 * the distance along the y-axis to the top frustum edge 12665 * @param zNear 12666 * near clipping plane distance. This value must be greater than zero. 12667 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12668 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12669 * @param zFar 12670 * far clipping plane distance. This value must be greater than zero. 12671 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12672 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12673 * @return this 12674 */ 12675 ref public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 12676 frustumLH(left, right, bottom, top, zNear, zFar, this); 12677 return this; 12678 } 12679 12680 /** 12681 * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12682 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12683 * <p> 12684 * In order to apply the perspective frustum transformation to an existing transformation, 12685 * use {@link #frustumLH(double, double, double, double, double, double, bool) frustumLH()}. 12686 * <p> 12687 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12688 * 12689 * @see #frustumLH(double, double, double, double, double, double, bool) 12690 * 12691 * @param left 12692 * the distance along the x-axis to the left frustum edge 12693 * @param right 12694 * the distance along the x-axis to the right frustum edge 12695 * @param bottom 12696 * the distance along the y-axis to the bottom frustum edge 12697 * @param top 12698 * the distance along the y-axis to the top frustum edge 12699 * @param zNear 12700 * near clipping plane distance. This value must be greater than zero. 12701 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12702 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12703 * @param zFar 12704 * far clipping plane distance. This value must be greater than zero. 12705 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12706 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12707 * @param zZeroToOne 12708 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12709 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12710 * @return this 12711 */ 12712 ref public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12713 if ((properties & PROPERTY_IDENTITY) == 0) 12714 _identity(); 12715 _m00((zNear + zNear) / (right - left)). 12716 _m11((zNear + zNear) / (top - bottom)). 12717 _m20((right + left) / (right - left)). 12718 _m21((top + bottom) / (top - bottom)); 12719 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12720 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12721 if (farInf) { 12722 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12723 double e = 1E-6; 12724 _m22(1.0 - e). 12725 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12726 } else if (nearInf) { 12727 double e = 1E-6; 12728 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12729 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12730 } else { 12731 _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)). 12732 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12733 } 12734 _m23(1.0). 12735 _m33(0.0). 12736 properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0; 12737 return this; 12738 } 12739 12740 /** 12741 * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12742 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12743 * <p> 12744 * In order to apply the perspective frustum transformation to an existing transformation, 12745 * use {@link #frustumLH(double, double, double, double, double, double) frustumLH()}. 12746 * <p> 12747 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12748 * 12749 * @see #frustumLH(double, double, double, double, double, double) 12750 * 12751 * @param left 12752 * the distance along the x-axis to the left frustum edge 12753 * @param right 12754 * the distance along the x-axis to the right frustum edge 12755 * @param bottom 12756 * the distance along the y-axis to the bottom frustum edge 12757 * @param top 12758 * the distance along the y-axis to the top frustum edge 12759 * @param zNear 12760 * near clipping plane distance. This value must be greater than zero. 12761 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12762 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12763 * @param zFar 12764 * far clipping plane distance. This value must be greater than zero. 12765 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12766 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12767 * @return this 12768 */ 12769 ref public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 12770 return setFrustumLH(left, right, bottom, top, zNear, zFar, false); 12771 } 12772 12773 /** 12774 * Set this matrix to represent a perspective projection equivalent to the given intrinsic camera calibration parameters. 12775 * The resulting matrix will be suited for a right-handed coordinate system using OpenGL's NDC z range of <code>[-1..+1]</code>. 12776 * <p> 12777 * See: <a href="https://en.wikipedia.org/wiki/Camera_resectioning#Intrinsic_parameters">https://en.wikipedia.org/</a> 12778 * <p> 12779 * Reference: <a href="http://ksimek.github.io/2013/06/03/calibrated_cameras_in_opengl/">http://ksimek.github.io/</a> 12780 * 12781 * @param alphaX 12782 * specifies the focal length and scale along the X axis 12783 * @param alphaY 12784 * specifies the focal length and scale along the Y axis 12785 * @param gamma 12786 * the skew coefficient between the X and Y axis (may be <code>0</code>) 12787 * @param u0 12788 * the X coordinate of the principal point in image/sensor units 12789 * @param v0 12790 * the Y coordinate of the principal point in image/sensor units 12791 * @param imgWidth 12792 * the width of the sensor/image image/sensor units 12793 * @param imgHeight 12794 * the height of the sensor/image image/sensor units 12795 * @param near 12796 * the distance to the near plane 12797 * @param far 12798 * the distance to the far plane 12799 * @return this 12800 */ 12801 ref public Matrix4d setFromIntrinsic(double alphaX, double alphaY, double gamma, double u0, double v0, int imgWidth, int imgHeight, double near, double far) return { 12802 double l00 = 2.0 / imgWidth; 12803 double l11 = 2.0 / imgHeight; 12804 double l22 = 2.0 / (near - far); 12805 setm00(l00 * alphaX); 12806 setm01(0.0); 12807 setm02(0.0); 12808 setm03(0.0); 12809 setm10(l00 * gamma); 12810 setm11(l11 * alphaY); 12811 setm12(0.0); 12812 setm13(0.0); 12813 setm20(l00 * u0 - 1.0); 12814 setm21(l11 * v0 - 1.0); 12815 setm22(l22 * -(near + far) + (far + near) / (near - far)); 12816 setm23(-1.0); 12817 setm30(0.0); 12818 setm31(0.0); 12819 setm32(l22 * -near * far); 12820 setm33(0.0); 12821 this.properties = PROPERTY_PERSPECTIVE; 12822 return this; 12823 } 12824 12825 public Vector4d frustumPlane(int plane, ref Vector4d dest) { 12826 switch (plane) { 12827 case PLANE_NX: 12828 dest.set(m03 + m00, m13 + m10, m23 + m20, m33 + m30).normalize3(); 12829 break; 12830 case PLANE_PX: 12831 dest.set(m03 - m00, m13 - m10, m23 - m20, m33 - m30).normalize3(); 12832 break; 12833 case PLANE_NY: 12834 dest.set(m03 + m01, m13 + m11, m23 + m21, m33 + m31).normalize3(); 12835 break; 12836 case PLANE_PY: 12837 dest.set(m03 - m01, m13 - m11, m23 - m21, m33 - m31).normalize3(); 12838 break; 12839 case PLANE_NZ: 12840 dest.set(m03 + m02, m13 + m12, m23 + m22, m33 + m32).normalize3(); 12841 break; 12842 case PLANE_PZ: 12843 dest.set(m03 - m02, m13 - m12, m23 - m22, m33 - m32).normalize3(); 12844 break; 12845 default: 12846 // do nothing 12847 } 12848 return dest; 12849 } 12850 12851 public Vector3d frustumCorner(int corner, ref Vector3d dest) { 12852 double d1, d2, d3; 12853 double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z; 12854 switch (corner) { 12855 case CORNER_NXNYNZ: // left, bottom, near 12856 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12857 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12858 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12859 break; 12860 case CORNER_PXNYNZ: // right, bottom, near 12861 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12862 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12863 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12864 break; 12865 case CORNER_PXPYNZ: // right, top, near 12866 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12867 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12868 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12869 break; 12870 case CORNER_NXPYNZ: // left, top, near 12871 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12872 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12873 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12874 break; 12875 case CORNER_PXNYPZ: // right, bottom, far 12876 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12877 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12878 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12879 break; 12880 case CORNER_NXNYPZ: // left, bottom, far 12881 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12882 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12883 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12884 break; 12885 case CORNER_NXPYPZ: // left, top, far 12886 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12887 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12888 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12889 break; 12890 case CORNER_PXPYPZ: // right, top, far 12891 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12892 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12893 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12894 break; 12895 default: 12896 // do nothing 12897 } 12898 double c23x, c23y, c23z; 12899 c23x = n2y * n3z - n2z * n3y; 12900 c23y = n2z * n3x - n2x * n3z; 12901 c23z = n2x * n3y - n2y * n3x; 12902 double c31x, c31y, c31z; 12903 c31x = n3y * n1z - n3z * n1y; 12904 c31y = n3z * n1x - n3x * n1z; 12905 c31z = n3x * n1y - n3y * n1x; 12906 double c12x, c12y, c12z; 12907 c12x = n1y * n2z - n1z * n2y; 12908 c12y = n1z * n2x - n1x * n2z; 12909 c12z = n1x * n2y - n1y * n2x; 12910 double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z); 12911 dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot; 12912 dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot; 12913 dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot; 12914 return dest; 12915 } 12916 12917 public Vector3d perspectiveOrigin(ref Vector3d dest) { 12918 /* 12919 * Simply compute the intersection point of the left, right and top frustum plane. 12920 */ 12921 double d1, d2, d3; 12922 double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z; 12923 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12924 n2x = m03 - m00; n2y = m13 - m10; n2z = m23 - m20; d2 = m33 - m30; // right 12925 n3x = m03 - m01; n3y = m13 - m11; n3z = m23 - m21; d3 = m33 - m31; // top 12926 double c23x, c23y, c23z; 12927 c23x = n2y * n3z - n2z * n3y; 12928 c23y = n2z * n3x - n2x * n3z; 12929 c23z = n2x * n3y - n2y * n3x; 12930 double c31x, c31y, c31z; 12931 c31x = n3y * n1z - n3z * n1y; 12932 c31y = n3z * n1x - n3x * n1z; 12933 c31z = n3x * n1y - n3y * n1x; 12934 double c12x, c12y, c12z; 12935 c12x = n1y * n2z - n1z * n2y; 12936 c12y = n1z * n2x - n1x * n2z; 12937 c12z = n1x * n2y - n1y * n2x; 12938 double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z); 12939 dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot; 12940 dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot; 12941 dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot; 12942 return dest; 12943 } 12944 12945 public Vector3d perspectiveInvOrigin(ref Vector3d dest) { 12946 double invW = 1.0 / m23; 12947 dest.x = m20 * invW; 12948 dest.y = m21 * invW; 12949 dest.z = m22 * invW; 12950 return dest; 12951 } 12952 12953 public double perspectiveFov() { 12954 /* 12955 * Compute the angle between the bottom and top frustum plane normals. 12956 */ 12957 double n1x, n1y, n1z, n2x, n2y, n2z; 12958 n1x = m03 + m01; n1y = m13 + m11; n1z = m23 + m21; // bottom 12959 n2x = m01 - m03; n2y = m11 - m13; n2z = m21 - m23; // top 12960 double n1len = Math.sqrt(n1x * n1x + n1y * n1y + n1z * n1z); 12961 double n2len = Math.sqrt(n2x * n2x + n2y * n2y + n2z * n2z); 12962 return Math.acos((n1x * n2x + n1y * n2y + n1z * n2z) / (n1len * n2len)); 12963 } 12964 12965 public double perspectiveNear() { 12966 return m32 / (m23 + m22); 12967 } 12968 12969 public double perspectiveFar() { 12970 return m32 / (m22 - m23); 12971 } 12972 12973 public Vector3d frustumRayDir(double x, double y, ref Vector3d dest) { 12974 /* 12975 * This method works by first obtaining the frustum plane normals, 12976 * then building the cross product to obtain the corner rays, 12977 * and finally bilinearly interpolating to obtain the desired direction. 12978 * The code below uses a condense form of doing all this making use 12979 * of some mathematical identities to simplify the overall expression. 12980 */ 12981 double a = m10 * m23, b = m13 * m21, c = m10 * m21, d = m11 * m23, e = m13 * m20, f = m11 * m20; 12982 double g = m03 * m20, h = m01 * m23, i = m01 * m20, j = m03 * m21, k = m00 * m23, l = m00 * m21; 12983 double m = m00 * m13, n = m03 * m11, o = m00 * m11, p = m01 * m13, q = m03 * m10, r = m01 * m10; 12984 double m1x, m1y, m1z; 12985 m1x = (d + e + f - a - b - c) * (1.0 - y) + (a - b - c + d - e + f) * y; 12986 m1y = (j + k + l - g - h - i) * (1.0 - y) + (g - h - i + j - k + l) * y; 12987 m1z = (p + q + r - m - n - o) * (1.0 - y) + (m - n - o + p - q + r) * y; 12988 double m2x, m2y, m2z; 12989 m2x = (b - c - d + e + f - a) * (1.0 - y) + (a + b - c - d - e + f) * y; 12990 m2y = (h - i - j + k + l - g) * (1.0 - y) + (g + h - i - j - k + l) * y; 12991 m2z = (n - o - p + q + r - m) * (1.0 - y) + (m + n - o - p - q + r) * y; 12992 dest.x = m1x * (1.0 - x) + m2x * x; 12993 dest.y = m1y * (1.0 - x) + m2y * x; 12994 dest.z = m1z * (1.0 - x) + m2z * x; 12995 return dest.normalize(dest); 12996 } 12997 12998 public Vector3d positiveZ(ref Vector3d dir) { 12999 if ((properties & PROPERTY_ORTHONORMAL) != 0) 13000 return normalizedPositiveZ(dir); 13001 return positiveZGeneric(dir); 13002 } 13003 private Vector3d positiveZGeneric(ref Vector3d dir) { 13004 return dir.set(m10 * m21 - m11 * m20, m20 * m01 - m21 * m00, m00 * m11 - m01 * m10).normalize(); 13005 } 13006 13007 public Vector3d normalizedPositiveZ(ref Vector3d dir) { 13008 return dir.set(m02, m12, m22); 13009 } 13010 13011 public Vector3d positiveX(ref Vector3d dir) { 13012 if ((properties & PROPERTY_ORTHONORMAL) != 0) 13013 return normalizedPositiveX(dir); 13014 return positiveXGeneric(dir); 13015 } 13016 private Vector3d positiveXGeneric(ref Vector3d dir) { 13017 return dir.set(m11 * m22 - m12 * m21, m02 * m21 - m01 * m22, m01 * m12 - m02 * m11).normalize(); 13018 } 13019 13020 public Vector3d normalizedPositiveX(ref Vector3d dir) { 13021 return dir.set(m00, m10, m20); 13022 } 13023 13024 public Vector3d positiveY(ref Vector3d dir) { 13025 if ((properties & PROPERTY_ORTHONORMAL) != 0) 13026 return normalizedPositiveY(dir); 13027 return positiveYGeneric(dir); 13028 } 13029 private Vector3d positiveYGeneric(ref Vector3d dir) { 13030 return dir.set(m12 * m20 - m10 * m22, m00 * m22 - m02 * m20, m02 * m10 - m00 * m12).normalize(); 13031 } 13032 13033 public Vector3d normalizedPositiveY(ref Vector3d dir) { 13034 return dir.set(m01, m11, m21); 13035 } 13036 13037 public Vector3d originAffine(ref Vector3d dest) { 13038 double a = m00 * m11 - m01 * m10; 13039 double b = m00 * m12 - m02 * m10; 13040 double d = m01 * m12 - m02 * m11; 13041 double g = m20 * m31 - m21 * m30; 13042 double h = m20 * m32 - m22 * m30; 13043 double j = m21 * m32 - m22 * m31; 13044 dest.x = -m10 * j + m11 * h - m12 * g; 13045 dest.y = m00 * j - m01 * h + m02 * g; 13046 dest.z = -m30 * d + m31 * b - m32 * a; 13047 return dest; 13048 } 13049 13050 public Vector3d origin(ref Vector3d dest) { 13051 if ((properties & PROPERTY_AFFINE) != 0) 13052 return originAffine(dest); 13053 return originGeneric(dest); 13054 } 13055 private Vector3d originGeneric(ref Vector3d dest) { 13056 double a = m00 * m11 - m01 * m10; 13057 double b = m00 * m12 - m02 * m10; 13058 double c = m00 * m13 - m03 * m10; 13059 double d = m01 * m12 - m02 * m11; 13060 double e = m01 * m13 - m03 * m11; 13061 double f = m02 * m13 - m03 * m12; 13062 double g = m20 * m31 - m21 * m30; 13063 double h = m20 * m32 - m22 * m30; 13064 double i = m20 * m33 - m23 * m30; 13065 double j = m21 * m32 - m22 * m31; 13066 double k = m21 * m33 - m23 * m31; 13067 double l = m22 * m33 - m23 * m32; 13068 double det = a * l - b * k + c * j + d * i - e * h + f * g; 13069 double invDet = 1.0 / det; 13070 double nm30 = (-m10 * j + m11 * h - m12 * g) * invDet; 13071 double nm31 = ( m00 * j - m01 * h + m02 * g) * invDet; 13072 double nm32 = (-m30 * d + m31 * b - m32 * a) * invDet; 13073 double nm33 = det / ( m20 * d - m21 * b + m22 * a); 13074 double x = nm30 * nm33; 13075 double y = nm31 * nm33; 13076 double z = nm32 * nm33; 13077 return dest.set(x, y, z); 13078 } 13079 13080 /** 13081 * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation 13082 * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>light</code>. 13083 * <p> 13084 * If <code>light.w</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light. 13085 * <p> 13086 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13087 * then the new matrix will be <code>M * S</code>. So when transforming a 13088 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13089 * shadow projection will be applied first! 13090 * <p> 13091 * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a> 13092 * 13093 * @param light 13094 * the light's vector 13095 * @param a 13096 * the x factor in the plane equation 13097 * @param b 13098 * the y factor in the plane equation 13099 * @param c 13100 * the z factor in the plane equation 13101 * @param d 13102 * the constant in the plane equation 13103 * @return this 13104 */ 13105 ref public Matrix4d shadow(ref Vector4d light, double a, double b, double c, double d) return { 13106 shadow(light.x, light.y, light.z, light.w, a, b, c, d, this); 13107 return this; 13108 } 13109 13110 public Matrix4d shadow(ref Vector4d light, double a, double b, double c, double d, ref Matrix4d dest) { 13111 return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest); 13112 } 13113 13114 /** 13115 * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation 13116 * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>. 13117 * <p> 13118 * If <code>lightW</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light. 13119 * <p> 13120 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13121 * then the new matrix will be <code>M * S</code>. So when transforming a 13122 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13123 * shadow projection will be applied first! 13124 * <p> 13125 * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a> 13126 * 13127 * @param lightX 13128 * the x-component of the light's vector 13129 * @param lightY 13130 * the y-component of the light's vector 13131 * @param lightZ 13132 * the z-component of the light's vector 13133 * @param lightW 13134 * the w-component of the light's vector 13135 * @param a 13136 * the x factor in the plane equation 13137 * @param b 13138 * the y factor in the plane equation 13139 * @param c 13140 * the z factor in the plane equation 13141 * @param d 13142 * the constant in the plane equation 13143 * @return this 13144 */ 13145 ref public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) return { 13146 shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this); 13147 return this; 13148 } 13149 13150 public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, ref Matrix4d dest) { 13151 // normalize plane 13152 double invPlaneLen = Math.invsqrt(a*a + b*b + c*c); 13153 double an = a * invPlaneLen; 13154 double bn = b * invPlaneLen; 13155 double cn = c * invPlaneLen; 13156 double dn = d * invPlaneLen; 13157 13158 double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW; 13159 13160 // compute right matrix elements 13161 double rm00 = dot - an * lightX; 13162 double rm01 = -an * lightY; 13163 double rm02 = -an * lightZ; 13164 double rm03 = -an * lightW; 13165 double rm10 = -bn * lightX; 13166 double rm11 = dot - bn * lightY; 13167 double rm12 = -bn * lightZ; 13168 double rm13 = -bn * lightW; 13169 double rm20 = -cn * lightX; 13170 double rm21 = -cn * lightY; 13171 double rm22 = dot - cn * lightZ; 13172 double rm23 = -cn * lightW; 13173 double rm30 = -dn * lightX; 13174 double rm31 = -dn * lightY; 13175 double rm32 = -dn * lightZ; 13176 double rm33 = dot - dn * lightW; 13177 13178 // matrix multiplication 13179 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03; 13180 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03; 13181 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03; 13182 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02 + m33 * rm03; 13183 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13; 13184 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13; 13185 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13; 13186 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12 + m33 * rm13; 13187 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23; 13188 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23; 13189 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23; 13190 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33 * rm23; 13191 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33) 13192 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33) 13193 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33) 13194 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33 * rm33) 13195 ._m00(nm00) 13196 ._m01(nm01) 13197 ._m02(nm02) 13198 ._m03(nm03) 13199 ._m10(nm10) 13200 ._m11(nm11) 13201 ._m12(nm12) 13202 ._m13(nm13) 13203 ._m20(nm20) 13204 ._m21(nm21) 13205 ._m22(nm22) 13206 ._m23(nm23) 13207 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 13208 return dest; 13209 } 13210 13211 public Matrix4d shadow(ref Vector4d light, Matrix4d planeTransform, ref Matrix4d dest) { 13212 // compute plane equation by transforming (y = 0) 13213 double a = planeTransform.m10; 13214 double b = planeTransform.m11; 13215 double c = planeTransform.m12; 13216 double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32; 13217 return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest); 13218 } 13219 13220 /** 13221 * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation 13222 * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>light</code>. 13223 * <p> 13224 * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>. 13225 * <p> 13226 * If <code>light.w</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light. 13227 * <p> 13228 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13229 * then the new matrix will be <code>M * S</code>. So when transforming a 13230 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13231 * shadow projection will be applied first! 13232 * 13233 * @param light 13234 * the light's vector 13235 * @param planeTransform 13236 * the transformation to transform the implied plane <code>y = 0</code> before applying the projection 13237 * @return this 13238 */ 13239 ref public Matrix4d shadow(ref Vector4d light, Matrix4d planeTransform) return { 13240 shadow(light, planeTransform, this); 13241 return this; 13242 } 13243 13244 public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4d planeTransform, ref Matrix4d dest) { 13245 // compute plane equation by transforming (y = 0) 13246 double a = planeTransform.m10; 13247 double b = planeTransform.m11; 13248 double c = planeTransform.m12; 13249 double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32; 13250 return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest); 13251 } 13252 13253 /** 13254 * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation 13255 * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>. 13256 * <p> 13257 * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>. 13258 * <p> 13259 * If <code>lightW</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light. 13260 * <p> 13261 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13262 * then the new matrix will be <code>M * S</code>. So when transforming a 13263 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13264 * shadow projection will be applied first! 13265 * 13266 * @param lightX 13267 * the x-component of the light vector 13268 * @param lightY 13269 * the y-component of the light vector 13270 * @param lightZ 13271 * the z-component of the light vector 13272 * @param lightW 13273 * the w-component of the light vector 13274 * @param planeTransform 13275 * the transformation to transform the implied plane <code>y = 0</code> before applying the projection 13276 * @return this 13277 */ 13278 ref public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4d planeTransform) return { 13279 shadow(lightX, lightY, lightZ, lightW, planeTransform, this); 13280 return this; 13281 } 13282 13283 /** 13284 * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13285 * a target position at <code>targetPos</code> while constraining a cylindrical rotation around the given <code>up</code> vector. 13286 * <p> 13287 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13288 * its position <code>objPos</code>. 13289 * 13290 * @param objPos 13291 * the position of the object to rotate towards <code>targetPos</code> 13292 * @param targetPos 13293 * the position of the target (for example the camera) towards which to rotate the object 13294 * @param up 13295 * the rotation axis (must be {@link Vector3d#normalize() normalized}) 13296 * @return this 13297 */ 13298 ref public Matrix4d billboardCylindrical(ref Vector3d objPos, Vector3d targetPos, Vector3d up) return { 13299 double dirX = targetPos.x - objPos.x; 13300 double dirY = targetPos.y - objPos.y; 13301 double dirZ = targetPos.z - objPos.z; 13302 // left = up x dir 13303 double leftX = up.y * dirZ - up.z * dirY; 13304 double leftY = up.z * dirX - up.x * dirZ; 13305 double leftZ = up.x * dirY - up.y * dirX; 13306 // normalize left 13307 double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 13308 leftX *= invLeftLen; 13309 leftY *= invLeftLen; 13310 leftZ *= invLeftLen; 13311 // recompute dir by constraining rotation around 'up' 13312 // dir = left x up 13313 dirX = leftY * up.z - leftZ * up.y; 13314 dirY = leftZ * up.x - leftX * up.z; 13315 dirZ = leftX * up.y - leftY * up.x; 13316 // normalize dir 13317 double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 13318 dirX *= invDirLen; 13319 dirY *= invDirLen; 13320 dirZ *= invDirLen; 13321 // set matrix elements 13322 _m00(leftX). 13323 _m01(leftY). 13324 _m02(leftZ). 13325 _m03(0.0). 13326 _m10(up.x). 13327 _m11(up.y). 13328 _m12(up.z). 13329 _m13(0.0). 13330 _m20(dirX). 13331 _m21(dirY). 13332 _m22(dirZ). 13333 _m23(0.0). 13334 _m30(objPos.x). 13335 _m31(objPos.y). 13336 _m32(objPos.z). 13337 _m33(1.0). 13338 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13339 return this; 13340 } 13341 13342 /** 13343 * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13344 * a target position at <code>targetPos</code>. 13345 * <p> 13346 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13347 * its position <code>objPos</code>. 13348 * <p> 13349 * If preserving an <i>up</i> vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained 13350 * using {@link #billboardSpherical(ref Vector3d, Vector3d)}. 13351 * 13352 * @see #billboardSpherical(ref Vector3d, Vector3d) 13353 * 13354 * @param objPos 13355 * the position of the object to rotate towards <code>targetPos</code> 13356 * @param targetPos 13357 * the position of the target (for example the camera) towards which to rotate the object 13358 * @param up 13359 * the up axis used to orient the object 13360 * @return this 13361 */ 13362 ref public Matrix4d billboardSpherical(ref Vector3d objPos, Vector3d targetPos, Vector3d up) return { 13363 double dirX = targetPos.x - objPos.x; 13364 double dirY = targetPos.y - objPos.y; 13365 double dirZ = targetPos.z - objPos.z; 13366 // normalize dir 13367 double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 13368 dirX *= invDirLen; 13369 dirY *= invDirLen; 13370 dirZ *= invDirLen; 13371 // left = up x dir 13372 double leftX = up.y * dirZ - up.z * dirY; 13373 double leftY = up.z * dirX - up.x * dirZ; 13374 double leftZ = up.x * dirY - up.y * dirX; 13375 // normalize left 13376 double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 13377 leftX *= invLeftLen; 13378 leftY *= invLeftLen; 13379 leftZ *= invLeftLen; 13380 // up = dir x left 13381 double upX = dirY * leftZ - dirZ * leftY; 13382 double upY = dirZ * leftX - dirX * leftZ; 13383 double upZ = dirX * leftY - dirY * leftX; 13384 // set matrix elements 13385 _m00(leftX). 13386 _m01(leftY). 13387 _m02(leftZ). 13388 _m03(0.0). 13389 _m10(upX). 13390 _m11(upY). 13391 _m12(upZ). 13392 _m13(0.0). 13393 _m20(dirX). 13394 _m21(dirY). 13395 _m22(dirZ). 13396 _m23(0.0). 13397 _m30(objPos.x). 13398 _m31(objPos.y). 13399 _m32(objPos.z). 13400 _m33(1.0). 13401 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13402 return this; 13403 } 13404 13405 /** 13406 * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13407 * a target position at <code>targetPos</code> using a shortest arc rotation by not preserving any <i>up</i> vector of the object. 13408 * <p> 13409 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13410 * its position <code>objPos</code>. 13411 * <p> 13412 * In order to specify an <i>up</i> vector which needs to be maintained when rotating the +Z axis of the object, 13413 * use {@link #billboardSpherical(ref Vector3d, Vector3d, Vector3d)}. 13414 * 13415 * @see #billboardSpherical(ref Vector3d, Vector3d, Vector3d) 13416 * 13417 * @param objPos 13418 * the position of the object to rotate towards <code>targetPos</code> 13419 * @param targetPos 13420 * the position of the target (for example the camera) towards which to rotate the object 13421 * @return this 13422 */ 13423 ref public Matrix4d billboardSpherical(ref Vector3d objPos, Vector3d targetPos) return { 13424 double toDirX = targetPos.x - objPos.x; 13425 double toDirY = targetPos.y - objPos.y; 13426 double toDirZ = targetPos.z - objPos.z; 13427 double x = -toDirY; 13428 double y = toDirX; 13429 double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ; 13430 double invNorm = Math.invsqrt(x * x + y * y + w * w); 13431 x *= invNorm; 13432 y *= invNorm; 13433 w *= invNorm; 13434 double q00 = (x + x) * x; 13435 double q11 = (y + y) * y; 13436 double q01 = (x + x) * y; 13437 double q03 = (x + x) * w; 13438 double q13 = (y + y) * w; 13439 _m00(1.0 - q11). 13440 _m01(q01). 13441 _m02(-q13). 13442 _m03(0.0). 13443 _m10(q01). 13444 _m11(1.0 - q00). 13445 _m12(q03). 13446 _m13(0.0). 13447 _m20(q13). 13448 _m21(-q03). 13449 _m22(1.0 - q11 - q00). 13450 _m23(0.0). 13451 _m30(objPos.x). 13452 _m31(objPos.y). 13453 _m32(objPos.z). 13454 _m33(1.0). 13455 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13456 return this; 13457 } 13458 13459 public int hashCode() { 13460 immutable int prime = 31; 13461 int result = 1; 13462 long temp; 13463 temp = Math.doubleToLongBits(m00); 13464 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13465 temp = Math.doubleToLongBits(m01); 13466 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13467 temp = Math.doubleToLongBits(m02); 13468 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13469 temp = Math.doubleToLongBits(m03); 13470 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13471 temp = Math.doubleToLongBits(m10); 13472 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13473 temp = Math.doubleToLongBits(m11); 13474 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13475 temp = Math.doubleToLongBits(m12); 13476 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13477 temp = Math.doubleToLongBits(m13); 13478 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13479 temp = Math.doubleToLongBits(m20); 13480 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13481 temp = Math.doubleToLongBits(m21); 13482 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13483 temp = Math.doubleToLongBits(m22); 13484 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13485 temp = Math.doubleToLongBits(m23); 13486 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13487 temp = Math.doubleToLongBits(m30); 13488 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13489 temp = Math.doubleToLongBits(m31); 13490 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13491 temp = Math.doubleToLongBits(m32); 13492 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13493 temp = Math.doubleToLongBits(m33); 13494 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13495 return result; 13496 } 13497 13498 public bool equals(Matrix4d m, double delta) { 13499 if (this == m) 13500 return true; 13501 if (!Math.equals(m00, m.m00, delta)) 13502 return false; 13503 if (!Math.equals(m01, m.m01, delta)) 13504 return false; 13505 if (!Math.equals(m02, m.m02, delta)) 13506 return false; 13507 if (!Math.equals(m03, m.m03, delta)) 13508 return false; 13509 if (!Math.equals(m10, m.m10, delta)) 13510 return false; 13511 if (!Math.equals(m11, m.m11, delta)) 13512 return false; 13513 if (!Math.equals(m12, m.m12, delta)) 13514 return false; 13515 if (!Math.equals(m13, m.m13, delta)) 13516 return false; 13517 if (!Math.equals(m20, m.m20, delta)) 13518 return false; 13519 if (!Math.equals(m21, m.m21, delta)) 13520 return false; 13521 if (!Math.equals(m22, m.m22, delta)) 13522 return false; 13523 if (!Math.equals(m23, m.m23, delta)) 13524 return false; 13525 if (!Math.equals(m30, m.m30, delta)) 13526 return false; 13527 if (!Math.equals(m31, m.m31, delta)) 13528 return false; 13529 if (!Math.equals(m32, m.m32, delta)) 13530 return false; 13531 if (!Math.equals(m33, m.m33, delta)) 13532 return false; 13533 return true; 13534 } 13535 13536 public Matrix4d pick(double x, double y, double width, double height, int[] viewport, ref Matrix4d dest) { 13537 double sx = viewport[2] / width; 13538 double sy = viewport[3] / height; 13539 double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width; 13540 double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height; 13541 dest._m30(m00 * tx + m10 * ty + m30) 13542 ._m31(m01 * tx + m11 * ty + m31) 13543 ._m32(m02 * tx + m12 * ty + m32) 13544 ._m33(m03 * tx + m13 * ty + m33) 13545 ._m00(m00 * sx) 13546 ._m01(m01 * sx) 13547 ._m02(m02 * sx) 13548 ._m03(m03 * sx) 13549 ._m10(m10 * sy) 13550 ._m11(m11 * sy) 13551 ._m12(m12 * sy) 13552 ._m13(m13 * sy) 13553 ._properties(0); 13554 return dest; 13555 } 13556 13557 /** 13558 * Apply a picking transformation to this matrix using the given window coordinates <code>(x, y)</code> as the pick center 13559 * and the given <code>(width, height)</code> as the size of the picking region in window coordinates. 13560 * 13561 * @param x 13562 * the x coordinate of the picking region center in window coordinates 13563 * @param y 13564 * the y coordinate of the picking region center in window coordinates 13565 * @param width 13566 * the width of the picking region in window coordinates 13567 * @param height 13568 * the height of the picking region in window coordinates 13569 * @param viewport 13570 * the viewport described by <code>[x, y, width, height]</code> 13571 * @return this 13572 */ 13573 ref public Matrix4d pick(double x, double y, double width, double height, int[] viewport) return { 13574 pick(x, y, width, height, viewport, this); 13575 return this; 13576 } 13577 13578 public bool isAffine() { 13579 return m03 == 0.0 && m13 == 0.0 && m23 == 0.0 && m33 == 1.0; 13580 } 13581 13582 /** 13583 * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix. 13584 * 13585 * @param other 13586 * the other matrix to exchange the values with 13587 * @return this 13588 */ 13589 ref public Matrix4d swap(ref Matrix4d other) return { 13590 double tmp; 13591 tmp = m00; m00 = other.m00; other.m00 = tmp; 13592 tmp = m01; m01 = other.m01; other.m01 = tmp; 13593 tmp = m02; m02 = other.m02; other.m02 = tmp; 13594 tmp = m03; m03 = other.m03; other.m03 = tmp; 13595 tmp = m10; m10 = other.m10; other.m10 = tmp; 13596 tmp = m11; m11 = other.m11; other.m11 = tmp; 13597 tmp = m12; m12 = other.m12; other.m12 = tmp; 13598 tmp = m13; m13 = other.m13; other.m13 = tmp; 13599 tmp = m20; m20 = other.m20; other.m20 = tmp; 13600 tmp = m21; m21 = other.m21; other.m21 = tmp; 13601 tmp = m22; m22 = other.m22; other.m22 = tmp; 13602 tmp = m23; m23 = other.m23; other.m23 = tmp; 13603 tmp = m30; m30 = other.m30; other.m30 = tmp; 13604 tmp = m31; m31 = other.m31; other.m31 = tmp; 13605 tmp = m32; m32 = other.m32; other.m32 = tmp; 13606 tmp = m33; m33 = other.m33; other.m33 = tmp; 13607 int props = properties; 13608 this.properties = other.properties; 13609 other.properties = props; 13610 return this; 13611 } 13612 13613 public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, ref Matrix4d dest) { 13614 double m30 = m20 * -radius + this.m30; 13615 double m31 = m21 * -radius + this.m31; 13616 double m32 = m22 * -radius + this.m32; 13617 double m33 = m23 * -radius + this.m33; 13618 double sin = Math.sin(angleX); 13619 double cos = Math.cosFromSin(sin, angleX); 13620 double nm10 = m10 * cos + m20 * sin; 13621 double nm11 = m11 * cos + m21 * sin; 13622 double nm12 = m12 * cos + m22 * sin; 13623 double nm13 = m13 * cos + m23 * sin; 13624 double m20 = this.m20 * cos - m10 * sin; 13625 double m21 = this.m21 * cos - m11 * sin; 13626 double m22 = this.m22 * cos - m12 * sin; 13627 double m23 = this.m23 * cos - m13 * sin; 13628 sin = Math.sin(angleY); 13629 cos = Math.cosFromSin(sin, angleY); 13630 double nm00 = m00 * cos - m20 * sin; 13631 double nm01 = m01 * cos - m21 * sin; 13632 double nm02 = m02 * cos - m22 * sin; 13633 double nm03 = m03 * cos - m23 * sin; 13634 double nm20 = m00 * sin + m20 * cos; 13635 double nm21 = m01 * sin + m21 * cos; 13636 double nm22 = m02 * sin + m22 * cos; 13637 double nm23 = m03 * sin + m23 * cos; 13638 dest._m30(-nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30) 13639 ._m31(-nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31) 13640 ._m32(-nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32) 13641 ._m33(-nm03 * centerX - nm13 * centerY - nm23 * centerZ + m33) 13642 ._m20(nm20) 13643 ._m21(nm21) 13644 ._m22(nm22) 13645 ._m23(nm23) 13646 ._m10(nm10) 13647 ._m11(nm11) 13648 ._m12(nm12) 13649 ._m13(nm13) 13650 ._m00(nm00) 13651 ._m01(nm01) 13652 ._m02(nm02) 13653 ._m03(nm03) 13654 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 13655 return dest; 13656 } 13657 13658 public Matrix4d arcball(double radius, Vector3d center, double angleX, double angleY, ref Matrix4d dest) { 13659 return arcball(radius, center.x, center.y, center.z, angleX, angleY, dest); 13660 } 13661 13662 /** 13663 * Apply an arcball view transformation to this matrix with the given <code>radius</code> and center <code>(centerX, centerY, centerZ)</code> 13664 * position of the arcball and the specified X and Y rotation angles. 13665 * <p> 13666 * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)</code> 13667 * 13668 * @param radius 13669 * the arcball radius 13670 * @param centerX 13671 * the x coordinate of the center position of the arcball 13672 * @param centerY 13673 * the y coordinate of the center position of the arcball 13674 * @param centerZ 13675 * the z coordinate of the center position of the arcball 13676 * @param angleX 13677 * the rotation angle around the X axis in radians 13678 * @param angleY 13679 * the rotation angle around the Y axis in radians 13680 * @return this 13681 */ 13682 ref public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) return { 13683 arcball(radius, centerX, centerY, centerZ, angleX, angleY, this); 13684 return this; 13685 } 13686 13687 /** 13688 * Apply an arcball view transformation to this matrix with the given <code>radius</code> and <code>center</code> 13689 * position of the arcball and the specified X and Y rotation angles. 13690 * <p> 13691 * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)</code> 13692 * 13693 * @param radius 13694 * the arcball radius 13695 * @param center 13696 * the center position of the arcball 13697 * @param angleX 13698 * the rotation angle around the X axis in radians 13699 * @param angleY 13700 * the rotation angle around the Y axis in radians 13701 * @return this 13702 */ 13703 ref public Matrix4d arcball(double radius, Vector3d center, double angleX, double angleY) return { 13704 arcball(radius, center.x, center.y, center.z, angleX, angleY, this); 13705 return this; 13706 } 13707 13708 /** 13709 * Compute the axis-aligned bounding box of the frustum described by <code>this</code> matrix and store the minimum corner 13710 * coordinates in the given <code>min</code> and the maximum corner coordinates in the given <code>max</code> vector. 13711 * <p> 13712 * The matrix <code>this</code> is assumed to be the {@link #invert() inverse} of the origial view-projection matrix 13713 * for which to compute the axis-aligned bounding box in world-space. 13714 * <p> 13715 * The axis-aligned bounding box of the unit frustum is <code>(-1, -1, -1)</code>, <code>(1, 1, 1)</code>. 13716 * 13717 * @param min 13718 * will hold the minimum corner coordinates of the axis-aligned bounding box 13719 * @param max 13720 * will hold the maximum corner coordinates of the axis-aligned bounding box 13721 * @return this 13722 */ 13723 ref public Matrix4d frustumAabb(ref Vector3d min, Vector3d max) return { 13724 double minX = double.infinity; 13725 double minY = double.infinity; 13726 double minZ = double.infinity; 13727 double maxX = -double.infinity; 13728 double maxY = -double.infinity; 13729 double maxZ = -double.infinity; 13730 for (int t = 0; t < 8; t++) { 13731 double x = ((t & 1) << 1) - 1.0; 13732 double y = (((t >>> 1) & 1) << 1) - 1.0; 13733 double z = (((t >>> 2) & 1) << 1) - 1.0; 13734 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 13735 double nx = (m00 * x + m10 * y + m20 * z + m30) * invW; 13736 double ny = (m01 * x + m11 * y + m21 * z + m31) * invW; 13737 double nz = (m02 * x + m12 * y + m22 * z + m32) * invW; 13738 minX = minX < nx ? minX : nx; 13739 minY = minY < ny ? minY : ny; 13740 minZ = minZ < nz ? minZ : nz; 13741 maxX = maxX > nx ? maxX : nx; 13742 maxY = maxY > ny ? maxY : ny; 13743 maxZ = maxZ > nz ? maxZ : nz; 13744 } 13745 min.x = minX; 13746 min.y = minY; 13747 min.z = minZ; 13748 max.x = maxX; 13749 max.y = maxY; 13750 max.z = maxZ; 13751 return this; 13752 } 13753 13754 public Matrix4d projectedGridRange(Matrix4d projector, double sLower, double sUpper, ref Matrix4d dest) { 13755 // Compute intersection with frustum edges and plane 13756 double minX = double.infinity, minY = double.infinity; 13757 double maxX = -double.infinity, maxY = -double.infinity; 13758 bool intersection = false; 13759 for (int t = 0; t < 3 * 4; t++) { 13760 double c0X, c0Y, c0Z; 13761 double c1X, c1Y, c1Z; 13762 if (t < 4) { 13763 // all x edges 13764 c0X = -1; c1X = +1; 13765 c0Y = c1Y = ((t & 1) << 1) - 1.0; 13766 c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0; 13767 } else if (t < 8) { 13768 // all y edges 13769 c0Y = -1; c1Y = +1; 13770 c0X = c1X = ((t & 1) << 1) - 1.0; 13771 c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0; 13772 } else { 13773 // all z edges 13774 c0Z = -1; c1Z = +1; 13775 c0X = c1X = ((t & 1) << 1) - 1.0; 13776 c0Y = c1Y = (((t >>> 1) & 1) << 1) - 1.0; 13777 } 13778 // unproject corners 13779 double invW = 1.0 / (m03 * c0X + m13 * c0Y + m23 * c0Z + m33); 13780 double p0x = (m00 * c0X + m10 * c0Y + m20 * c0Z + m30) * invW; 13781 double p0y = (m01 * c0X + m11 * c0Y + m21 * c0Z + m31) * invW; 13782 double p0z = (m02 * c0X + m12 * c0Y + m22 * c0Z + m32) * invW; 13783 invW = 1.0 / (m03 * c1X + m13 * c1Y + m23 * c1Z + m33); 13784 double p1x = (m00 * c1X + m10 * c1Y + m20 * c1Z + m30) * invW; 13785 double p1y = (m01 * c1X + m11 * c1Y + m21 * c1Z + m31) * invW; 13786 double p1z = (m02 * c1X + m12 * c1Y + m22 * c1Z + m32) * invW; 13787 double dirX = p1x - p0x; 13788 double dirY = p1y - p0y; 13789 double dirZ = p1z - p0z; 13790 double invDenom = 1.0 / dirY; 13791 // test for intersection 13792 for (int s = 0; s < 2; s++) { 13793 double isectT = -(p0y + (s == 0 ? sLower : sUpper)) * invDenom; 13794 if (isectT >= 0.0 && isectT <= 1.0) { 13795 intersection = true; 13796 // project with projector matrix 13797 double ix = p0x + isectT * dirX; 13798 double iz = p0z + isectT * dirZ; 13799 invW = 1.0 / (projector.m03 * ix + projector.m23 * iz + projector.m33); 13800 double px = (projector.m00 * ix + projector.m20 * iz + projector.m30) * invW; 13801 double py = (projector.m01 * ix + projector.m21 * iz + projector.m31) * invW; 13802 minX = minX < px ? minX : px; 13803 minY = minY < py ? minY : py; 13804 maxX = maxX > px ? maxX : px; 13805 maxY = maxY > py ? maxY : py; 13806 } 13807 } 13808 } 13809 if (!intersection) 13810 return dest; // <- projected grid is not visible 13811 dest.set(maxX - minX, 0, 0, 0, 0, maxY - minY, 0, 0, 0, 0, 1, 0, minX, minY, 0, 1) 13812 ._properties(PROPERTY_AFFINE); 13813 return dest; 13814 } 13815 13816 public Matrix4d perspectiveFrustumSlice(double near, double far, ref Matrix4d dest) { 13817 double invOldNear = (m23 + m22) / m32; 13818 double invNearFar = 1.0 / (near - far); 13819 dest._m00(m00 * invOldNear * near) 13820 ._m01(m01) 13821 ._m02(m02) 13822 ._m03(m03) 13823 ._m10(m10) 13824 ._m11(m11 * invOldNear * near) 13825 ._m12(m12) 13826 ._m13(m13) 13827 ._m20(m20) 13828 ._m21(m21) 13829 ._m22((far + near) * invNearFar) 13830 ._m23(m23) 13831 ._m30(m30) 13832 ._m31(m31) 13833 ._m32((far + far) * near * invNearFar) 13834 ._m33(m33) 13835 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 13836 return dest; 13837 } 13838 13839 public Matrix4d orthoCrop(Matrix4d view, ref Matrix4d dest) { 13840 // determine min/max world z and min/max orthographically view-projected x/y 13841 double minX = double.infinity, maxX = -double.infinity; 13842 double minY = double.infinity, maxY = -double.infinity; 13843 double minZ = double.infinity, maxZ = -double.infinity; 13844 for (int t = 0; t < 8; t++) { 13845 double x = ((t & 1) << 1) - 1.0; 13846 double y = (((t >>> 1) & 1) << 1) - 1.0; 13847 double z = (((t >>> 2) & 1) << 1) - 1.0; 13848 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 13849 double wx = (m00 * x + m10 * y + m20 * z + m30) * invW; 13850 double wy = (m01 * x + m11 * y + m21 * z + m31) * invW; 13851 double wz = (m02 * x + m12 * y + m22 * z + m32) * invW; 13852 invW = 1.0 / (view.m03 * wx + view.m13 * wy + view.m23 * wz + view.m33); 13853 double vx = view.m00 * wx + view.m10 * wy + view.m20 * wz + view.m30; 13854 double vy = view.m01 * wx + view.m11 * wy + view.m21 * wz + view.m31; 13855 double vz = (view.m02 * wx + view.m12 * wy + view.m22 * wz + view.m32) * invW; 13856 minX = minX < vx ? minX : vx; 13857 maxX = maxX > vx ? maxX : vx; 13858 minY = minY < vy ? minY : vy; 13859 maxY = maxY > vy ? maxY : vy; 13860 minZ = minZ < vz ? minZ : vz; 13861 maxZ = maxZ > vz ? maxZ : vz; 13862 } 13863 // build crop projection matrix to fit 'this' frustum into view 13864 return dest.setOrtho(minX, maxX, minY, maxY, -maxZ, -minZ); 13865 } 13866 13867 /** 13868 * Set <code>this</code> matrix to a perspective transformation that maps the trapezoid spanned by the four corner coordinates 13869 * <code>(p0x, p0y)</code>, <code>(p1x, p1y)</code>, <code>(p2x, p2y)</code> and <code>(p3x, p3y)</code> to the unit square <code>[(-1, -1)..(+1, +1)]</code>. 13870 * <p> 13871 * The corner coordinates are given in counter-clockwise order starting from the <i>left</i> corner on the smaller parallel side of the trapezoid 13872 * seen when looking at the trapezoid oriented with its shorter parallel edge at the bottom and its longer parallel edge at the top. 13873 * <p> 13874 * Reference: <a href="http://www.comp.nus.edu.sg/~tants/tsm/TSM_recipe.html">Trapezoidal Shadow Maps (TSM) - Recipe</a> 13875 * 13876 * @param p0x 13877 * the x coordinate of the left corner at the shorter edge of the trapezoid 13878 * @param p0y 13879 * the y coordinate of the left corner at the shorter edge of the trapezoid 13880 * @param p1x 13881 * the x coordinate of the right corner at the shorter edge of the trapezoid 13882 * @param p1y 13883 * the y coordinate of the right corner at the shorter edge of the trapezoid 13884 * @param p2x 13885 * the x coordinate of the right corner at the longer edge of the trapezoid 13886 * @param p2y 13887 * the y coordinate of the right corner at the longer edge of the trapezoid 13888 * @param p3x 13889 * the x coordinate of the left corner at the longer edge of the trapezoid 13890 * @param p3y 13891 * the y coordinate of the left corner at the longer edge of the trapezoid 13892 * @return this 13893 */ 13894 ref public Matrix4d trapezoidCrop(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y, double p3x, double p3y) return { 13895 double aX = p1y - p0y, aY = p0x - p1x; 13896 double nm00 = aY; 13897 double nm10 = -aX; 13898 double nm30 = aX * p0y - aY * p0x; 13899 double nm01 = aX; 13900 double nm11 = aY; 13901 double nm31 = -(aX * p0x + aY * p0y); 13902 double c3x = nm00 * p3x + nm10 * p3y + nm30; 13903 double c3y = nm01 * p3x + nm11 * p3y + nm31; 13904 double s = -c3x / c3y; 13905 nm00 += s * nm01; 13906 nm10 += s * nm11; 13907 nm30 += s * nm31; 13908 double d1x = nm00 * p1x + nm10 * p1y + nm30; 13909 double d2x = nm00 * p2x + nm10 * p2y + nm30; 13910 double d = d1x * c3y / (d2x - d1x); 13911 nm31 += d; 13912 double sx = 2.0 / d2x; 13913 double sy = 1.0 / (c3y + d); 13914 double u = (sy + sy) * d / (1.0 - sy * d); 13915 double m03 = nm01 * sy; 13916 double m13 = nm11 * sy; 13917 double m33 = nm31 * sy; 13918 nm01 = (u + 1.0) * m03; 13919 nm11 = (u + 1.0) * m13; 13920 nm31 = (u + 1.0) * m33 - u; 13921 nm00 = sx * nm00 - m03; 13922 nm10 = sx * nm10 - m13; 13923 nm30 = sx * nm30 - m33; 13924 set(nm00, nm01, 0, m03, 13925 nm10, nm11, 0, m13, 13926 0, 0, 1, 0, 13927 nm30, nm31, 0, m33); 13928 properties = 0; 13929 return this; 13930 } 13931 13932 ref public Matrix4d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, ref Vector3d outMin, ref Vector3d outMax) return { 13933 double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX; 13934 double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX; 13935 double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY; 13936 double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY; 13937 double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ; 13938 double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ; 13939 double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz; 13940 double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz; 13941 if (xax < xbx) { 13942 xminx = xax; 13943 xmaxx = xbx; 13944 } else { 13945 xminx = xbx; 13946 xmaxx = xax; 13947 } 13948 if (xay < xby) { 13949 xminy = xay; 13950 xmaxy = xby; 13951 } else { 13952 xminy = xby; 13953 xmaxy = xay; 13954 } 13955 if (xaz < xbz) { 13956 xminz = xaz; 13957 xmaxz = xbz; 13958 } else { 13959 xminz = xbz; 13960 xmaxz = xaz; 13961 } 13962 if (yax < ybx) { 13963 yminx = yax; 13964 ymaxx = ybx; 13965 } else { 13966 yminx = ybx; 13967 ymaxx = yax; 13968 } 13969 if (yay < yby) { 13970 yminy = yay; 13971 ymaxy = yby; 13972 } else { 13973 yminy = yby; 13974 ymaxy = yay; 13975 } 13976 if (yaz < ybz) { 13977 yminz = yaz; 13978 ymaxz = ybz; 13979 } else { 13980 yminz = ybz; 13981 ymaxz = yaz; 13982 } 13983 if (zax < zbx) { 13984 zminx = zax; 13985 zmaxx = zbx; 13986 } else { 13987 zminx = zbx; 13988 zmaxx = zax; 13989 } 13990 if (zay < zby) { 13991 zminy = zay; 13992 zmaxy = zby; 13993 } else { 13994 zminy = zby; 13995 zmaxy = zay; 13996 } 13997 if (zaz < zbz) { 13998 zminz = zaz; 13999 zmaxz = zbz; 14000 } else { 14001 zminz = zbz; 14002 zmaxz = zaz; 14003 } 14004 outMin.x = xminx + yminx + zminx + m30; 14005 outMin.y = xminy + yminy + zminy + m31; 14006 outMin.z = xminz + yminz + zminz + m32; 14007 outMax.x = xmaxx + ymaxx + zmaxx + m30; 14008 outMax.y = xmaxy + ymaxy + zmaxy + m31; 14009 outMax.z = xmaxz + ymaxz + zmaxz + m32; 14010 return this; 14011 } 14012 14013 ref public Matrix4d transformAab(ref Vector3d min, ref Vector3d max, ref Vector3d outMin, ref Vector3d outMax) return { 14014 return transformAab(min.x, min.y, min.z, max.x, max.y, max.z, outMin, outMax); 14015 } 14016 14017 /** 14018 * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code> 14019 * and store the result in <code>this</code>. 14020 * <p> 14021 * If <code>t</code> is <code>0.0</code> then the result is <code>this</code>. If the interpolation factor is <code>1.0</code> 14022 * then the result is <code>other</code>. 14023 * 14024 * @param other 14025 * the other matrix 14026 * @param t 14027 * the interpolation factor between 0.0 and 1.0 14028 * @return this 14029 */ 14030 ref public Matrix4d lerp(Matrix4d other, double t) return { 14031 lerp(other, t, this); 14032 return this; 14033 } 14034 14035 public Matrix4d lerp(Matrix4d other, double t, ref Matrix4d dest) { 14036 dest._m00(Math.fma(other.m00 - m00, t, m00)) 14037 ._m01(Math.fma(other.m01 - m01, t, m01)) 14038 ._m02(Math.fma(other.m02 - m02, t, m02)) 14039 ._m03(Math.fma(other.m03 - m03, t, m03)) 14040 ._m10(Math.fma(other.m10 - m10, t, m10)) 14041 ._m11(Math.fma(other.m11 - m11, t, m11)) 14042 ._m12(Math.fma(other.m12 - m12, t, m12)) 14043 ._m13(Math.fma(other.m13 - m13, t, m13)) 14044 ._m20(Math.fma(other.m20 - m20, t, m20)) 14045 ._m21(Math.fma(other.m21 - m21, t, m21)) 14046 ._m22(Math.fma(other.m22 - m22, t, m22)) 14047 ._m23(Math.fma(other.m23 - m23, t, m23)) 14048 ._m30(Math.fma(other.m30 - m30, t, m30)) 14049 ._m31(Math.fma(other.m31 - m31, t, m31)) 14050 ._m32(Math.fma(other.m32 - m32, t, m32)) 14051 ._m33(Math.fma(other.m33 - m33, t, m33)) 14052 ._properties(properties & other.properties); 14053 return dest; 14054 } 14055 14056 /** 14057 * Apply a model transformation to this matrix for a right-handed coordinate system, 14058 * that aligns the local <code>+Z</code> axis with <code>direction</code> 14059 * and store the result in <code>dest</code>. 14060 * <p> 14061 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14062 * then the new matrix will be <code>M * L</code>. So when transforming a 14063 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14064 * the lookat transformation will be applied first! 14065 * <p> 14066 * In order to set the matrix to a rotation transformation without post-multiplying it, 14067 * use {@link #rotationTowards(ref Vector3d, Vector3d) rotationTowards()}. 14068 * <p> 14069 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine(), dest)</code> 14070 * 14071 * @see #rotateTowards(double, double, double, double, double, double, Matrix4d) 14072 * @see #rotationTowards(ref Vector3d, Vector3d) 14073 * 14074 * @param direction 14075 * the direction to rotate towards 14076 * @param up 14077 * the up vector 14078 * @param dest 14079 * will hold the result 14080 * @return dest 14081 */ 14082 public Matrix4d rotateTowards(ref Vector3d direction, Vector3d up, ref Matrix4d dest) { 14083 return rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, dest); 14084 } 14085 14086 /** 14087 * Apply a model transformation to this matrix for a right-handed coordinate system, 14088 * that aligns the local <code>+Z</code> axis with <code>direction</code>. 14089 * <p> 14090 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14091 * then the new matrix will be <code>M * L</code>. So when transforming a 14092 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14093 * the lookat transformation will be applied first! 14094 * <p> 14095 * In order to set the matrix to a rotation transformation without post-multiplying it, 14096 * use {@link #rotationTowards(ref Vector3d, Vector3d) rotationTowards()}. 14097 * <p> 14098 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine())</code> 14099 * 14100 * @see #rotateTowards(double, double, double, double, double, double) 14101 * @see #rotationTowards(ref Vector3d, Vector3d) 14102 * 14103 * @param direction 14104 * the direction to orient towards 14105 * @param up 14106 * the up vector 14107 * @return this 14108 */ 14109 ref public Matrix4d rotateTowards(ref Vector3d direction, Vector3d up) return { 14110 rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, this); 14111 return this; 14112 } 14113 14114 /** 14115 * Apply a model transformation to this matrix for a right-handed coordinate system, 14116 * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>. 14117 * <p> 14118 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14119 * then the new matrix will be <code>M * L</code>. So when transforming a 14120 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14121 * the lookat transformation will be applied first! 14122 * <p> 14123 * In order to set the matrix to a rotation transformation without post-multiplying it, 14124 * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}. 14125 * <p> 14126 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine())</code> 14127 * 14128 * @see #rotateTowards(ref Vector3d, Vector3d) 14129 * @see #rotationTowards(double, double, double, double, double, double) 14130 * 14131 * @param dirX 14132 * the x-coordinate of the direction to rotate towards 14133 * @param dirY 14134 * the y-coordinate of the direction to rotate towards 14135 * @param dirZ 14136 * the z-coordinate of the direction to rotate towards 14137 * @param upX 14138 * the x-coordinate of the up vector 14139 * @param upY 14140 * the y-coordinate of the up vector 14141 * @param upZ 14142 * the z-coordinate of the up vector 14143 * @return this 14144 */ 14145 ref public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14146 rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this); 14147 return this; 14148 } 14149 14150 /** 14151 * Apply a model transformation to this matrix for a right-handed coordinate system, 14152 * that aligns the local <code>+Z</code> axis with <code>dir</code> 14153 * and store the result in <code>dest</code>. 14154 * <p> 14155 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14156 * then the new matrix will be <code>M * L</code>. So when transforming a 14157 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14158 * the lookat transformation will be applied first! 14159 * <p> 14160 * In order to set the matrix to a rotation transformation without post-multiplying it, 14161 * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}. 14162 * <p> 14163 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)</code> 14164 * 14165 * @see #rotateTowards(ref Vector3d, Vector3d) 14166 * @see #rotationTowards(double, double, double, double, double, double) 14167 * 14168 * @param dirX 14169 * the x-coordinate of the direction to rotate towards 14170 * @param dirY 14171 * the y-coordinate of the direction to rotate towards 14172 * @param dirZ 14173 * the z-coordinate of the direction to rotate towards 14174 * @param upX 14175 * the x-coordinate of the up vector 14176 * @param upY 14177 * the y-coordinate of the up vector 14178 * @param upZ 14179 * the z-coordinate of the up vector 14180 * @param dest 14181 * will hold the result 14182 * @return dest 14183 */ 14184 public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 14185 // Normalize direction 14186 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14187 double ndirX = dirX * invDirLength; 14188 double ndirY = dirY * invDirLength; 14189 double ndirZ = dirZ * invDirLength; 14190 // left = up x direction 14191 double leftX, leftY, leftZ; 14192 leftX = upY * ndirZ - upZ * ndirY; 14193 leftY = upZ * ndirX - upX * ndirZ; 14194 leftZ = upX * ndirY - upY * ndirX; 14195 // normalize left 14196 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14197 leftX *= invLeftLength; 14198 leftY *= invLeftLength; 14199 leftZ *= invLeftLength; 14200 // up = direction x left 14201 double upnX = ndirY * leftZ - ndirZ * leftY; 14202 double upnY = ndirZ * leftX - ndirX * leftZ; 14203 double upnZ = ndirX * leftY - ndirY * leftX; 14204 double rm00 = leftX; 14205 double rm01 = leftY; 14206 double rm02 = leftZ; 14207 double rm10 = upnX; 14208 double rm11 = upnY; 14209 double rm12 = upnZ; 14210 double rm20 = ndirX; 14211 double rm21 = ndirY; 14212 double rm22 = ndirZ; 14213 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 14214 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 14215 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 14216 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 14217 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 14218 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 14219 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 14220 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 14221 dest._m30(m30) 14222 ._m31(m31) 14223 ._m32(m32) 14224 ._m33(m33) 14225 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 14226 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 14227 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 14228 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 14229 ._m00(nm00) 14230 ._m01(nm01) 14231 ._m02(nm02) 14232 ._m03(nm03) 14233 ._m10(nm10) 14234 ._m11(nm11) 14235 ._m12(nm12) 14236 ._m13(nm13) 14237 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 14238 return dest; 14239 } 14240 14241 /** 14242 * Set this matrix to a model transformation for a right-handed coordinate system, 14243 * that aligns the local <code>-z</code> axis with <code>dir</code>. 14244 * <p> 14245 * In order to apply the rotation transformation to a previous existing transformation, 14246 * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}. 14247 * <p> 14248 * This method is equivalent to calling: <code>setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine()</code> 14249 * 14250 * @see #rotationTowards(ref Vector3d, Vector3d) 14251 * @see #rotateTowards(double, double, double, double, double, double) 14252 * 14253 * @param dir 14254 * the direction to orient the local -z axis towards 14255 * @param up 14256 * the up vector 14257 * @return this 14258 */ 14259 ref public Matrix4d rotationTowards(ref Vector3d dir, Vector3d up) return { 14260 return rotationTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z); 14261 } 14262 14263 /** 14264 * Set this matrix to a model transformation for a right-handed coordinate system, 14265 * that aligns the local <code>-z</code> axis with <code>dir</code>. 14266 * <p> 14267 * In order to apply the rotation transformation to a previous existing transformation, 14268 * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}. 14269 * <p> 14270 * This method is equivalent to calling: <code>setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine()</code> 14271 * 14272 * @see #rotateTowards(ref Vector3d, Vector3d) 14273 * @see #rotationTowards(double, double, double, double, double, double) 14274 * 14275 * @param dirX 14276 * the x-coordinate of the direction to rotate towards 14277 * @param dirY 14278 * the y-coordinate of the direction to rotate towards 14279 * @param dirZ 14280 * the z-coordinate of the direction to rotate towards 14281 * @param upX 14282 * the x-coordinate of the up vector 14283 * @param upY 14284 * the y-coordinate of the up vector 14285 * @param upZ 14286 * the z-coordinate of the up vector 14287 * @return this 14288 */ 14289 ref public Matrix4d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14290 // Normalize direction 14291 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14292 double ndirX = dirX * invDirLength; 14293 double ndirY = dirY * invDirLength; 14294 double ndirZ = dirZ * invDirLength; 14295 // left = up x direction 14296 double leftX, leftY, leftZ; 14297 leftX = upY * ndirZ - upZ * ndirY; 14298 leftY = upZ * ndirX - upX * ndirZ; 14299 leftZ = upX * ndirY - upY * ndirX; 14300 // normalize left 14301 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14302 leftX *= invLeftLength; 14303 leftY *= invLeftLength; 14304 leftZ *= invLeftLength; 14305 // up = direction x left 14306 double upnX = ndirY * leftZ - ndirZ * leftY; 14307 double upnY = ndirZ * leftX - ndirX * leftZ; 14308 double upnZ = ndirX * leftY - ndirY * leftX; 14309 if ((properties & PROPERTY_IDENTITY) == 0) 14310 this._identity(); 14311 setm00(leftX); 14312 setm01(leftY); 14313 setm02(leftZ); 14314 setm10(upnX); 14315 setm11(upnY); 14316 setm12(upnZ); 14317 setm20(ndirX); 14318 setm21(ndirY); 14319 setm22(ndirZ); 14320 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 14321 return this; 14322 } 14323 14324 /** 14325 * Set this matrix to a model transformation for a right-handed coordinate system, 14326 * that translates to the given <code>pos</code> and aligns the local <code>-z</code> 14327 * axis with <code>dir</code>. 14328 * <p> 14329 * This method is equivalent to calling: <code>translation(pos).rotateTowards(dir, up)</code> 14330 * 14331 * @see #translation(ref Vector3d) 14332 * @see #rotateTowards(ref Vector3d, Vector3d) 14333 * 14334 * @param pos 14335 * the position to translate to 14336 * @param dir 14337 * the direction to rotate towards 14338 * @param up 14339 * the up vector 14340 * @return this 14341 */ 14342 ref public Matrix4d translationRotateTowards(ref Vector3d pos, Vector3d dir, Vector3d up) return { 14343 return translationRotateTowards(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); 14344 } 14345 14346 /** 14347 * Set this matrix to a model transformation for a right-handed coordinate system, 14348 * that translates to the given <code>(posX, posY, posZ)</code> and aligns the local <code>-z</code> 14349 * axis with <code>(dirX, dirY, dirZ)</code>. 14350 * <p> 14351 * This method is equivalent to calling: <code>translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)</code> 14352 * 14353 * @see #translation(double, double, double) 14354 * @see #rotateTowards(double, double, double, double, double, double) 14355 * 14356 * @param posX 14357 * the x-coordinate of the position to translate to 14358 * @param posY 14359 * the y-coordinate of the position to translate to 14360 * @param posZ 14361 * the z-coordinate of the position to translate to 14362 * @param dirX 14363 * the x-coordinate of the direction to rotate towards 14364 * @param dirY 14365 * the y-coordinate of the direction to rotate towards 14366 * @param dirZ 14367 * the z-coordinate of the direction to rotate towards 14368 * @param upX 14369 * the x-coordinate of the up vector 14370 * @param upY 14371 * the y-coordinate of the up vector 14372 * @param upZ 14373 * the z-coordinate of the up vector 14374 * @return this 14375 */ 14376 ref public Matrix4d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14377 // Normalize direction 14378 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14379 double ndirX = dirX * invDirLength; 14380 double ndirY = dirY * invDirLength; 14381 double ndirZ = dirZ * invDirLength; 14382 // left = up x direction 14383 double leftX, leftY, leftZ; 14384 leftX = upY * ndirZ - upZ * ndirY; 14385 leftY = upZ * ndirX - upX * ndirZ; 14386 leftZ = upX * ndirY - upY * ndirX; 14387 // normalize left 14388 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14389 leftX *= invLeftLength; 14390 leftY *= invLeftLength; 14391 leftZ *= invLeftLength; 14392 // up = direction x left 14393 double upnX = ndirY * leftZ - ndirZ * leftY; 14394 double upnY = ndirZ * leftX - ndirX * leftZ; 14395 double upnZ = ndirX * leftY - ndirY * leftX; 14396 setm00(leftX); 14397 setm01(leftY); 14398 setm02(leftZ); 14399 setm03(0.0); 14400 setm10(upnX); 14401 setm11(upnY); 14402 setm12(upnZ); 14403 setm13(0.0); 14404 setm20(ndirX); 14405 setm21(ndirY); 14406 setm22(ndirZ); 14407 setm23(0.0); 14408 setm30(posX); 14409 setm31(posY); 14410 setm32(posZ); 14411 setm33(1.0); 14412 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 14413 return this; 14414 } 14415 14416 public Vector3d getEulerAnglesZYX(ref Vector3d dest) { 14417 dest.x = Math.atan2(m12, m22); 14418 dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02)); 14419 dest.z = Math.atan2(m01, m00); 14420 return dest; 14421 } 14422 14423 public Vector3d getEulerAnglesXYZ(ref Vector3d dest) { 14424 dest.x = Math.atan2(-m21, m22); 14425 dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20)); 14426 dest.z = Math.atan2(-m10, m00); 14427 return dest; 14428 } 14429 14430 /** 14431 * Compute the extents of the coordinate system before this {@link #isAffine() affine} transformation was applied 14432 * and store the resulting corner coordinates in <code>corner</code> and the span vectors in 14433 * <code>xDir</code>, <code>yDir</code> and <code>zDir</code>. 14434 * <p> 14435 * That means, given the maximum extents of the coordinate system between <code>[-1..+1]</code> in all dimensions, 14436 * this method returns one corner and the length and direction of the three base axis vectors in the coordinate 14437 * system before this transformation is applied, which transforms into the corner coordinates <code>[-1, +1]</code>. 14438 * <p> 14439 * This method is equivalent to computing at least three adjacent corners using {@link #frustumCorner(int, Vector3d)} 14440 * and subtracting them to obtain the length and direction of the span vectors. 14441 * 14442 * @param corner 14443 * will hold one corner of the span (usually the corner {@link Matrix4d#CORNER_NXNYNZ}) 14444 * @param xDir 14445 * will hold the direction and length of the span along the positive X axis 14446 * @param yDir 14447 * will hold the direction and length of the span along the positive Y axis 14448 * @param zDir 14449 * will hold the direction and length of the span along the positive z axis 14450 * @return this 14451 */ 14452 ref public Matrix4d affineSpan(ref Vector3d corner, ref Vector3d xDir, ref Vector3d yDir, ref Vector3d zDir) return { 14453 double a = m10 * m22, b = m10 * m21, c = m10 * m02, d = m10 * m01; 14454 double e = m11 * m22, f = m11 * m20, g = m11 * m02, h = m11 * m00; 14455 double i = m12 * m21, j = m12 * m20, k = m12 * m01, l = m12 * m00; 14456 double m = m20 * m02, n = m20 * m01, o = m21 * m02, p = m21 * m00; 14457 double q = m22 * m01, r = m22 * m00; 14458 double s = 1.0 / (m00 * m11 - m01 * m10) * m22 + (m02 * m10 - m00 * m12) * m21 + (m01 * m12 - m02 * m11) * m20; 14459 double nm00 = (e - i) * s, nm01 = (o - q) * s, nm02 = (k - g) * s; 14460 double nm10 = (j - a) * s, nm11 = (r - m) * s, nm12 = (c - l) * s; 14461 double nm20 = (b - f) * s, nm21 = (n - p) * s, nm22 = (h - d) * s; 14462 corner.x = -nm00 - nm10 - nm20 + (a * m31 - b * m32 + f * m32 - e * m30 + i * m30 - j * m31) * s; 14463 corner.y = -nm01 - nm11 - nm21 + (m * m31 - n * m32 + p * m32 - o * m30 + q * m30 - r * m31) * s; 14464 corner.z = -nm02 - nm12 - nm22 + (g * m30 - k * m30 + l * m31 - c * m31 + d * m32 - h * m32) * s; 14465 xDir.x = 2.0 * nm00; xDir.y = 2.0 * nm01; xDir.z = 2.0 * nm02; 14466 yDir.x = 2.0 * nm10; yDir.y = 2.0 * nm11; yDir.z = 2.0 * nm12; 14467 zDir.x = 2.0 * nm20; zDir.y = 2.0 * nm21; zDir.z = 2.0 * nm22; 14468 return this; 14469 } 14470 14471 public bool testPoint(double x, double y, double z) { 14472 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14473 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14474 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14475 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14476 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14477 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14478 return nxX * x + nxY * y + nxZ * z + nxW >= 0 && pxX * x + pxY * y + pxZ * z + pxW >= 0 && 14479 nyX * x + nyY * y + nyZ * z + nyW >= 0 && pyX * x + pyY * y + pyZ * z + pyW >= 0 && 14480 nzX * x + nzY * y + nzZ * z + nzW >= 0 && pzX * x + pzY * y + pzZ * z + pzW >= 0; 14481 } 14482 14483 public bool testSphere(double x, double y, double z, double r) { 14484 double invl; 14485 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14486 invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ); 14487 nxX *= invl; nxY *= invl; nxZ *= invl; nxW *= invl; 14488 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14489 invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ); 14490 pxX *= invl; pxY *= invl; pxZ *= invl; pxW *= invl; 14491 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14492 invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ); 14493 nyX *= invl; nyY *= invl; nyZ *= invl; nyW *= invl; 14494 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14495 invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ); 14496 pyX *= invl; pyY *= invl; pyZ *= invl; pyW *= invl; 14497 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14498 invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ); 14499 nzX *= invl; nzY *= invl; nzZ *= invl; nzW *= invl; 14500 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14501 invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ); 14502 pzX *= invl; pzY *= invl; pzZ *= invl; pzW *= invl; 14503 return nxX * x + nxY * y + nxZ * z + nxW >= -r && pxX * x + pxY * y + pxZ * z + pxW >= -r && 14504 nyX * x + nyY * y + nyZ * z + nyW >= -r && pyX * x + pyY * y + pyZ * z + pyW >= -r && 14505 nzX * x + nzY * y + nzZ * z + nzW >= -r && pzX * x + pzY * y + pzZ * z + pzW >= -r; 14506 } 14507 14508 public bool testAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { 14509 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14510 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14511 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14512 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14513 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14514 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14515 /* 14516 * This is an implementation of the "2.4 Basic intersection test" of the mentioned site. 14517 * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted. 14518 */ 14519 return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW && 14520 pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW && 14521 nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW && 14522 pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW && 14523 nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW && 14524 pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW; 14525 } 14526 14527 /** 14528 * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and 14529 * <code>b</code>. 14530 * <p> 14531 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix, 14532 * then the new matrix will be <code>M * O</code>. So when transforming a 14533 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 14534 * oblique transformation will be applied first! 14535 * <p> 14536 * The oblique transformation is defined as: 14537 * <pre> 14538 * x' = x + a*z 14539 * y' = y + a*z 14540 * z' = z 14541 * </pre> 14542 * or in matrix form: 14543 * <pre> 14544 * 1 0 a 0 14545 * 0 1 b 0 14546 * 0 0 1 0 14547 * 0 0 0 1 14548 * </pre> 14549 * 14550 * @param a 14551 * the value for the z factor that applies to x 14552 * @param b 14553 * the value for the z factor that applies to y 14554 * @return this 14555 */ 14556 ref public Matrix4d obliqueZ(double a, double b) return { 14557 setm20(m00 * a + m10 * b + m20); 14558 setm21(m01 * a + m11 * b + m21); 14559 setm22(m02 * a + m12 * b + m22); 14560 this.properties &= PROPERTY_AFFINE; 14561 return this; 14562 } 14563 14564 /** 14565 * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and 14566 * <code>b</code> and store the result in <code>dest</code>. 14567 * <p> 14568 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix, 14569 * then the new matrix will be <code>M * O</code>. So when transforming a 14570 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 14571 * oblique transformation will be applied first! 14572 * <p> 14573 * The oblique transformation is defined as: 14574 * <pre> 14575 * x' = x + a*z 14576 * y' = y + a*z 14577 * z' = z 14578 * </pre> 14579 * or in matrix form: 14580 * <pre> 14581 * 1 0 a 0 14582 * 0 1 b 0 14583 * 0 0 1 0 14584 * 0 0 0 1 14585 * </pre> 14586 * 14587 * @param a 14588 * the value for the z factor that applies to x 14589 * @param b 14590 * the value for the z factor that applies to y 14591 * @param dest 14592 * will hold the result 14593 * @return dest 14594 */ 14595 public Matrix4d obliqueZ(double a, double b, ref Matrix4d dest) { 14596 dest._m00(m00) 14597 ._m01(m01) 14598 ._m02(m02) 14599 ._m03(m03) 14600 ._m10(m10) 14601 ._m11(m11) 14602 ._m12(m12) 14603 ._m13(m13) 14604 ._m20(m00 * a + m10 * b + m20) 14605 ._m21(m01 * a + m11 * b + m21) 14606 ._m22(m02 * a + m12 * b + m22) 14607 ._m23(m23) 14608 ._m30(m30) 14609 ._m31(m31) 14610 ._m32(m32) 14611 ._m33(m33) 14612 ._properties(properties & PROPERTY_AFFINE); 14613 return dest; 14614 } 14615 14616 /** 14617 * Create a view and projection matrix from a given <code>eye</code> position, a given bottom left corner position <code>p</code> of the near plane rectangle 14618 * and the extents of the near plane rectangle along its local <code>x</code> and <code>y</code> axes, and store the resulting matrices 14619 * in <code>projDest</code> and <code>viewDest</code>. 14620 * <p> 14621 * This method creates a view and perspective projection matrix assuming that there is a pinhole camera at position <code>eye</code> 14622 * projecting the scene onto the near plane defined by the rectangle. 14623 * <p> 14624 * All positions and lengths are in the same (world) unit. 14625 * 14626 * @param eye 14627 * the position of the camera 14628 * @param p 14629 * the bottom left corner of the near plane rectangle (will map to the bottom left corner in window coordinates) 14630 * @param x 14631 * the direction and length of the local "bottom/top" X axis/side of the near plane rectangle 14632 * @param y 14633 * the direction and length of the local "left/right" Y axis/side of the near plane rectangle 14634 * @param nearFarDist 14635 * the distance between the far and near plane (the near plane will be calculated by this method). 14636 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 14637 * If the special value {@link Double#NEGATIVE_INFINITY} is used, the near and far planes will be swapped and 14638 * the near clipping plane will be at positive infinity. 14639 * If a negative value is used (except for {@link Double#NEGATIVE_INFINITY}) the near and far planes will be swapped 14640 * @param zeroToOne 14641 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 14642 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 14643 * @param projDest 14644 * will hold the resulting projection matrix 14645 * @param viewDest 14646 * will hold the resulting view matrix 14647 */ 14648 public static void projViewFromRectangle( 14649 Vector3d eye, Vector3d p, Vector3d x, Vector3d y, double nearFarDist, bool zeroToOne, 14650 ref Matrix4d projDest, ref Matrix4d viewDest) { 14651 double zx = y.y * x.z - y.z * x.y, zy = y.z * x.x - y.x * x.z, zz = y.x * x.y - y.y * x.x; 14652 double zd = zx * (p.x - eye.x) + zy * (p.y - eye.y) + zz * (p.z - eye.z); 14653 double zs = zd >= 0 ? 1 : -1; zx *= zs; zy *= zs; zz *= zs; zd *= zs; 14654 viewDest.setLookAt(eye.x, eye.y, eye.z, eye.x + zx, eye.y + zy, eye.z + zz, y.x, y.y, y.z); 14655 double px = viewDest.m00 * p.x + viewDest.m10 * p.y + viewDest.m20 * p.z + viewDest.m30; 14656 double py = viewDest.m01 * p.x + viewDest.m11 * p.y + viewDest.m21 * p.z + viewDest.m31; 14657 double tx = viewDest.m00 * x.x + viewDest.m10 * x.y + viewDest.m20 * x.z; 14658 double ty = viewDest.m01 * y.x + viewDest.m11 * y.y + viewDest.m21 * y.z; 14659 double len = Math.sqrt(zx * zx + zy * zy + zz * zz); 14660 double near = zd / len, far; 14661 if (Math.isInfinite(nearFarDist) && nearFarDist < 0.0) { 14662 far = near; 14663 near = double.infinity; 14664 } else if (Math.isInfinite(nearFarDist) && nearFarDist > 0.0) { 14665 far = double.infinity; 14666 } else if (nearFarDist < 0.0) { 14667 far = near; 14668 near = near + nearFarDist; 14669 } else { 14670 far = near + nearFarDist; 14671 } 14672 projDest.setFrustum(px, px + tx, py, py + ty, near, far, zeroToOne); 14673 } 14674 14675 /** 14676 * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(ref Vector3d)}) 14677 * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(ref Vector3d)}) and the 14678 * given vector <code>up</code>. 14679 * <p> 14680 * This effectively ensures that the resulting matrix will be equal to the one obtained from 14681 * {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)} called with the current 14682 * local origin of this matrix (as obtained by {@link #originAffine(ref Vector3d)}), the sum of this position and the 14683 * negated local Z axis as well as the given vector <code>up</code>. 14684 * <p> 14685 * This method must only be called on {@link #isAffine()} matrices. 14686 * 14687 * @param up 14688 * the up vector 14689 * @return this 14690 */ 14691 ref public Matrix4d withLookAtUp(ref Vector3d up) return { 14692 withLookAtUp(up.x, up.y, up.z, this); 14693 return this; 14694 } 14695 14696 public Matrix4d withLookAtUp(ref Vector3d up, ref Matrix4d dest) { 14697 return dest.withLookAtUp(up.x, up.y, up.z); 14698 } 14699 14700 /** 14701 * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(ref Vector3d)}) 14702 * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(ref Vector3d)}) and the 14703 * given vector <code>(upX, upY, upZ)</code>. 14704 * <p> 14705 * This effectively ensures that the resulting matrix will be equal to the one obtained from 14706 * {@link #setLookAt(double, double, double, double, double, double, double, double, double)} called with the current 14707 * local origin of this matrix (as obtained by {@link #originAffine(ref Vector3d)}), the sum of this position and the 14708 * negated local Z axis as well as the given vector <code>(upX, upY, upZ)</code>. 14709 * <p> 14710 * This method must only be called on {@link #isAffine()} matrices. 14711 * 14712 * @param upX 14713 * the x coordinate of the up vector 14714 * @param upY 14715 * the y coordinate of the up vector 14716 * @param upZ 14717 * the z coordinate of the up vector 14718 * @return this 14719 */ 14720 ref public Matrix4d withLookAtUp(double upX, double upY, double upZ) return { 14721 withLookAtUp(upX, upY, upZ, this); 14722 return this; 14723 } 14724 14725 public Matrix4d withLookAtUp(double upX, double upY, double upZ, ref Matrix4d dest) { 14726 double y = (upY * m21 - upZ * m11) * m02 + 14727 (upZ * m01 - upX * m21) * m12 + 14728 (upX * m11 - upY * m01) * m22; 14729 double x = upX * m01 + upY * m11 + upZ * m21; 14730 if ((properties & PROPERTY_ORTHONORMAL) == 0) 14731 x *= Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21); 14732 double invsqrt = Math.invsqrt(y * y + x * x); 14733 double c = x * invsqrt, s = y * invsqrt; 14734 double nm00 = c * m00 - s * m01, nm10 = c * m10 - s * m11, nm20 = c * m20 - s * m21, nm31 = s * m30 + c * m31; 14735 double nm01 = s * m00 + c * m01, nm11 = s * m10 + c * m11, nm21 = s * m20 + c * m21, nm30 = c * m30 - s * m31; 14736 dest._m00(nm00)._m10(nm10)._m20(nm20)._m30(nm30) 14737 ._m01(nm01)._m11(nm11)._m21(nm21)._m31(nm31); 14738 if (dest != this) { 14739 dest 14740 ._m02(m02)._m12(m12)._m22(m22)._m32(m32) 14741 ._m03(m03)._m13(m13)._m23(m23)._m33(m33); 14742 } 14743 dest._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 14744 return dest; 14745 } 14746 14747 /** 14748 * Multiply <code>this</code> by the matrix 14749 * <pre> 14750 * 1 0 0 0 14751 * 0 0 1 0 14752 * 0 1 0 0 14753 * 0 0 0 1 14754 * </pre> 14755 * 14756 * @return this 14757 */ 14758 ref public Matrix4d mapXZY() return { 14759 mapXZY(this); 14760 return this; 14761 } 14762 public Matrix4d mapXZY(ref Matrix4d dest) { 14763 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14764 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14765 } 14766 /** 14767 * Multiply <code>this</code> by the matrix 14768 * <pre> 14769 * 1 0 0 0 14770 * 0 0 -1 0 14771 * 0 1 0 0 14772 * 0 0 0 1 14773 * </pre> 14774 * 14775 * @return this 14776 */ 14777 ref public Matrix4d mapXZnY() return { 14778 mapXZnY(this); 14779 return this; 14780 } 14781 public Matrix4d mapXZnY(ref Matrix4d dest) { 14782 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14783 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14784 } 14785 /** 14786 * Multiply <code>this</code> by the matrix 14787 * <pre> 14788 * 1 0 0 0 14789 * 0 -1 0 0 14790 * 0 0 -1 0 14791 * 0 0 0 1 14792 * </pre> 14793 * 14794 * @return this 14795 */ 14796 ref public Matrix4d mapXnYnZ() return { 14797 mapXnYnZ(this); 14798 return this; 14799 } 14800 public Matrix4d mapXnYnZ(ref Matrix4d dest) { 14801 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14802 } 14803 /** 14804 * Multiply <code>this</code> by the matrix 14805 * <pre> 14806 * 1 0 0 0 14807 * 0 0 1 0 14808 * 0 -1 0 0 14809 * 0 0 0 1 14810 * </pre> 14811 * 14812 * @return this 14813 */ 14814 ref public Matrix4d mapXnZY() return { 14815 mapXnZY(this); 14816 return this; 14817 } 14818 public Matrix4d mapXnZY(ref Matrix4d dest) { 14819 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14820 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14821 } 14822 /** 14823 * Multiply <code>this</code> by the matrix 14824 * <pre> 14825 * 1 0 0 0 14826 * 0 0 -1 0 14827 * 0 -1 0 0 14828 * 0 0 0 1 14829 * </pre> 14830 * 14831 * @return this 14832 */ 14833 ref public Matrix4d mapXnZnY() return { 14834 mapXnZnY(this); 14835 return this; 14836 } 14837 public Matrix4d mapXnZnY(ref Matrix4d dest) { 14838 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14839 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14840 } 14841 /** 14842 * Multiply <code>this</code> by the matrix 14843 * <pre> 14844 * 0 1 0 0 14845 * 1 0 0 0 14846 * 0 0 1 0 14847 * 0 0 0 1 14848 * </pre> 14849 * 14850 * @return this 14851 */ 14852 ref public Matrix4d mapYXZ() return { 14853 mapYXZ(this); 14854 return this; 14855 } 14856 public Matrix4d mapYXZ(ref Matrix4d dest) { 14857 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14858 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14859 } 14860 /** 14861 * Multiply <code>this</code> by the matrix 14862 * <pre> 14863 * 0 1 0 0 14864 * 1 0 0 0 14865 * 0 0 -1 0 14866 * 0 0 0 1 14867 * </pre> 14868 * 14869 * @return this 14870 */ 14871 ref public Matrix4d mapYXnZ() return { 14872 mapYXnZ(this); 14873 return this; 14874 } 14875 public Matrix4d mapYXnZ(ref Matrix4d dest) { 14876 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14877 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14878 } 14879 /** 14880 * Multiply <code>this</code> by the matrix 14881 * <pre> 14882 * 0 0 1 0 14883 * 1 0 0 0 14884 * 0 1 0 0 14885 * 0 0 0 1 14886 * </pre> 14887 * 14888 * @return this 14889 */ 14890 ref public Matrix4d mapYZX() return { 14891 mapYZX(this); 14892 return this; 14893 } 14894 public Matrix4d mapYZX(ref Matrix4d dest) { 14895 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14896 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14897 } 14898 /** 14899 * Multiply <code>this</code> by the matrix 14900 * <pre> 14901 * 0 0 -1 0 14902 * 1 0 0 0 14903 * 0 1 0 0 14904 * 0 0 0 1 14905 * </pre> 14906 * 14907 * @return this 14908 */ 14909 ref public Matrix4d mapYZnX() return { 14910 mapYZnX(this); 14911 return this; 14912 } 14913 public Matrix4d mapYZnX(ref Matrix4d dest) { 14914 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14915 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14916 } 14917 /** 14918 * Multiply <code>this</code> by the matrix 14919 * <pre> 14920 * 0 -1 0 0 14921 * 1 0 0 0 14922 * 0 0 1 0 14923 * 0 0 0 1 14924 * </pre> 14925 * 14926 * @return this 14927 */ 14928 ref public Matrix4d mapYnXZ() return { 14929 mapYnXZ(this); 14930 return this; 14931 } 14932 public Matrix4d mapYnXZ(ref Matrix4d dest) { 14933 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14934 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14935 } 14936 /** 14937 * Multiply <code>this</code> by the matrix 14938 * <pre> 14939 * 0 -1 0 0 14940 * 1 0 0 0 14941 * 0 0 -1 0 14942 * 0 0 0 1 14943 * </pre> 14944 * 14945 * @return this 14946 */ 14947 ref public Matrix4d mapYnXnZ() return { 14948 mapYnXnZ(this); 14949 return this; 14950 } 14951 public Matrix4d mapYnXnZ(ref Matrix4d dest) { 14952 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14953 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14954 } 14955 /** 14956 * Multiply <code>this</code> by the matrix 14957 * <pre> 14958 * 0 0 1 0 14959 * 1 0 0 0 14960 * 0 -1 0 0 14961 * 0 0 0 1 14962 * </pre> 14963 * 14964 * @return this 14965 */ 14966 ref public Matrix4d mapYnZX() return { 14967 mapYnZX(this); 14968 return this; 14969 } 14970 public Matrix4d mapYnZX(ref Matrix4d dest) { 14971 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14972 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14973 } 14974 /** 14975 * Multiply <code>this</code> by the matrix 14976 * <pre> 14977 * 0 0 -1 0 14978 * 1 0 0 0 14979 * 0 -1 0 0 14980 * 0 0 0 1 14981 * </pre> 14982 * 14983 * @return this 14984 */ 14985 ref public Matrix4d mapYnZnX() return { 14986 mapYnZnX(this); 14987 return this; 14988 } 14989 public Matrix4d mapYnZnX(ref Matrix4d dest) { 14990 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14991 return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 14992 } 14993 /** 14994 * Multiply <code>this</code> by the matrix 14995 * <pre> 14996 * 0 1 0 0 14997 * 0 0 1 0 14998 * 1 0 0 0 14999 * 0 0 0 1 15000 * </pre> 15001 * 15002 * @return this 15003 */ 15004 ref public Matrix4d mapZXY() return { 15005 mapZXY(this); 15006 return this; 15007 } 15008 public Matrix4d mapZXY(ref Matrix4d dest) { 15009 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15010 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15011 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15012 } 15013 /** 15014 * Multiply <code>this</code> by the matrix 15015 * <pre> 15016 * 0 1 0 0 15017 * 0 0 -1 0 15018 * 1 0 0 0 15019 * 0 0 0 1 15020 * </pre> 15021 * 15022 * @return this 15023 */ 15024 ref public Matrix4d mapZXnY() return { 15025 mapZXnY(this); 15026 return this; 15027 } 15028 public Matrix4d mapZXnY(ref Matrix4d dest) { 15029 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15030 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15031 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15032 } 15033 /** 15034 * Multiply <code>this</code> by the matrix 15035 * <pre> 15036 * 0 0 1 0 15037 * 0 1 0 0 15038 * 1 0 0 0 15039 * 0 0 0 1 15040 * </pre> 15041 * 15042 * @return this 15043 */ 15044 ref public Matrix4d mapZYX() return { 15045 mapZYX(this); 15046 return this; 15047 } 15048 public Matrix4d mapZYX(ref Matrix4d dest) { 15049 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15050 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15051 } 15052 /** 15053 * Multiply <code>this</code> by the matrix 15054 * <pre> 15055 * 0 0 -1 0 15056 * 0 1 0 0 15057 * 1 0 0 0 15058 * 0 0 0 1 15059 * </pre> 15060 * 15061 * @return this 15062 */ 15063 ref public Matrix4d mapZYnX() return { 15064 mapZYnX(this); 15065 return this; 15066 } 15067 public Matrix4d mapZYnX(ref Matrix4d dest) { 15068 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15069 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15070 } 15071 /** 15072 * Multiply <code>this</code> by the matrix 15073 * <pre> 15074 * 0 -1 0 0 15075 * 0 0 1 0 15076 * 1 0 0 0 15077 * 0 0 0 1 15078 * </pre> 15079 * 15080 * @return this 15081 */ 15082 ref public Matrix4d mapZnXY() return { 15083 mapZnXY(this); 15084 return this; 15085 } 15086 public Matrix4d mapZnXY(ref Matrix4d dest) { 15087 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15088 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15089 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15090 } 15091 /** 15092 * Multiply <code>this</code> by the matrix 15093 * <pre> 15094 * 0 -1 0 0 15095 * 0 0 -1 0 15096 * 1 0 0 0 15097 * 0 0 0 1 15098 * </pre> 15099 * 15100 * @return this 15101 */ 15102 ref public Matrix4d mapZnXnY() return { 15103 mapZnXnY(this); 15104 return this; 15105 } 15106 public Matrix4d mapZnXnY(ref Matrix4d dest) { 15107 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15108 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15109 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15110 } 15111 /** 15112 * Multiply <code>this</code> by the matrix 15113 * <pre> 15114 * 0 0 1 0 15115 * 0 -1 0 0 15116 * 1 0 0 0 15117 * 0 0 0 1 15118 * </pre> 15119 * 15120 * @return this 15121 */ 15122 ref public Matrix4d mapZnYX() return { 15123 mapZnYX(this); 15124 return this; 15125 } 15126 public Matrix4d mapZnYX(ref Matrix4d dest) { 15127 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15128 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15129 } 15130 /** 15131 * Multiply <code>this</code> by the matrix 15132 * <pre> 15133 * 0 0 -1 0 15134 * 0 -1 0 0 15135 * 1 0 0 0 15136 * 0 0 0 1 15137 * </pre> 15138 * 15139 * @return this 15140 */ 15141 ref public Matrix4d mapZnYnX() return { 15142 mapZnYnX(this); 15143 return this; 15144 } 15145 public Matrix4d mapZnYnX(ref Matrix4d dest) { 15146 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15147 return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15148 } 15149 /** 15150 * Multiply <code>this</code> by the matrix 15151 * <pre> 15152 * -1 0 0 0 15153 * 0 1 0 0 15154 * 0 0 -1 0 15155 * 0 0 0 1 15156 * </pre> 15157 * 15158 * @return this 15159 */ 15160 ref public Matrix4d mapnXYnZ() return { 15161 mapnXYnZ(this); 15162 return this; 15163 } 15164 public Matrix4d mapnXYnZ(ref Matrix4d dest) { 15165 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15166 } 15167 /** 15168 * Multiply <code>this</code> by the matrix 15169 * <pre> 15170 * -1 0 0 0 15171 * 0 0 1 0 15172 * 0 1 0 0 15173 * 0 0 0 1 15174 * </pre> 15175 * 15176 * @return this 15177 */ 15178 ref public Matrix4d mapnXZY() return { 15179 mapnXZY(this); 15180 return this; 15181 } 15182 public Matrix4d mapnXZY(ref Matrix4d dest) { 15183 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15184 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15185 } 15186 /** 15187 * Multiply <code>this</code> by the matrix 15188 * <pre> 15189 * -1 0 0 0 15190 * 0 0 -1 0 15191 * 0 1 0 0 15192 * 0 0 0 1 15193 * </pre> 15194 * 15195 * @return this 15196 */ 15197 ref public Matrix4d mapnXZnY() return { 15198 mapnXZnY(this); 15199 return this; 15200 } 15201 public Matrix4d mapnXZnY(ref Matrix4d dest) { 15202 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15203 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15204 } 15205 /** 15206 * Multiply <code>this</code> by the matrix 15207 * <pre> 15208 * -1 0 0 0 15209 * 0 -1 0 0 15210 * 0 0 1 0 15211 * 0 0 0 1 15212 * </pre> 15213 * 15214 * @return this 15215 */ 15216 ref public Matrix4d mapnXnYZ() return { 15217 mapnXnYZ(this); 15218 return this; 15219 } 15220 public Matrix4d mapnXnYZ(ref Matrix4d dest) { 15221 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15222 } 15223 /** 15224 * Multiply <code>this</code> by the matrix 15225 * <pre> 15226 * -1 0 0 0 15227 * 0 -1 0 0 15228 * 0 0 -1 0 15229 * 0 0 0 1 15230 * </pre> 15231 * 15232 * @return this 15233 */ 15234 ref public Matrix4d mapnXnYnZ() return { 15235 mapnXnYnZ(this); 15236 return this; 15237 } 15238 public Matrix4d mapnXnYnZ(ref Matrix4d dest) { 15239 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15240 } 15241 /** 15242 * Multiply <code>this</code> by the matrix 15243 * <pre> 15244 * -1 0 0 0 15245 * 0 0 1 0 15246 * 0 -1 0 0 15247 * 0 0 0 1 15248 * </pre> 15249 * 15250 * @return this 15251 */ 15252 ref public Matrix4d mapnXnZY() return { 15253 mapnXnZY(this); 15254 return this; 15255 } 15256 public Matrix4d mapnXnZY(ref Matrix4d dest) { 15257 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15258 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15259 } 15260 /** 15261 * Multiply <code>this</code> by the matrix 15262 * <pre> 15263 * -1 0 0 0 15264 * 0 0 -1 0 15265 * 0 -1 0 0 15266 * 0 0 0 1 15267 * </pre> 15268 * 15269 * @return this 15270 */ 15271 ref public Matrix4d mapnXnZnY() return { 15272 mapnXnZnY(this); 15273 return this; 15274 } 15275 public Matrix4d mapnXnZnY(ref Matrix4d dest) { 15276 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15277 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15278 } 15279 /** 15280 * Multiply <code>this</code> by the matrix 15281 * <pre> 15282 * 0 1 0 0 15283 * -1 0 0 0 15284 * 0 0 1 0 15285 * 0 0 0 1 15286 * </pre> 15287 * 15288 * @return this 15289 */ 15290 ref public Matrix4d mapnYXZ() return { 15291 mapnYXZ(this); 15292 return this; 15293 } 15294 public Matrix4d mapnYXZ(ref Matrix4d dest) { 15295 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15296 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15297 } 15298 /** 15299 * Multiply <code>this</code> by the matrix 15300 * <pre> 15301 * 0 1 0 0 15302 * -1 0 0 0 15303 * 0 0 -1 0 15304 * 0 0 0 1 15305 * </pre> 15306 * 15307 * @return this 15308 */ 15309 ref public Matrix4d mapnYXnZ() return { 15310 mapnYXnZ(this); 15311 return this; 15312 } 15313 public Matrix4d mapnYXnZ(ref Matrix4d dest) { 15314 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15315 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15316 } 15317 /** 15318 * Multiply <code>this</code> by the matrix 15319 * <pre> 15320 * 0 0 1 0 15321 * -1 0 0 0 15322 * 0 1 0 0 15323 * 0 0 0 1 15324 * </pre> 15325 * 15326 * @return this 15327 */ 15328 ref public Matrix4d mapnYZX() return { 15329 mapnYZX(this); 15330 return this; 15331 } 15332 public Matrix4d mapnYZX(ref Matrix4d dest) { 15333 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15334 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15335 } 15336 /** 15337 * Multiply <code>this</code> by the matrix 15338 * <pre> 15339 * 0 0 -1 0 15340 * -1 0 0 0 15341 * 0 1 0 0 15342 * 0 0 0 1 15343 * </pre> 15344 * 15345 * @return this 15346 */ 15347 ref public Matrix4d mapnYZnX() return { 15348 mapnYZnX(this); 15349 return this; 15350 } 15351 public Matrix4d mapnYZnX(ref Matrix4d dest) { 15352 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15353 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15354 } 15355 /** 15356 * Multiply <code>this</code> by the matrix 15357 * <pre> 15358 * 0 -1 0 0 15359 * -1 0 0 0 15360 * 0 0 1 0 15361 * 0 0 0 1 15362 * </pre> 15363 * 15364 * @return this 15365 */ 15366 ref public Matrix4d mapnYnXZ() return { 15367 mapnYnXZ(this); 15368 return this; 15369 } 15370 public Matrix4d mapnYnXZ(ref Matrix4d dest) { 15371 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15372 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15373 } 15374 /** 15375 * Multiply <code>this</code> by the matrix 15376 * <pre> 15377 * 0 -1 0 0 15378 * -1 0 0 0 15379 * 0 0 -1 0 15380 * 0 0 0 1 15381 * </pre> 15382 * 15383 * @return this 15384 */ 15385 ref public Matrix4d mapnYnXnZ() return { 15386 mapnYnXnZ(this); 15387 return this; 15388 } 15389 public Matrix4d mapnYnXnZ(ref Matrix4d dest) { 15390 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15391 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15392 } 15393 /** 15394 * Multiply <code>this</code> by the matrix 15395 * <pre> 15396 * 0 0 1 0 15397 * -1 0 0 0 15398 * 0 -1 0 0 15399 * 0 0 0 1 15400 * </pre> 15401 * 15402 * @return this 15403 */ 15404 ref public Matrix4d mapnYnZX() return { 15405 mapnYnZX(this); 15406 return this; 15407 } 15408 public Matrix4d mapnYnZX(ref Matrix4d dest) { 15409 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15410 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15411 } 15412 /** 15413 * Multiply <code>this</code> by the matrix 15414 * <pre> 15415 * 0 0 -1 0 15416 * -1 0 0 0 15417 * 0 -1 0 0 15418 * 0 0 0 1 15419 * </pre> 15420 * 15421 * @return this 15422 */ 15423 ref public Matrix4d mapnYnZnX() return { 15424 mapnYnZnX(this); 15425 return this; 15426 } 15427 public Matrix4d mapnYnZnX(ref Matrix4d dest) { 15428 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15429 return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15430 } 15431 /** 15432 * Multiply <code>this</code> by the matrix 15433 * <pre> 15434 * 0 1 0 0 15435 * 0 0 1 0 15436 * -1 0 0 0 15437 * 0 0 0 1 15438 * </pre> 15439 * 15440 * @return this 15441 */ 15442 ref public Matrix4d mapnZXY() return { 15443 mapnZXY(this); 15444 return this; 15445 } 15446 public Matrix4d mapnZXY(ref Matrix4d dest) { 15447 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15448 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15449 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15450 } 15451 /** 15452 * Multiply <code>this</code> by the matrix 15453 * <pre> 15454 * 0 1 0 0 15455 * 0 0 -1 0 15456 * -1 0 0 0 15457 * 0 0 0 1 15458 * </pre> 15459 * 15460 * @return this 15461 */ 15462 ref public Matrix4d mapnZXnY() return { 15463 mapnZXnY(this); 15464 return this; 15465 } 15466 public Matrix4d mapnZXnY(ref Matrix4d dest) { 15467 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15468 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15469 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15470 } 15471 /** 15472 * Multiply <code>this</code> by the matrix 15473 * <pre> 15474 * 0 0 1 0 15475 * 0 1 0 0 15476 * -1 0 0 0 15477 * 0 0 0 1 15478 * </pre> 15479 * 15480 * @return this 15481 */ 15482 ref public Matrix4d mapnZYX() return { 15483 mapnZYX(this); 15484 return this; 15485 } 15486 public Matrix4d mapnZYX(ref Matrix4d dest) { 15487 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15488 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15489 } 15490 /** 15491 * Multiply <code>this</code> by the matrix 15492 * <pre> 15493 * 0 0 -1 0 15494 * 0 1 0 0 15495 * -1 0 0 0 15496 * 0 0 0 1 15497 * </pre> 15498 * 15499 * @return this 15500 */ 15501 ref public Matrix4d mapnZYnX() return { 15502 mapnZYnX(this); 15503 return this; 15504 } 15505 public Matrix4d mapnZYnX(ref Matrix4d dest) { 15506 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15507 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15508 } 15509 /** 15510 * Multiply <code>this</code> by the matrix 15511 * <pre> 15512 * 0 -1 0 0 15513 * 0 0 1 0 15514 * -1 0 0 0 15515 * 0 0 0 1 15516 * </pre> 15517 * 15518 * @return this 15519 */ 15520 ref public Matrix4d mapnZnXY() return { 15521 mapnZnXY(this); 15522 return this; 15523 } 15524 public Matrix4d mapnZnXY(ref Matrix4d dest) { 15525 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15526 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15527 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15528 } 15529 /** 15530 * Multiply <code>this</code> by the matrix 15531 * <pre> 15532 * 0 -1 0 0 15533 * 0 0 -1 0 15534 * -1 0 0 0 15535 * 0 0 0 1 15536 * </pre> 15537 * 15538 * @return this 15539 */ 15540 ref public Matrix4d mapnZnXnY() return { 15541 mapnZnXnY(this); 15542 return this; 15543 } 15544 public Matrix4d mapnZnXnY(ref Matrix4d dest) { 15545 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15546 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15547 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15548 } 15549 /** 15550 * Multiply <code>this</code> by the matrix 15551 * <pre> 15552 * 0 0 1 0 15553 * 0 -1 0 0 15554 * -1 0 0 0 15555 * 0 0 0 1 15556 * </pre> 15557 * 15558 * @return this 15559 */ 15560 ref public Matrix4d mapnZnYX() return { 15561 mapnZnYX(this); 15562 return this; 15563 } 15564 public Matrix4d mapnZnYX(ref Matrix4d dest) { 15565 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15566 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15567 } 15568 /** 15569 * Multiply <code>this</code> by the matrix 15570 * <pre> 15571 * 0 0 -1 0 15572 * 0 -1 0 0 15573 * -1 0 0 0 15574 * 0 0 0 1 15575 * </pre> 15576 * 15577 * @return this 15578 */ 15579 ref public Matrix4d mapnZnYnX() return { 15580 mapnZnYnX(this); 15581 return this; 15582 } 15583 public Matrix4d mapnZnYnX(ref Matrix4d dest) { 15584 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15585 return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15586 } 15587 15588 /** 15589 * Multiply <code>this</code> by the matrix 15590 * <pre> 15591 * -1 0 0 0 15592 * 0 1 0 0 15593 * 0 0 1 0 15594 * 0 0 0 1 15595 * </pre> 15596 * 15597 * @return this 15598 */ 15599 ref public Matrix4d negateX() return { 15600 return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15601 } 15602 public Matrix4d negateX(ref Matrix4d dest) { 15603 return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15604 } 15605 15606 /** 15607 * Multiply <code>this</code> by the matrix 15608 * <pre> 15609 * 1 0 0 0 15610 * 0 -1 0 0 15611 * 0 0 1 0 15612 * 0 0 0 1 15613 * </pre> 15614 * 15615 * @return this 15616 */ 15617 ref public Matrix4d negateY() return { 15618 return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15619 } 15620 public Matrix4d negateY(ref Matrix4d dest) { 15621 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15622 } 15623 15624 /** 15625 * Multiply <code>this</code> by the matrix 15626 * <pre> 15627 * 1 0 0 0 15628 * 0 1 0 0 15629 * 0 0 -1 0 15630 * 0 0 0 1 15631 * </pre> 15632 * 15633 * @return this 15634 */ 15635 ref public Matrix4d negateZ() return { 15636 return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15637 } 15638 public Matrix4d negateZ(ref Matrix4d dest) { 15639 return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15640 } 15641 15642 public bool isFinite() { 15643 return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) && Math.isFinite(m03) && 15644 Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) && Math.isFinite(m13) && 15645 Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) && Math.isFinite(m23) && 15646 Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32) && Math.isFinite(m33); 15647 } 15648 15649 }