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 public double[] get(ref double[] dest, int offset) { 2927 dest[offset+0] = m00; 2928 dest[offset+1] = m01; 2929 dest[offset+2] = m02; 2930 dest[offset+3] = m03; 2931 dest[offset+4] = m10; 2932 dest[offset+5] = m11; 2933 dest[offset+6] = m12; 2934 dest[offset+7] = m13; 2935 dest[offset+8] = m20; 2936 dest[offset+9] = m21; 2937 dest[offset+10] = m22; 2938 dest[offset+11] = m23; 2939 dest[offset+12] = m30; 2940 dest[offset+13] = m31; 2941 dest[offset+14] = m32; 2942 dest[offset+15] = m33; 2943 return dest; 2944 } 2945 2946 public double[] get(ref double[] dest) { 2947 return get(dest, 0); 2948 } 2949 2950 /** 2951 * Set all the values within this matrix to 0. 2952 * 2953 * @return this 2954 */ 2955 ref public Matrix4d zero() return { 2956 return 2957 _m00(0.0). 2958 _m01(0.0). 2959 _m02(0.0). 2960 _m03(0.0). 2961 _m10(0.0). 2962 _m11(0.0). 2963 _m12(0.0). 2964 _m13(0.0). 2965 _m20(0.0). 2966 _m21(0.0). 2967 _m22(0.0). 2968 _m23(0.0). 2969 _m30(0.0). 2970 _m31(0.0). 2971 _m32(0.0). 2972 _m33(0.0). 2973 _properties(0); 2974 } 2975 2976 /** 2977 * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor. 2978 * <p> 2979 * The resulting matrix can be multiplied against another transformation 2980 * matrix to obtain an additional scaling. 2981 * <p> 2982 * In order to post-multiply a scaling transformation directly to a 2983 * matrix, use {@link #scale(double) scale()} instead. 2984 * 2985 * @see #scale(double) 2986 * 2987 * @param factor 2988 * the scale factor in x, y and z 2989 * @return this 2990 */ 2991 ref public Matrix4d scaling(double factor) return { 2992 return scaling(factor, factor, factor); 2993 } 2994 2995 /** 2996 * Set this matrix to be a simple scale matrix. 2997 * 2998 * @param x 2999 * the scale in x 3000 * @param y 3001 * the scale in y 3002 * @param z 3003 * the scale in z 3004 * @return this 3005 */ 3006 ref public Matrix4d scaling(double x, double y, double z) return { 3007 if ((properties & PROPERTY_IDENTITY) == 0) 3008 identity(); 3009 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3010 _m00(x). 3011 _m11(y). 3012 _m22(z). 3013 properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0); 3014 return this; 3015 } 3016 3017 /** 3018 * Set this matrix to be a simple scale matrix which scales the base axes by 3019 * <code>xyz.x</code>, <code>xyz.y</code> and <code>xyz.z</code>, respectively. 3020 * <p> 3021 * The resulting matrix can be multiplied against another transformation 3022 * matrix to obtain an additional scaling. 3023 * <p> 3024 * In order to post-multiply a scaling transformation directly to a 3025 * matrix use {@link #scale(ref Vector3d) scale()} instead. 3026 * 3027 * @see #scale(ref Vector3d) 3028 * 3029 * @param xyz 3030 * the scale in x, y and z, respectively 3031 * @return this 3032 */ 3033 ref public Matrix4d scaling(ref Vector3d xyz) return { 3034 return scaling(xyz.x, xyz.y, xyz.z); 3035 } 3036 3037 /** 3038 * Set this matrix to a rotation matrix which rotates the given radians about a given axis. 3039 * <p> 3040 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3041 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3042 * When used with a left-handed coordinate system, the rotation is clockwise. 3043 * <p> 3044 * From <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">Wikipedia</a> 3045 * 3046 * @param angle 3047 * the angle in radians 3048 * @param x 3049 * the x-coordinate of the axis to rotate about 3050 * @param y 3051 * the y-coordinate of the axis to rotate about 3052 * @param z 3053 * the z-coordinate of the axis to rotate about 3054 * @return this 3055 */ 3056 ref public Matrix4d rotation(double angle, double x, double y, double z) return { 3057 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 3058 rotationX(x * angle); 3059 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 3060 rotationY(y * angle); 3061 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 3062 rotationZ(z * angle); 3063 else 3064 rotationInternal(angle, x, y, z); 3065 return this; 3066 } 3067 private Matrix4d rotationInternal(double angle, double x, double y, double z) { 3068 double sin = Math.sin(angle); 3069 double cos = Math.cosFromSin(sin, angle); 3070 double C = 1.0 - cos; 3071 double xy = x * y, xz = x * z, yz = y * z; 3072 if ((properties & PROPERTY_IDENTITY) == 0) 3073 this._identity(); 3074 _m00(cos + x * x * C). 3075 _m10(xy * C - z * sin). 3076 _m20(xz * C + y * sin). 3077 _m01(xy * C + z * sin). 3078 _m11(cos + y * y * C). 3079 _m21(yz * C - x * sin). 3080 _m02(xz * C - y * sin). 3081 _m12(yz * C + x * sin). 3082 _m22(cos + z * z * C). 3083 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3084 return this; 3085 } 3086 3087 /** 3088 * Set this matrix to a rotation transformation about the X axis. 3089 * <p> 3090 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3091 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3092 * When used with a left-handed coordinate system, the rotation is clockwise. 3093 * <p> 3094 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3095 * 3096 * @param ang 3097 * the angle in radians 3098 * @return this 3099 */ 3100 ref public Matrix4d rotationX(double ang) return { 3101 double sin, cos; 3102 sin = Math.sin(ang); 3103 cos = Math.cosFromSin(sin, ang); 3104 if ((properties & PROPERTY_IDENTITY) == 0) 3105 this._identity(); 3106 _m11(cos). 3107 _m12(sin). 3108 _m21(-sin). 3109 _m22(cos). 3110 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3111 return this; 3112 } 3113 3114 /** 3115 * Set this matrix to a rotation transformation about the Y axis. 3116 * <p> 3117 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3118 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3119 * When used with a left-handed coordinate system, the rotation is clockwise. 3120 * <p> 3121 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3122 * 3123 * @param ang 3124 * the angle in radians 3125 * @return this 3126 */ 3127 ref public Matrix4d rotationY(double ang) return { 3128 double sin, cos; 3129 sin = Math.sin(ang); 3130 cos = Math.cosFromSin(sin, ang); 3131 if ((properties & PROPERTY_IDENTITY) == 0) 3132 this._identity(); 3133 _m00(cos). 3134 _m02(-sin). 3135 _m20(sin). 3136 _m22(cos). 3137 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3138 return this; 3139 } 3140 3141 /** 3142 * Set this matrix to a rotation transformation about the Z axis. 3143 * <p> 3144 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3145 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3146 * When used with a left-handed coordinate system, the rotation is clockwise. 3147 * <p> 3148 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3149 * 3150 * @param ang 3151 * the angle in radians 3152 * @return this 3153 */ 3154 ref public Matrix4d rotationZ(double ang) return { 3155 double sin, cos; 3156 sin = Math.sin(ang); 3157 cos = Math.cosFromSin(sin, ang); 3158 if ((properties & PROPERTY_IDENTITY) == 0) 3159 this._identity(); 3160 _m00(cos). 3161 _m01(sin). 3162 _m10(-sin). 3163 _m11(cos). 3164 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3165 return this; 3166 } 3167 3168 /** 3169 * Set this matrix to a rotation transformation about the Z axis to align the local <code>+X</code> towards <code>(dirX, dirY)</code>. 3170 * <p> 3171 * The vector <code>(dirX, dirY)</code> must be a unit vector. 3172 * 3173 * @param dirX 3174 * the x component of the normalized direction 3175 * @param dirY 3176 * the y component of the normalized direction 3177 * @return this 3178 */ 3179 ref public Matrix4d rotationTowardsXY(double dirX, double dirY) return { 3180 if ((properties & PROPERTY_IDENTITY) == 0) 3181 this._identity(); 3182 setm00(dirY); 3183 setm01(dirX); 3184 setm10(-dirX); 3185 setm11(dirY); 3186 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3187 return this; 3188 } 3189 3190 /** 3191 * Set this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation 3192 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3193 * <p> 3194 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3195 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3196 * When used with a left-handed coordinate system, the rotation is clockwise. 3197 * <p> 3198 * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 3199 * 3200 * @param angleX 3201 * the angle to rotate about X 3202 * @param angleY 3203 * the angle to rotate about Y 3204 * @param angleZ 3205 * the angle to rotate about Z 3206 * @return this 3207 */ 3208 ref public Matrix4d rotationXYZ(double angleX, double angleY, double angleZ) return { 3209 double sinX = Math.sin(angleX); 3210 double cosX = Math.cosFromSin(sinX, angleX); 3211 double sinY = Math.sin(angleY); 3212 double cosY = Math.cosFromSin(sinY, angleY); 3213 double sinZ = Math.sin(angleZ); 3214 double cosZ = Math.cosFromSin(sinZ, angleZ); 3215 double m_sinX = -sinX; 3216 double m_sinY = -sinY; 3217 double m_sinZ = -sinZ; 3218 if ((properties & PROPERTY_IDENTITY) == 0) 3219 this._identity(); 3220 3221 // rotateX 3222 double nm11 = cosX; 3223 double nm12 = sinX; 3224 double nm21 = m_sinX; 3225 double nm22 = cosX; 3226 // rotateY 3227 double nm00 = cosY; 3228 double nm01 = nm21 * m_sinY; 3229 double nm02 = nm22 * m_sinY; 3230 _m20(sinY). 3231 _m21(nm21 * cosY). 3232 _m22(nm22 * cosY). 3233 // rotateZ 3234 _m00(nm00 * cosZ). 3235 _m01(nm01 * cosZ + nm11 * sinZ). 3236 _m02(nm02 * cosZ + nm12 * sinZ). 3237 _m10(nm00 * m_sinZ). 3238 _m11(nm01 * m_sinZ + nm11 * cosZ). 3239 _m12(nm02 * m_sinZ + nm12 * cosZ). 3240 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3241 return this; 3242 } 3243 3244 /** 3245 * Set this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation 3246 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis. 3247 * <p> 3248 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3249 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3250 * When used with a left-handed coordinate system, the rotation is clockwise. 3251 * <p> 3252 * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 3253 * 3254 * @param angleZ 3255 * the angle to rotate about Z 3256 * @param angleY 3257 * the angle to rotate about Y 3258 * @param angleX 3259 * the angle to rotate about X 3260 * @return this 3261 */ 3262 ref public Matrix4d rotationZYX(double angleZ, double angleY, double angleX) return { 3263 double sinX = Math.sin(angleX); 3264 double cosX = Math.cosFromSin(sinX, angleX); 3265 double sinY = Math.sin(angleY); 3266 double cosY = Math.cosFromSin(sinY, angleY); 3267 double sinZ = Math.sin(angleZ); 3268 double cosZ = Math.cosFromSin(sinZ, angleZ); 3269 double m_sinZ = -sinZ; 3270 double m_sinY = -sinY; 3271 double m_sinX = -sinX; 3272 if ((properties & PROPERTY_IDENTITY) == 0) 3273 this._identity(); 3274 3275 // rotateZ 3276 double nm00 = cosZ; 3277 double nm01 = sinZ; 3278 double nm10 = m_sinZ; 3279 double nm11 = cosZ; 3280 // rotateY 3281 double nm20 = nm00 * sinY; 3282 double nm21 = nm01 * sinY; 3283 double nm22 = cosY; 3284 _m00(nm00 * cosY). 3285 _m01(nm01 * cosY). 3286 _m02(m_sinY). 3287 // rotateX 3288 _m10(nm10 * cosX + nm20 * sinX). 3289 _m11(nm11 * cosX + nm21 * sinX). 3290 _m12(nm22 * sinX). 3291 _m20(nm10 * m_sinX + nm20 * cosX). 3292 _m21(nm11 * m_sinX + nm21 * cosX). 3293 _m22(nm22 * cosX). 3294 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3295 return this; 3296 } 3297 3298 /** 3299 * Set this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation 3300 * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3301 * <p> 3302 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3303 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3304 * When used with a left-handed coordinate system, the rotation is clockwise. 3305 * <p> 3306 * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 3307 * 3308 * @param angleY 3309 * the angle to rotate about Y 3310 * @param angleX 3311 * the angle to rotate about X 3312 * @param angleZ 3313 * the angle to rotate about Z 3314 * @return this 3315 */ 3316 ref public Matrix4d rotationYXZ(double angleY, double angleX, double angleZ) return { 3317 double sinX = Math.sin(angleX); 3318 double cosX = Math.cosFromSin(sinX, angleX); 3319 double sinY = Math.sin(angleY); 3320 double cosY = Math.cosFromSin(sinY, angleY); 3321 double sinZ = Math.sin(angleZ); 3322 double cosZ = Math.cosFromSin(sinZ, angleZ); 3323 double m_sinY = -sinY; 3324 double m_sinX = -sinX; 3325 double m_sinZ = -sinZ; 3326 3327 // rotateY 3328 double nm00 = cosY; 3329 double nm02 = m_sinY; 3330 double nm20 = sinY; 3331 double nm22 = cosY; 3332 // rotateX 3333 double nm10 = nm20 * sinX; 3334 double nm11 = cosX; 3335 double nm12 = nm22 * sinX; 3336 _m20(nm20 * cosX). 3337 _m21(m_sinX). 3338 _m22(nm22 * cosX). 3339 _m23(0.0). 3340 // rotateZ 3341 _m00(nm00 * cosZ + nm10 * sinZ). 3342 _m01(nm11 * sinZ). 3343 _m02(nm02 * cosZ + nm12 * sinZ). 3344 _m03(0.0). 3345 _m10(nm00 * m_sinZ + nm10 * cosZ). 3346 _m11(nm11 * cosZ). 3347 _m12(nm02 * m_sinZ + nm12 * cosZ). 3348 _m13(0.0). 3349 // set last column to identity 3350 _m30(0.0). 3351 _m31(0.0). 3352 _m32(0.0). 3353 _m33(1.0). 3354 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3355 return this; 3356 } 3357 3358 /** 3359 * 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 3360 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3361 * <p> 3362 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3363 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3364 * When used with a left-handed coordinate system, the rotation is clockwise. 3365 * 3366 * @param angleX 3367 * the angle to rotate about X 3368 * @param angleY 3369 * the angle to rotate about Y 3370 * @param angleZ 3371 * the angle to rotate about Z 3372 * @return this 3373 */ 3374 ref public Matrix4d setRotationXYZ(double angleX, double angleY, double angleZ) return { 3375 double sinX = Math.sin(angleX); 3376 double cosX = Math.cosFromSin(sinX, angleX); 3377 double sinY = Math.sin(angleY); 3378 double cosY = Math.cosFromSin(sinY, angleY); 3379 double sinZ = Math.sin(angleZ); 3380 double cosZ = Math.cosFromSin(sinZ, angleZ); 3381 double m_sinX = -sinX; 3382 double m_sinY = -sinY; 3383 double m_sinZ = -sinZ; 3384 3385 // rotateX 3386 double nm11 = cosX; 3387 double nm12 = sinX; 3388 double nm21 = m_sinX; 3389 double nm22 = cosX; 3390 // rotateY 3391 double nm00 = cosY; 3392 double nm01 = nm21 * m_sinY; 3393 double nm02 = nm22 * m_sinY; 3394 _m20(sinY). 3395 _m21(nm21 * cosY). 3396 _m22(nm22 * cosY). 3397 // rotateZ 3398 _m00(nm00 * cosZ). 3399 _m01(nm01 * cosZ + nm11 * sinZ). 3400 _m02(nm02 * cosZ + nm12 * sinZ). 3401 _m10(nm00 * m_sinZ). 3402 _m11(nm01 * m_sinZ + nm11 * cosZ). 3403 _m12(nm02 * m_sinZ + nm12 * cosZ). 3404 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3405 return this; 3406 } 3407 3408 /** 3409 * 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 3410 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis. 3411 * <p> 3412 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3413 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3414 * When used with a left-handed coordinate system, the rotation is clockwise. 3415 * 3416 * @param angleZ 3417 * the angle to rotate about Z 3418 * @param angleY 3419 * the angle to rotate about Y 3420 * @param angleX 3421 * the angle to rotate about X 3422 * @return this 3423 */ 3424 ref public Matrix4d setRotationZYX(double angleZ, double angleY, double angleX) return { 3425 double sinX = Math.sin(angleX); 3426 double cosX = Math.cosFromSin(sinX, angleX); 3427 double sinY = Math.sin(angleY); 3428 double cosY = Math.cosFromSin(sinY, angleY); 3429 double sinZ = Math.sin(angleZ); 3430 double cosZ = Math.cosFromSin(sinZ, angleZ); 3431 double m_sinZ = -sinZ; 3432 double m_sinY = -sinY; 3433 double m_sinX = -sinX; 3434 3435 // rotateZ 3436 double nm00 = cosZ; 3437 double nm01 = sinZ; 3438 double nm10 = m_sinZ; 3439 double nm11 = cosZ; 3440 // rotateY 3441 double nm20 = nm00 * sinY; 3442 double nm21 = nm01 * sinY; 3443 double nm22 = cosY; 3444 _m00(nm00 * cosY). 3445 _m01(nm01 * cosY). 3446 _m02(m_sinY). 3447 // rotateX 3448 _m10(nm10 * cosX + nm20 * sinX). 3449 _m11(nm11 * cosX + nm21 * sinX). 3450 _m12(nm22 * sinX). 3451 _m20(nm10 * m_sinX + nm20 * cosX). 3452 _m21(nm11 * m_sinX + nm21 * cosX). 3453 _m22(nm22 * cosX). 3454 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3455 return this; 3456 } 3457 3458 /** 3459 * 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 3460 * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3461 * <p> 3462 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3463 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3464 * When used with a left-handed coordinate system, the rotation is clockwise. 3465 * 3466 * @param angleY 3467 * the angle to rotate about Y 3468 * @param angleX 3469 * the angle to rotate about X 3470 * @param angleZ 3471 * the angle to rotate about Z 3472 * @return this 3473 */ 3474 ref public Matrix4d setRotationYXZ(double angleY, double angleX, double angleZ) return { 3475 double sinX = Math.sin(angleX); 3476 double cosX = Math.cosFromSin(sinX, angleX); 3477 double sinY = Math.sin(angleY); 3478 double cosY = Math.cosFromSin(sinY, angleY); 3479 double sinZ = Math.sin(angleZ); 3480 double cosZ = Math.cosFromSin(sinZ, angleZ); 3481 double m_sinY = -sinY; 3482 double m_sinX = -sinX; 3483 double m_sinZ = -sinZ; 3484 3485 // rotateY 3486 double nm00 = cosY; 3487 double nm02 = m_sinY; 3488 double nm20 = sinY; 3489 double nm22 = cosY; 3490 // rotateX 3491 double nm10 = nm20 * sinX; 3492 double nm11 = cosX; 3493 double nm12 = nm22 * sinX; 3494 _m20(nm20 * cosX). 3495 _m21(m_sinX). 3496 _m22(nm22 * cosX). 3497 // rotateZ 3498 _m00(nm00 * cosZ + nm10 * sinZ). 3499 _m01(nm11 * sinZ). 3500 _m02(nm02 * cosZ + nm12 * sinZ). 3501 _m10(nm00 * m_sinZ + nm10 * cosZ). 3502 _m11(nm11 * cosZ). 3503 _m12(nm02 * m_sinZ + nm12 * cosZ). 3504 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3505 return this; 3506 } 3507 3508 /** 3509 * Set this matrix to a rotation matrix which rotates the given radians about a given axis. 3510 * <p> 3511 * The axis described by the <code>axis</code> vector needs to be a unit vector. 3512 * <p> 3513 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3514 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3515 * When used with a left-handed coordinate system, the rotation is clockwise. 3516 * 3517 * @param angle 3518 * the angle in radians 3519 * @param axis 3520 * the axis to rotate about 3521 * @return this 3522 */ 3523 ref public Matrix4d rotation(double angle, Vector3d axis) return { 3524 return rotation(angle, axis.x, axis.y, axis.z); 3525 } 3526 3527 3528 public Vector4d transform(ref Vector4d v) { 3529 return v.mul(this); 3530 } 3531 3532 public Vector4d transform(ref Vector4d v, ref Vector4d dest) { 3533 return v.mul(this, dest); 3534 } 3535 3536 public Vector4d transform(double x, double y, double z, double w, ref Vector4d dest) { 3537 return dest.set(m00 * x + m10 * y + m20 * z + m30 * w, 3538 m01 * x + m11 * y + m21 * z + m31 * w, 3539 m02 * x + m12 * y + m22 * z + m32 * w, 3540 m03 * x + m13 * y + m23 * z + m33 * w); 3541 } 3542 3543 public Vector4d transformTranspose(ref Vector4d v) { 3544 return v.mulTranspose(this); 3545 } 3546 public Vector4d transformTranspose(ref Vector4d v, ref Vector4d dest) { 3547 return v.mulTranspose(this, dest); 3548 } 3549 public Vector4d transformTranspose(double x, double y, double z, double w, ref Vector4d dest) { 3550 return dest.set(x, y, z, w).mulTranspose(this); 3551 } 3552 3553 public Vector4d transformProject(ref Vector4d v) { 3554 return v.mulProject(this); 3555 } 3556 3557 public Vector4d transformProject(ref Vector4d v, ref Vector4d dest) { 3558 return v.mulProject(this, dest); 3559 } 3560 3561 public Vector4d transformProject(double x, double y, double z, double w, ref Vector4d dest) { 3562 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33 * w); 3563 return dest.set((m00 * x + m10 * y + m20 * z + m30 * w) * invW, 3564 (m01 * x + m11 * y + m21 * z + m31 * w) * invW, 3565 (m02 * x + m12 * y + m22 * z + m32 * w) * invW, 3566 1.0); 3567 } 3568 3569 public Vector3d transformProject(ref Vector3d v) { 3570 return v.mulProject(this); 3571 } 3572 3573 public Vector3d transformProject(ref Vector3d v, ref Vector3d dest) { 3574 return v.mulProject(this, dest); 3575 } 3576 3577 public Vector3d transformProject(double x, double y, double z, ref Vector3d dest) { 3578 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 3579 return dest.set((m00 * x + m10 * y + m20 * z + m30) * invW, 3580 (m01 * x + m11 * y + m21 * z + m31) * invW, 3581 (m02 * x + m12 * y + m22 * z + m32) * invW); 3582 } 3583 3584 public Vector3d transformProject(ref Vector4d v, ref Vector3d dest) { 3585 return v.mulProject(this, dest); 3586 } 3587 3588 public Vector3d transformProject(double x, double y, double z, double w, ref Vector3d dest) { 3589 dest.x = x; 3590 dest.y = y; 3591 dest.z = z; 3592 return dest.mulProject(this, w, dest); 3593 } 3594 3595 public Vector3d transformPosition(ref Vector3d dest) { 3596 return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z + m30, 3597 m01 * dest.x + m11 * dest.y + m21 * dest.z + m31, 3598 m02 * dest.x + m12 * dest.y + m22 * dest.z + m32); 3599 } 3600 3601 public Vector3d transformPosition(ref Vector3d v, ref Vector3d dest) { 3602 return transformPosition(v.x, v.y, v.z, dest); 3603 } 3604 3605 public Vector3d transformPosition(double x, double y, double z, ref Vector3d dest) { 3606 return dest.set(m00 * x + m10 * y + m20 * z + m30, 3607 m01 * x + m11 * y + m21 * z + m31, 3608 m02 * x + m12 * y + m22 * z + m32); 3609 } 3610 3611 public Vector3d transformDirection(ref Vector3d dest) { 3612 return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z, 3613 m01 * dest.x + m11 * dest.y + m21 * dest.z, 3614 m02 * dest.x + m12 * dest.y + m22 * dest.z); 3615 } 3616 3617 public Vector3d transformDirection(ref Vector3d v, ref Vector3d dest) { 3618 return dest.set(m00 * v.x + m10 * v.y + m20 * v.z, 3619 m01 * v.x + m11 * v.y + m21 * v.z, 3620 m02 * v.x + m12 * v.y + m22 * v.z); 3621 } 3622 3623 public Vector3d transformDirection(double x, double y, double z, ref Vector3d dest) { 3624 return dest.set(m00 * x + m10 * y + m20 * z, 3625 m01 * x + m11 * y + m21 * z, 3626 m02 * x + m12 * y + m22 * z); 3627 } 3628 3629 public Vector4d transformAffine(ref Vector4d dest) { 3630 return dest.mulAffine(this, dest); 3631 } 3632 3633 public Vector4d transformAffine(ref Vector4d v, ref Vector4d dest) { 3634 return transformAffine(v.x, v.y, v.z, v.w, dest); 3635 } 3636 3637 public Vector4d transformAffine(double x, double y, double z, double w, ref Vector4d dest) { 3638 double rx = m00 * x + m10 * y + m20 * z + m30 * w; 3639 double ry = m01 * x + m11 * y + m21 * z + m31 * w; 3640 double rz = m02 * x + m12 * y + m22 * z + m32 * w; 3641 dest.x = rx; 3642 dest.y = ry; 3643 dest.z = rz; 3644 dest.w = w; 3645 return dest; 3646 } 3647 3648 /** 3649 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3d} and don't change the other elements. 3650 * 3651 * @param mat 3652 * the 3x3 matrix 3653 * @return this 3654 */ 3655 ref public Matrix4d set3x3(Matrix3d mat) return { 3656 return 3657 _m00(mat.m00). 3658 _m01(mat.m01). 3659 _m02(mat.m02). 3660 _m10(mat.m10). 3661 _m11(mat.m11). 3662 _m12(mat.m12). 3663 _m20(mat.m20). 3664 _m21(mat.m21). 3665 _m22(mat.m22). 3666 _properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 3667 } 3668 3669 public Matrix4d scale(ref Vector3d xyz, ref Matrix4d dest) { 3670 return scale(xyz.x, xyz.y, xyz.z, dest); 3671 } 3672 3673 /** 3674 * Apply scaling to this matrix by scaling the base axes by the given <code>xyz.x</code>, 3675 * <code>xyz.y</code> and <code>xyz.z</code> factors, respectively. 3676 * <p> 3677 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3678 * then the new matrix will be <code>M * S</code>. So when transforming a 3679 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3680 * scaling will be applied first! 3681 * 3682 * @param xyz 3683 * the factors of the x, y and z component, respectively 3684 * @return this 3685 */ 3686 ref public Matrix4d scale(ref Vector3d xyz) return { 3687 scale(xyz.x, xyz.y, xyz.z, this); 3688 return this; 3689 } 3690 3691 public Matrix4d scale(double x, double y, double z, ref Matrix4d dest) { 3692 if ((properties & PROPERTY_IDENTITY) != 0) 3693 return dest.scaling(x, y, z); 3694 return scaleGeneric(x, y, z, dest); 3695 } 3696 private Matrix4d scaleGeneric(double x, double y, double z, ref Matrix4d dest) { 3697 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3698 dest._m00(m00 * x) 3699 ._m01(m01 * x) 3700 ._m02(m02 * x) 3701 ._m03(m03 * x) 3702 ._m10(m10 * y) 3703 ._m11(m11 * y) 3704 ._m12(m12 * y) 3705 ._m13(m13 * y) 3706 ._m20(m20 * z) 3707 ._m21(m21 * z) 3708 ._m22(m22 * z) 3709 ._m23(m23 * z) 3710 ._m30(m30) 3711 ._m31(m31) 3712 ._m32(m32) 3713 ._m33(m33) 3714 ._properties(properties 3715 & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL))); 3716 return dest; 3717 } 3718 3719 /** 3720 * Apply scaling to <code>this</code> matrix by scaling the base axes by the given x, 3721 * y and z factors. 3722 * <p> 3723 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3724 * then the new matrix will be <code>M * S</code>. So when transforming a 3725 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 3726 * , the scaling will be applied first! 3727 * 3728 * @param x 3729 * the factor of the x component 3730 * @param y 3731 * the factor of the y component 3732 * @param z 3733 * the factor of the z component 3734 * @return this 3735 */ 3736 ref public Matrix4d scale(double x, double y, double z) return { 3737 scale(x, y, z, this); 3738 return this; 3739 } 3740 3741 public Matrix4d scale(double xyz, ref Matrix4d dest) { 3742 return scale(xyz, xyz, xyz, dest); 3743 } 3744 3745 /** 3746 * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor. 3747 * <p> 3748 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3749 * then the new matrix will be <code>M * S</code>. So when transforming a 3750 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 3751 * , the scaling will be applied first! 3752 * 3753 * @see #scale(double, double, double) 3754 * 3755 * @param xyz 3756 * the factor for all components 3757 * @return this 3758 */ 3759 ref public Matrix4d scale(double xyz) return { 3760 return scale(xyz, xyz, xyz); 3761 } 3762 3763 public Matrix4d scaleXY(double x, double y, ref Matrix4d dest) { 3764 return scale(x, y, 1.0, dest); 3765 } 3766 3767 /** 3768 * Apply scaling to this matrix by scaling the X axis by <code>x</code> and the Y axis by <code>y</code>. 3769 * <p> 3770 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3771 * then the new matrix will be <code>M * S</code>. So when transforming a 3772 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3773 * scaling will be applied first! 3774 * 3775 * @param x 3776 * the factor of the x component 3777 * @param y 3778 * the factor of the y component 3779 * @return this 3780 */ 3781 ref public Matrix4d scaleXY(double x, double y) return { 3782 return scale(x, y, 1.0); 3783 } 3784 3785 public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4d dest) { 3786 double nm30 = m00 * ox + m10 * oy + m20 * oz + m30; 3787 double nm31 = m01 * ox + m11 * oy + m21 * oz + m31; 3788 double nm32 = m02 * ox + m12 * oy + m22 * oz + m32; 3789 double nm33 = m03 * ox + m13 * oy + m23 * oz + m33; 3790 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 3791 return dest 3792 ._m00(m00 * sx) 3793 ._m01(m01 * sx) 3794 ._m02(m02 * sx) 3795 ._m03(m03 * sx) 3796 ._m10(m10 * sy) 3797 ._m11(m11 * sy) 3798 ._m12(m12 * sy) 3799 ._m13(m13 * sy) 3800 ._m20(m20 * sz) 3801 ._m21(m21 * sz) 3802 ._m22(m22 * sz) 3803 ._m23(m23 * sz) 3804 ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30) 3805 ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31) 3806 ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32) 3807 ._m33(-dest.m03 * ox - dest.m13 * oy - dest.m23 * oz + nm33) 3808 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3809 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3810 } 3811 3812 /** 3813 * Apply scaling to this matrix by scaling the base axes by the given sx, 3814 * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin. 3815 * <p> 3816 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3817 * then the new matrix will be <code>M * S</code>. So when transforming a 3818 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3819 * scaling will be applied first! 3820 * <p> 3821 * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)</code> 3822 * 3823 * @param sx 3824 * the scaling factor of the x component 3825 * @param sy 3826 * the scaling factor of the y component 3827 * @param sz 3828 * the scaling factor of the z component 3829 * @param ox 3830 * the x coordinate of the scaling origin 3831 * @param oy 3832 * the y coordinate of the scaling origin 3833 * @param oz 3834 * the z coordinate of the scaling origin 3835 * @return this 3836 */ 3837 ref public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) return { 3838 scaleAround(sx, sy, sz, ox, oy, oz, this); 3839 return this; 3840 } 3841 3842 /** 3843 * Apply scaling to this matrix by scaling all three base axes by the given <code>factor</code> 3844 * while using <code>(ox, oy, oz)</code> as the scaling origin. 3845 * <p> 3846 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3847 * then the new matrix will be <code>M * S</code>. So when transforming a 3848 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3849 * scaling will be applied first! 3850 * <p> 3851 * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)</code> 3852 * 3853 * @param factor 3854 * the scaling factor for all three axes 3855 * @param ox 3856 * the x coordinate of the scaling origin 3857 * @param oy 3858 * the y coordinate of the scaling origin 3859 * @param oz 3860 * the z coordinate of the scaling origin 3861 * @return this 3862 */ 3863 ref public Matrix4d scaleAround(double factor, double ox, double oy, double oz) return { 3864 scaleAround(factor, factor, factor, ox, oy, oz, this); 3865 return this; 3866 } 3867 3868 public Matrix4d scaleAround(double factor, double ox, double oy, double oz, ref Matrix4d dest) { 3869 return scaleAround(factor, factor, factor, ox, oy, oz, dest); 3870 } 3871 3872 public Matrix4d scaleLocal(double x, double y, double z, ref Matrix4d dest) { 3873 if ((properties & PROPERTY_IDENTITY) != 0) 3874 return dest.scaling(x, y, z); 3875 return scaleLocalGeneric(x, y, z, dest); 3876 } 3877 private Matrix4d scaleLocalGeneric(double x, double y, double z, ref Matrix4d dest) { 3878 double nm00 = x * m00; 3879 double nm01 = y * m01; 3880 double nm02 = z * m02; 3881 double nm10 = x * m10; 3882 double nm11 = y * m11; 3883 double nm12 = z * m12; 3884 double nm20 = x * m20; 3885 double nm21 = y * m21; 3886 double nm22 = z * m22; 3887 double nm30 = x * m30; 3888 double nm31 = y * m31; 3889 double nm32 = z * m32; 3890 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3891 dest._m00(nm00) 3892 ._m01(nm01) 3893 ._m02(nm02) 3894 ._m03(m03) 3895 ._m10(nm10) 3896 ._m11(nm11) 3897 ._m12(nm12) 3898 ._m13(m13) 3899 ._m20(nm20) 3900 ._m21(nm21) 3901 ._m22(nm22) 3902 ._m23(m23) 3903 ._m30(nm30) 3904 ._m31(nm31) 3905 ._m32(nm32) 3906 ._m33(m33) 3907 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3908 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3909 return dest; 3910 } 3911 3912 public Matrix4d scaleLocal(double xyz, ref Matrix4d dest) { 3913 return scaleLocal(xyz, xyz, xyz, dest); 3914 } 3915 3916 /** 3917 * Pre-multiply scaling to this matrix by scaling the base axes by the given xyz factor. 3918 * <p> 3919 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3920 * then the new matrix will be <code>S * M</code>. So when transforming a 3921 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3922 * scaling will be applied last! 3923 * 3924 * @param xyz 3925 * the factor of the x, y and z component 3926 * @return this 3927 */ 3928 ref public Matrix4d scaleLocal(double xyz) return { 3929 scaleLocal(xyz, this); 3930 return this; 3931 } 3932 3933 /** 3934 * Pre-multiply scaling to this matrix by scaling the base axes by the given x, 3935 * y and z factors. 3936 * <p> 3937 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3938 * then the new matrix will be <code>S * M</code>. So when transforming a 3939 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3940 * scaling will be applied last! 3941 * 3942 * @param x 3943 * the factor of the x component 3944 * @param y 3945 * the factor of the y component 3946 * @param z 3947 * the factor of the z component 3948 * @return this 3949 */ 3950 ref public Matrix4d scaleLocal(double x, double y, double z) return { 3951 scaleLocal(x, y, z, this); 3952 return this; 3953 } 3954 3955 public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4d dest) { 3956 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 3957 dest._m00(sx * (m00 - ox * m03) + ox * m03) 3958 ._m01(sy * (m01 - oy * m03) + oy * m03) 3959 ._m02(sz * (m02 - oz * m03) + oz * m03) 3960 ._m03(m03) 3961 ._m10(sx * (m10 - ox * m13) + ox * m13) 3962 ._m11(sy * (m11 - oy * m13) + oy * m13) 3963 ._m12(sz * (m12 - oz * m13) + oz * m13) 3964 ._m13(m13) 3965 ._m20(sx * (m20 - ox * m23) + ox * m23) 3966 ._m21(sy * (m21 - oy * m23) + oy * m23) 3967 ._m22(sz * (m22 - oz * m23) + oz * m23) 3968 ._m23(m23) 3969 ._m30(sx * (m30 - ox * m33) + ox * m33) 3970 ._m31(sy * (m31 - oy * m33) + oy * m33) 3971 ._m32(sz * (m32 - oz * m33) + oz * m33) 3972 ._m33(m33) 3973 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3974 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3975 return dest; 3976 } 3977 3978 /** 3979 * Pre-multiply scaling to this matrix by scaling the base axes by the given sx, 3980 * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin. 3981 * <p> 3982 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3983 * then the new matrix will be <code>S * M</code>. So when transforming a 3984 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3985 * scaling will be applied last! 3986 * <p> 3987 * 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> 3988 * 3989 * @param sx 3990 * the scaling factor of the x component 3991 * @param sy 3992 * the scaling factor of the y component 3993 * @param sz 3994 * the scaling factor of the z component 3995 * @param ox 3996 * the x coordinate of the scaling origin 3997 * @param oy 3998 * the y coordinate of the scaling origin 3999 * @param oz 4000 * the z coordinate of the scaling origin 4001 * @return this 4002 */ 4003 ref public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz) return { 4004 scaleAroundLocal(sx, sy, sz, ox, oy, oz, this); 4005 return this; 4006 } 4007 4008 /** 4009 * Pre-multiply scaling to this matrix by scaling all three base axes by the given <code>factor</code> 4010 * while using <code>(ox, oy, oz)</code> as the scaling origin. 4011 * <p> 4012 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 4013 * then the new matrix will be <code>S * M</code>. So when transforming a 4014 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 4015 * scaling will be applied last! 4016 * <p> 4017 * This method is equivalent to calling: <code>new Matrix4d().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, this)</code> 4018 * 4019 * @param factor 4020 * the scaling factor for all three axes 4021 * @param ox 4022 * the x coordinate of the scaling origin 4023 * @param oy 4024 * the y coordinate of the scaling origin 4025 * @param oz 4026 * the z coordinate of the scaling origin 4027 * @return this 4028 */ 4029 ref public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz) return { 4030 scaleAroundLocal(factor, factor, factor, ox, oy, oz, this); 4031 return this; 4032 } 4033 4034 public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz, ref Matrix4d dest) { 4035 return scaleAroundLocal(factor, factor, factor, ox, oy, oz, dest); 4036 } 4037 4038 public Matrix4d rotate(double ang, double x, double y, double z, ref Matrix4d dest) { 4039 if ((properties & PROPERTY_IDENTITY) != 0) 4040 return dest.rotation(ang, x, y, z); 4041 else if ((properties & PROPERTY_TRANSLATION) != 0) 4042 return rotateTranslation(ang, x, y, z, dest); 4043 else if ((properties & PROPERTY_AFFINE) != 0) 4044 return rotateAffine(ang, x, y, z, dest); 4045 return rotateGeneric(ang, x, y, z, dest); 4046 } 4047 private Matrix4d rotateGeneric(double ang, double x, double y, double z, ref Matrix4d dest) { 4048 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4049 return rotateX(x * ang, dest); 4050 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4051 return rotateY(y * ang, dest); 4052 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4053 return rotateZ(z * ang, dest); 4054 return rotateGenericInternal(ang, x, y, z, dest); 4055 } 4056 private Matrix4d rotateGenericInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4057 double s = Math.sin(ang); 4058 double c = Math.cosFromSin(s, ang); 4059 double C = 1.0 - c; 4060 double xx = x * x, xy = x * y, xz = x * z; 4061 double yy = y * y, yz = y * z; 4062 double zz = z * z; 4063 double rm00 = xx * C + c; 4064 double rm01 = xy * C + z * s; 4065 double rm02 = xz * C - y * s; 4066 double rm10 = xy * C - z * s; 4067 double rm11 = yy * C + c; 4068 double rm12 = yz * C + x * s; 4069 double rm20 = xz * C + y * s; 4070 double rm21 = yz * C - x * s; 4071 double rm22 = zz * C + c; 4072 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4073 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4074 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4075 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 4076 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4077 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4078 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4079 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 4080 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4081 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4082 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4083 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 4084 ._m00(nm00) 4085 ._m01(nm01) 4086 ._m02(nm02) 4087 ._m03(nm03) 4088 ._m10(nm10) 4089 ._m11(nm11) 4090 ._m12(nm12) 4091 ._m13(nm13) 4092 ._m30(m30) 4093 ._m31(m31) 4094 ._m32(m32) 4095 ._m33(m33) 4096 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4097 return dest; 4098 } 4099 4100 /** 4101 * Apply rotation to this matrix by rotating the given amount of radians 4102 * about the given axis specified as x, y and z components. 4103 * <p> 4104 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4105 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4106 * When used with a left-handed coordinate system, the rotation is clockwise. 4107 * <p> 4108 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4109 * then the new matrix will be <code>M * R</code>. So when transforming a 4110 * vector <code>v</code> with the new matrix by using <code>M * R * v</code> 4111 * , the rotation will be applied first! 4112 * <p> 4113 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4114 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4115 * 4116 * @see #rotation(double, double, double, double) 4117 * 4118 * @param ang 4119 * the angle is in radians 4120 * @param x 4121 * the x component of the axis 4122 * @param y 4123 * the y component of the axis 4124 * @param z 4125 * the z component of the axis 4126 * @return this 4127 */ 4128 ref public Matrix4d rotate(double ang, double x, double y, double z) return { 4129 rotate(ang, x, y, z, this); 4130 return this; 4131 } 4132 4133 /** 4134 * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians 4135 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4136 * <p> 4137 * This method assumes <code>this</code> to only contain a translation. 4138 * <p> 4139 * The axis described by the three components needs to be a unit vector. 4140 * <p> 4141 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4142 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4143 * When used with a left-handed coordinate system, the rotation is clockwise. 4144 * <p> 4145 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4146 * then the new matrix will be <code>M * R</code>. So when transforming a 4147 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4148 * rotation will be applied first! 4149 * <p> 4150 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4151 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4152 * <p> 4153 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4154 * 4155 * @see #rotation(double, double, double, double) 4156 * 4157 * @param ang 4158 * the angle in radians 4159 * @param x 4160 * the x component of the axis 4161 * @param y 4162 * the y component of the axis 4163 * @param z 4164 * the z component of the axis 4165 * @param dest 4166 * will hold the result 4167 * @return dest 4168 */ 4169 public Matrix4d rotateTranslation(double ang, double x, double y, double z, ref Matrix4d dest) { 4170 double tx = m30, ty = m31, tz = m32; 4171 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4172 return dest.rotationX(x * ang).setTranslation(tx, ty, tz); 4173 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4174 return dest.rotationY(y * ang).setTranslation(tx, ty, tz); 4175 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4176 return dest.rotationZ(z * ang).setTranslation(tx, ty, tz); 4177 return rotateTranslationInternal(ang, x, y, z, dest); 4178 } 4179 private Matrix4d rotateTranslationInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4180 double s = Math.sin(ang); 4181 double c = Math.cosFromSin(s, ang); 4182 double C = 1.0 - c; 4183 double xx = x * x, xy = x * y, xz = x * z; 4184 double yy = y * y, yz = y * z; 4185 double zz = z * z; 4186 double rm00 = xx * C + c; 4187 double rm01 = xy * C + z * s; 4188 double rm02 = xz * C - y * s; 4189 double rm10 = xy * C - z * s; 4190 double rm11 = yy * C + c; 4191 double rm12 = yz * C + x * s; 4192 double rm20 = xz * C + y * s; 4193 double rm21 = yz * C - x * s; 4194 double rm22 = zz * C + c; 4195 return dest 4196 ._m20(rm20) 4197 ._m21(rm21) 4198 ._m22(rm22) 4199 ._m23(0.0) 4200 ._m00(rm00) 4201 ._m01(rm01) 4202 ._m02(rm02) 4203 ._m03(0.0) 4204 ._m10(rm10) 4205 ._m11(rm11) 4206 ._m12(rm12) 4207 ._m13(0.0) 4208 ._m30(m30) 4209 ._m31(m31) 4210 ._m32(m32) 4211 ._m33(1.0) 4212 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4213 } 4214 4215 /** 4216 * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians 4217 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4218 * <p> 4219 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 4220 * <p> 4221 * The axis described by the three components needs to be a unit vector. 4222 * <p> 4223 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4224 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4225 * When used with a left-handed coordinate system, the rotation is clockwise. 4226 * <p> 4227 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4228 * then the new matrix will be <code>M * R</code>. So when transforming a 4229 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4230 * rotation will be applied first! 4231 * <p> 4232 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4233 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4234 * <p> 4235 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4236 * 4237 * @see #rotation(double, double, double, double) 4238 * 4239 * @param ang 4240 * the angle in radians 4241 * @param x 4242 * the x component of the axis 4243 * @param y 4244 * the y component of the axis 4245 * @param z 4246 * the z component of the axis 4247 * @param dest 4248 * will hold the result 4249 * @return dest 4250 */ 4251 public Matrix4d rotateAffine(double ang, double x, double y, double z, ref Matrix4d dest) { 4252 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4253 return rotateX(x * ang, dest); 4254 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4255 return rotateY(y * ang, dest); 4256 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4257 return rotateZ(z * ang, dest); 4258 return rotateAffineInternal(ang, x, y, z, dest); 4259 } 4260 private Matrix4d rotateAffineInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4261 double s = Math.sin(ang); 4262 double c = Math.cosFromSin(s, ang); 4263 double C = 1.0 - c; 4264 double xx = x * x, xy = x * y, xz = x * z; 4265 double yy = y * y, yz = y * z; 4266 double zz = z * z; 4267 double rm00 = xx * C + c; 4268 double rm01 = xy * C + z * s; 4269 double rm02 = xz * C - y * s; 4270 double rm10 = xy * C - z * s; 4271 double rm11 = yy * C + c; 4272 double rm12 = yz * C + x * s; 4273 double rm20 = xz * C + y * s; 4274 double rm21 = yz * C - x * s; 4275 double rm22 = zz * C + c; 4276 // add temporaries for dependent values 4277 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4278 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4279 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4280 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4281 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4282 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4283 // set non-dependent values directly 4284 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4285 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4286 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4287 ._m23(0.0) 4288 // set other values 4289 ._m00(nm00) 4290 ._m01(nm01) 4291 ._m02(nm02) 4292 ._m03(0.0) 4293 ._m10(nm10) 4294 ._m11(nm11) 4295 ._m12(nm12) 4296 ._m13(0.0) 4297 ._m30(m30) 4298 ._m31(m31) 4299 ._m32(m32) 4300 ._m33(m33) 4301 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4302 return dest; 4303 } 4304 4305 /** 4306 * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians 4307 * about the specified <code>(x, y, z)</code> axis. 4308 * <p> 4309 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 4310 * <p> 4311 * The axis described by the three components needs to be a unit vector. 4312 * <p> 4313 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4314 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4315 * When used with a left-handed coordinate system, the rotation is clockwise. 4316 * <p> 4317 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4318 * then the new matrix will be <code>M * R</code>. So when transforming a 4319 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4320 * rotation will be applied first! 4321 * <p> 4322 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4323 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4324 * <p> 4325 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4326 * 4327 * @see #rotation(double, double, double, double) 4328 * 4329 * @param ang 4330 * the angle in radians 4331 * @param x 4332 * the x component of the axis 4333 * @param y 4334 * the y component of the axis 4335 * @param z 4336 * the z component of the axis 4337 * @return this 4338 */ 4339 ref public Matrix4d rotateAffine(double ang, double x, double y, double z) return { 4340 rotateAffine(ang, x, y, z, this); 4341 return this; 4342 } 4343 4344 /** 4345 * Apply the rotation transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> as the rotation origin. 4346 * <p> 4347 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4348 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4349 * When used with a left-handed coordinate system, the rotation is clockwise. 4350 * <p> 4351 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 4352 * then the new matrix will be <code>M * Q</code>. So when transforming a 4353 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 4354 * the quaternion rotation will be applied first! 4355 * <p> 4356 * This method is equivalent to calling: <code>translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code> 4357 * <p> 4358 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4359 * 4360 * @param quat 4361 * the {@link Quaterniond} 4362 * @param ox 4363 * the x coordinate of the rotation origin 4364 * @param oy 4365 * the y coordinate of the rotation origin 4366 * @param oz 4367 * the z coordinate of the rotation origin 4368 * @return this 4369 */ 4370 ref public Matrix4d rotateAround(ref Quaterniond quat, double ox, double oy, double oz) return { 4371 rotateAround(quat, ox, oy, oz, this); 4372 return this; 4373 } 4374 4375 public Matrix4d rotateAroundAffine(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4376 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4377 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4378 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4379 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4380 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4381 double rm00 = w2 + x2 - z2 - y2; 4382 double rm01 = dxy + dzw; 4383 double rm02 = dxz - dyw; 4384 double rm10 = -dzw + dxy; 4385 double rm11 = y2 - z2 + w2 - x2; 4386 double rm12 = dyz + dxw; 4387 double rm20 = dyw + dxz; 4388 double rm21 = dyz - dxw; 4389 double rm22 = z2 - y2 - x2 + w2; 4390 double tm30 = m00 * ox + m10 * oy + m20 * oz + m30; 4391 double tm31 = m01 * ox + m11 * oy + m21 * oz + m31; 4392 double tm32 = m02 * ox + m12 * oy + m22 * oz + m32; 4393 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4394 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4395 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4396 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4397 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4398 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4399 dest 4400 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4401 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4402 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4403 ._m23(0.0) 4404 ._m00(nm00) 4405 ._m01(nm01) 4406 ._m02(nm02) 4407 ._m03(0.0) 4408 ._m10(nm10) 4409 ._m11(nm11) 4410 ._m12(nm12) 4411 ._m13(0.0) 4412 ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30) 4413 ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31) 4414 ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32) 4415 ._m33(1.0) 4416 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4417 return dest; 4418 } 4419 4420 public Matrix4d rotateAround(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4421 if ((properties & PROPERTY_IDENTITY) != 0) 4422 return rotationAround(quat, ox, oy, oz); 4423 else if ((properties & PROPERTY_AFFINE) != 0) 4424 return rotateAroundAffine(quat, ox, oy, oz, this); 4425 return rotateAroundGeneric(quat, ox, oy, oz, this); 4426 } 4427 private Matrix4d rotateAroundGeneric(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4428 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4429 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4430 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4431 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4432 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4433 double rm00 = w2 + x2 - z2 - y2; 4434 double rm01 = dxy + dzw; 4435 double rm02 = dxz - dyw; 4436 double rm10 = -dzw + dxy; 4437 double rm11 = y2 - z2 + w2 - x2; 4438 double rm12 = dyz + dxw; 4439 double rm20 = dyw + dxz; 4440 double rm21 = dyz - dxw; 4441 double rm22 = z2 - y2 - x2 + w2; 4442 double tm30 = m00 * ox + m10 * oy + m20 * oz + m30; 4443 double tm31 = m01 * ox + m11 * oy + m21 * oz + m31; 4444 double tm32 = m02 * ox + m12 * oy + m22 * oz + m32; 4445 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4446 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4447 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4448 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 4449 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4450 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4451 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4452 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 4453 dest 4454 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4455 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4456 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4457 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 4458 ._m00(nm00) 4459 ._m01(nm01) 4460 ._m02(nm02) 4461 ._m03(nm03) 4462 ._m10(nm10) 4463 ._m11(nm11) 4464 ._m12(nm12) 4465 ._m13(nm13) 4466 ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30) 4467 ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31) 4468 ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32) 4469 ._m33(m33) 4470 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4471 return dest; 4472 } 4473 4474 /** 4475 * 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. 4476 * <p> 4477 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4478 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4479 * When used with a left-handed coordinate system, the rotation is clockwise. 4480 * <p> 4481 * This method is equivalent to calling: <code>translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code> 4482 * <p> 4483 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4484 * 4485 * @param quat 4486 * the {@link Quaterniond} 4487 * @param ox 4488 * the x coordinate of the rotation origin 4489 * @param oy 4490 * the y coordinate of the rotation origin 4491 * @param oz 4492 * the z coordinate of the rotation origin 4493 * @return this 4494 */ 4495 ref public Matrix4d rotationAround(ref Quaterniond quat, double ox, double oy, double oz) return { 4496 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4497 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4498 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4499 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4500 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4501 this._m20(dyw + dxz); 4502 this._m21(dyz - dxw); 4503 this._m22(z2 - y2 - x2 + w2); 4504 this._m23(0.0); 4505 this._m00(w2 + x2 - z2 - y2); 4506 this._m01(dxy + dzw); 4507 this._m02(dxz - dyw); 4508 this._m03(0.0); 4509 this._m10(-dzw + dxy); 4510 this._m11(y2 - z2 + w2 - x2); 4511 this._m12(dyz + dxw); 4512 this._m13(0.0); 4513 this._m30(-m00 * ox - m10 * oy - m20 * oz + ox); 4514 this._m31(-m01 * ox - m11 * oy - m21 * oz + oy); 4515 this._m32(-m02 * ox - m12 * oy - m22 * oz + oz); 4516 this._m33(1.0); 4517 this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 4518 return this; 4519 } 4520 4521 /** 4522 * Pre-multiply a rotation to this matrix by rotating the given amount of radians 4523 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4524 * <p> 4525 * The axis described by the three components needs to be a unit vector. 4526 * <p> 4527 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4528 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4529 * When used with a left-handed coordinate system, the rotation is clockwise. 4530 * <p> 4531 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4532 * then the new matrix will be <code>R * M</code>. So when transforming a 4533 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 4534 * rotation will be applied last! 4535 * <p> 4536 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 4537 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4538 * <p> 4539 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4540 * 4541 * @see #rotation(double, double, double, double) 4542 * 4543 * @param ang 4544 * the angle in radians 4545 * @param x 4546 * the x component of the axis 4547 * @param y 4548 * the y component of the axis 4549 * @param z 4550 * the z component of the axis 4551 * @param dest 4552 * will hold the result 4553 * @return dest 4554 */ 4555 public Matrix4d rotateLocal(double ang, double x, double y, double z, ref Matrix4d dest) { 4556 if ((properties & PROPERTY_IDENTITY) != 0) 4557 return dest.rotation(ang, x, y, z); 4558 return rotateLocalGeneric(ang, x, y, z, dest); 4559 } 4560 private Matrix4d rotateLocalGeneric(double ang, double x, double y, double z, ref Matrix4d dest) { 4561 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4562 return rotateLocalX(x * ang, dest); 4563 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4564 return rotateLocalY(y * ang, dest); 4565 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4566 return rotateLocalZ(z * ang, dest); 4567 return rotateLocalGenericInternal(ang, x, y, z, dest); 4568 } 4569 private Matrix4d rotateLocalGenericInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4570 double s = Math.sin(ang); 4571 double c = Math.cosFromSin(s, ang); 4572 double C = 1.0 - c; 4573 double xx = x * x, xy = x * y, xz = x * z; 4574 double yy = y * y, yz = y * z; 4575 double zz = z * z; 4576 double lm00 = xx * C + c; 4577 double lm01 = xy * C + z * s; 4578 double lm02 = xz * C - y * s; 4579 double lm10 = xy * C - z * s; 4580 double lm11 = yy * C + c; 4581 double lm12 = yz * C + x * s; 4582 double lm20 = xz * C + y * s; 4583 double lm21 = yz * C - x * s; 4584 double lm22 = zz * C + c; 4585 double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; 4586 double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; 4587 double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; 4588 double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; 4589 double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; 4590 double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; 4591 double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; 4592 double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; 4593 double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; 4594 double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32; 4595 double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32; 4596 double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32; 4597 dest._m00(nm00) 4598 ._m01(nm01) 4599 ._m02(nm02) 4600 ._m03(m03) 4601 ._m10(nm10) 4602 ._m11(nm11) 4603 ._m12(nm12) 4604 ._m13(m13) 4605 ._m20(nm20) 4606 ._m21(nm21) 4607 ._m22(nm22) 4608 ._m23(m23) 4609 ._m30(nm30) 4610 ._m31(nm31) 4611 ._m32(nm32) 4612 ._m33(m33) 4613 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4614 return dest; 4615 } 4616 4617 /** 4618 * Pre-multiply a rotation to this matrix by rotating the given amount of radians 4619 * about the specified <code>(x, y, z)</code> axis. 4620 * <p> 4621 * The axis described by the three components needs to be a unit vector. 4622 * <p> 4623 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4624 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4625 * When used with a left-handed coordinate system, the rotation is clockwise. 4626 * <p> 4627 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4628 * then the new matrix will be <code>R * M</code>. So when transforming a 4629 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 4630 * rotation will be applied last! 4631 * <p> 4632 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 4633 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4634 * <p> 4635 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4636 * 4637 * @see #rotation(double, double, double, double) 4638 * 4639 * @param ang 4640 * the angle in radians 4641 * @param x 4642 * the x component of the axis 4643 * @param y 4644 * the y component of the axis 4645 * @param z 4646 * the z component of the axis 4647 * @return this 4648 */ 4649 ref public Matrix4d rotateLocal(double ang, double x, double y, double z) return { 4650 rotateLocal(ang, x, y, z, this); 4651 return this; 4652 } 4653 4654 public Matrix4d rotateAroundLocal(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4655 double w2 = quat.w * quat.w; 4656 double x2 = quat.x * quat.x; 4657 double y2 = quat.y * quat.y; 4658 double z2 = quat.z * quat.z; 4659 double zw = quat.z * quat.w; 4660 double xy = quat.x * quat.y; 4661 double xz = quat.x * quat.z; 4662 double yw = quat.y * quat.w; 4663 double yz = quat.y * quat.z; 4664 double xw = quat.x * quat.w; 4665 double lm00 = w2 + x2 - z2 - y2; 4666 double lm01 = xy + zw + zw + xy; 4667 double lm02 = xz - yw + xz - yw; 4668 double lm10 = -zw + xy - zw + xy; 4669 double lm11 = y2 - z2 + w2 - x2; 4670 double lm12 = yz + yz + xw + xw; 4671 double lm20 = yw + xz + xz + yw; 4672 double lm21 = yz + yz - xw - xw; 4673 double lm22 = z2 - y2 - x2 + w2; 4674 double tm00 = m00 - ox * m03; 4675 double tm01 = m01 - oy * m03; 4676 double tm02 = m02 - oz * m03; 4677 double tm10 = m10 - ox * m13; 4678 double tm11 = m11 - oy * m13; 4679 double tm12 = m12 - oz * m13; 4680 double tm20 = m20 - ox * m23; 4681 double tm21 = m21 - oy * m23; 4682 double tm22 = m22 - oz * m23; 4683 double tm30 = m30 - ox * m33; 4684 double tm31 = m31 - oy * m33; 4685 double tm32 = m32 - oz * m33; 4686 dest._m00(lm00 * tm00 + lm10 * tm01 + lm20 * tm02 + ox * m03) 4687 ._m01(lm01 * tm00 + lm11 * tm01 + lm21 * tm02 + oy * m03) 4688 ._m02(lm02 * tm00 + lm12 * tm01 + lm22 * tm02 + oz * m03) 4689 ._m03(m03) 4690 ._m10(lm00 * tm10 + lm10 * tm11 + lm20 * tm12 + ox * m13) 4691 ._m11(lm01 * tm10 + lm11 * tm11 + lm21 * tm12 + oy * m13) 4692 ._m12(lm02 * tm10 + lm12 * tm11 + lm22 * tm12 + oz * m13) 4693 ._m13(m13) 4694 ._m20(lm00 * tm20 + lm10 * tm21 + lm20 * tm22 + ox * m23) 4695 ._m21(lm01 * tm20 + lm11 * tm21 + lm21 * tm22 + oy * m23) 4696 ._m22(lm02 * tm20 + lm12 * tm21 + lm22 * tm22 + oz * m23) 4697 ._m23(m23) 4698 ._m30(lm00 * tm30 + lm10 * tm31 + lm20 * tm32 + ox * m33) 4699 ._m31(lm01 * tm30 + lm11 * tm31 + lm21 * tm32 + oy * m33) 4700 ._m32(lm02 * tm30 + lm12 * tm31 + lm22 * tm32 + oz * m33) 4701 ._m33(m33) 4702 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4703 return dest; 4704 } 4705 4706 /** 4707 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> 4708 * as the rotation origin. 4709 * <p> 4710 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4711 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4712 * When used with a left-handed coordinate system, the rotation is clockwise. 4713 * <p> 4714 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 4715 * then the new matrix will be <code>Q * M</code>. So when transforming a 4716 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 4717 * the quaternion rotation will be applied last! 4718 * <p> 4719 * This method is equivalent to calling: <code>translateLocal(-ox, -oy, -oz).rotateLocal(quat).translateLocal(ox, oy, oz)</code> 4720 * <p> 4721 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4722 * 4723 * @param quat 4724 * the {@link Quaterniond} 4725 * @param ox 4726 * the x coordinate of the rotation origin 4727 * @param oy 4728 * the y coordinate of the rotation origin 4729 * @param oz 4730 * the z coordinate of the rotation origin 4731 * @return this 4732 */ 4733 ref public Matrix4d rotateAroundLocal(ref Quaterniond quat, double ox, double oy, double oz) return { 4734 rotateAroundLocal(quat, ox, oy, oz, this); 4735 return this; 4736 } 4737 4738 /** 4739 * Apply a translation to this matrix by translating by the given number of 4740 * units in x, y and z. 4741 * <p> 4742 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4743 * matrix, then the new matrix will be <code>M * T</code>. So when 4744 * transforming a vector <code>v</code> with the new matrix by using 4745 * <code>M * T * v</code>, the translation will be applied first! 4746 * <p> 4747 * In order to set the matrix to a translation transformation without post-multiplying 4748 * it, use {@link #translation(ref Vector3d)}. 4749 * 4750 * @see #translation(ref Vector3d) 4751 * 4752 * @param offset 4753 * the number of units in x, y and z by which to translate 4754 * @return this 4755 */ 4756 ref public Matrix4d translate(ref Vector3d offset) return { 4757 return translate(offset.x, offset.y, offset.z); 4758 } 4759 4760 /** 4761 * Apply a translation to this matrix by translating by the given number of 4762 * units in x, y and z and store the result in <code>dest</code>. 4763 * <p> 4764 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4765 * matrix, then the new matrix will be <code>M * T</code>. So when 4766 * transforming a vector <code>v</code> with the new matrix by using 4767 * <code>M * T * v</code>, the translation will be applied first! 4768 * <p> 4769 * In order to set the matrix to a translation transformation without post-multiplying 4770 * it, use {@link #translation(ref Vector3d)}. 4771 * 4772 * @see #translation(ref Vector3d) 4773 * 4774 * @param offset 4775 * the number of units in x, y and z by which to translate 4776 * @param dest 4777 * will hold the result 4778 * @return dest 4779 */ 4780 public Matrix4d translate(ref Vector3d offset, ref Matrix4d dest) { 4781 return translate(offset.x, offset.y, offset.z, dest); 4782 } 4783 4784 4785 4786 /** 4787 * Apply a translation to this matrix by translating by the given number of 4788 * units in x, y and z and store the result in <code>dest</code>. 4789 * <p> 4790 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4791 * matrix, then the new matrix will be <code>M * T</code>. So when 4792 * transforming a vector <code>v</code> with the new matrix by using 4793 * <code>M * T * v</code>, the translation will be applied first! 4794 * <p> 4795 * In order to set the matrix to a translation transformation without post-multiplying 4796 * it, use {@link #translation(double, double, double)}. 4797 * 4798 * @see #translation(double, double, double) 4799 * 4800 * @param x 4801 * the offset to translate in x 4802 * @param y 4803 * the offset to translate in y 4804 * @param z 4805 * the offset to translate in z 4806 * @param dest 4807 * will hold the result 4808 * @return dest 4809 */ 4810 public Matrix4d translate(double x, double y, double z, ref Matrix4d dest) { 4811 if ((properties & PROPERTY_IDENTITY) != 0) 4812 return dest.translation(x, y, z); 4813 return translateGeneric(x, y, z, dest); 4814 } 4815 private Matrix4d translateGeneric(double x, double y, double z, ref Matrix4d dest) { 4816 dest._m00(m00) 4817 ._m01(m01) 4818 ._m02(m02) 4819 ._m03(m03) 4820 ._m10(m10) 4821 ._m11(m11) 4822 ._m12(m12) 4823 ._m13(m13) 4824 ._m20(m20) 4825 ._m21(m21) 4826 ._m22(m22) 4827 ._m23(m23) 4828 ._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30)))) 4829 ._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31)))) 4830 ._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32)))) 4831 ._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)))) 4832 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY)); 4833 return dest; 4834 } 4835 4836 /** 4837 * Apply a translation to this matrix by translating by the given number of 4838 * units in x, y and z. 4839 * <p> 4840 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4841 * matrix, then the new matrix will be <code>M * T</code>. So when 4842 * transforming a vector <code>v</code> with the new matrix by using 4843 * <code>M * T * v</code>, the translation will be applied first! 4844 * <p> 4845 * In order to set the matrix to a translation transformation without post-multiplying 4846 * it, use {@link #translation(double, double, double)}. 4847 * 4848 * @see #translation(double, double, double) 4849 * 4850 * @param x 4851 * the offset to translate in x 4852 * @param y 4853 * the offset to translate in y 4854 * @param z 4855 * the offset to translate in z 4856 * @return this 4857 */ 4858 ref public Matrix4d translate(double x, double y, double z) return { 4859 if ((properties & PROPERTY_IDENTITY) != 0) 4860 return translation(x, y, z); 4861 this._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30)))); 4862 this._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31)))); 4863 this._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32)))); 4864 this._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)))); 4865 this.properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY); 4866 return this; 4867 } 4868 4869 /** 4870 * Pre-multiply a translation to this matrix by translating by the given number of 4871 * units in x, y and z. 4872 * <p> 4873 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4874 * matrix, then the new matrix will be <code>T * M</code>. So when 4875 * transforming a vector <code>v</code> with the new matrix by using 4876 * <code>T * M * v</code>, the translation will be applied last! 4877 * <p> 4878 * In order to set the matrix to a translation transformation without pre-multiplying 4879 * it, use {@link #translation(ref Vector3d)}. 4880 * 4881 * @see #translation(ref Vector3d) 4882 * 4883 * @param offset 4884 * the number of units in x, y and z by which to translate 4885 * @return this 4886 */ 4887 ref public Matrix4d translateLocal(ref Vector3d offset) return { 4888 return translateLocal(offset.x, offset.y, offset.z); 4889 } 4890 4891 /** 4892 * Pre-multiply a translation to this matrix by translating by the given number of 4893 * units in x, y and z and store the result in <code>dest</code>. 4894 * <p> 4895 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4896 * matrix, then the new matrix will be <code>T * M</code>. So when 4897 * transforming a vector <code>v</code> with the new matrix by using 4898 * <code>T * M * v</code>, the translation will be applied last! 4899 * <p> 4900 * In order to set the matrix to a translation transformation without pre-multiplying 4901 * it, use {@link #translation(ref Vector3d)}. 4902 * 4903 * @see #translation(ref Vector3d) 4904 * 4905 * @param offset 4906 * the number of units in x, y and z by which to translate 4907 * @param dest 4908 * will hold the result 4909 * @return dest 4910 */ 4911 public Matrix4d translateLocal(ref Vector3d offset, ref Matrix4d dest) { 4912 return translateLocal(offset.x, offset.y, offset.z, dest); 4913 } 4914 4915 /** 4916 * Pre-multiply a translation to this matrix by translating by the given number of 4917 * units in x, y and z and store the result in <code>dest</code>. 4918 * <p> 4919 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4920 * matrix, then the new matrix will be <code>T * M</code>. So when 4921 * transforming a vector <code>v</code> with the new matrix by using 4922 * <code>T * M * v</code>, the translation will be applied last! 4923 * <p> 4924 * In order to set the matrix to a translation transformation without pre-multiplying 4925 * it, use {@link #translation(double, double, double)}. 4926 * 4927 * @see #translation(double, double, double) 4928 * 4929 * @param x 4930 * the offset to translate in x 4931 * @param y 4932 * the offset to translate in y 4933 * @param z 4934 * the offset to translate in z 4935 * @param dest 4936 * will hold the result 4937 * @return dest 4938 */ 4939 public Matrix4d translateLocal(double x, double y, double z, ref Matrix4d dest) { 4940 if ((properties & PROPERTY_IDENTITY) != 0) 4941 return dest.translation(x, y, z); 4942 return translateLocalGeneric(x, y, z, dest); 4943 } 4944 private Matrix4d translateLocalGeneric(double x, double y, double z, ref Matrix4d dest) { 4945 double nm00 = m00 + x * m03; 4946 double nm01 = m01 + y * m03; 4947 double nm02 = m02 + z * m03; 4948 double nm10 = m10 + x * m13; 4949 double nm11 = m11 + y * m13; 4950 double nm12 = m12 + z * m13; 4951 double nm20 = m20 + x * m23; 4952 double nm21 = m21 + y * m23; 4953 double nm22 = m22 + z * m23; 4954 double nm30 = m30 + x * m33; 4955 double nm31 = m31 + y * m33; 4956 double nm32 = m32 + z * m33; 4957 return dest 4958 ._m00(nm00) 4959 ._m01(nm01) 4960 ._m02(nm02) 4961 ._m03(m03) 4962 ._m10(nm10) 4963 ._m11(nm11) 4964 ._m12(nm12) 4965 ._m13(m13) 4966 ._m20(nm20) 4967 ._m21(nm21) 4968 ._m22(nm22) 4969 ._m23(m23) 4970 ._m30(nm30) 4971 ._m31(nm31) 4972 ._m32(nm32) 4973 ._m33(m33) 4974 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY)); 4975 } 4976 4977 /** 4978 * Pre-multiply a translation to this matrix by translating by the given number of 4979 * units in x, y and z. 4980 * <p> 4981 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4982 * matrix, then the new matrix will be <code>T * M</code>. So when 4983 * transforming a vector <code>v</code> with the new matrix by using 4984 * <code>T * M * v</code>, the translation will be applied last! 4985 * <p> 4986 * In order to set the matrix to a translation transformation without pre-multiplying 4987 * it, use {@link #translation(double, double, double)}. 4988 * 4989 * @see #translation(double, double, double) 4990 * 4991 * @param x 4992 * the offset to translate in x 4993 * @param y 4994 * the offset to translate in y 4995 * @param z 4996 * the offset to translate in z 4997 * @return this 4998 */ 4999 ref public Matrix4d translateLocal(double x, double y, double z) return { 5000 translateLocal(x, y, z, this); 5001 return this; 5002 } 5003 5004 /** 5005 * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians 5006 * about the X axis and store the result in <code>dest</code>. 5007 * <p> 5008 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5009 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5010 * When used with a left-handed coordinate system, the rotation is clockwise. 5011 * <p> 5012 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5013 * then the new matrix will be <code>R * M</code>. So when transforming a 5014 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5015 * rotation will be applied last! 5016 * <p> 5017 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5018 * transformation, use {@link #rotationX(double) rotationX()}. 5019 * <p> 5020 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5021 * 5022 * @see #rotationX(double) 5023 * 5024 * @param ang 5025 * the angle in radians to rotate about the X axis 5026 * @param dest 5027 * will hold the result 5028 * @return dest 5029 */ 5030 public Matrix4d rotateLocalX(double ang, ref Matrix4d dest) { 5031 double sin = Math.sin(ang); 5032 double cos = Math.cosFromSin(sin, ang); 5033 double nm02 = sin * m01 + cos * m02; 5034 double nm12 = sin * m11 + cos * m12; 5035 double nm22 = sin * m21 + cos * m22; 5036 double nm32 = sin * m31 + cos * m32; 5037 dest 5038 ._m00(m00) 5039 ._m01(cos * m01 - sin * m02) 5040 ._m02(nm02) 5041 ._m03(m03) 5042 ._m10(m10) 5043 ._m11(cos * m11 - sin * m12) 5044 ._m12(nm12) 5045 ._m13(m13) 5046 ._m20(m20) 5047 ._m21(cos * m21 - sin * m22) 5048 ._m22(nm22) 5049 ._m23(m23) 5050 ._m30(m30) 5051 ._m31(cos * m31 - sin * m32) 5052 ._m32(nm32) 5053 ._m33(m33) 5054 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5055 return dest; 5056 } 5057 5058 /** 5059 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis. 5060 * <p> 5061 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5062 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5063 * When used with a left-handed coordinate system, the rotation is clockwise. 5064 * <p> 5065 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5066 * then the new matrix will be <code>R * M</code>. So when transforming a 5067 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5068 * rotation will be applied last! 5069 * <p> 5070 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5071 * transformation, use {@link #rotationX(double) rotationX()}. 5072 * <p> 5073 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5074 * 5075 * @see #rotationX(double) 5076 * 5077 * @param ang 5078 * the angle in radians to rotate about the X axis 5079 * @return this 5080 */ 5081 ref public Matrix4d rotateLocalX(double ang) return { 5082 rotateLocalX(ang, this); 5083 return this; 5084 } 5085 5086 /** 5087 * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians 5088 * about the Y axis and store the result in <code>dest</code>. 5089 * <p> 5090 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5091 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5092 * When used with a left-handed coordinate system, the rotation is clockwise. 5093 * <p> 5094 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5095 * then the new matrix will be <code>R * M</code>. So when transforming a 5096 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5097 * rotation will be applied last! 5098 * <p> 5099 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5100 * transformation, use {@link #rotationY(double) rotationY()}. 5101 * <p> 5102 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5103 * 5104 * @see #rotationY(double) 5105 * 5106 * @param ang 5107 * the angle in radians to rotate about the Y axis 5108 * @param dest 5109 * will hold the result 5110 * @return dest 5111 */ 5112 public Matrix4d rotateLocalY(double ang, ref Matrix4d dest) { 5113 double sin = Math.sin(ang); 5114 double cos = Math.cosFromSin(sin, ang); 5115 double nm02 = -sin * m00 + cos * m02; 5116 double nm12 = -sin * m10 + cos * m12; 5117 double nm22 = -sin * m20 + cos * m22; 5118 double nm32 = -sin * m30 + cos * m32; 5119 dest 5120 ._m00(cos * m00 + sin * m02) 5121 ._m01(m01) 5122 ._m02(nm02) 5123 ._m03(m03) 5124 ._m10(cos * m10 + sin * m12) 5125 ._m11(m11) 5126 ._m12(nm12) 5127 ._m13(m13) 5128 ._m20(cos * m20 + sin * m22) 5129 ._m21(m21) 5130 ._m22(nm22) 5131 ._m23(m23) 5132 ._m30(cos * m30 + sin * m32) 5133 ._m31(m31) 5134 ._m32(nm32) 5135 ._m33(m33) 5136 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5137 return dest; 5138 } 5139 5140 /** 5141 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis. 5142 * <p> 5143 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5144 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5145 * When used with a left-handed coordinate system, the rotation is clockwise. 5146 * <p> 5147 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5148 * then the new matrix will be <code>R * M</code>. So when transforming a 5149 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5150 * rotation will be applied last! 5151 * <p> 5152 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5153 * transformation, use {@link #rotationY(double) rotationY()}. 5154 * <p> 5155 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5156 * 5157 * @see #rotationY(double) 5158 * 5159 * @param ang 5160 * the angle in radians to rotate about the Y axis 5161 * @return this 5162 */ 5163 ref public Matrix4d rotateLocalY(double ang) return { 5164 rotateLocalY(ang, this); 5165 return this; 5166 } 5167 5168 /** 5169 * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians 5170 * about the Z axis and store the result in <code>dest</code>. 5171 * <p> 5172 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5173 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5174 * When used with a left-handed coordinate system, the rotation is clockwise. 5175 * <p> 5176 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5177 * then the new matrix will be <code>R * M</code>. So when transforming a 5178 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5179 * rotation will be applied last! 5180 * <p> 5181 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5182 * transformation, use {@link #rotationZ(double) rotationZ()}. 5183 * <p> 5184 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5185 * 5186 * @see #rotationZ(double) 5187 * 5188 * @param ang 5189 * the angle in radians to rotate about the Z axis 5190 * @param dest 5191 * will hold the result 5192 * @return dest 5193 */ 5194 public Matrix4d rotateLocalZ(double ang, ref Matrix4d dest) { 5195 double sin = Math.sin(ang); 5196 double cos = Math.cosFromSin(sin, ang); 5197 double nm01 = sin * m00 + cos * m01; 5198 double nm11 = sin * m10 + cos * m11; 5199 double nm21 = sin * m20 + cos * m21; 5200 double nm31 = sin * m30 + cos * m31; 5201 dest 5202 ._m00(cos * m00 - sin * m01) 5203 ._m01(nm01) 5204 ._m02(m02) 5205 ._m03(m03) 5206 ._m10(cos * m10 - sin * m11) 5207 ._m11(nm11) 5208 ._m12(m12) 5209 ._m13(m13) 5210 ._m20(cos * m20 - sin * m21) 5211 ._m21(nm21) 5212 ._m22(m22) 5213 ._m23(m23) 5214 ._m30(cos * m30 - sin * m31) 5215 ._m31(nm31) 5216 ._m32(m32) 5217 ._m33(m33) 5218 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5219 return dest; 5220 } 5221 5222 /** 5223 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis. 5224 * <p> 5225 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5226 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5227 * When used with a left-handed coordinate system, the rotation is clockwise. 5228 * <p> 5229 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5230 * then the new matrix will be <code>R * M</code>. So when transforming a 5231 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5232 * rotation will be applied last! 5233 * <p> 5234 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5235 * transformation, use {@link #rotationZ(double) rotationY()}. 5236 * <p> 5237 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5238 * 5239 * @see #rotationY(double) 5240 * 5241 * @param ang 5242 * the angle in radians to rotate about the Z axis 5243 * @return this 5244 */ 5245 ref public Matrix4d rotateLocalZ(double ang) return { 5246 rotateLocalZ(ang, this); 5247 return this; 5248 } 5249 5250 public Matrix4d rotateX(double ang, ref Matrix4d dest) { 5251 if ((properties & PROPERTY_IDENTITY) != 0) 5252 return dest.rotationX(ang); 5253 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5254 double x = m30, y = m31, z = m32; 5255 return dest.rotationX(ang).setTranslation(x, y, z); 5256 } 5257 return rotateXInternal(ang, dest); 5258 } 5259 private Matrix4d rotateXInternal(double ang, ref Matrix4d dest) { 5260 double sin, cos; 5261 sin = Math.sin(ang); 5262 cos = Math.cosFromSin(sin, ang); 5263 double rm11 = cos; 5264 double rm12 = sin; 5265 double rm21 = -sin; 5266 double rm22 = cos; 5267 5268 // add temporaries for dependent values 5269 double nm10 = m10 * rm11 + m20 * rm12; 5270 double nm11 = m11 * rm11 + m21 * rm12; 5271 double nm12 = m12 * rm11 + m22 * rm12; 5272 double nm13 = m13 * rm11 + m23 * rm12; 5273 // set non-dependent values directly 5274 dest._m20(m10 * rm21 + m20 * rm22) 5275 ._m21(m11 * rm21 + m21 * rm22) 5276 ._m22(m12 * rm21 + m22 * rm22) 5277 ._m23(m13 * rm21 + m23 * rm22) 5278 // set other values 5279 ._m10(nm10) 5280 ._m11(nm11) 5281 ._m12(nm12) 5282 ._m13(nm13) 5283 ._m00(m00) 5284 ._m01(m01) 5285 ._m02(m02) 5286 ._m03(m03) 5287 ._m30(m30) 5288 ._m31(m31) 5289 ._m32(m32) 5290 ._m33(m33) 5291 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5292 return dest; 5293 } 5294 5295 /** 5296 * Apply rotation about the X axis to this matrix by rotating the given amount of radians. 5297 * <p> 5298 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5299 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5300 * When used with a left-handed coordinate system, the rotation is clockwise. 5301 * <p> 5302 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5303 * then the new matrix will be <code>M * R</code>. So when transforming a 5304 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5305 * rotation will be applied first! 5306 * <p> 5307 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5308 * 5309 * @param ang 5310 * the angle in radians 5311 * @return this 5312 */ 5313 ref public Matrix4d rotateX(double ang) return { 5314 rotateX(ang, this); 5315 return this; 5316 } 5317 5318 public Matrix4d rotateY(double ang, ref Matrix4d dest) { 5319 if ((properties & PROPERTY_IDENTITY) != 0) 5320 return dest.rotationY(ang); 5321 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5322 double x = m30, y = m31, z = m32; 5323 return dest.rotationY(ang).setTranslation(x, y, z); 5324 } 5325 return rotateYInternal(ang, dest); 5326 } 5327 private Matrix4d rotateYInternal(double ang, ref Matrix4d dest) { 5328 double sin, cos; 5329 sin = Math.sin(ang); 5330 cos = Math.cosFromSin(sin, ang); 5331 double rm00 = cos; 5332 double rm02 = -sin; 5333 double rm20 = sin; 5334 double rm22 = cos; 5335 5336 // add temporaries for dependent values 5337 double nm00 = m00 * rm00 + m20 * rm02; 5338 double nm01 = m01 * rm00 + m21 * rm02; 5339 double nm02 = m02 * rm00 + m22 * rm02; 5340 double nm03 = m03 * rm00 + m23 * rm02; 5341 // set non-dependent values directly 5342 dest._m20(m00 * rm20 + m20 * rm22) 5343 ._m21(m01 * rm20 + m21 * rm22) 5344 ._m22(m02 * rm20 + m22 * rm22) 5345 ._m23(m03 * rm20 + m23 * rm22) 5346 // set other values 5347 ._m00(nm00) 5348 ._m01(nm01) 5349 ._m02(nm02) 5350 ._m03(nm03) 5351 ._m10(m10) 5352 ._m11(m11) 5353 ._m12(m12) 5354 ._m13(m13) 5355 ._m30(m30) 5356 ._m31(m31) 5357 ._m32(m32) 5358 ._m33(m33) 5359 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5360 return dest; 5361 } 5362 5363 /** 5364 * Apply rotation about the Y axis to this matrix by rotating the given amount of radians. 5365 * <p> 5366 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5367 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5368 * When used with a left-handed coordinate system, the rotation is clockwise. 5369 * <p> 5370 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5371 * then the new matrix will be <code>M * R</code>. So when transforming a 5372 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5373 * rotation will be applied first! 5374 * <p> 5375 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5376 * 5377 * @param ang 5378 * the angle in radians 5379 * @return this 5380 */ 5381 ref public Matrix4d rotateY(double ang) return { 5382 rotateY(ang, this); 5383 return this; 5384 } 5385 5386 public Matrix4d rotateZ(double ang, ref Matrix4d dest) { 5387 if ((properties & PROPERTY_IDENTITY) != 0) 5388 return dest.rotationZ(ang); 5389 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5390 double x = m30, y = m31, z = m32; 5391 return dest.rotationZ(ang).setTranslation(x, y, z); 5392 } 5393 return rotateZInternal(ang, dest); 5394 } 5395 private Matrix4d rotateZInternal(double ang, ref Matrix4d dest) { 5396 double sin = Math.sin(ang); 5397 double cos = Math.cosFromSin(sin, ang); 5398 return rotateTowardsXY(sin, cos, dest); 5399 } 5400 5401 /** 5402 * Apply rotation about the Z axis to this matrix by rotating the given amount of radians. 5403 * <p> 5404 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5405 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5406 * When used with a left-handed coordinate system, the rotation is clockwise. 5407 * <p> 5408 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5409 * then the new matrix will be <code>M * R</code>. So when transforming a 5410 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5411 * rotation will be applied first! 5412 * <p> 5413 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5414 * 5415 * @param ang 5416 * the angle in radians 5417 * @return this 5418 */ 5419 ref public Matrix4d rotateZ(double ang) return { 5420 rotateZ(ang, this); 5421 return this; 5422 } 5423 5424 /** 5425 * Apply rotation about the Z axis to align the local <code>+X</code> towards <code>(dirX, dirY)</code>. 5426 * <p> 5427 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5428 * then the new matrix will be <code>M * R</code>. So when transforming a 5429 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5430 * rotation will be applied first! 5431 * <p> 5432 * The vector <code>(dirX, dirY)</code> must be a unit vector. 5433 * 5434 * @param dirX 5435 * the x component of the normalized direction 5436 * @param dirY 5437 * the y component of the normalized direction 5438 * @return this 5439 */ 5440 ref public Matrix4d rotateTowardsXY(double dirX, double dirY) return { 5441 rotateTowardsXY(dirX, dirY, this); 5442 return this; 5443 } 5444 5445 public Matrix4d rotateTowardsXY(double dirX, double dirY, ref Matrix4d dest) { 5446 if ((properties & PROPERTY_IDENTITY) != 0) 5447 return dest.rotationTowardsXY(dirX, dirY); 5448 double rm00 = dirY; 5449 double rm01 = dirX; 5450 double rm10 = -dirX; 5451 double rm11 = dirY; 5452 double nm00 = m00 * rm00 + m10 * rm01; 5453 double nm01 = m01 * rm00 + m11 * rm01; 5454 double nm02 = m02 * rm00 + m12 * rm01; 5455 double nm03 = m03 * rm00 + m13 * rm01; 5456 dest._m10(m00 * rm10 + m10 * rm11) 5457 ._m11(m01 * rm10 + m11 * rm11) 5458 ._m12(m02 * rm10 + m12 * rm11) 5459 ._m13(m03 * rm10 + m13 * rm11) 5460 ._m00(nm00) 5461 ._m01(nm01) 5462 ._m02(nm02) 5463 ._m03(nm03) 5464 ._m20(m20) 5465 ._m21(m21) 5466 ._m22(m22) 5467 ._m23(m23) 5468 ._m30(m30) 5469 ._m31(m31) 5470 ._m32(m32) 5471 ._m33(m33) 5472 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5473 return dest; 5474 } 5475 5476 /** 5477 * 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 5478 * followed by a rotation of <code>angles.z</code> radians about the Z axis. 5479 * <p> 5480 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5481 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5482 * When used with a left-handed coordinate system, the rotation is clockwise. 5483 * <p> 5484 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5485 * then the new matrix will be <code>M * R</code>. So when transforming a 5486 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5487 * rotation will be applied first! 5488 * <p> 5489 * This method is equivalent to calling: <code>rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)</code> 5490 * 5491 * @param angles 5492 * the Euler angles 5493 * @return this 5494 */ 5495 ref public Matrix4d rotateXYZ(ref Vector3d angles) return { 5496 return rotateXYZ(angles.x, angles.y, angles.z); 5497 } 5498 5499 /** 5500 * 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 5501 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5502 * <p> 5503 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5504 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5505 * When used with a left-handed coordinate system, the rotation is clockwise. 5506 * <p> 5507 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5508 * then the new matrix will be <code>M * R</code>. So when transforming a 5509 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5510 * rotation will be applied first! 5511 * <p> 5512 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 5513 * 5514 * @param angleX 5515 * the angle to rotate about X 5516 * @param angleY 5517 * the angle to rotate about Y 5518 * @param angleZ 5519 * the angle to rotate about Z 5520 * @return this 5521 */ 5522 ref public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ) return { 5523 rotateXYZ(angleX, angleY, angleZ, this); 5524 return this; 5525 } 5526 5527 public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5528 if ((properties & PROPERTY_IDENTITY) != 0) 5529 return dest.rotationXYZ(angleX, angleY, angleZ); 5530 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5531 double tx = m30, ty = m31, tz = m32; 5532 return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz); 5533 } else if ((properties & PROPERTY_AFFINE) != 0) 5534 return dest.rotateAffineXYZ(angleX, angleY, angleZ); 5535 return rotateXYZInternal(angleX, angleY, angleZ, dest); 5536 } 5537 private Matrix4d rotateXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5538 double sinX = Math.sin(angleX); 5539 double cosX = Math.cosFromSin(sinX, angleX); 5540 double sinY = Math.sin(angleY); 5541 double cosY = Math.cosFromSin(sinY, angleY); 5542 double sinZ = Math.sin(angleZ); 5543 double cosZ = Math.cosFromSin(sinZ, angleZ); 5544 double m_sinX = -sinX; 5545 double m_sinY = -sinY; 5546 double m_sinZ = -sinZ; 5547 5548 // rotateX 5549 double nm10 = m10 * cosX + m20 * sinX; 5550 double nm11 = m11 * cosX + m21 * sinX; 5551 double nm12 = m12 * cosX + m22 * sinX; 5552 double nm13 = m13 * cosX + m23 * sinX; 5553 double nm20 = m10 * m_sinX + m20 * cosX; 5554 double nm21 = m11 * m_sinX + m21 * cosX; 5555 double nm22 = m12 * m_sinX + m22 * cosX; 5556 double nm23 = m13 * m_sinX + m23 * cosX; 5557 // rotateY 5558 double nm00 = m00 * cosY + nm20 * m_sinY; 5559 double nm01 = m01 * cosY + nm21 * m_sinY; 5560 double nm02 = m02 * cosY + nm22 * m_sinY; 5561 double nm03 = m03 * cosY + nm23 * m_sinY; 5562 dest._m20(m00 * sinY + nm20 * cosY) 5563 ._m21(m01 * sinY + nm21 * cosY) 5564 ._m22(m02 * sinY + nm22 * cosY) 5565 ._m23(m03 * sinY + nm23 * cosY) 5566 // rotateZ 5567 ._m00(nm00 * cosZ + nm10 * sinZ) 5568 ._m01(nm01 * cosZ + nm11 * sinZ) 5569 ._m02(nm02 * cosZ + nm12 * sinZ) 5570 ._m03(nm03 * cosZ + nm13 * sinZ) 5571 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5572 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5573 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5574 ._m13(nm03 * m_sinZ + nm13 * cosZ) 5575 // copy last column from 'this' 5576 ._m30(m30) 5577 ._m31(m31) 5578 ._m32(m32) 5579 ._m33(m33) 5580 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5581 return dest; 5582 } 5583 5584 /** 5585 * 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 5586 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5587 * <p> 5588 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5589 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5590 * When used with a left-handed coordinate system, the rotation is clockwise. 5591 * <p> 5592 * 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>) 5593 * 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). 5594 * <p> 5595 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5596 * then the new matrix will be <code>M * R</code>. So when transforming a 5597 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5598 * rotation will be applied first! 5599 * <p> 5600 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 5601 * 5602 * @param angleX 5603 * the angle to rotate about X 5604 * @param angleY 5605 * the angle to rotate about Y 5606 * @param angleZ 5607 * the angle to rotate about Z 5608 * @return this 5609 */ 5610 ref public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ) return { 5611 rotateAffineXYZ(angleX, angleY, angleZ, this); 5612 return this; 5613 } 5614 5615 public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5616 if ((properties & PROPERTY_IDENTITY) != 0) 5617 return dest.rotationXYZ(angleX, angleY, angleZ); 5618 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5619 double tx = m30, ty = m31, tz = m32; 5620 return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz); 5621 } 5622 return rotateAffineXYZInternal(angleX, angleY, angleZ, dest); 5623 } 5624 private Matrix4d rotateAffineXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5625 double sinX = Math.sin(angleX); 5626 double cosX = Math.cosFromSin(sinX, angleX); 5627 double sinY = Math.sin(angleY); 5628 double cosY = Math.cosFromSin(sinY, angleY); 5629 double sinZ = Math.sin(angleZ); 5630 double cosZ = Math.cosFromSin(sinZ, angleZ); 5631 double m_sinX = -sinX; 5632 double m_sinY = -sinY; 5633 double m_sinZ = -sinZ; 5634 5635 // rotateX 5636 double nm10 = m10 * cosX + m20 * sinX; 5637 double nm11 = m11 * cosX + m21 * sinX; 5638 double nm12 = m12 * cosX + m22 * sinX; 5639 double nm20 = m10 * m_sinX + m20 * cosX; 5640 double nm21 = m11 * m_sinX + m21 * cosX; 5641 double nm22 = m12 * m_sinX + m22 * cosX; 5642 // rotateY 5643 double nm00 = m00 * cosY + nm20 * m_sinY; 5644 double nm01 = m01 * cosY + nm21 * m_sinY; 5645 double nm02 = m02 * cosY + nm22 * m_sinY; 5646 dest._m20(m00 * sinY + nm20 * cosY) 5647 ._m21(m01 * sinY + nm21 * cosY) 5648 ._m22(m02 * sinY + nm22 * cosY) 5649 ._m23(0.0) 5650 // rotateZ 5651 ._m00(nm00 * cosZ + nm10 * sinZ) 5652 ._m01(nm01 * cosZ + nm11 * sinZ) 5653 ._m02(nm02 * cosZ + nm12 * sinZ) 5654 ._m03(0.0) 5655 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5656 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5657 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5658 ._m13(0.0) 5659 // copy last column from 'this' 5660 ._m30(m30) 5661 ._m31(m31) 5662 ._m32(m32) 5663 ._m33(m33) 5664 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5665 return dest; 5666 } 5667 5668 /** 5669 * 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 5670 * followed by a rotation of <code>angles.x</code> radians about the X axis. 5671 * <p> 5672 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5673 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5674 * When used with a left-handed coordinate system, the rotation is clockwise. 5675 * <p> 5676 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5677 * then the new matrix will be <code>M * R</code>. So when transforming a 5678 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5679 * rotation will be applied first! 5680 * <p> 5681 * This method is equivalent to calling: <code>rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)</code> 5682 * 5683 * @param angles 5684 * the Euler angles 5685 * @return this 5686 */ 5687 ref public Matrix4d rotateZYX(ref Vector3d angles) return { 5688 return rotateZYX(angles.z, angles.y, angles.x); 5689 } 5690 5691 /** 5692 * 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 5693 * followed by a rotation of <code>angleX</code> radians about the X axis. 5694 * <p> 5695 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5696 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5697 * When used with a left-handed coordinate system, the rotation is clockwise. 5698 * <p> 5699 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5700 * then the new matrix will be <code>M * R</code>. So when transforming a 5701 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5702 * rotation will be applied first! 5703 * <p> 5704 * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 5705 * 5706 * @param angleZ 5707 * the angle to rotate about Z 5708 * @param angleY 5709 * the angle to rotate about Y 5710 * @param angleX 5711 * the angle to rotate about X 5712 * @return this 5713 */ 5714 ref public Matrix4d rotateZYX(double angleZ, double angleY, double angleX) return { 5715 rotateZYX(angleZ, angleY, angleX, this); 5716 return this; 5717 } 5718 5719 public Matrix4d rotateZYX(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5720 if ((properties & PROPERTY_IDENTITY) != 0) 5721 return dest.rotationZYX(angleZ, angleY, angleX); 5722 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5723 double tx = m30, ty = m31, tz = m32; 5724 return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz); 5725 } else if ((properties & PROPERTY_AFFINE) != 0) 5726 return dest.rotateAffineZYX(angleZ, angleY, angleX); 5727 return rotateZYXInternal(angleZ, angleY, angleX, dest); 5728 } 5729 private Matrix4d rotateZYXInternal(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5730 double sinX = Math.sin(angleX); 5731 double cosX = Math.cosFromSin(sinX, angleX); 5732 double sinY = Math.sin(angleY); 5733 double cosY = Math.cosFromSin(sinY, angleY); 5734 double sinZ = Math.sin(angleZ); 5735 double cosZ = Math.cosFromSin(sinZ, angleZ); 5736 double m_sinZ = -sinZ; 5737 double m_sinY = -sinY; 5738 double m_sinX = -sinX; 5739 5740 // rotateZ 5741 double nm00 = m00 * cosZ + m10 * sinZ; 5742 double nm01 = m01 * cosZ + m11 * sinZ; 5743 double nm02 = m02 * cosZ + m12 * sinZ; 5744 double nm03 = m03 * cosZ + m13 * sinZ; 5745 double nm10 = m00 * m_sinZ + m10 * cosZ; 5746 double nm11 = m01 * m_sinZ + m11 * cosZ; 5747 double nm12 = m02 * m_sinZ + m12 * cosZ; 5748 double nm13 = m03 * m_sinZ + m13 * cosZ; 5749 // rotateY 5750 double nm20 = nm00 * sinY + m20 * cosY; 5751 double nm21 = nm01 * sinY + m21 * cosY; 5752 double nm22 = nm02 * sinY + m22 * cosY; 5753 double nm23 = nm03 * sinY + m23 * cosY; 5754 dest._m00(nm00 * cosY + m20 * m_sinY) 5755 ._m01(nm01 * cosY + m21 * m_sinY) 5756 ._m02(nm02 * cosY + m22 * m_sinY) 5757 ._m03(nm03 * cosY + m23 * m_sinY) 5758 // rotateX 5759 ._m10(nm10 * cosX + nm20 * sinX) 5760 ._m11(nm11 * cosX + nm21 * sinX) 5761 ._m12(nm12 * cosX + nm22 * sinX) 5762 ._m13(nm13 * cosX + nm23 * sinX) 5763 ._m20(nm10 * m_sinX + nm20 * cosX) 5764 ._m21(nm11 * m_sinX + nm21 * cosX) 5765 ._m22(nm12 * m_sinX + nm22 * cosX) 5766 ._m23(nm13 * m_sinX + nm23 * cosX) 5767 // copy last column from 'this' 5768 ._m30(m30) 5769 ._m31(m31) 5770 ._m32(m32) 5771 ._m33(m33) 5772 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5773 return dest; 5774 } 5775 5776 /** 5777 * 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 5778 * followed by a rotation of <code>angleX</code> radians about the X axis. 5779 * <p> 5780 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5781 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5782 * When used with a left-handed coordinate system, the rotation is clockwise. 5783 * <p> 5784 * 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>) 5785 * 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). 5786 * <p> 5787 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5788 * then the new matrix will be <code>M * R</code>. So when transforming a 5789 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5790 * rotation will be applied first! 5791 * 5792 * @param angleZ 5793 * the angle to rotate about Z 5794 * @param angleY 5795 * the angle to rotate about Y 5796 * @param angleX 5797 * the angle to rotate about X 5798 * @return this 5799 */ 5800 ref public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX) return { 5801 rotateAffineZYX(angleZ, angleY, angleX, this); 5802 return this; 5803 } 5804 5805 public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5806 double sinX = Math.sin(angleX); 5807 double cosX = Math.cosFromSin(sinX, angleX); 5808 double sinY = Math.sin(angleY); 5809 double cosY = Math.cosFromSin(sinY, angleY); 5810 double sinZ = Math.sin(angleZ); 5811 double cosZ = Math.cosFromSin(sinZ, angleZ); 5812 double m_sinZ = -sinZ; 5813 double m_sinY = -sinY; 5814 double m_sinX = -sinX; 5815 5816 // rotateZ 5817 double nm00 = m00 * cosZ + m10 * sinZ; 5818 double nm01 = m01 * cosZ + m11 * sinZ; 5819 double nm02 = m02 * cosZ + m12 * sinZ; 5820 double nm10 = m00 * m_sinZ + m10 * cosZ; 5821 double nm11 = m01 * m_sinZ + m11 * cosZ; 5822 double nm12 = m02 * m_sinZ + m12 * cosZ; 5823 // rotateY 5824 double nm20 = nm00 * sinY + m20 * cosY; 5825 double nm21 = nm01 * sinY + m21 * cosY; 5826 double nm22 = nm02 * sinY + m22 * cosY; 5827 dest._m00(nm00 * cosY + m20 * m_sinY) 5828 ._m01(nm01 * cosY + m21 * m_sinY) 5829 ._m02(nm02 * cosY + m22 * m_sinY) 5830 ._m03(0.0) 5831 // rotateX 5832 ._m10(nm10 * cosX + nm20 * sinX) 5833 ._m11(nm11 * cosX + nm21 * sinX) 5834 ._m12(nm12 * cosX + nm22 * sinX) 5835 ._m13(0.0) 5836 ._m20(nm10 * m_sinX + nm20 * cosX) 5837 ._m21(nm11 * m_sinX + nm21 * cosX) 5838 ._m22(nm12 * m_sinX + nm22 * cosX) 5839 ._m23(0.0) 5840 // copy last column from 'this' 5841 ._m30(m30) 5842 ._m31(m31) 5843 ._m32(m32) 5844 ._m33(m33) 5845 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5846 return dest; 5847 } 5848 5849 /** 5850 * 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 5851 * followed by a rotation of <code>angles.z</code> radians about the Z axis. 5852 * <p> 5853 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5854 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5855 * When used with a left-handed coordinate system, the rotation is clockwise. 5856 * <p> 5857 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5858 * then the new matrix will be <code>M * R</code>. So when transforming a 5859 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5860 * rotation will be applied first! 5861 * <p> 5862 * This method is equivalent to calling: <code>rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)</code> 5863 * 5864 * @param angles 5865 * the Euler angles 5866 * @return this 5867 */ 5868 ref public Matrix4d rotateYXZ(ref Vector3d angles) return { 5869 return rotateYXZ(angles.y, angles.x, angles.z); 5870 } 5871 5872 /** 5873 * 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 5874 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5875 * <p> 5876 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5877 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5878 * When used with a left-handed coordinate system, the rotation is clockwise. 5879 * <p> 5880 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5881 * then the new matrix will be <code>M * R</code>. So when transforming a 5882 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5883 * rotation will be applied first! 5884 * <p> 5885 * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 5886 * 5887 * @param angleY 5888 * the angle to rotate about Y 5889 * @param angleX 5890 * the angle to rotate about X 5891 * @param angleZ 5892 * the angle to rotate about Z 5893 * @return this 5894 */ 5895 ref public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ) return { 5896 rotateYXZ(angleY, angleX, angleZ, this); 5897 return this; 5898 } 5899 5900 public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5901 if ((properties & PROPERTY_IDENTITY) != 0) 5902 return dest.rotationYXZ(angleY, angleX, angleZ); 5903 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5904 double tx = m30, ty = m31, tz = m32; 5905 return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz); 5906 } else if ((properties & PROPERTY_AFFINE) != 0) 5907 return dest.rotateAffineYXZ(angleY, angleX, angleZ); 5908 return rotateYXZInternal(angleY, angleX, angleZ, dest); 5909 } 5910 private Matrix4d rotateYXZInternal(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5911 double sinX = Math.sin(angleX); 5912 double cosX = Math.cosFromSin(sinX, angleX); 5913 double sinY = Math.sin(angleY); 5914 double cosY = Math.cosFromSin(sinY, angleY); 5915 double sinZ = Math.sin(angleZ); 5916 double cosZ = Math.cosFromSin(sinZ, angleZ); 5917 double m_sinY = -sinY; 5918 double m_sinX = -sinX; 5919 double m_sinZ = -sinZ; 5920 5921 // rotateY 5922 double nm20 = m00 * sinY + m20 * cosY; 5923 double nm21 = m01 * sinY + m21 * cosY; 5924 double nm22 = m02 * sinY + m22 * cosY; 5925 double nm23 = m03 * sinY + m23 * cosY; 5926 double nm00 = m00 * cosY + m20 * m_sinY; 5927 double nm01 = m01 * cosY + m21 * m_sinY; 5928 double nm02 = m02 * cosY + m22 * m_sinY; 5929 double nm03 = m03 * cosY + m23 * m_sinY; 5930 // rotateX 5931 double nm10 = m10 * cosX + nm20 * sinX; 5932 double nm11 = m11 * cosX + nm21 * sinX; 5933 double nm12 = m12 * cosX + nm22 * sinX; 5934 double nm13 = m13 * cosX + nm23 * sinX; 5935 dest._m20(m10 * m_sinX + nm20 * cosX) 5936 ._m21(m11 * m_sinX + nm21 * cosX) 5937 ._m22(m12 * m_sinX + nm22 * cosX) 5938 ._m23(m13 * m_sinX + nm23 * cosX) 5939 // rotateZ 5940 ._m00(nm00 * cosZ + nm10 * sinZ) 5941 ._m01(nm01 * cosZ + nm11 * sinZ) 5942 ._m02(nm02 * cosZ + nm12 * sinZ) 5943 ._m03(nm03 * cosZ + nm13 * sinZ) 5944 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5945 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5946 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5947 ._m13(nm03 * m_sinZ + nm13 * cosZ) 5948 // copy last column from 'this' 5949 ._m30(m30) 5950 ._m31(m31) 5951 ._m32(m32) 5952 ._m33(m33) 5953 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5954 return dest; 5955 } 5956 5957 /** 5958 * 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 5959 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5960 * <p> 5961 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5962 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5963 * When used with a left-handed coordinate system, the rotation is clockwise. 5964 * <p> 5965 * 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>) 5966 * 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). 5967 * <p> 5968 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5969 * then the new matrix will be <code>M * R</code>. So when transforming a 5970 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5971 * rotation will be applied first! 5972 * 5973 * @param angleY 5974 * the angle to rotate about Y 5975 * @param angleX 5976 * the angle to rotate about X 5977 * @param angleZ 5978 * the angle to rotate about Z 5979 * @return this 5980 */ 5981 ref public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ) return { 5982 rotateAffineYXZ(angleY, angleX, angleZ, this); 5983 return this; 5984 } 5985 5986 public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5987 double sinX = Math.sin(angleX); 5988 double cosX = Math.cosFromSin(sinX, angleX); 5989 double sinY = Math.sin(angleY); 5990 double cosY = Math.cosFromSin(sinY, angleY); 5991 double sinZ = Math.sin(angleZ); 5992 double cosZ = Math.cosFromSin(sinZ, angleZ); 5993 double m_sinY = -sinY; 5994 double m_sinX = -sinX; 5995 double m_sinZ = -sinZ; 5996 5997 // rotateY 5998 double nm20 = m00 * sinY + m20 * cosY; 5999 double nm21 = m01 * sinY + m21 * cosY; 6000 double nm22 = m02 * sinY + m22 * cosY; 6001 double nm00 = m00 * cosY + m20 * m_sinY; 6002 double nm01 = m01 * cosY + m21 * m_sinY; 6003 double nm02 = m02 * cosY + m22 * m_sinY; 6004 // rotateX 6005 double nm10 = m10 * cosX + nm20 * sinX; 6006 double nm11 = m11 * cosX + nm21 * sinX; 6007 double nm12 = m12 * cosX + nm22 * sinX; 6008 dest._m20(m10 * m_sinX + nm20 * cosX) 6009 ._m21(m11 * m_sinX + nm21 * cosX) 6010 ._m22(m12 * m_sinX + nm22 * cosX) 6011 ._m23(0.0) 6012 // rotateZ 6013 ._m00(nm00 * cosZ + nm10 * sinZ) 6014 ._m01(nm01 * cosZ + nm11 * sinZ) 6015 ._m02(nm02 * cosZ + nm12 * sinZ) 6016 ._m03(0.0) 6017 ._m10(nm00 * m_sinZ + nm10 * cosZ) 6018 ._m11(nm01 * m_sinZ + nm11 * cosZ) 6019 ._m12(nm02 * m_sinZ + nm12 * cosZ) 6020 ._m13(0.0) 6021 // copy last column from 'this' 6022 ._m30(m30) 6023 ._m31(m31) 6024 ._m32(m32) 6025 ._m33(m33) 6026 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6027 return dest; 6028 } 6029 6030 /** 6031 * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}. 6032 * <p> 6033 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6034 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6035 * When used with a left-handed coordinate system, the rotation is clockwise. 6036 * <p> 6037 * The resulting matrix can be multiplied against another transformation 6038 * matrix to obtain an additional rotation. 6039 * <p> 6040 * In order to apply the rotation transformation to an existing transformation, 6041 * use {@link #rotate(ref AxisAngle4d) rotate()} instead. 6042 * <p> 6043 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 6044 * 6045 * @see #rotate(ref AxisAngle4d) 6046 * 6047 * @param angleAxis 6048 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 6049 * @return this 6050 */ 6051 ref public Matrix4d rotation(ref AxisAngle4d angleAxis) return { 6052 return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z); 6053 } 6054 6055 /** 6056 * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniond}. 6057 * <p> 6058 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6059 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6060 * When used with a left-handed coordinate system, the rotation is clockwise. 6061 * <p> 6062 * The resulting matrix can be multiplied against another transformation 6063 * matrix to obtain an additional rotation. 6064 * <p> 6065 * In order to apply the rotation transformation to an existing transformation, 6066 * use {@link #rotate(ref Quaterniond) rotate()} instead. 6067 * <p> 6068 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6069 * 6070 * @see #rotate(ref Quaterniond) 6071 * 6072 * @param quat 6073 * the {@link Quaterniond} 6074 * @return this 6075 */ 6076 ref public Matrix4d rotation(ref Quaterniond quat) return { 6077 double w2 = quat.w * quat.w; 6078 double x2 = quat.x * quat.x; 6079 double y2 = quat.y * quat.y; 6080 double z2 = quat.z * quat.z; 6081 double zw = quat.z * quat.w, dzw = zw + zw; 6082 double xy = quat.x * quat.y, dxy = xy + xy; 6083 double xz = quat.x * quat.z, dxz = xz + xz; 6084 double yw = quat.y * quat.w, dyw = yw + yw; 6085 double yz = quat.y * quat.z, dyz = yz + yz; 6086 double xw = quat.x * quat.w, dxw = xw + xw; 6087 if ((properties & PROPERTY_IDENTITY) == 0) 6088 this._identity(); 6089 _m00(w2 + x2 - z2 - y2). 6090 _m01(dxy + dzw). 6091 _m02(dxz - dyw). 6092 _m10(-dzw + dxy). 6093 _m11(y2 - z2 + w2 - x2). 6094 _m12(dyz + dxw). 6095 _m20(dyw + dxz). 6096 _m21(dyz - dxw). 6097 _m22(z2 - y2 - x2 + w2). 6098 _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 6099 return this; 6100 } 6101 6102 6103 /** 6104 * 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>, 6105 * <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 6106 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>. 6107 * <p> 6108 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6109 * at last the translation. 6110 * <p> 6111 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6112 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6113 * When used with a left-handed coordinate system, the rotation is clockwise. 6114 * <p> 6115 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)</code> 6116 * 6117 * @see #translation(double, double, double) 6118 * @see #rotate(ref Quaterniond) 6119 * @see #scale(double, double, double) 6120 * 6121 * @param tx 6122 * the number of units by which to translate the x-component 6123 * @param ty 6124 * the number of units by which to translate the y-component 6125 * @param tz 6126 * the number of units by which to translate the z-component 6127 * @param qx 6128 * the x-coordinate of the vector part of the quaternion 6129 * @param qy 6130 * the y-coordinate of the vector part of the quaternion 6131 * @param qz 6132 * the z-coordinate of the vector part of the quaternion 6133 * @param qw 6134 * the scalar part of the quaternion 6135 * @param sx 6136 * the scaling factor for the x-axis 6137 * @param sy 6138 * the scaling factor for the y-axis 6139 * @param sz 6140 * the scaling factor for the z-axis 6141 * @return this 6142 */ 6143 ref public Matrix4d translationRotateScale(double tx, double ty, double tz, 6144 double qx, double qy, double qz, double qw, 6145 double sx, double sy, double sz) return { 6146 double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz; 6147 double q00 = dqx * qx; 6148 double q11 = dqy * qy; 6149 double q22 = dqz * qz; 6150 double q01 = dqx * qy; 6151 double q02 = dqx * qz; 6152 double q03 = dqx * qw; 6153 double q12 = dqy * qz; 6154 double q13 = dqy * qw; 6155 double q23 = dqz * qw; 6156 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6157 _m00(sx - (q11 + q22) * sx). 6158 _m01((q01 + q23) * sx). 6159 _m02((q02 - q13) * sx). 6160 _m03(0.0). 6161 _m10((q01 - q23) * sy). 6162 _m11(sy - (q22 + q00) * sy). 6163 _m12((q12 + q03) * sy). 6164 _m13(0.0). 6165 _m20((q02 + q13) * sz). 6166 _m21((q12 - q03) * sz). 6167 _m22(sz - (q11 + q00) * sz). 6168 _m23(0.0). 6169 _m30(tx). 6170 _m31(ty). 6171 _m32(tz). 6172 _m33(1.0). 6173 properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0); 6174 return this; 6175 } 6176 6177 /** 6178 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>, 6179 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6180 * which scales the axes by <code>scale</code>. 6181 * <p> 6182 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6183 * at last the translation. 6184 * <p> 6185 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6186 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6187 * When used with a left-handed coordinate system, the rotation is clockwise. 6188 * <p> 6189 * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code> 6190 * 6191 * @see #translation(ref Vector3d) 6192 * @see #rotate(ref Quaterniond) 6193 * @see #scale(ref Vector3d) 6194 * 6195 * @param translation 6196 * the translation 6197 * @param quat 6198 * the quaternion representing a rotation 6199 * @param scale 6200 * the scaling factors 6201 * @return this 6202 */ 6203 ref public Matrix4d translationRotateScale(ref Vector3d translation, 6204 Quaterniond quat, 6205 Vector3d scale) return { 6206 return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale.x, scale.y, scale.z); 6207 } 6208 6209 /** 6210 * 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>, 6211 * <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 6212 * which scales all three axes by <code>scale</code>. 6213 * <p> 6214 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6215 * at last the translation. 6216 * <p> 6217 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6218 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6219 * When used with a left-handed coordinate system, the rotation is clockwise. 6220 * <p> 6221 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(scale)</code> 6222 * 6223 * @see #translation(double, double, double) 6224 * @see #rotate(ref Quaterniond) 6225 * @see #scale(double) 6226 * 6227 * @param tx 6228 * the number of units by which to translate the x-component 6229 * @param ty 6230 * the number of units by which to translate the y-component 6231 * @param tz 6232 * the number of units by which to translate the z-component 6233 * @param qx 6234 * the x-coordinate of the vector part of the quaternion 6235 * @param qy 6236 * the y-coordinate of the vector part of the quaternion 6237 * @param qz 6238 * the z-coordinate of the vector part of the quaternion 6239 * @param qw 6240 * the scalar part of the quaternion 6241 * @param scale 6242 * the scaling factor for all three axes 6243 * @return this 6244 */ 6245 ref public Matrix4d translationRotateScale(double tx, double ty, double tz, 6246 double qx, double qy, double qz, double qw, 6247 double scale) return { 6248 return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, scale, scale, scale); 6249 } 6250 6251 /** 6252 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>, 6253 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6254 * which scales all three axes by <code>scale</code>. 6255 * <p> 6256 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6257 * at last the translation. 6258 * <p> 6259 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6260 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6261 * When used with a left-handed coordinate system, the rotation is clockwise. 6262 * <p> 6263 * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code> 6264 * 6265 * @see #translation(ref Vector3d) 6266 * @see #rotate(ref Quaterniond) 6267 * @see #scale(double) 6268 * 6269 * @param translation 6270 * the translation 6271 * @param quat 6272 * the quaternion representing a rotation 6273 * @param scale 6274 * the scaling factors 6275 * @return this 6276 */ 6277 ref public Matrix4d translationRotateScale(ref Vector3d translation, 6278 Quaterniond quat, 6279 double scale) return { 6280 return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale, scale, scale); 6281 } 6282 6283 6284 /** 6285 * 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>, 6286 * <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 6287 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>. 6288 * <p> 6289 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6290 * 6291 * @see #translationRotateScale(double, double, double, double, double, double, double, double, double, double) 6292 * @see #invert() 6293 * 6294 * @param tx 6295 * the number of units by which to translate the x-component 6296 * @param ty 6297 * the number of units by which to translate the y-component 6298 * @param tz 6299 * the number of units by which to translate the z-component 6300 * @param qx 6301 * the x-coordinate of the vector part of the quaternion 6302 * @param qy 6303 * the y-coordinate of the vector part of the quaternion 6304 * @param qz 6305 * the z-coordinate of the vector part of the quaternion 6306 * @param qw 6307 * the scalar part of the quaternion 6308 * @param sx 6309 * the scaling factor for the x-axis 6310 * @param sy 6311 * the scaling factor for the y-axis 6312 * @param sz 6313 * the scaling factor for the z-axis 6314 * @return this 6315 */ 6316 ref public Matrix4d translationRotateScaleInvert(double tx, double ty, double tz, 6317 double qx, double qy, double qz, double qw, 6318 double sx, double sy, double sz) return { 6319 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6320 if (one) 6321 return translationRotateInvert(tx, ty, tz, qx, qy, qz, qw); 6322 double nqx = -qx, nqy = -qy, nqz = -qz; 6323 double dqx = nqx + nqx; 6324 double dqy = nqy + nqy; 6325 double dqz = nqz + nqz; 6326 double q00 = dqx * nqx; 6327 double q11 = dqy * nqy; 6328 double q22 = dqz * nqz; 6329 double q01 = dqx * nqy; 6330 double q02 = dqx * nqz; 6331 double q03 = dqx * qw; 6332 double q12 = dqy * nqz; 6333 double q13 = dqy * qw; 6334 double q23 = dqz * qw; 6335 double isx = 1/sx, isy = 1/sy, isz = 1/sz; 6336 _m00(isx * (1.0 - q11 - q22)). 6337 _m01(isy * (q01 + q23)). 6338 _m02(isz * (q02 - q13)). 6339 _m03(0.0). 6340 _m10(isx * (q01 - q23)). 6341 _m11(isy * (1.0 - q22 - q00)). 6342 _m12(isz * (q12 + q03)). 6343 _m13(0.0). 6344 _m20(isx * (q02 + q13)). 6345 _m21(isy * (q12 - q03)). 6346 _m22(isz * (1.0 - q11 - q00)). 6347 _m23(0.0). 6348 _m30(-m00 * tx - m10 * ty - m20 * tz). 6349 _m31(-m01 * tx - m11 * ty - m21 * tz). 6350 _m32(-m02 * tx - m12 * ty - m22 * tz). 6351 _m33(1.0). 6352 properties = PROPERTY_AFFINE; 6353 return this; 6354 } 6355 6356 /** 6357 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code>, 6358 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6359 * which scales the axes by <code>scale</code>. 6360 * <p> 6361 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6362 * 6363 * @see #translationRotateScale(ref Vector3d, Quaterniond, Vector3d) 6364 * @see #invert() 6365 * 6366 * @param translation 6367 * the translation 6368 * @param quat 6369 * the quaternion representing a rotation 6370 * @param scale 6371 * the scaling factors 6372 * @return this 6373 */ 6374 ref public Matrix4d translationRotateScaleInvert(ref Vector3d translation, 6375 Quaterniond quat, 6376 Vector3d scale) return { 6377 return translationRotateScaleInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale.x, scale.y, scale.z); 6378 } 6379 6380 6381 /** 6382 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code>, 6383 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6384 * which scales all three axes by <code>scale</code>. 6385 * <p> 6386 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6387 * 6388 * @see #translationRotateScale(ref Vector3d, Quaterniond, double) 6389 * @see #invert() 6390 * 6391 * @param translation 6392 * the translation 6393 * @param quat 6394 * the quaternion representing a rotation 6395 * @param scale 6396 * the scaling factors 6397 * @return this 6398 */ 6399 ref public Matrix4d translationRotateScaleInvert(ref Vector3d translation, 6400 Quaterniond quat, 6401 double scale) return { 6402 return translationRotateScaleInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale, scale, scale); 6403 } 6404 6405 6406 /** 6407 * 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>, 6408 * <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 6409 * 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. 6410 * <p> 6411 * 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 6412 * at last the translation. 6413 * <p> 6414 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6415 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6416 * When used with a left-handed coordinate system, the rotation is clockwise. 6417 * <p> 6418 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mulAffine(m)</code> 6419 * 6420 * @see #translation(double, double, double) 6421 * @see #rotate(ref Quaterniond) 6422 * @see #scale(double, double, double) 6423 * @see #mulAffine(Matrix4d) 6424 * 6425 * @param tx 6426 * the number of units by which to translate the x-component 6427 * @param ty 6428 * the number of units by which to translate the y-component 6429 * @param tz 6430 * the number of units by which to translate the z-component 6431 * @param qx 6432 * the x-coordinate of the vector part of the quaternion 6433 * @param qy 6434 * the y-coordinate of the vector part of the quaternion 6435 * @param qz 6436 * the z-coordinate of the vector part of the quaternion 6437 * @param qw 6438 * the scalar part of the quaternion 6439 * @param sx 6440 * the scaling factor for the x-axis 6441 * @param sy 6442 * the scaling factor for the y-axis 6443 * @param sz 6444 * the scaling factor for the z-axis 6445 * @param m 6446 * the {@link #isAffine() affine} matrix to multiply by 6447 * @return this 6448 */ 6449 ref public Matrix4d translationRotateScaleMulAffine(double tx, double ty, double tz, 6450 double qx, double qy, double qz, double qw, 6451 double sx, double sy, double sz, 6452 Matrix4d m) return { 6453 double w2 = qw * qw; 6454 double x2 = qx * qx; 6455 double y2 = qy * qy; 6456 double z2 = qz * qz; 6457 double zw = qz * qw; 6458 double xy = qx * qy; 6459 double xz = qx * qz; 6460 double yw = qy * qw; 6461 double yz = qy * qz; 6462 double xw = qx * qw; 6463 double nm00 = w2 + x2 - z2 - y2; 6464 double nm01 = xy + zw + zw + xy; 6465 double nm02 = xz - yw + xz - yw; 6466 double nm10 = -zw + xy - zw + xy; 6467 double nm11 = y2 - z2 + w2 - x2; 6468 double nm12 = yz + yz + xw + xw; 6469 double nm20 = yw + xz + xz + yw; 6470 double nm21 = yz + yz - xw - xw; 6471 double nm22 = z2 - y2 - x2 + w2; 6472 double m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02; 6473 double m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02; 6474 setm02(nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02); 6475 setm00(m00); 6476 setm01(m01); 6477 setm03(0.0); 6478 double m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12; 6479 double m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12; 6480 setm12(nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12); 6481 setm10(m10); 6482 setm11(m11); 6483 setm13(0.0); 6484 double m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22; 6485 double m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22; 6486 setm22(nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22); 6487 setm20(m20); 6488 setm21(m21); 6489 setm23(0.0); 6490 double m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx; 6491 double m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty; 6492 setm32(nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz); 6493 setm30(m30); 6494 setm31(m31); 6495 setm33(1.0); 6496 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6497 properties = PROPERTY_AFFINE | (one && (m.properties & PROPERTY_ORTHONORMAL) != 0 ? PROPERTY_ORTHONORMAL : 0); 6498 return this; 6499 } 6500 6501 6502 6503 /** 6504 * 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 6505 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>. 6506 * <p> 6507 * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation. 6508 * <p> 6509 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6510 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6511 * When used with a left-handed coordinate system, the rotation is clockwise. 6512 * <p> 6513 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code> 6514 * 6515 * @see #translation(double, double, double) 6516 * @see #rotate(ref Quaterniond) 6517 * 6518 * @param tx 6519 * the number of units by which to translate the x-component 6520 * @param ty 6521 * the number of units by which to translate the y-component 6522 * @param tz 6523 * the number of units by which to translate the z-component 6524 * @param qx 6525 * the x-coordinate of the vector part of the quaternion 6526 * @param qy 6527 * the y-coordinate of the vector part of the quaternion 6528 * @param qz 6529 * the z-coordinate of the vector part of the quaternion 6530 * @param qw 6531 * the scalar part of the quaternion 6532 * @return this 6533 */ 6534 ref public Matrix4d translationRotate(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return { 6535 double w2 = qw * qw; 6536 double x2 = qx * qx; 6537 double y2 = qy * qy; 6538 double z2 = qz * qz; 6539 double zw = qz * qw; 6540 double xy = qx * qy; 6541 double xz = qx * qz; 6542 double yw = qy * qw; 6543 double yz = qy * qz; 6544 double xw = qx * qw; 6545 setm00(w2 + x2 - z2 - y2); 6546 setm01(xy + zw + zw + xy); 6547 setm02(xz - yw + xz - yw); 6548 setm10(-zw + xy - zw + xy); 6549 setm11(y2 - z2 + w2 - x2); 6550 setm12(yz + yz + xw + xw); 6551 setm20(yw + xz + xz + yw); 6552 setm21(yz + yz - xw - xw); 6553 setm22(z2 - y2 - x2 + w2); 6554 setm30(tx); 6555 setm31(ty); 6556 setm32(tz); 6557 setm33(1.0); 6558 this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 6559 return this; 6560 } 6561 6562 /** 6563 * 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 6564 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the given quaternion. 6565 * <p> 6566 * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation. 6567 * <p> 6568 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6569 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6570 * When used with a left-handed coordinate system, the rotation is clockwise. 6571 * <p> 6572 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code> 6573 * 6574 * @see #translation(double, double, double) 6575 * @see #rotate(ref Quaterniond) 6576 * 6577 * @param tx 6578 * the number of units by which to translate the x-component 6579 * @param ty 6580 * the number of units by which to translate the y-component 6581 * @param tz 6582 * the number of units by which to translate the z-component 6583 * @param quat 6584 * the quaternion representing a rotation 6585 * @return this 6586 */ 6587 ref public Matrix4d translationRotate(double tx, double ty, double tz, Quaterniond quat) return { 6588 return translationRotate(tx, ty, tz, quat.x, quat.y, quat.z, quat.w); 6589 } 6590 6591 /** 6592 * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is the given <code>translation</code> and 6593 * <code>R</code> is a rotation transformation specified by the given quaternion. 6594 * <p> 6595 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6596 * at last the translation. 6597 * <p> 6598 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6599 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6600 * When used with a left-handed coordinate system, the rotation is clockwise. 6601 * <p> 6602 * This method is equivalent to calling: <code>translation(translation).rotate(quat)</code> 6603 * 6604 * @see #translation(ref Vector3d) 6605 * @see #rotate(ref Quaterniond) 6606 * 6607 * @param translation 6608 * the translation 6609 * @param quat 6610 * the quaternion representing a rotation 6611 * @return this 6612 */ 6613 ref public Matrix4d translationRotate(ref Vector3d translation, 6614 Quaterniond quat) return { 6615 return translationRotate(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w); 6616 } 6617 6618 /** 6619 * 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 6620 * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>. 6621 * <p> 6622 * This method is equivalent to calling: <code>translationRotate(...).invert()</code> 6623 * 6624 * @see #translationRotate(double, double, double, double, double, double, double) 6625 * @see #invert() 6626 * 6627 * @param tx 6628 * the number of units by which to translate the x-component 6629 * @param ty 6630 * the number of units by which to translate the y-component 6631 * @param tz 6632 * the number of units by which to translate the z-component 6633 * @param qx 6634 * the x-coordinate of the vector part of the quaternion 6635 * @param qy 6636 * the y-coordinate of the vector part of the quaternion 6637 * @param qz 6638 * the z-coordinate of the vector part of the quaternion 6639 * @param qw 6640 * the scalar part of the quaternion 6641 * @return this 6642 */ 6643 ref public Matrix4d translationRotateInvert(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return { 6644 double nqx = -qx, nqy = -qy, nqz = -qz; 6645 double dqx = nqx + nqx; 6646 double dqy = nqy + nqy; 6647 double dqz = nqz + nqz; 6648 double q00 = dqx * nqx; 6649 double q11 = dqy * nqy; 6650 double q22 = dqz * nqz; 6651 double q01 = dqx * nqy; 6652 double q02 = dqx * nqz; 6653 double q03 = dqx * qw; 6654 double q12 = dqy * nqz; 6655 double q13 = dqy * qw; 6656 double q23 = dqz * qw; 6657 return this 6658 ._m00(1.0 - q11 - q22) 6659 ._m01(q01 + q23) 6660 ._m02(q02 - q13) 6661 ._m03(0.0) 6662 ._m10(q01 - q23) 6663 ._m11(1.0 - q22 - q00) 6664 ._m12(q12 + q03) 6665 ._m13(0.0) 6666 ._m20(q02 + q13) 6667 ._m21(q12 - q03) 6668 ._m22(1.0 - q11 - q00) 6669 ._m23(0.0) 6670 ._m30(-m00 * tx - m10 * ty - m20 * tz) 6671 ._m31(-m01 * tx - m11 * ty - m21 * tz) 6672 ._m32(-m02 * tx - m12 * ty - m22 * tz) 6673 ._m33(1.0) 6674 ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 6675 } 6676 6677 6678 6679 /** 6680 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store 6681 * the result in <code>dest</code>. 6682 * <p> 6683 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6684 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6685 * When used with a left-handed coordinate system, the rotation is clockwise. 6686 * <p> 6687 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6688 * then the new matrix will be <code>M * Q</code>. So when transforming a 6689 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6690 * the quaternion rotation will be applied first! 6691 * <p> 6692 * In order to set the matrix to a rotation transformation without post-multiplying, 6693 * use {@link #rotation(ref Quaterniond)}. 6694 * <p> 6695 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6696 * 6697 * @see #rotation(ref Quaterniond) 6698 * 6699 * @param quat 6700 * the {@link Quaterniond} 6701 * @param dest 6702 * will hold the result 6703 * @return dest 6704 */ 6705 public Matrix4d rotate(ref Quaterniond quat, ref Matrix4d dest) { 6706 if ((properties & PROPERTY_IDENTITY) != 0) 6707 return dest.rotation(quat); 6708 else if ((properties & PROPERTY_TRANSLATION) != 0) 6709 return rotateTranslation(quat, dest); 6710 else if ((properties & PROPERTY_AFFINE) != 0) 6711 return rotateAffine(quat, dest); 6712 return rotateGeneric(quat, dest); 6713 } 6714 private Matrix4d rotateGeneric(ref Quaterniond quat, ref Matrix4d dest) { 6715 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6716 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6717 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6718 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6719 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6720 double rm00 = w2 + x2 - z2 - y2; 6721 double rm01 = dxy + dzw; 6722 double rm02 = dxz - dyw; 6723 double rm10 = -dzw + dxy; 6724 double rm11 = y2 - z2 + w2 - x2; 6725 double rm12 = dyz + dxw; 6726 double rm20 = dyw + dxz; 6727 double rm21 = dyz - dxw; 6728 double rm22 = z2 - y2 - x2 + w2; 6729 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 6730 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 6731 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 6732 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 6733 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 6734 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 6735 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 6736 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 6737 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 6738 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 6739 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 6740 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 6741 ._m00(nm00) 6742 ._m01(nm01) 6743 ._m02(nm02) 6744 ._m03(nm03) 6745 ._m10(nm10) 6746 ._m11(nm11) 6747 ._m12(nm12) 6748 ._m13(nm13) 6749 ._m30(m30) 6750 ._m31(m31) 6751 ._m32(m32) 6752 ._m33(m33) 6753 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6754 return dest; 6755 } 6756 6757 6758 /** 6759 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 6760 * <p> 6761 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6762 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6763 * When used with a left-handed coordinate system, the rotation is clockwise. 6764 * <p> 6765 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6766 * then the new matrix will be <code>M * Q</code>. So when transforming a 6767 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6768 * the quaternion rotation will be applied first! 6769 * <p> 6770 * In order to set the matrix to a rotation transformation without post-multiplying, 6771 * use {@link #rotation(ref Quaterniond)}. 6772 * <p> 6773 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6774 * 6775 * @see #rotation(ref Quaterniond) 6776 * 6777 * @param quat 6778 * the {@link Quaterniond} 6779 * @return this 6780 */ 6781 ref public Matrix4d rotate(ref Quaterniond quat) return { 6782 rotate(quat, this); 6783 return this; 6784 } 6785 6786 6787 /** 6788 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this {@link #isAffine() affine} matrix and store 6789 * the result in <code>dest</code>. 6790 * <p> 6791 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 6792 * <p> 6793 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6794 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6795 * When used with a left-handed coordinate system, the rotation is clockwise. 6796 * <p> 6797 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6798 * then the new matrix will be <code>M * Q</code>. So when transforming a 6799 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6800 * the quaternion rotation will be applied first! 6801 * <p> 6802 * In order to set the matrix to a rotation transformation without post-multiplying, 6803 * use {@link #rotation(ref Quaterniond)}. 6804 * <p> 6805 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6806 * 6807 * @see #rotation(ref Quaterniond) 6808 * 6809 * @param quat 6810 * the {@link Quaterniond} 6811 * @param dest 6812 * will hold the result 6813 * @return dest 6814 */ 6815 public Matrix4d rotateAffine(ref Quaterniond quat, ref Matrix4d dest) { 6816 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6817 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6818 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6819 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6820 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6821 double rm00 = w2 + x2 - z2 - y2; 6822 double rm01 = dxy + dzw; 6823 double rm02 = dxz - dyw; 6824 double rm10 = -dzw + dxy; 6825 double rm11 = y2 - z2 + w2 - x2; 6826 double rm12 = dyz + dxw; 6827 double rm20 = dyw + dxz; 6828 double rm21 = dyz - dxw; 6829 double rm22 = z2 - y2 - x2 + w2; 6830 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 6831 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 6832 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 6833 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 6834 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 6835 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 6836 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 6837 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 6838 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 6839 ._m23(0.0) 6840 ._m00(nm00) 6841 ._m01(nm01) 6842 ._m02(nm02) 6843 ._m03(0.0) 6844 ._m10(nm10) 6845 ._m11(nm11) 6846 ._m12(nm12) 6847 ._m13(0.0) 6848 ._m30(m30) 6849 ._m31(m31) 6850 ._m32(m32) 6851 ._m33(m33) 6852 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6853 return dest; 6854 } 6855 6856 /** 6857 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 6858 * <p> 6859 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 6860 * <p> 6861 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6862 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6863 * When used with a left-handed coordinate system, the rotation is clockwise. 6864 * <p> 6865 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6866 * then the new matrix will be <code>M * Q</code>. So when transforming a 6867 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6868 * the quaternion rotation will be applied first! 6869 * <p> 6870 * In order to set the matrix to a rotation transformation without post-multiplying, 6871 * use {@link #rotation(ref Quaterniond)}. 6872 * <p> 6873 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6874 * 6875 * @see #rotation(ref Quaterniond) 6876 * 6877 * @param quat 6878 * the {@link Quaterniond} 6879 * @return this 6880 */ 6881 ref public Matrix4d rotateAffine(ref Quaterniond quat) return { 6882 rotateAffine(quat, this); 6883 return this; 6884 } 6885 6886 /** 6887 * 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 6888 * the result in <code>dest</code>. 6889 * <p> 6890 * This method assumes <code>this</code> to only contain a translation. 6891 * <p> 6892 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6893 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6894 * When used with a left-handed coordinate system, the rotation is clockwise. 6895 * <p> 6896 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6897 * then the new matrix will be <code>M * Q</code>. So when transforming a 6898 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6899 * the quaternion rotation will be applied first! 6900 * <p> 6901 * In order to set the matrix to a rotation transformation without post-multiplying, 6902 * use {@link #rotation(ref Quaterniond)}. 6903 * <p> 6904 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6905 * 6906 * @see #rotation(ref Quaterniond) 6907 * 6908 * @param quat 6909 * the {@link Quaterniond} 6910 * @param dest 6911 * will hold the result 6912 * @return dest 6913 */ 6914 public Matrix4d rotateTranslation(ref Quaterniond quat, ref Matrix4d dest) { 6915 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6916 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6917 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6918 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6919 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6920 double rm00 = w2 + x2 - z2 - y2; 6921 double rm01 = dxy + dzw; 6922 double rm02 = dxz - dyw; 6923 double rm10 = -dzw + dxy; 6924 double rm11 = y2 - z2 + w2 - x2; 6925 double rm12 = dyz + dxw; 6926 double rm20 = dyw + dxz; 6927 double rm21 = dyz - dxw; 6928 double rm22 = z2 - y2 - x2 + w2; 6929 dest._m20(rm20) 6930 ._m21(rm21) 6931 ._m22(rm22) 6932 ._m23(0.0) 6933 ._m00(rm00) 6934 ._m01(rm01) 6935 ._m02(rm02) 6936 ._m03(0.0) 6937 ._m10(rm10) 6938 ._m11(rm11) 6939 ._m12(rm12) 6940 ._m13(0.0) 6941 ._m30(m30) 6942 ._m31(m31) 6943 ._m32(m32) 6944 ._m33(1.0) 6945 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6946 return dest; 6947 } 6948 6949 6950 /** 6951 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store 6952 * the result in <code>dest</code>. 6953 * <p> 6954 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6955 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6956 * When used with a left-handed coordinate system, the rotation is clockwise. 6957 * <p> 6958 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6959 * then the new matrix will be <code>Q * M</code>. So when transforming a 6960 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 6961 * the quaternion rotation will be applied last! 6962 * <p> 6963 * In order to set the matrix to a rotation transformation without pre-multiplying, 6964 * use {@link #rotation(ref Quaterniond)}. 6965 * <p> 6966 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6967 * 6968 * @see #rotation(ref Quaterniond) 6969 * 6970 * @param quat 6971 * the {@link Quaterniond} 6972 * @param dest 6973 * will hold the result 6974 * @return dest 6975 */ 6976 public Matrix4d rotateLocal(ref Quaterniond quat, ref Matrix4d dest) { 6977 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6978 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6979 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6980 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6981 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6982 double lm00 = w2 + x2 - z2 - y2; 6983 double lm01 = dxy + dzw; 6984 double lm02 = dxz - dyw; 6985 double lm10 = -dzw + dxy; 6986 double lm11 = y2 - z2 + w2 - x2; 6987 double lm12 = dyz + dxw; 6988 double lm20 = dyw + dxz; 6989 double lm21 = dyz - dxw; 6990 double lm22 = z2 - y2 - x2 + w2; 6991 double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; 6992 double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; 6993 double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; 6994 double nm03 = m03; 6995 double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; 6996 double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; 6997 double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; 6998 double nm13 = m13; 6999 double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; 7000 double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; 7001 double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; 7002 double nm23 = m23; 7003 double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32; 7004 double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32; 7005 double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32; 7006 dest._m00(nm00) 7007 ._m01(nm01) 7008 ._m02(nm02) 7009 ._m03(nm03) 7010 ._m10(nm10) 7011 ._m11(nm11) 7012 ._m12(nm12) 7013 ._m13(nm13) 7014 ._m20(nm20) 7015 ._m21(nm21) 7016 ._m22(nm22) 7017 ._m23(nm23) 7018 ._m30(nm30) 7019 ._m31(nm31) 7020 ._m32(nm32) 7021 ._m33(m33) 7022 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7023 return dest; 7024 } 7025 7026 /** 7027 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 7028 * <p> 7029 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7030 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7031 * When used with a left-handed coordinate system, the rotation is clockwise. 7032 * <p> 7033 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 7034 * then the new matrix will be <code>Q * M</code>. So when transforming a 7035 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 7036 * the quaternion rotation will be applied last! 7037 * <p> 7038 * In order to set the matrix to a rotation transformation without pre-multiplying, 7039 * use {@link #rotation(ref Quaterniond)}. 7040 * <p> 7041 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 7042 * 7043 * @see #rotation(ref Quaterniond) 7044 * 7045 * @param quat 7046 * the {@link Quaterniond} 7047 * @return this 7048 */ 7049 ref public Matrix4d rotateLocal(ref Quaterniond quat) return { 7050 rotateLocal(quat, this); 7051 return this; 7052 } 7053 7054 7055 /** 7056 * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix. 7057 * <p> 7058 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7059 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7060 * When used with a left-handed coordinate system, the rotation is clockwise. 7061 * <p> 7062 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d}, 7063 * then the new matrix will be <code>M * A</code>. So when transforming a 7064 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7065 * the {@link AxisAngle4d} rotation will be applied first! 7066 * <p> 7067 * In order to set the matrix to a rotation transformation without post-multiplying, 7068 * use {@link #rotation(ref AxisAngle4d)}. 7069 * <p> 7070 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7071 * 7072 * @see #rotate(double, double, double, double) 7073 * @see #rotation(ref AxisAngle4d) 7074 * 7075 * @param axisAngle 7076 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 7077 * @return this 7078 */ 7079 ref public Matrix4d rotate(ref AxisAngle4d axisAngle) return { 7080 return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z); 7081 } 7082 7083 /** 7084 * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in <code>dest</code>. 7085 * <p> 7086 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7087 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7088 * When used with a left-handed coordinate system, the rotation is clockwise. 7089 * <p> 7090 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d}, 7091 * then the new matrix will be <code>M * A</code>. So when transforming a 7092 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7093 * the {@link AxisAngle4d} rotation will be applied first! 7094 * <p> 7095 * In order to set the matrix to a rotation transformation without post-multiplying, 7096 * use {@link #rotation(ref AxisAngle4d)}. 7097 * <p> 7098 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7099 * 7100 * @see #rotate(double, double, double, double) 7101 * @see #rotation(ref AxisAngle4d) 7102 * 7103 * @param axisAngle 7104 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 7105 * @param dest 7106 * will hold the result 7107 * @return dest 7108 */ 7109 public Matrix4d rotate(ref AxisAngle4d axisAngle, ref Matrix4d dest) { 7110 return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest); 7111 } 7112 7113 /** 7114 * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix. 7115 * <p> 7116 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7117 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7118 * When used with a left-handed coordinate system, the rotation is clockwise. 7119 * <p> 7120 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis, 7121 * then the new matrix will be <code>M * A</code>. So when transforming a 7122 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7123 * the axis-angle rotation will be applied first! 7124 * <p> 7125 * In order to set the matrix to a rotation transformation without post-multiplying, 7126 * use {@link #rotation(double, Vector3d)}. 7127 * <p> 7128 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7129 * 7130 * @see #rotate(double, double, double, double) 7131 * @see #rotation(double, Vector3d) 7132 * 7133 * @param angle 7134 * the angle in radians 7135 * @param axis 7136 * the rotation axis (needs to be {@link Vector3d#normalize() normalized}) 7137 * @return this 7138 */ 7139 ref public Matrix4d rotate(double angle, Vector3d axis) return { 7140 return rotate(angle, axis.x, axis.y, axis.z); 7141 } 7142 7143 /** 7144 * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in <code>dest</code>. 7145 * <p> 7146 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7147 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7148 * When used with a left-handed coordinate system, the rotation is clockwise. 7149 * <p> 7150 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis, 7151 * then the new matrix will be <code>M * A</code>. So when transforming a 7152 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7153 * the axis-angle rotation will be applied first! 7154 * <p> 7155 * In order to set the matrix to a rotation transformation without post-multiplying, 7156 * use {@link #rotation(double, Vector3d)}. 7157 * <p> 7158 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7159 * 7160 * @see #rotate(double, double, double, double) 7161 * @see #rotation(double, Vector3d) 7162 * 7163 * @param angle 7164 * the angle in radians 7165 * @param axis 7166 * the rotation axis (needs to be {@link Vector3d#normalize() normalized}) 7167 * @param dest 7168 * will hold the result 7169 * @return dest 7170 */ 7171 public Matrix4d rotate(double angle, Vector3d axis, ref Matrix4d dest) { 7172 return rotate(angle, axis.x, axis.y, axis.z, dest); 7173 } 7174 7175 public Vector4d getRow(int row, ref Vector4d dest) { 7176 switch (row) { 7177 case 0: 7178 dest.x = m00; 7179 dest.y = m10; 7180 dest.z = m20; 7181 dest.w = m30; 7182 break; 7183 case 1: 7184 dest.x = m01; 7185 dest.y = m11; 7186 dest.z = m21; 7187 dest.w = m31; 7188 break; 7189 case 2: 7190 dest.x = m02; 7191 dest.y = m12; 7192 dest.z = m22; 7193 dest.w = m32; 7194 break; 7195 case 3: 7196 dest.x = m03; 7197 dest.y = m13; 7198 dest.z = m23; 7199 dest.w = m33; 7200 break; 7201 default: {} 7202 } 7203 return dest; 7204 } 7205 7206 public Vector3d getRow(int row, ref Vector3d dest){ 7207 switch (row) { 7208 case 0: 7209 dest.x = m00; 7210 dest.y = m10; 7211 dest.z = m20; 7212 break; 7213 case 1: 7214 dest.x = m01; 7215 dest.y = m11; 7216 dest.z = m21; 7217 break; 7218 case 2: 7219 dest.x = m02; 7220 dest.y = m12; 7221 dest.z = m22; 7222 break; 7223 case 3: 7224 dest.x = m03; 7225 dest.y = m13; 7226 dest.z = m23; 7227 break; 7228 default: {} 7229 } 7230 return dest; 7231 } 7232 7233 /** 7234 * Set the row at the given <code>row</code> index, starting with <code>0</code>. 7235 * 7236 * @param row 7237 * the row index in <code>[0..3]</code> 7238 * @param src 7239 * the row components to set 7240 * @return this 7241 * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..3]</code> 7242 */ 7243 ref public Matrix4d setRow(int row, Vector4d src) return { 7244 switch (row) { 7245 case 0: 7246 return _m00(src.x)._m10(src.y)._m20(src.z)._m30(src.w)._properties(0); 7247 case 1: 7248 return _m01(src.x)._m11(src.y)._m21(src.z)._m31(src.w)._properties(0); 7249 case 2: 7250 return _m02(src.x)._m12(src.y)._m22(src.z)._m32(src.w)._properties(0); 7251 case 3: 7252 return _m03(src.x)._m13(src.y)._m23(src.z)._m33(src.w)._properties(0); 7253 default: 7254 return this; 7255 } 7256 } 7257 7258 public Vector4d getColumn(int column, ref Vector4d dest) { 7259 switch (column) { 7260 case 0: 7261 dest.x = m00; 7262 dest.y = m01; 7263 dest.z = m02; 7264 dest.w = m03; 7265 break; 7266 case 1: 7267 dest.x = m10; 7268 dest.y = m11; 7269 dest.z = m12; 7270 dest.w = m13; 7271 break; 7272 case 2: 7273 dest.x = m20; 7274 dest.y = m21; 7275 dest.z = m22; 7276 dest.w = m23; 7277 break; 7278 case 3: 7279 dest.x = m30; 7280 dest.y = m31; 7281 dest.z = m32; 7282 dest.w = m33; 7283 break; 7284 default: {} 7285 } 7286 return dest; 7287 } 7288 7289 public Vector3d getColumn(int column, ref Vector3d dest) { 7290 switch (column) { 7291 case 0: 7292 dest.x = m00; 7293 dest.y = m01; 7294 dest.z = m02; 7295 break; 7296 case 1: 7297 dest.x = m10; 7298 dest.y = m11; 7299 dest.z = m12; 7300 break; 7301 case 2: 7302 dest.x = m20; 7303 dest.y = m21; 7304 dest.z = m22; 7305 break; 7306 case 3: 7307 dest.x = m30; 7308 dest.y = m31; 7309 dest.z = m32; 7310 break; 7311 default: {} 7312 } 7313 return dest; 7314 } 7315 7316 /** 7317 * Set the column at the given <code>column</code> index, starting with <code>0</code>. 7318 * 7319 * @param column 7320 * the column index in <code>[0..3]</code> 7321 * @param src 7322 * the column components to set 7323 * @return this 7324 * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..3]</code> 7325 */ 7326 ref public Matrix4d setColumn(int column, Vector4d src) return { 7327 switch (column) { 7328 case 0: 7329 return _m00(src.x)._m01(src.y)._m02(src.z)._m03(src.w)._properties(0); 7330 case 1: 7331 return _m10(src.x)._m11(src.y)._m12(src.z)._m13(src.w)._properties(0); 7332 case 2: 7333 return _m20(src.x)._m21(src.y)._m22(src.z)._m23(src.w)._properties(0); 7334 case 3: 7335 return _m30(src.x)._m31(src.y)._m32(src.z)._m33(src.w)._properties(0); 7336 default: 7337 return this; 7338 } 7339 } 7340 7341 public double get(int column, int row) { 7342 return MemUtil.get(this, column, row); 7343 } 7344 7345 /** 7346 * Set the matrix element at the given column and row to the specified value. 7347 * 7348 * @param column 7349 * the colum index in <code>[0..3]</code> 7350 * @param row 7351 * the row index in <code>[0..3]</code> 7352 * @param value 7353 * the value 7354 * @return this 7355 */ 7356 ref public Matrix4d set(int column, int row, double value) return { 7357 MemUtil.set(this, column, row, value); 7358 return this; 7359 } 7360 7361 public double getRowColumn(int row, int column) { 7362 return MemUtil.get(this, column, row); 7363 } 7364 7365 /** 7366 * Set the matrix element at the given row and column to the specified value. 7367 * 7368 * @param row 7369 * the row index in <code>[0..3]</code> 7370 * @param column 7371 * the colum index in <code>[0..3]</code> 7372 * @param value 7373 * the value 7374 * @return this 7375 */ 7376 ref public Matrix4d setRowColumn(int row, int column, double value) return { 7377 MemUtil.set(this, column, row, value); 7378 return this; 7379 } 7380 7381 /** 7382 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7383 * and store it into the upper left 3x3 submatrix of <code>this</code>. 7384 * All other values of <code>this</code> will be set to {@link #identity() identity}. 7385 * <p> 7386 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7387 * <p> 7388 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7389 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7390 * In that case, use {@link #set3x3(Matrix4d)} to set a given Matrix4f to only the upper left 3x3 submatrix 7391 * of this matrix. 7392 * 7393 * @see #set3x3(Matrix4d) 7394 * 7395 * @return this 7396 */ 7397 ref public Matrix4d normal() return { 7398 normal(this); 7399 return this; 7400 } 7401 7402 /** 7403 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7404 * and store it into the upper left 3x3 submatrix of <code>dest</code>. 7405 * All other values of <code>dest</code> will be set to {@link #identity() identity}. 7406 * <p> 7407 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7408 * <p> 7409 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7410 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7411 * In that case, use {@link #set3x3(Matrix4d)} to set a given Matrix4d to only the upper left 3x3 submatrix 7412 * of a given matrix. 7413 * 7414 * @see #set3x3(Matrix4d) 7415 * 7416 * @param dest 7417 * will hold the result 7418 * @return dest 7419 */ 7420 public Matrix4d normal(ref Matrix4d dest) { 7421 if ((properties & PROPERTY_IDENTITY) != 0) 7422 return dest.identity(); 7423 else if ((properties & PROPERTY_ORTHONORMAL) != 0) 7424 return normalOrthonormal(dest); 7425 return normalGeneric(dest); 7426 } 7427 private Matrix4d normalOrthonormal(ref Matrix4d dest) { 7428 if (dest != this) 7429 dest.set(this); 7430 return dest._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 7431 } 7432 private Matrix4d normalGeneric(ref Matrix4d dest) { 7433 double m00m11 = m00 * m11; 7434 double m01m10 = m01 * m10; 7435 double m02m10 = m02 * m10; 7436 double m00m12 = m00 * m12; 7437 double m01m12 = m01 * m12; 7438 double m02m11 = m02 * m11; 7439 double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; 7440 double s = 1.0 / det; 7441 /* Invert and transpose in one go */ 7442 double nm00 = (m11 * m22 - m21 * m12) * s; 7443 double nm01 = (m20 * m12 - m10 * m22) * s; 7444 double nm02 = (m10 * m21 - m20 * m11) * s; 7445 double nm10 = (m21 * m02 - m01 * m22) * s; 7446 double nm11 = (m00 * m22 - m20 * m02) * s; 7447 double nm12 = (m20 * m01 - m00 * m21) * s; 7448 double nm20 = (m01m12 - m02m11) * s; 7449 double nm21 = (m02m10 - m00m12) * s; 7450 double nm22 = (m00m11 - m01m10) * s; 7451 return dest 7452 ._m00(nm00) 7453 ._m01(nm01) 7454 ._m02(nm02) 7455 ._m03(0.0) 7456 ._m10(nm10) 7457 ._m11(nm11) 7458 ._m12(nm12) 7459 ._m13(0.0) 7460 ._m20(nm20) 7461 ._m21(nm21) 7462 ._m22(nm22) 7463 ._m23(0.0) 7464 ._m30(0.0) 7465 ._m31(0.0) 7466 ._m32(0.0) 7467 ._m33(1.0) 7468 ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE)); 7469 } 7470 7471 /** 7472 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7473 * and store it into <code>dest</code>. 7474 * <p> 7475 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7476 * <p> 7477 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7478 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7479 * In that case, use {@link Matrix3d#set(Matrix4d)} to set a given Matrix3d to only the upper left 3x3 submatrix 7480 * of this matrix. 7481 * 7482 * @see Matrix3d#set(Matrix4d) 7483 * @see #get3x3(Matrix3d) 7484 * 7485 * @param dest 7486 * will hold the result 7487 * @return dest 7488 */ 7489 public Matrix3d normal(ref Matrix3d dest) { 7490 if ((properties & PROPERTY_ORTHONORMAL) != 0) 7491 return normalOrthonormal(dest); 7492 return normalGeneric(dest); 7493 } 7494 private Matrix3d normalOrthonormal(ref Matrix3d dest) { 7495 dest.set(this); 7496 return dest; 7497 } 7498 private Matrix3d normalGeneric(ref Matrix3d dest) { 7499 double m00m11 = m00 * m11; 7500 double m01m10 = m01 * m10; 7501 double m02m10 = m02 * m10; 7502 double m00m12 = m00 * m12; 7503 double m01m12 = m01 * m12; 7504 double m02m11 = m02 * m11; 7505 double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; 7506 double s = 1.0 / det; 7507 /* Invert and transpose in one go */ 7508 return dest._m00((m11 * m22 - m21 * m12) * s) 7509 ._m01((m20 * m12 - m10 * m22) * s) 7510 ._m02((m10 * m21 - m20 * m11) * s) 7511 ._m10((m21 * m02 - m01 * m22) * s) 7512 ._m11((m00 * m22 - m20 * m02) * s) 7513 ._m12((m20 * m01 - m00 * m21) * s) 7514 ._m20((m01m12 - m02m11) * s) 7515 ._m21((m02m10 - m00m12) * s) 7516 ._m22((m00m11 - m01m10) * s); 7517 } 7518 7519 /** 7520 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code>. 7521 * <p> 7522 * The cofactor matrix can be used instead of {@link #normal()} to transform normals 7523 * when the orientation of the normals with respect to the surface should be preserved. 7524 * 7525 * @return this 7526 */ 7527 ref public Matrix4d cofactor3x3() return { 7528 cofactor3x3(this); 7529 return this; 7530 } 7531 7532 /** 7533 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code> 7534 * and store it into <code>dest</code>. 7535 * <p> 7536 * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals 7537 * when the orientation of the normals with respect to the surface should be preserved. 7538 * 7539 * @param dest 7540 * will hold the result 7541 * @return dest 7542 */ 7543 public Matrix3d cofactor3x3(ref Matrix3d dest) { 7544 return dest._m00(m11 * m22 - m21 * m12) 7545 ._m01(m20 * m12 - m10 * m22) 7546 ._m02(m10 * m21 - m20 * m11) 7547 ._m10(m21 * m02 - m01 * m22) 7548 ._m11(m00 * m22 - m20 * m02) 7549 ._m12(m20 * m01 - m00 * m21) 7550 ._m20(m01 * m12 - m02 * m11) 7551 ._m21(m02 * m10 - m00 * m12) 7552 ._m22(m00 * m11 - m01 * m10); 7553 } 7554 7555 /** 7556 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code> 7557 * and store it into <code>dest</code>. 7558 * All other values of <code>dest</code> will be set to {@link #identity() identity}. 7559 * <p> 7560 * The cofactor matrix can be used instead of {@link #normal(Matrix4d)} to transform normals 7561 * when the orientation of the normals with respect to the surface should be preserved. 7562 * 7563 * @param dest 7564 * will hold the result 7565 * @return dest 7566 */ 7567 public Matrix4d cofactor3x3(ref Matrix4d dest) { 7568 double nm10 = m21 * m02 - m01 * m22; 7569 double nm11 = m00 * m22 - m20 * m02; 7570 double nm12 = m20 * m01 - m00 * m21; 7571 double nm20 = m01 * m12 - m11 * m02; 7572 double nm21 = m02 * m10 - m12 * m00; 7573 double nm22 = m00 * m11 - m10 * m01; 7574 return dest 7575 ._m00(m11 * m22 - m21 * m12) 7576 ._m01(m20 * m12 - m10 * m22) 7577 ._m02(m10 * m21 - m20 * m11) 7578 ._m03(0.0) 7579 ._m10(nm10) 7580 ._m11(nm11) 7581 ._m12(nm12) 7582 ._m13(0.0) 7583 ._m20(nm20) 7584 ._m21(nm21) 7585 ._m22(nm22) 7586 ._m23(0.0) 7587 ._m30(0.0) 7588 ._m31(0.0) 7589 ._m32(0.0) 7590 ._m33(1.0) 7591 ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE)); 7592 } 7593 7594 /** 7595 * Normalize the upper left 3x3 submatrix of this matrix. 7596 * <p> 7597 * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit 7598 * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself 7599 * (i.e. had <i>skewing</i>). 7600 * 7601 * @return this 7602 */ 7603 ref public Matrix4d normalize3x3() return { 7604 normalize3x3(this); 7605 return this; 7606 } 7607 7608 public Matrix4d normalize3x3(ref Matrix4d dest) { 7609 double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 7610 double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 7611 double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 7612 dest._m00(m00 * invXlen)._m01(m01 * invXlen)._m02(m02 * invXlen) 7613 ._m10(m10 * invYlen)._m11(m11 * invYlen)._m12(m12 * invYlen) 7614 ._m20(m20 * invZlen)._m21(m21 * invZlen)._m22(m22 * invZlen) 7615 ._m30(m30)._m31(m31)._m32(m32)._m33(m33) 7616 ._properties(properties); 7617 return dest; 7618 } 7619 7620 public Matrix3d normalize3x3(ref Matrix3d dest) { 7621 double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 7622 double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 7623 double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 7624 dest.m00 = (m00 * invXlen); 7625 dest.m01 = (m01 * invXlen); 7626 dest.m02 = (m02 * invXlen); 7627 7628 dest.m10 = (m10 * invYlen); 7629 dest.m11 = (m11 * invYlen); 7630 dest.m12 = (m12 * invYlen); 7631 7632 dest.m20 = (m20 * invZlen); 7633 dest.m21 = (m21 * invZlen); 7634 dest.m22 = (m22 * invZlen); 7635 return dest; 7636 } 7637 7638 public Vector4d unproject(double winX, double winY, double winZ, int[] viewport, ref Vector4d dest) { 7639 double a = m00 * m11 - m01 * m10; 7640 double b = m00 * m12 - m02 * m10; 7641 double c = m00 * m13 - m03 * m10; 7642 double d = m01 * m12 - m02 * m11; 7643 double e = m01 * m13 - m03 * m11; 7644 double f = m02 * m13 - m03 * m12; 7645 double g = m20 * m31 - m21 * m30; 7646 double h = m20 * m32 - m22 * m30; 7647 double i = m20 * m33 - m23 * m30; 7648 double j = m21 * m32 - m22 * m31; 7649 double k = m21 * m33 - m23 * m31; 7650 double l = m22 * m33 - m23 * m32; 7651 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7652 det = 1.0 / det; 7653 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7654 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7655 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7656 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7657 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7658 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7659 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7660 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7661 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7662 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7663 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7664 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7665 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7666 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7667 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7668 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7669 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7670 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7671 double ndcZ = winZ+winZ-1.0; 7672 double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); 7673 dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW; 7674 dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW; 7675 dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW; 7676 dest.w = 1.0; 7677 return dest; 7678 } 7679 7680 public Vector3d unproject(double winX, double winY, double winZ, int[] viewport, ref Vector3d dest) { 7681 double a = m00 * m11 - m01 * m10; 7682 double b = m00 * m12 - m02 * m10; 7683 double c = m00 * m13 - m03 * m10; 7684 double d = m01 * m12 - m02 * m11; 7685 double e = m01 * m13 - m03 * m11; 7686 double f = m02 * m13 - m03 * m12; 7687 double g = m20 * m31 - m21 * m30; 7688 double h = m20 * m32 - m22 * m30; 7689 double i = m20 * m33 - m23 * m30; 7690 double j = m21 * m32 - m22 * m31; 7691 double k = m21 * m33 - m23 * m31; 7692 double l = m22 * m33 - m23 * m32; 7693 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7694 det = 1.0 / det; 7695 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7696 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7697 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7698 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7699 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7700 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7701 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7702 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7703 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7704 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7705 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7706 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7707 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7708 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7709 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7710 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7711 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7712 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7713 double ndcZ = winZ+winZ-1.0; 7714 double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); 7715 dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW; 7716 dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW; 7717 dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW; 7718 return dest; 7719 } 7720 7721 public Vector4d unproject(ref Vector3d winCoords, int[] viewport, ref Vector4d dest) { 7722 return unproject(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7723 } 7724 7725 public Vector3d unproject(ref Vector3d winCoords, int[] viewport, ref Vector3d dest) { 7726 return unproject(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7727 } 7728 7729 ref public Matrix4d unprojectRay(double winX, double winY, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) return { 7730 double a = m00 * m11 - m01 * m10; 7731 double b = m00 * m12 - m02 * m10; 7732 double c = m00 * m13 - m03 * m10; 7733 double d = m01 * m12 - m02 * m11; 7734 double e = m01 * m13 - m03 * m11; 7735 double f = m02 * m13 - m03 * m12; 7736 double g = m20 * m31 - m21 * m30; 7737 double h = m20 * m32 - m22 * m30; 7738 double i = m20 * m33 - m23 * m30; 7739 double j = m21 * m32 - m22 * m31; 7740 double k = m21 * m33 - m23 * m31; 7741 double l = m22 * m33 - m23 * m32; 7742 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7743 det = 1.0 / det; 7744 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7745 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7746 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7747 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7748 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7749 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7750 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7751 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7752 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7753 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7754 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7755 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7756 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7757 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7758 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7759 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7760 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7761 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7762 double px = im00 * ndcX + im10 * ndcY + im30; 7763 double py = im01 * ndcX + im11 * ndcY + im31; 7764 double pz = im02 * ndcX + im12 * ndcY + im32; 7765 double invNearW = 1.0 / (im03 * ndcX + im13 * ndcY - im23 + im33); 7766 double nearX = (px - im20) * invNearW; 7767 double nearY = (py - im21) * invNearW; 7768 double nearZ = (pz - im22) * invNearW; 7769 double invW0 = 1.0 / (im03 * ndcX + im13 * ndcY + im33); 7770 double x0 = px * invW0; 7771 double y0 = py * invW0; 7772 double z0 = pz * invW0; 7773 originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ; 7774 dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ; 7775 return this; 7776 } 7777 7778 public Matrix4d unprojectRay(ref Vector2d winCoords, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) { 7779 return unprojectRay(winCoords.x, winCoords.y, viewport, originDest, dirDest); 7780 } 7781 7782 public Vector4d unprojectInv(ref Vector3d winCoords, int[] viewport, ref Vector4d dest) { 7783 return unprojectInv(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7784 } 7785 7786 public Vector4d unprojectInv(double winX, double winY, double winZ, int[] viewport, ref Vector4d dest) { 7787 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7788 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7789 double ndcZ = winZ+winZ-1.0; 7790 double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33); 7791 dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW; 7792 dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW; 7793 dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW; 7794 dest.w = 1.0; 7795 return dest; 7796 } 7797 7798 public Vector3d unprojectInv(ref Vector3d winCoords, int[] viewport, ref Vector3d dest) { 7799 return unprojectInv(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7800 } 7801 7802 public Vector3d unprojectInv(double winX, double winY, double winZ, int[] viewport, ref Vector3d dest) { 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 ndcZ = winZ+winZ-1.0; 7806 double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33); 7807 dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW; 7808 dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW; 7809 dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW; 7810 return dest; 7811 } 7812 7813 public Matrix4d unprojectInvRay(ref Vector2d winCoords, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) { 7814 return unprojectInvRay(winCoords.x, winCoords.y, viewport, originDest, dirDest); 7815 } 7816 7817 ref public Matrix4d unprojectInvRay(double winX, double winY, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) return { 7818 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7819 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7820 double px = m00 * ndcX + m10 * ndcY + m30; 7821 double py = m01 * ndcX + m11 * ndcY + m31; 7822 double pz = m02 * ndcX + m12 * ndcY + m32; 7823 double invNearW = 1.0 / (m03 * ndcX + m13 * ndcY - m23 + m33); 7824 double nearX = (px - m20) * invNearW; 7825 double nearY = (py - m21) * invNearW; 7826 double nearZ = (pz - m22) * invNearW; 7827 double invW0 = 1.0 / (m03 * ndcX + m13 * ndcY + m33); 7828 double x0 = px * invW0; 7829 double y0 = py * invW0; 7830 double z0 = pz * invW0; 7831 originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ; 7832 dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ; 7833 return this; 7834 } 7835 7836 public Vector4d project(double x, double y, double z, int[] viewport, ref Vector4d winCoordsDest) { 7837 double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))); 7838 double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW; 7839 double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW; 7840 double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW; 7841 return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]), 7842 Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]), 7843 Math.fma(0.5, nz, 0.5), 7844 1.0); 7845 } 7846 7847 public Vector3d project(double x, double y, double z, int[] viewport, ref Vector3d winCoordsDest) { 7848 double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))); 7849 double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW; 7850 double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW; 7851 double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW; 7852 winCoordsDest.x = Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]); 7853 winCoordsDest.y = Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]); 7854 winCoordsDest.z = Math.fma(0.5, nz, 0.5); 7855 return winCoordsDest; 7856 } 7857 7858 public Vector4d project(ref Vector3d position, int[] viewport, ref Vector4d dest) { 7859 return project(position.x, position.y, position.z, viewport, dest); 7860 } 7861 7862 public Vector3d project(ref Vector3d position, int[] viewport, ref Vector3d dest) { 7863 return project(position.x, position.y, position.z, viewport, dest); 7864 } 7865 7866 public Matrix4d reflect(double a, double b, double c, double d, ref Matrix4d dest) { 7867 if ((properties & PROPERTY_IDENTITY) != 0) 7868 return dest.reflection(a, b, c, d); 7869 if ((properties & PROPERTY_IDENTITY) != 0) 7870 return dest.reflection(a, b, c, d); 7871 else if ((properties & PROPERTY_AFFINE) != 0) 7872 return reflectAffine(a, b, c, d, dest); 7873 return reflectGeneric(a, b, c, d, dest); 7874 } 7875 private Matrix4d reflectAffine(double a, double b, double c, double d, ref Matrix4d dest) { 7876 double da = a + a, db = b + b, dc = c + c, dd = d + d; 7877 double rm00 = 1.0 - da * a; 7878 double rm01 = -da * b; 7879 double rm02 = -da * c; 7880 double rm10 = -db * a; 7881 double rm11 = 1.0 - db * b; 7882 double rm12 = -db * c; 7883 double rm20 = -dc * a; 7884 double rm21 = -dc * b; 7885 double rm22 = 1.0 - dc * c; 7886 double rm30 = -dd * a; 7887 double rm31 = -dd * b; 7888 double rm32 = -dd * c; 7889 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 7890 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 7891 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 7892 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 7893 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 7894 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 7895 // matrix multiplication 7896 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 7897 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 7898 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 7899 ._m33(m33) 7900 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 7901 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 7902 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 7903 ._m23(0.0) 7904 ._m00(nm00) 7905 ._m01(nm01) 7906 ._m02(nm02) 7907 ._m03(0.0) 7908 ._m10(nm10) 7909 ._m11(nm11) 7910 ._m12(nm12) 7911 ._m13(0.0) 7912 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7913 return dest; 7914 } 7915 private Matrix4d reflectGeneric(double a, double b, double c, double d, ref Matrix4d dest) { 7916 double da = a + a, db = b + b, dc = c + c, dd = d + d; 7917 double rm00 = 1.0 - da * a; 7918 double rm01 = -da * b; 7919 double rm02 = -da * c; 7920 double rm10 = -db * a; 7921 double rm11 = 1.0 - db * b; 7922 double rm12 = -db * c; 7923 double rm20 = -dc * a; 7924 double rm21 = -dc * b; 7925 double rm22 = 1.0 - dc * c; 7926 double rm30 = -dd * a; 7927 double rm31 = -dd * b; 7928 double rm32 = -dd * c; 7929 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 7930 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 7931 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 7932 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 7933 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 7934 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 7935 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 7936 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 7937 // matrix multiplication 7938 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 7939 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 7940 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 7941 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 7942 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 7943 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 7944 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 7945 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 7946 ._m00(nm00) 7947 ._m01(nm01) 7948 ._m02(nm02) 7949 ._m03(nm03) 7950 ._m10(nm10) 7951 ._m11(nm11) 7952 ._m12(nm12) 7953 ._m13(nm13) 7954 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7955 return dest; 7956 } 7957 7958 /** 7959 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 7960 * specified via the equation <code>x*a + y*b + z*c + d = 0</code>. 7961 * <p> 7962 * The vector <code>(a, b, c)</code> must be a unit vector. 7963 * <p> 7964 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 7965 * then the new matrix will be <code>M * R</code>. So when transforming a 7966 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 7967 * reflection will be applied first! 7968 * <p> 7969 * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a> 7970 * 7971 * @param a 7972 * the x factor in the plane equation 7973 * @param b 7974 * the y factor in the plane equation 7975 * @param c 7976 * the z factor in the plane equation 7977 * @param d 7978 * the constant in the plane equation 7979 * @return this 7980 */ 7981 ref public Matrix4d reflect(double a, double b, double c, double d) return { 7982 reflect(a, b, c, d, this); 7983 return this; 7984 } 7985 7986 /** 7987 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 7988 * specified via the plane normal and a point on the plane. 7989 * <p> 7990 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 7991 * then the new matrix will be <code>M * R</code>. So when transforming a 7992 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 7993 * reflection will be applied first! 7994 * 7995 * @param nx 7996 * the x-coordinate of the plane normal 7997 * @param ny 7998 * the y-coordinate of the plane normal 7999 * @param nz 8000 * the z-coordinate of the plane normal 8001 * @param px 8002 * the x-coordinate of a point on the plane 8003 * @param py 8004 * the y-coordinate of a point on the plane 8005 * @param pz 8006 * the z-coordinate of a point on the plane 8007 * @return this 8008 */ 8009 ref public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz) return { 8010 reflect(nx, ny, nz, px, py, pz, this); 8011 return this; 8012 } 8013 8014 public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz, ref Matrix4d dest) { 8015 double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz); 8016 double nnx = nx * invLength; 8017 double nny = ny * invLength; 8018 double nnz = nz * invLength; 8019 /* See: http://mathworld.wolfram.com/Plane.html */ 8020 return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest); 8021 } 8022 8023 /** 8024 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 8025 * specified via the plane normal and a point on the plane. 8026 * <p> 8027 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8028 * then the new matrix will be <code>M * R</code>. So when transforming a 8029 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8030 * reflection will be applied first! 8031 * 8032 * @param normal 8033 * the plane normal 8034 * @param point 8035 * a point on the plane 8036 * @return this 8037 */ 8038 ref public Matrix4d reflect(ref Vector3d normal, Vector3d point) return { 8039 return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z); 8040 } 8041 8042 /** 8043 * Apply a mirror/reflection transformation to this matrix that reflects about a plane 8044 * specified via the plane orientation and a point on the plane. 8045 * <p> 8046 * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. 8047 * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is 8048 * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>. 8049 * <p> 8050 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8051 * then the new matrix will be <code>M * R</code>. So when transforming a 8052 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8053 * reflection will be applied first! 8054 * 8055 * @param orientation 8056 * the plane orientation relative to an implied normal vector of <code>(0, 0, 1)</code> 8057 * @param point 8058 * a point on the plane 8059 * @return this 8060 */ 8061 ref public Matrix4d reflect(ref Quaterniond orientation, Vector3d point) return { 8062 reflect(orientation, point, this); 8063 return this; 8064 } 8065 8066 public Matrix4d reflect(ref Quaterniond orientation, Vector3d point, ref Matrix4d dest) { 8067 double num1 = orientation.x + orientation.x; 8068 double num2 = orientation.y + orientation.y; 8069 double num3 = orientation.z + orientation.z; 8070 double normalX = orientation.x * num3 + orientation.w * num2; 8071 double normalY = orientation.y * num3 - orientation.w * num1; 8072 double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2); 8073 return reflect(normalX, normalY, normalZ, point.x, point.y, point.z, dest); 8074 } 8075 8076 public Matrix4d reflect(ref Vector3d normal, Vector3d point, ref Matrix4d dest) { 8077 return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z, dest); 8078 } 8079 8080 /** 8081 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8082 * specified via the equation <code>x*a + y*b + z*c + d = 0</code>. 8083 * <p> 8084 * The vector <code>(a, b, c)</code> must be a unit vector. 8085 * <p> 8086 * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a> 8087 * 8088 * @param a 8089 * the x factor in the plane equation 8090 * @param b 8091 * the y factor in the plane equation 8092 * @param c 8093 * the z factor in the plane equation 8094 * @param d 8095 * the constant in the plane equation 8096 * @return this 8097 */ 8098 ref public Matrix4d reflection(double a, double b, double c, double d) return { 8099 double da = a + a, db = b + b, dc = c + c, dd = d + d; 8100 _m00(1.0 - da * a). 8101 _m01(-da * b). 8102 _m02(-da * c). 8103 _m03(0.0). 8104 _m10(-db * a). 8105 _m11(1.0 - db * b). 8106 _m12(-db * c). 8107 _m13(0.0). 8108 _m20(-dc * a). 8109 _m21(-dc * b). 8110 _m22(1.0 - dc * c). 8111 _m23(0.0). 8112 _m30(-dd * a). 8113 _m31(-dd * b). 8114 _m32(-dd * c). 8115 _m33(1.0). 8116 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 8117 return this; 8118 } 8119 8120 /** 8121 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8122 * specified via the plane normal and a point on the plane. 8123 * 8124 * @param nx 8125 * the x-coordinate of the plane normal 8126 * @param ny 8127 * the y-coordinate of the plane normal 8128 * @param nz 8129 * the z-coordinate of the plane normal 8130 * @param px 8131 * the x-coordinate of a point on the plane 8132 * @param py 8133 * the y-coordinate of a point on the plane 8134 * @param pz 8135 * the z-coordinate of a point on the plane 8136 * @return this 8137 */ 8138 ref public Matrix4d reflection(double nx, double ny, double nz, double px, double py, double pz) return { 8139 double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz); 8140 double nnx = nx * invLength; 8141 double nny = ny * invLength; 8142 double nnz = nz * invLength; 8143 /* See: http://mathworld.wolfram.com/Plane.html */ 8144 return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz); 8145 } 8146 8147 /** 8148 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8149 * specified via the plane normal and a point on the plane. 8150 * 8151 * @param normal 8152 * the plane normal 8153 * @param point 8154 * a point on the plane 8155 * @return this 8156 */ 8157 ref public Matrix4d reflection(ref Vector3d normal, Vector3d point) return { 8158 return reflection(normal.x, normal.y, normal.z, point.x, point.y, point.z); 8159 } 8160 8161 /** 8162 * Set this matrix to a mirror/reflection transformation that reflects about a plane 8163 * specified via the plane orientation and a point on the plane. 8164 * <p> 8165 * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. 8166 * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is 8167 * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>. 8168 * 8169 * @param orientation 8170 * the plane orientation 8171 * @param point 8172 * a point on the plane 8173 * @return this 8174 */ 8175 ref public Matrix4d reflection(ref Quaterniond orientation, Vector3d point) return { 8176 double num1 = orientation.x + orientation.x; 8177 double num2 = orientation.y + orientation.y; 8178 double num3 = orientation.z + orientation.z; 8179 double normalX = orientation.x * num3 + orientation.w * num2; 8180 double normalY = orientation.y * num3 - orientation.w * num1; 8181 double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2); 8182 return reflection(normalX, normalY, normalZ, point.x, point.y, point.z); 8183 } 8184 8185 /** 8186 * Apply an orthographic projection transformation for a right-handed coordinate system 8187 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8188 * <p> 8189 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8190 * then the new matrix will be <code>M * O</code>. So when transforming a 8191 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8192 * orthographic projection transformation will be applied first! 8193 * <p> 8194 * In order to set the matrix to an orthographic projection without post-multiplying it, 8195 * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}. 8196 * <p> 8197 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8198 * 8199 * @see #setOrtho(double, double, double, double, double, double, bool) 8200 * 8201 * @param left 8202 * the distance from the center to the left frustum edge 8203 * @param right 8204 * the distance from the center to the right frustum edge 8205 * @param bottom 8206 * the distance from the center to the bottom frustum edge 8207 * @param top 8208 * the distance from the center to the top frustum edge 8209 * @param zNear 8210 * near clipping plane distance 8211 * @param zFar 8212 * far clipping plane distance 8213 * @param zZeroToOne 8214 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8215 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8216 * @param dest 8217 * will hold the result 8218 * @return dest 8219 */ 8220 public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8221 if ((properties & PROPERTY_IDENTITY) != 0) 8222 return dest.setOrtho(left, right, bottom, top, zNear, zFar, zZeroToOne); 8223 return orthoGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 8224 } 8225 private Matrix4d orthoGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8226 // calculate right matrix elements 8227 double rm00 = 2.0 / (right - left); 8228 double rm11 = 2.0 / (top - bottom); 8229 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar); 8230 double rm30 = (left + right) / (left - right); 8231 double rm31 = (top + bottom) / (bottom - top); 8232 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8233 // perform optimized multiplication 8234 // compute the last column first, because other columns do not depend on it 8235 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 8236 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 8237 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 8238 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 8239 ._m00(m00 * rm00) 8240 ._m01(m01 * rm00) 8241 ._m02(m02 * rm00) 8242 ._m03(m03 * rm00) 8243 ._m10(m10 * rm11) 8244 ._m11(m11 * rm11) 8245 ._m12(m12 * rm11) 8246 ._m13(m13 * rm11) 8247 ._m20(m20 * rm22) 8248 ._m21(m21 * rm22) 8249 ._m22(m22 * rm22) 8250 ._m23(m23 * rm22) 8251 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8252 return dest; 8253 } 8254 8255 /** 8256 * Apply an orthographic projection transformation for a right-handed coordinate system 8257 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8258 * <p> 8259 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8260 * then the new matrix will be <code>M * O</code>. So when transforming a 8261 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8262 * orthographic projection transformation will be applied first! 8263 * <p> 8264 * In order to set the matrix to an orthographic projection without post-multiplying it, 8265 * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}. 8266 * <p> 8267 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8268 * 8269 * @see #setOrtho(double, double, double, double, double, double) 8270 * 8271 * @param left 8272 * the distance from the center to the left frustum edge 8273 * @param right 8274 * the distance from the center to the right frustum edge 8275 * @param bottom 8276 * the distance from the center to the bottom frustum edge 8277 * @param top 8278 * the distance from the center to the top frustum edge 8279 * @param zNear 8280 * near clipping plane distance 8281 * @param zFar 8282 * far clipping plane distance 8283 * @param dest 8284 * will hold the result 8285 * @return dest 8286 */ 8287 public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 8288 return ortho(left, right, bottom, top, zNear, zFar, false, dest); 8289 } 8290 8291 /** 8292 * Apply an orthographic projection transformation for a right-handed coordinate system 8293 * using the given NDC z range to this matrix. 8294 * <p> 8295 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8296 * then the new matrix will be <code>M * O</code>. So when transforming a 8297 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8298 * orthographic projection transformation will be applied first! 8299 * <p> 8300 * In order to set the matrix to an orthographic projection without post-multiplying it, 8301 * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}. 8302 * <p> 8303 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8304 * 8305 * @see #setOrtho(double, double, double, double, double, double, bool) 8306 * 8307 * @param left 8308 * the distance from the center to the left frustum edge 8309 * @param right 8310 * the distance from the center to the right frustum edge 8311 * @param bottom 8312 * the distance from the center to the bottom frustum edge 8313 * @param top 8314 * the distance from the center to the top frustum edge 8315 * @param zNear 8316 * near clipping plane distance 8317 * @param zFar 8318 * far clipping plane distance 8319 * @param zZeroToOne 8320 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8321 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8322 * @return this 8323 */ 8324 ref public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8325 ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 8326 return this; 8327 } 8328 8329 /** 8330 * Apply an orthographic projection transformation for a right-handed coordinate system 8331 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8332 * <p> 8333 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8334 * then the new matrix will be <code>M * O</code>. So when transforming a 8335 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8336 * orthographic projection transformation will be applied first! 8337 * <p> 8338 * In order to set the matrix to an orthographic projection without post-multiplying it, 8339 * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}. 8340 * <p> 8341 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8342 * 8343 * @see #setOrtho(double, double, double, double, double, double) 8344 * 8345 * @param left 8346 * the distance from the center to the left frustum edge 8347 * @param right 8348 * the distance from the center to the right frustum edge 8349 * @param bottom 8350 * the distance from the center to the bottom frustum edge 8351 * @param top 8352 * the distance from the center to the top frustum edge 8353 * @param zNear 8354 * near clipping plane distance 8355 * @param zFar 8356 * far clipping plane distance 8357 * @return this 8358 */ 8359 ref public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar) return { 8360 return ortho(left, right, bottom, top, zNear, zFar, false); 8361 } 8362 8363 /** 8364 * Apply an orthographic projection transformation for a left-handed coordiante system 8365 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8366 * <p> 8367 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8368 * then the new matrix will be <code>M * O</code>. So when transforming a 8369 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8370 * orthographic projection transformation will be applied first! 8371 * <p> 8372 * In order to set the matrix to an orthographic projection without post-multiplying it, 8373 * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}. 8374 * <p> 8375 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8376 * 8377 * @see #setOrthoLH(double, double, double, double, double, double, bool) 8378 * 8379 * @param left 8380 * the distance from the center to the left frustum edge 8381 * @param right 8382 * the distance from the center to the right frustum edge 8383 * @param bottom 8384 * the distance from the center to the bottom frustum edge 8385 * @param top 8386 * the distance from the center to the top frustum edge 8387 * @param zNear 8388 * near clipping plane distance 8389 * @param zFar 8390 * far clipping plane distance 8391 * @param zZeroToOne 8392 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8393 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8394 * @param dest 8395 * will hold the result 8396 * @return dest 8397 */ 8398 public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8399 if ((properties & PROPERTY_IDENTITY) != 0) 8400 return dest.setOrthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne); 8401 return orthoLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 8402 } 8403 private Matrix4d orthoLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8404 // calculate right matrix elements 8405 double rm00 = 2.0 / (right - left); 8406 double rm11 = 2.0 / (top - bottom); 8407 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear); 8408 double rm30 = (left + right) / (left - right); 8409 double rm31 = (top + bottom) / (bottom - top); 8410 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8411 // perform optimized multiplication 8412 // compute the last column first, because other columns do not depend on it 8413 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 8414 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 8415 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 8416 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 8417 ._m00(m00 * rm00) 8418 ._m01(m01 * rm00) 8419 ._m02(m02 * rm00) 8420 ._m03(m03 * rm00) 8421 ._m10(m10 * rm11) 8422 ._m11(m11 * rm11) 8423 ._m12(m12 * rm11) 8424 ._m13(m13 * rm11) 8425 ._m20(m20 * rm22) 8426 ._m21(m21 * rm22) 8427 ._m22(m22 * rm22) 8428 ._m23(m23 * rm22) 8429 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8430 return dest; 8431 } 8432 8433 /** 8434 * Apply an orthographic projection transformation for a left-handed coordiante system 8435 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8436 * <p> 8437 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8438 * then the new matrix will be <code>M * O</code>. So when transforming a 8439 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8440 * orthographic projection transformation will be applied first! 8441 * <p> 8442 * In order to set the matrix to an orthographic projection without post-multiplying it, 8443 * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}. 8444 * <p> 8445 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8446 * 8447 * @see #setOrthoLH(double, double, double, double, double, double) 8448 * 8449 * @param left 8450 * the distance from the center to the left frustum edge 8451 * @param right 8452 * the distance from the center to the right frustum edge 8453 * @param bottom 8454 * the distance from the center to the bottom frustum edge 8455 * @param top 8456 * the distance from the center to the top frustum edge 8457 * @param zNear 8458 * near clipping plane distance 8459 * @param zFar 8460 * far clipping plane distance 8461 * @param dest 8462 * will hold the result 8463 * @return dest 8464 */ 8465 public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 8466 return orthoLH(left, right, bottom, top, zNear, zFar, false, dest); 8467 } 8468 8469 /** 8470 * Apply an orthographic projection transformation for a left-handed coordiante system 8471 * using the given NDC z range to this matrix. 8472 * <p> 8473 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8474 * then the new matrix will be <code>M * O</code>. So when transforming a 8475 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8476 * orthographic projection transformation will be applied first! 8477 * <p> 8478 * In order to set the matrix to an orthographic projection without post-multiplying it, 8479 * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}. 8480 * <p> 8481 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8482 * 8483 * @see #setOrthoLH(double, double, double, double, double, double, bool) 8484 * 8485 * @param left 8486 * the distance from the center to the left frustum edge 8487 * @param right 8488 * the distance from the center to the right frustum edge 8489 * @param bottom 8490 * the distance from the center to the bottom frustum edge 8491 * @param top 8492 * the distance from the center to the top frustum edge 8493 * @param zNear 8494 * near clipping plane distance 8495 * @param zFar 8496 * far clipping plane distance 8497 * @param zZeroToOne 8498 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8499 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8500 * @return this 8501 */ 8502 ref public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8503 orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 8504 return this; 8505 } 8506 8507 /** 8508 * Apply an orthographic projection transformation for a left-handed coordiante system 8509 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8510 * <p> 8511 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8512 * then the new matrix will be <code>M * O</code>. So when transforming a 8513 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8514 * orthographic projection transformation will be applied first! 8515 * <p> 8516 * In order to set the matrix to an orthographic projection without post-multiplying it, 8517 * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}. 8518 * <p> 8519 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8520 * 8521 * @see #setOrthoLH(double, double, double, double, double, double) 8522 * 8523 * @param left 8524 * the distance from the center to the left frustum edge 8525 * @param right 8526 * the distance from the center to the right frustum edge 8527 * @param bottom 8528 * the distance from the center to the bottom frustum edge 8529 * @param top 8530 * the distance from the center to the top frustum edge 8531 * @param zNear 8532 * near clipping plane distance 8533 * @param zFar 8534 * far clipping plane distance 8535 * @return this 8536 */ 8537 ref public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 8538 return orthoLH(left, right, bottom, top, zNear, zFar, false); 8539 } 8540 8541 /** 8542 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system 8543 * using the given NDC z range. 8544 * <p> 8545 * In order to apply the orthographic projection to an already existing transformation, 8546 * use {@link #ortho(double, double, double, double, double, double, bool) ortho()}. 8547 * <p> 8548 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8549 * 8550 * @see #ortho(double, double, double, double, double, double, bool) 8551 * 8552 * @param left 8553 * the distance from the center to the left frustum edge 8554 * @param right 8555 * the distance from the center to the right frustum edge 8556 * @param bottom 8557 * the distance from the center to the bottom frustum edge 8558 * @param top 8559 * the distance from the center to the top frustum edge 8560 * @param zNear 8561 * near clipping plane distance 8562 * @param zFar 8563 * far clipping plane distance 8564 * @param zZeroToOne 8565 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8566 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8567 * @return this 8568 */ 8569 ref public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8570 if ((properties & PROPERTY_IDENTITY) == 0) 8571 _identity(); 8572 _m00(2.0 / (right - left)). 8573 _m11(2.0 / (top - bottom)). 8574 _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)). 8575 _m30((right + left) / (left - right)). 8576 _m31((top + bottom) / (bottom - top)). 8577 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 8578 properties = PROPERTY_AFFINE; 8579 return this; 8580 } 8581 8582 /** 8583 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system 8584 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 8585 * <p> 8586 * In order to apply the orthographic projection to an already existing transformation, 8587 * use {@link #ortho(double, double, double, double, double, double) ortho()}. 8588 * <p> 8589 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8590 * 8591 * @see #ortho(double, double, double, double, double, double) 8592 * 8593 * @param left 8594 * the distance from the center to the left frustum edge 8595 * @param right 8596 * the distance from the center to the right frustum edge 8597 * @param bottom 8598 * the distance from the center to the bottom frustum edge 8599 * @param top 8600 * the distance from the center to the top frustum edge 8601 * @param zNear 8602 * near clipping plane distance 8603 * @param zFar 8604 * far clipping plane distance 8605 * @return this 8606 */ 8607 ref public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) return { 8608 return setOrtho(left, right, bottom, top, zNear, zFar, false); 8609 } 8610 8611 /** 8612 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system 8613 * using the given NDC z range. 8614 * <p> 8615 * In order to apply the orthographic projection to an already existing transformation, 8616 * use {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()}. 8617 * <p> 8618 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8619 * 8620 * @see #orthoLH(double, double, double, double, double, double, bool) 8621 * 8622 * @param left 8623 * the distance from the center to the left frustum edge 8624 * @param right 8625 * the distance from the center to the right frustum edge 8626 * @param bottom 8627 * the distance from the center to the bottom frustum edge 8628 * @param top 8629 * the distance from the center to the top frustum edge 8630 * @param zNear 8631 * near clipping plane distance 8632 * @param zFar 8633 * far clipping plane distance 8634 * @param zZeroToOne 8635 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8636 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8637 * @return this 8638 */ 8639 ref public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8640 if ((properties & PROPERTY_IDENTITY) == 0) 8641 _identity(); 8642 _m00(2.0 / (right - left)). 8643 _m11(2.0 / (top - bottom)). 8644 _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)). 8645 _m30((right + left) / (left - right)). 8646 _m31((top + bottom) / (bottom - top)). 8647 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 8648 properties = PROPERTY_AFFINE; 8649 return this; 8650 } 8651 8652 /** 8653 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system 8654 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 8655 * <p> 8656 * In order to apply the orthographic projection to an already existing transformation, 8657 * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}. 8658 * <p> 8659 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8660 * 8661 * @see #orthoLH(double, double, double, double, double, double) 8662 * 8663 * @param left 8664 * the distance from the center to the left frustum edge 8665 * @param right 8666 * the distance from the center to the right frustum edge 8667 * @param bottom 8668 * the distance from the center to the bottom frustum edge 8669 * @param top 8670 * the distance from the center to the top frustum edge 8671 * @param zNear 8672 * near clipping plane distance 8673 * @param zFar 8674 * far clipping plane distance 8675 * @return this 8676 */ 8677 ref public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 8678 return setOrthoLH(left, right, bottom, top, zNear, zFar, false); 8679 } 8680 8681 /** 8682 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8683 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8684 * <p> 8685 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool, Matrix4d) ortho()} with 8686 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8687 * <p> 8688 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8689 * then the new matrix will be <code>M * O</code>. So when transforming a 8690 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8691 * orthographic projection transformation will be applied first! 8692 * <p> 8693 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8694 * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}. 8695 * <p> 8696 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8697 * 8698 * @see #setOrthoSymmetric(double, double, double, double, bool) 8699 * 8700 * @param width 8701 * the distance between the right and left frustum edges 8702 * @param height 8703 * the distance between the top and bottom frustum edges 8704 * @param zNear 8705 * near clipping plane distance 8706 * @param zFar 8707 * far clipping plane distance 8708 * @param dest 8709 * will hold the result 8710 * @param zZeroToOne 8711 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8712 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8713 * @return dest 8714 */ 8715 public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8716 if ((properties & PROPERTY_IDENTITY) != 0) 8717 return dest.setOrthoSymmetric(width, height, zNear, zFar, zZeroToOne); 8718 return orthoSymmetricGeneric(width, height, zNear, zFar, zZeroToOne, dest); 8719 } 8720 private Matrix4d orthoSymmetricGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8721 // calculate right matrix elements 8722 double rm00 = 2.0 / width; 8723 double rm11 = 2.0 / height; 8724 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar); 8725 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8726 // perform optimized multiplication 8727 // compute the last column first, because other columns do not depend on it 8728 dest._m30(m20 * rm32 + m30) 8729 ._m31(m21 * rm32 + m31) 8730 ._m32(m22 * rm32 + m32) 8731 ._m33(m23 * rm32 + m33) 8732 ._m00(m00 * rm00) 8733 ._m01(m01 * rm00) 8734 ._m02(m02 * rm00) 8735 ._m03(m03 * rm00) 8736 ._m10(m10 * rm11) 8737 ._m11(m11 * rm11) 8738 ._m12(m12 * rm11) 8739 ._m13(m13 * rm11) 8740 ._m20(m20 * rm22) 8741 ._m21(m21 * rm22) 8742 ._m22(m22 * rm22) 8743 ._m23(m23 * rm22) 8744 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8745 return dest; 8746 } 8747 8748 /** 8749 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8750 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8751 * <p> 8752 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with 8753 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8754 * <p> 8755 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8756 * then the new matrix will be <code>M * O</code>. So when transforming a 8757 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8758 * orthographic projection transformation will be applied first! 8759 * <p> 8760 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8761 * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}. 8762 * <p> 8763 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8764 * 8765 * @see #setOrthoSymmetric(double, double, double, double) 8766 * 8767 * @param width 8768 * the distance between the right and left frustum edges 8769 * @param height 8770 * the distance between the top and bottom frustum edges 8771 * @param zNear 8772 * near clipping plane distance 8773 * @param zFar 8774 * far clipping plane distance 8775 * @param dest 8776 * will hold the result 8777 * @return dest 8778 */ 8779 public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 8780 return orthoSymmetric(width, height, zNear, zFar, false, dest); 8781 } 8782 8783 /** 8784 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8785 * using the given NDC z range to this matrix. 8786 * <p> 8787 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool) ortho()} with 8788 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8789 * <p> 8790 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8791 * then the new matrix will be <code>M * O</code>. So when transforming a 8792 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8793 * orthographic projection transformation will be applied first! 8794 * <p> 8795 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8796 * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}. 8797 * <p> 8798 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8799 * 8800 * @see #setOrthoSymmetric(double, double, double, double, bool) 8801 * 8802 * @param width 8803 * the distance between the right and left frustum edges 8804 * @param height 8805 * the distance between the top and bottom frustum edges 8806 * @param zNear 8807 * near clipping plane distance 8808 * @param zFar 8809 * far clipping plane distance 8810 * @param zZeroToOne 8811 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8812 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8813 * @return this 8814 */ 8815 ref public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 8816 orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this); 8817 return this; 8818 } 8819 8820 /** 8821 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8822 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8823 * <p> 8824 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with 8825 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8826 * <p> 8827 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8828 * then the new matrix will be <code>M * O</code>. So when transforming a 8829 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8830 * orthographic projection transformation will be applied first! 8831 * <p> 8832 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8833 * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}. 8834 * <p> 8835 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8836 * 8837 * @see #setOrthoSymmetric(double, double, double, double) 8838 * 8839 * @param width 8840 * the distance between the right and left frustum edges 8841 * @param height 8842 * the distance between the top and bottom frustum edges 8843 * @param zNear 8844 * near clipping plane distance 8845 * @param zFar 8846 * far clipping plane distance 8847 * @return this 8848 */ 8849 ref public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar) return { 8850 orthoSymmetric(width, height, zNear, zFar, false, this); 8851 return this; 8852 } 8853 8854 /** 8855 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8856 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8857 * <p> 8858 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool, Matrix4d) orthoLH()} with 8859 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8860 * <p> 8861 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8862 * then the new matrix will be <code>M * O</code>. So when transforming a 8863 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8864 * orthographic projection transformation will be applied first! 8865 * <p> 8866 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8867 * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}. 8868 * <p> 8869 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8870 * 8871 * @see #setOrthoSymmetricLH(double, double, double, double, bool) 8872 * 8873 * @param width 8874 * the distance between the right and left frustum edges 8875 * @param height 8876 * the distance between the top and bottom frustum edges 8877 * @param zNear 8878 * near clipping plane distance 8879 * @param zFar 8880 * far clipping plane distance 8881 * @param dest 8882 * will hold the result 8883 * @param zZeroToOne 8884 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8885 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8886 * @return dest 8887 */ 8888 public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8889 if ((properties & PROPERTY_IDENTITY) != 0) 8890 return dest.setOrthoSymmetricLH(width, height, zNear, zFar, zZeroToOne); 8891 return orthoSymmetricLHGeneric(width, height, zNear, zFar, zZeroToOne, dest); 8892 } 8893 private Matrix4d orthoSymmetricLHGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8894 // calculate right matrix elements 8895 double rm00 = 2.0 / width; 8896 double rm11 = 2.0 / height; 8897 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear); 8898 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8899 // perform optimized multiplication 8900 // compute the last column first, because other columns do not depend on it 8901 dest._m30(m20 * rm32 + m30) 8902 ._m31(m21 * rm32 + m31) 8903 ._m32(m22 * rm32 + m32) 8904 ._m33(m23 * rm32 + m33) 8905 ._m00(m00 * rm00) 8906 ._m01(m01 * rm00) 8907 ._m02(m02 * rm00) 8908 ._m03(m03 * rm00) 8909 ._m10(m10 * rm11) 8910 ._m11(m11 * rm11) 8911 ._m12(m12 * rm11) 8912 ._m13(m13 * rm11) 8913 ._m20(m20 * rm22) 8914 ._m21(m21 * rm22) 8915 ._m22(m22 * rm22) 8916 ._m23(m23 * rm22) 8917 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8918 return dest; 8919 } 8920 8921 /** 8922 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8923 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8924 * <p> 8925 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with 8926 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8927 * <p> 8928 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8929 * then the new matrix will be <code>M * O</code>. So when transforming a 8930 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8931 * orthographic projection transformation will be applied first! 8932 * <p> 8933 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8934 * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}. 8935 * <p> 8936 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8937 * 8938 * @see #setOrthoSymmetricLH(double, double, double, double) 8939 * 8940 * @param width 8941 * the distance between the right and left frustum edges 8942 * @param height 8943 * the distance between the top and bottom frustum edges 8944 * @param zNear 8945 * near clipping plane distance 8946 * @param zFar 8947 * far clipping plane distance 8948 * @param dest 8949 * will hold the result 8950 * @return dest 8951 */ 8952 public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 8953 return orthoSymmetricLH(width, height, zNear, zFar, false, dest); 8954 } 8955 8956 /** 8957 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8958 * using the given NDC z range to this matrix. 8959 * <p> 8960 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()} with 8961 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8962 * <p> 8963 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8964 * then the new matrix will be <code>M * O</code>. So when transforming a 8965 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8966 * orthographic projection transformation will be applied first! 8967 * <p> 8968 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8969 * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}. 8970 * <p> 8971 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8972 * 8973 * @see #setOrthoSymmetricLH(double, double, double, double, bool) 8974 * 8975 * @param width 8976 * the distance between the right and left frustum edges 8977 * @param height 8978 * the distance between the top and bottom frustum edges 8979 * @param zNear 8980 * near clipping plane distance 8981 * @param zFar 8982 * far clipping plane distance 8983 * @param zZeroToOne 8984 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8985 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8986 * @return this 8987 */ 8988 ref public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 8989 orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this); 8990 return this; 8991 } 8992 8993 /** 8994 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8995 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8996 * <p> 8997 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with 8998 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8999 * <p> 9000 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9001 * then the new matrix will be <code>M * O</code>. So when transforming a 9002 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9003 * orthographic projection transformation will be applied first! 9004 * <p> 9005 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 9006 * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}. 9007 * <p> 9008 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9009 * 9010 * @see #setOrthoSymmetricLH(double, double, double, double) 9011 * 9012 * @param width 9013 * the distance between the right and left frustum edges 9014 * @param height 9015 * the distance between the top and bottom frustum edges 9016 * @param zNear 9017 * near clipping plane distance 9018 * @param zFar 9019 * far clipping plane distance 9020 * @return this 9021 */ 9022 ref public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar) return { 9023 orthoSymmetricLH(width, height, zNear, zFar, false, this); 9024 return this; 9025 } 9026 9027 /** 9028 * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system 9029 * using the given NDC z range. 9030 * <p> 9031 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with 9032 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9033 * <p> 9034 * In order to apply the symmetric orthographic projection to an already existing transformation, 9035 * use {@link #orthoSymmetric(double, double, double, double, bool) orthoSymmetric()}. 9036 * <p> 9037 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9038 * 9039 * @see #orthoSymmetric(double, double, double, double, bool) 9040 * 9041 * @param width 9042 * the distance between the right and left frustum edges 9043 * @param height 9044 * the distance between the top and bottom frustum edges 9045 * @param zNear 9046 * near clipping plane distance 9047 * @param zFar 9048 * far clipping plane distance 9049 * @param zZeroToOne 9050 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9051 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9052 * @return this 9053 */ 9054 ref public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9055 if ((properties & PROPERTY_IDENTITY) == 0) 9056 _identity(); 9057 _m00(2.0 / width). 9058 _m11(2.0 / height). 9059 _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)). 9060 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 9061 properties = PROPERTY_AFFINE; 9062 return this; 9063 } 9064 9065 /** 9066 * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system 9067 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 9068 * <p> 9069 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with 9070 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9071 * <p> 9072 * In order to apply the symmetric orthographic projection to an already existing transformation, 9073 * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}. 9074 * <p> 9075 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9076 * 9077 * @see #orthoSymmetric(double, double, double, double) 9078 * 9079 * @param width 9080 * the distance between the right and left frustum edges 9081 * @param height 9082 * the distance between the top and bottom frustum edges 9083 * @param zNear 9084 * near clipping plane distance 9085 * @param zFar 9086 * far clipping plane distance 9087 * @return this 9088 */ 9089 ref public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar) return { 9090 return setOrthoSymmetric(width, height, zNear, zFar, false); 9091 } 9092 9093 /** 9094 * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range. 9095 * <p> 9096 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with 9097 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9098 * <p> 9099 * In order to apply the symmetric orthographic projection to an already existing transformation, 9100 * use {@link #orthoSymmetricLH(double, double, double, double, bool) orthoSymmetricLH()}. 9101 * <p> 9102 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9103 * 9104 * @see #orthoSymmetricLH(double, double, double, double, bool) 9105 * 9106 * @param width 9107 * the distance between the right and left frustum edges 9108 * @param height 9109 * the distance between the top and bottom frustum edges 9110 * @param zNear 9111 * near clipping plane distance 9112 * @param zFar 9113 * far clipping plane distance 9114 * @param zZeroToOne 9115 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9116 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9117 * @return this 9118 */ 9119 ref public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9120 if ((properties & PROPERTY_IDENTITY) == 0) 9121 _identity(); 9122 _m00(2.0 / width). 9123 _m11(2.0 / height). 9124 _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)). 9125 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 9126 properties = PROPERTY_AFFINE; 9127 return this; 9128 } 9129 9130 /** 9131 * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system 9132 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 9133 * <p> 9134 * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with 9135 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9136 * <p> 9137 * In order to apply the symmetric orthographic projection to an already existing transformation, 9138 * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}. 9139 * <p> 9140 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9141 * 9142 * @see #orthoSymmetricLH(double, double, double, double) 9143 * 9144 * @param width 9145 * the distance between the right and left frustum edges 9146 * @param height 9147 * the distance between the top and bottom frustum edges 9148 * @param zNear 9149 * near clipping plane distance 9150 * @param zFar 9151 * far clipping plane distance 9152 * @return this 9153 */ 9154 ref public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) return { 9155 return setOrthoSymmetricLH(width, height, zNear, zFar, false); 9156 } 9157 9158 /** 9159 * Apply an orthographic projection transformation for a right-handed coordinate system 9160 * to this matrix and store the result in <code>dest</code>. 9161 * <p> 9162 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with 9163 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9164 * <p> 9165 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9166 * then the new matrix will be <code>M * O</code>. So when transforming a 9167 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9168 * orthographic projection transformation will be applied first! 9169 * <p> 9170 * In order to set the matrix to an orthographic projection without post-multiplying it, 9171 * use {@link #setOrtho2D(double, double, double, double) setOrtho()}. 9172 * <p> 9173 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9174 * 9175 * @see #ortho(double, double, double, double, double, double, Matrix4d) 9176 * @see #setOrtho2D(double, double, double, double) 9177 * 9178 * @param left 9179 * the distance from the center to the left frustum edge 9180 * @param right 9181 * the distance from the center to the right frustum edge 9182 * @param bottom 9183 * the distance from the center to the bottom frustum edge 9184 * @param top 9185 * the distance from the center to the top frustum edge 9186 * @param dest 9187 * will hold the result 9188 * @return dest 9189 */ 9190 public Matrix4d ortho2D(double left, double right, double bottom, double top, ref Matrix4d dest) { 9191 if ((properties & PROPERTY_IDENTITY) != 0) 9192 return dest.setOrtho2D(left, right, bottom, top); 9193 return ortho2DGeneric(left, right, bottom, top, dest); 9194 } 9195 private Matrix4d ortho2DGeneric(double left, double right, double bottom, double top, ref Matrix4d dest) { 9196 // calculate right matrix elements 9197 double rm00 = 2.0 / (right - left); 9198 double rm11 = 2.0 / (top - bottom); 9199 double rm30 = (right + left) / (left - right); 9200 double rm31 = (top + bottom) / (bottom - top); 9201 // perform optimized multiplication 9202 // compute the last column first, because other columns do not depend on it 9203 dest._m30(m00 * rm30 + m10 * rm31 + m30) 9204 ._m31(m01 * rm30 + m11 * rm31 + m31) 9205 ._m32(m02 * rm30 + m12 * rm31 + m32) 9206 ._m33(m03 * rm30 + m13 * rm31 + m33) 9207 ._m00(m00 * rm00) 9208 ._m01(m01 * rm00) 9209 ._m02(m02 * rm00) 9210 ._m03(m03 * rm00) 9211 ._m10(m10 * rm11) 9212 ._m11(m11 * rm11) 9213 ._m12(m12 * rm11) 9214 ._m13(m13 * rm11) 9215 ._m20(-m20) 9216 ._m21(-m21) 9217 ._m22(-m22) 9218 ._m23(-m23) 9219 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 9220 return dest; 9221 } 9222 9223 /** 9224 * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix. 9225 * <p> 9226 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with 9227 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9228 * <p> 9229 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9230 * then the new matrix will be <code>M * O</code>. So when transforming a 9231 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9232 * orthographic projection transformation will be applied first! 9233 * <p> 9234 * In order to set the matrix to an orthographic projection without post-multiplying it, 9235 * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}. 9236 * <p> 9237 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9238 * 9239 * @see #ortho(double, double, double, double, double, double) 9240 * @see #setOrtho2D(double, double, double, double) 9241 * 9242 * @param left 9243 * the distance from the center to the left frustum edge 9244 * @param right 9245 * the distance from the center to the right frustum edge 9246 * @param bottom 9247 * the distance from the center to the bottom frustum edge 9248 * @param top 9249 * the distance from the center to the top frustum edge 9250 * @return this 9251 */ 9252 ref public Matrix4d ortho2D(double left, double right, double bottom, double top) return { 9253 ortho2D(left, right, bottom, top, this); 9254 return this; 9255 } 9256 9257 /** 9258 * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in <code>dest</code>. 9259 * <p> 9260 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with 9261 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9262 * <p> 9263 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9264 * then the new matrix will be <code>M * O</code>. So when transforming a 9265 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9266 * orthographic projection transformation will be applied first! 9267 * <p> 9268 * In order to set the matrix to an orthographic projection without post-multiplying it, 9269 * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}. 9270 * <p> 9271 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9272 * 9273 * @see #orthoLH(double, double, double, double, double, double, Matrix4d) 9274 * @see #setOrtho2DLH(double, double, double, double) 9275 * 9276 * @param left 9277 * the distance from the center to the left frustum edge 9278 * @param right 9279 * the distance from the center to the right frustum edge 9280 * @param bottom 9281 * the distance from the center to the bottom frustum edge 9282 * @param top 9283 * the distance from the center to the top frustum edge 9284 * @param dest 9285 * will hold the result 9286 * @return dest 9287 */ 9288 public Matrix4d ortho2DLH(double left, double right, double bottom, double top, ref Matrix4d dest) { 9289 if ((properties & PROPERTY_IDENTITY) != 0) 9290 return dest.setOrtho2DLH(left, right, bottom, top); 9291 return ortho2DLHGeneric(left, right, bottom, top, dest); 9292 } 9293 private Matrix4d ortho2DLHGeneric(double left, double right, double bottom, double top, ref Matrix4d dest) { 9294 // calculate right matrix elements 9295 double rm00 = 2.0 / (right - left); 9296 double rm11 = 2.0 / (top - bottom); 9297 double rm30 = (right + left) / (left - right); 9298 double rm31 = (top + bottom) / (bottom - top); 9299 // perform optimized multiplication 9300 // compute the last column first, because other columns do not depend on it 9301 dest._m30(m00 * rm30 + m10 * rm31 + m30) 9302 ._m31(m01 * rm30 + m11 * rm31 + m31) 9303 ._m32(m02 * rm30 + m12 * rm31 + m32) 9304 ._m33(m03 * rm30 + m13 * rm31 + m33) 9305 ._m00(m00 * rm00) 9306 ._m01(m01 * rm00) 9307 ._m02(m02 * rm00) 9308 ._m03(m03 * rm00) 9309 ._m10(m10 * rm11) 9310 ._m11(m11 * rm11) 9311 ._m12(m12 * rm11) 9312 ._m13(m13 * rm11) 9313 ._m20(m20) 9314 ._m21(m21) 9315 ._m22(m22) 9316 ._m23(m23) 9317 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 9318 return dest; 9319 } 9320 9321 /** 9322 * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix. 9323 * <p> 9324 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with 9325 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9326 * <p> 9327 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9328 * then the new matrix will be <code>M * O</code>. So when transforming a 9329 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9330 * orthographic projection transformation will be applied first! 9331 * <p> 9332 * In order to set the matrix to an orthographic projection without post-multiplying it, 9333 * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}. 9334 * <p> 9335 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9336 * 9337 * @see #orthoLH(double, double, double, double, double, double) 9338 * @see #setOrtho2DLH(double, double, double, double) 9339 * 9340 * @param left 9341 * the distance from the center to the left frustum edge 9342 * @param right 9343 * the distance from the center to the right frustum edge 9344 * @param bottom 9345 * the distance from the center to the bottom frustum edge 9346 * @param top 9347 * the distance from the center to the top frustum edge 9348 * @return this 9349 */ 9350 ref public Matrix4d ortho2DLH(double left, double right, double bottom, double top) return { 9351 ortho2DLH(left, right, bottom, top, this); 9352 return this; 9353 } 9354 9355 /** 9356 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system. 9357 * <p> 9358 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with 9359 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9360 * <p> 9361 * In order to apply the orthographic projection to an already existing transformation, 9362 * use {@link #ortho2D(double, double, double, double) ortho2D()}. 9363 * <p> 9364 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9365 * 9366 * @see #setOrtho(double, double, double, double, double, double) 9367 * @see #ortho2D(double, double, double, double) 9368 * 9369 * @param left 9370 * the distance from the center to the left frustum edge 9371 * @param right 9372 * the distance from the center to the right frustum edge 9373 * @param bottom 9374 * the distance from the center to the bottom frustum edge 9375 * @param top 9376 * the distance from the center to the top frustum edge 9377 * @return this 9378 */ 9379 ref public Matrix4d setOrtho2D(double left, double right, double bottom, double top) return { 9380 if ((properties & PROPERTY_IDENTITY) == 0) 9381 _identity(); 9382 _m00(2.0 / (right - left)). 9383 _m11(2.0 / (top - bottom)). 9384 _m22(-1.0). 9385 _m30((right + left) / (left - right)). 9386 _m31((top + bottom) / (bottom - top)). 9387 properties = PROPERTY_AFFINE; 9388 return this; 9389 } 9390 9391 /** 9392 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system. 9393 * <p> 9394 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with 9395 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9396 * <p> 9397 * In order to apply the orthographic projection to an already existing transformation, 9398 * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}. 9399 * <p> 9400 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9401 * 9402 * @see #setOrthoLH(double, double, double, double, double, double) 9403 * @see #ortho2DLH(double, double, double, double) 9404 * 9405 * @param left 9406 * the distance from the center to the left frustum edge 9407 * @param right 9408 * the distance from the center to the right frustum edge 9409 * @param bottom 9410 * the distance from the center to the bottom frustum edge 9411 * @param top 9412 * the distance from the center to the top frustum edge 9413 * @return this 9414 */ 9415 ref public Matrix4d setOrtho2DLH(double left, double right, double bottom, double top) return { 9416 if ((properties & PROPERTY_IDENTITY) == 0) 9417 _identity(); 9418 _m00(2.0 / (right - left)). 9419 _m11(2.0 / (top - bottom)). 9420 _m30((right + left) / (left - right)). 9421 _m31((top + bottom) / (bottom - top)). 9422 properties = PROPERTY_AFFINE; 9423 return this; 9424 } 9425 9426 /** 9427 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 9428 * <p> 9429 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9430 * then the new matrix will be <code>M * L</code>. So when transforming a 9431 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9432 * lookalong rotation transformation will be applied first! 9433 * <p> 9434 * This is equivalent to calling 9435 * {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt} 9436 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9437 * <p> 9438 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9439 * use {@link #setLookAlong(ref Vector3d, Vector3d) setLookAlong()}. 9440 * 9441 * @see #lookAlong(double, double, double, double, double, double) 9442 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9443 * @see #setLookAlong(ref Vector3d, Vector3d) 9444 * 9445 * @param dir 9446 * the direction in space to look along 9447 * @param up 9448 * the direction of 'up' 9449 * @return this 9450 */ 9451 ref public Matrix4d lookAlong(ref Vector3d dir, Vector3d up) return { 9452 lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this); 9453 return this; 9454 } 9455 9456 /** 9457 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code> 9458 * and store the result in <code>dest</code>. 9459 * <p> 9460 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9461 * then the new matrix will be <code>M * L</code>. So when transforming a 9462 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9463 * lookalong rotation transformation will be applied first! 9464 * <p> 9465 * This is equivalent to calling 9466 * {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt} 9467 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9468 * <p> 9469 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9470 * use {@link #setLookAlong(ref Vector3d, Vector3d) setLookAlong()}. 9471 * 9472 * @see #lookAlong(double, double, double, double, double, double) 9473 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9474 * @see #setLookAlong(ref Vector3d, Vector3d) 9475 * 9476 * @param dir 9477 * the direction in space to look along 9478 * @param up 9479 * the direction of 'up' 9480 * @param dest 9481 * will hold the result 9482 * @return dest 9483 */ 9484 public Matrix4d lookAlong(ref Vector3d dir, Vector3d up, ref Matrix4d dest) { 9485 return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest); 9486 } 9487 9488 /** 9489 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code> 9490 * and store the result in <code>dest</code>. 9491 * <p> 9492 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9493 * then the new matrix will be <code>M * L</code>. So when transforming a 9494 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9495 * lookalong rotation transformation will be applied first! 9496 * <p> 9497 * This is equivalent to calling 9498 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()} 9499 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9500 * <p> 9501 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9502 * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()} 9503 * 9504 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9505 * @see #setLookAlong(double, double, double, double, double, double) 9506 * 9507 * @param dirX 9508 * the x-coordinate of the direction to look along 9509 * @param dirY 9510 * the y-coordinate of the direction to look along 9511 * @param dirZ 9512 * the z-coordinate of the direction to look along 9513 * @param upX 9514 * the x-coordinate of the up vector 9515 * @param upY 9516 * the y-coordinate of the up vector 9517 * @param upZ 9518 * the z-coordinate of the up vector 9519 * @param dest 9520 * will hold the result 9521 * @return dest 9522 */ 9523 public Matrix4d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 9524 if ((properties & PROPERTY_IDENTITY) != 0) 9525 return dest.setLookAlong(dirX, dirY, dirZ, upX, upY, upZ); 9526 return lookAlongGeneric(dirX, dirY, dirZ, upX, upY, upZ, dest); 9527 } 9528 9529 private Matrix4d lookAlongGeneric(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 9530 // Normalize direction 9531 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9532 dirX *= -invDirLength; 9533 dirY *= -invDirLength; 9534 dirZ *= -invDirLength; 9535 // left = up x direction 9536 double leftX, leftY, leftZ; 9537 leftX = upY * dirZ - upZ * dirY; 9538 leftY = upZ * dirX - upX * dirZ; 9539 leftZ = upX * dirY - upY * dirX; 9540 // normalize left 9541 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9542 leftX *= invLeftLength; 9543 leftY *= invLeftLength; 9544 leftZ *= invLeftLength; 9545 // up = direction x left 9546 double upnX = dirY * leftZ - dirZ * leftY; 9547 double upnY = dirZ * leftX - dirX * leftZ; 9548 double upnZ = dirX * leftY - dirY * leftX; 9549 // calculate right matrix elements 9550 double rm00 = leftX; 9551 double rm01 = upnX; 9552 double rm02 = dirX; 9553 double rm10 = leftY; 9554 double rm11 = upnY; 9555 double rm12 = dirY; 9556 double rm20 = leftZ; 9557 double rm21 = upnZ; 9558 double rm22 = dirZ; 9559 // perform optimized matrix multiplication 9560 // introduce temporaries for dependent results 9561 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 9562 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 9563 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 9564 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 9565 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 9566 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 9567 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 9568 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 9569 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 9570 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 9571 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 9572 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 9573 // set the rest of the matrix elements 9574 ._m00(nm00) 9575 ._m01(nm01) 9576 ._m02(nm02) 9577 ._m03(nm03) 9578 ._m10(nm10) 9579 ._m11(nm11) 9580 ._m12(nm12) 9581 ._m13(nm13) 9582 ._m30(m30) 9583 ._m31(m31) 9584 ._m32(m32) 9585 ._m33(m33) 9586 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 9587 return dest; 9588 } 9589 9590 /** 9591 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 9592 * <p> 9593 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9594 * then the new matrix will be <code>M * L</code>. So when transforming a 9595 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9596 * lookalong rotation transformation will be applied first! 9597 * <p> 9598 * This is equivalent to calling 9599 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()} 9600 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9601 * <p> 9602 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9603 * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()} 9604 * 9605 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9606 * @see #setLookAlong(double, double, double, double, double, double) 9607 * 9608 * @param dirX 9609 * the x-coordinate of the direction to look along 9610 * @param dirY 9611 * the y-coordinate of the direction to look along 9612 * @param dirZ 9613 * the z-coordinate of the direction to look along 9614 * @param upX 9615 * the x-coordinate of the up vector 9616 * @param upY 9617 * the y-coordinate of the up vector 9618 * @param upZ 9619 * the z-coordinate of the up vector 9620 * @return this 9621 */ 9622 ref public Matrix4d lookAlong(double dirX, double dirY, double dirZ, 9623 double upX, double upY, double upZ) return { 9624 lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this); 9625 return this; 9626 } 9627 9628 /** 9629 * Set this matrix to a rotation transformation to make <code>-z</code> 9630 * point along <code>dir</code>. 9631 * <p> 9632 * This is equivalent to calling 9633 * {@link #setLookAt(ref Vector3d, Vector3d, Vector3d) setLookAt()} 9634 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9635 * <p> 9636 * In order to apply the lookalong transformation to any previous existing transformation, 9637 * use {@link #lookAlong(ref Vector3d, Vector3d)}. 9638 * 9639 * @see #setLookAlong(ref Vector3d, Vector3d) 9640 * @see #lookAlong(ref Vector3d, Vector3d) 9641 * 9642 * @param dir 9643 * the direction in space to look along 9644 * @param up 9645 * the direction of 'up' 9646 * @return this 9647 */ 9648 ref public Matrix4d setLookAlong(ref Vector3d dir, Vector3d up) return { 9649 return setLookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z); 9650 } 9651 9652 /** 9653 * Set this matrix to a rotation transformation to make <code>-z</code> 9654 * point along <code>dir</code>. 9655 * <p> 9656 * This is equivalent to calling 9657 * {@link #setLookAt(double, double, double, double, double, double, double, double, double) 9658 * setLookAt()} with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9659 * <p> 9660 * In order to apply the lookalong transformation to any previous existing transformation, 9661 * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()} 9662 * 9663 * @see #setLookAlong(double, double, double, double, double, double) 9664 * @see #lookAlong(double, double, double, double, double, double) 9665 * 9666 * @param dirX 9667 * the x-coordinate of the direction to look along 9668 * @param dirY 9669 * the y-coordinate of the direction to look along 9670 * @param dirZ 9671 * the z-coordinate of the direction to look along 9672 * @param upX 9673 * the x-coordinate of the up vector 9674 * @param upY 9675 * the y-coordinate of the up vector 9676 * @param upZ 9677 * the z-coordinate of the up vector 9678 * @return this 9679 */ 9680 ref public Matrix4d setLookAlong(double dirX, double dirY, double dirZ, 9681 double upX, double upY, double upZ) return { 9682 // Normalize direction 9683 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9684 dirX *= -invDirLength; 9685 dirY *= -invDirLength; 9686 dirZ *= -invDirLength; 9687 // left = up x direction 9688 double leftX, leftY, leftZ; 9689 leftX = upY * dirZ - upZ * dirY; 9690 leftY = upZ * dirX - upX * dirZ; 9691 leftZ = upX * dirY - upY * dirX; 9692 // normalize left 9693 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9694 leftX *= invLeftLength; 9695 leftY *= invLeftLength; 9696 leftZ *= invLeftLength; 9697 // up = direction x left 9698 double upnX = dirY * leftZ - dirZ * leftY; 9699 double upnY = dirZ * leftX - dirX * leftZ; 9700 double upnZ = dirX * leftY - dirY * leftX; 9701 _m00(leftX). 9702 _m01(upnX). 9703 _m02(dirX). 9704 _m03(0.0). 9705 _m10(leftY). 9706 _m11(upnY). 9707 _m12(dirY). 9708 _m13(0.0). 9709 _m20(leftZ). 9710 _m21(upnZ). 9711 _m22(dirZ). 9712 _m23(0.0). 9713 _m30(0.0). 9714 _m31(0.0). 9715 _m32(0.0). 9716 _m33(1.0). 9717 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 9718 return this; 9719 } 9720 9721 /** 9722 * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns 9723 * <code>-z</code> with <code>center - eye</code>. 9724 * <p> 9725 * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives, 9726 * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()} 9727 * instead. 9728 * <p> 9729 * In order to apply the lookat transformation to a previous existing transformation, 9730 * use {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt()}. 9731 * 9732 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 9733 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9734 * 9735 * @param eye 9736 * the position of the camera 9737 * @param center 9738 * the point in space to look at 9739 * @param up 9740 * the direction of 'up' 9741 * @return this 9742 */ 9743 ref public Matrix4d setLookAt(ref Vector3d eye, Vector3d center, Vector3d up) return { 9744 return setLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z); 9745 } 9746 9747 /** 9748 * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, 9749 * that aligns <code>-z</code> with <code>center - eye</code>. 9750 * <p> 9751 * In order to apply the lookat transformation to a previous existing transformation, 9752 * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}. 9753 * 9754 * @see #setLookAt(ref Vector3d, Vector3d, Vector3d) 9755 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9756 * 9757 * @param eyeX 9758 * the x-coordinate of the eye/camera location 9759 * @param eyeY 9760 * the y-coordinate of the eye/camera location 9761 * @param eyeZ 9762 * the z-coordinate of the eye/camera location 9763 * @param centerX 9764 * the x-coordinate of the point to look at 9765 * @param centerY 9766 * the y-coordinate of the point to look at 9767 * @param centerZ 9768 * the z-coordinate of the point to look at 9769 * @param upX 9770 * the x-coordinate of the up vector 9771 * @param upY 9772 * the y-coordinate of the up vector 9773 * @param upZ 9774 * the z-coordinate of the up vector 9775 * @return this 9776 */ 9777 ref public Matrix4d setLookAt(double eyeX, double eyeY, double eyeZ, 9778 double centerX, double centerY, double centerZ, 9779 double upX, double upY, double upZ) return { 9780 // Compute direction from position to lookAt 9781 double dirX, dirY, dirZ; 9782 dirX = eyeX - centerX; 9783 dirY = eyeY - centerY; 9784 dirZ = eyeZ - centerZ; 9785 // Normalize direction 9786 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9787 dirX *= invDirLength; 9788 dirY *= invDirLength; 9789 dirZ *= invDirLength; 9790 // left = up x direction 9791 double leftX, leftY, leftZ; 9792 leftX = upY * dirZ - upZ * dirY; 9793 leftY = upZ * dirX - upX * dirZ; 9794 leftZ = upX * dirY - upY * dirX; 9795 // normalize left 9796 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9797 leftX *= invLeftLength; 9798 leftY *= invLeftLength; 9799 leftZ *= invLeftLength; 9800 // up = direction x left 9801 double upnX = dirY * leftZ - dirZ * leftY; 9802 double upnY = dirZ * leftX - dirX * leftZ; 9803 double upnZ = dirX * leftY - dirY * leftX; 9804 return this. 9805 _m00(leftX). 9806 _m01(upnX). 9807 _m02(dirX). 9808 _m03(0.0). 9809 _m10(leftY). 9810 _m11(upnY). 9811 _m12(dirY). 9812 _m13(0.0). 9813 _m20(leftZ). 9814 _m21(upnZ). 9815 _m22(dirZ). 9816 _m23(0.0). 9817 _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)). 9818 _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)). 9819 _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)). 9820 _m33(1.0). 9821 _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 9822 } 9823 9824 /** 9825 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9826 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 9827 * <p> 9828 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9829 * then the new matrix will be <code>M * L</code>. So when transforming a 9830 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9831 * the lookat transformation will be applied first! 9832 * <p> 9833 * In order to set the matrix to a lookat transformation without post-multiplying it, 9834 * use {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)}. 9835 * 9836 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9837 * @see #setLookAlong(ref Vector3d, Vector3d) 9838 * 9839 * @param eye 9840 * the position of the camera 9841 * @param center 9842 * the point in space to look at 9843 * @param up 9844 * the direction of 'up' 9845 * @param dest 9846 * will hold the result 9847 * @return dest 9848 */ 9849 public Matrix4d lookAt(ref Vector3d eye, Vector3d center, Vector3d up, ref Matrix4d dest) { 9850 return lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest); 9851 } 9852 9853 /** 9854 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9855 * that aligns <code>-z</code> with <code>center - eye</code>. 9856 * <p> 9857 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9858 * then the new matrix will be <code>M * L</code>. So when transforming a 9859 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9860 * the lookat transformation will be applied first! 9861 * <p> 9862 * In order to set the matrix to a lookat transformation without post-multiplying it, 9863 * use {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)}. 9864 * 9865 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9866 * @see #setLookAlong(ref Vector3d, Vector3d) 9867 * 9868 * @param eye 9869 * the position of the camera 9870 * @param center 9871 * the point in space to look at 9872 * @param up 9873 * the direction of 'up' 9874 * @return this 9875 */ 9876 ref public Matrix4d lookAt(ref Vector3d eye, Vector3d center, Vector3d up) return { 9877 lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this); 9878 return this; 9879 } 9880 9881 /** 9882 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9883 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 9884 * <p> 9885 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9886 * then the new matrix will be <code>M * L</code>. So when transforming a 9887 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9888 * the lookat transformation will be applied first! 9889 * <p> 9890 * In order to set the matrix to a lookat transformation without post-multiplying it, 9891 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 9892 * 9893 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9894 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 9895 * 9896 * @param eyeX 9897 * the x-coordinate of the eye/camera location 9898 * @param eyeY 9899 * the y-coordinate of the eye/camera location 9900 * @param eyeZ 9901 * the z-coordinate of the eye/camera location 9902 * @param centerX 9903 * the x-coordinate of the point to look at 9904 * @param centerY 9905 * the y-coordinate of the point to look at 9906 * @param centerZ 9907 * the z-coordinate of the point to look at 9908 * @param upX 9909 * the x-coordinate of the up vector 9910 * @param upY 9911 * the y-coordinate of the up vector 9912 * @param upZ 9913 * the z-coordinate of the up vector 9914 * @param dest 9915 * will hold the result 9916 * @return dest 9917 */ 9918 public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, 9919 double centerX, double centerY, double centerZ, 9920 double upX, double upY, double upZ, ref Matrix4d dest) { 9921 if ((properties & PROPERTY_IDENTITY) != 0) 9922 return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 9923 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 9924 return lookAtPerspective(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 9925 return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 9926 } 9927 private Matrix4d lookAtGeneric(double eyeX, double eyeY, double eyeZ, 9928 double centerX, double centerY, double centerZ, 9929 double upX, double upY, double upZ, ref Matrix4d dest) { 9930 // Compute direction from position to lookAt 9931 double dirX, dirY, dirZ; 9932 dirX = eyeX - centerX; 9933 dirY = eyeY - centerY; 9934 dirZ = eyeZ - centerZ; 9935 // Normalize direction 9936 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9937 dirX *= invDirLength; 9938 dirY *= invDirLength; 9939 dirZ *= invDirLength; 9940 // left = up x direction 9941 double leftX, leftY, leftZ; 9942 leftX = upY * dirZ - upZ * dirY; 9943 leftY = upZ * dirX - upX * dirZ; 9944 leftZ = upX * dirY - upY * dirX; 9945 // normalize left 9946 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9947 leftX *= invLeftLength; 9948 leftY *= invLeftLength; 9949 leftZ *= invLeftLength; 9950 // up = direction x left 9951 double upnX = dirY * leftZ - dirZ * leftY; 9952 double upnY = dirZ * leftX - dirX * leftZ; 9953 double upnZ = dirX * leftY - dirY * leftX; 9954 // calculate right matrix elements 9955 double rm00 = leftX; 9956 double rm01 = upnX; 9957 double rm02 = dirX; 9958 double rm10 = leftY; 9959 double rm11 = upnY; 9960 double rm12 = dirY; 9961 double rm20 = leftZ; 9962 double rm21 = upnZ; 9963 double rm22 = dirZ; 9964 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 9965 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 9966 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 9967 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 9968 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 9969 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 9970 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 9971 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 9972 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 9973 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 9974 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 9975 // perform optimized matrix multiplication 9976 // compute last column first, because others do not depend on it 9977 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 9978 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 9979 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 9980 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 9981 // introduce temporaries for dependent results 9982 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 9983 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 9984 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 9985 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 9986 // set the rest of the matrix elements 9987 ._m00(nm00) 9988 ._m01(nm01) 9989 ._m02(nm02) 9990 ._m03(nm03) 9991 ._m10(nm10) 9992 ._m11(nm11) 9993 ._m12(nm12) 9994 ._m13(nm13) 9995 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 9996 return dest; 9997 } 9998 9999 /** 10000 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 10001 * that aligns <code>-z</code> with <code>center - eye</code>. 10002 * <p> 10003 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10004 * then the new matrix will be <code>M * L</code>. So when transforming a 10005 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10006 * the lookat transformation will be applied first! 10007 * <p> 10008 * In order to set the matrix to a lookat transformation without post-multiplying it, 10009 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 10010 * 10011 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 10012 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 10013 * 10014 * @param eyeX 10015 * the x-coordinate of the eye/camera location 10016 * @param eyeY 10017 * the y-coordinate of the eye/camera location 10018 * @param eyeZ 10019 * the z-coordinate of the eye/camera location 10020 * @param centerX 10021 * the x-coordinate of the point to look at 10022 * @param centerY 10023 * the y-coordinate of the point to look at 10024 * @param centerZ 10025 * the z-coordinate of the point to look at 10026 * @param upX 10027 * the x-coordinate of the up vector 10028 * @param upY 10029 * the y-coordinate of the up vector 10030 * @param upZ 10031 * the z-coordinate of the up vector 10032 * @return this 10033 */ 10034 ref public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, 10035 double centerX, double centerY, double centerZ, 10036 double upX, double upY, double upZ) return { 10037 lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this); 10038 return this; 10039 } 10040 10041 /** 10042 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 10043 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10044 * <p> 10045 * This method assumes <code>this</code> to be a perspective transformation, obtained via 10046 * {@link #frustum(double, double, double, double, double, double) frustum()} or {@link #perspective(double, double, double, double) perspective()} or 10047 * one of their overloads. 10048 * <p> 10049 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10050 * then the new matrix will be <code>M * L</code>. So when transforming a 10051 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10052 * the lookat transformation will be applied first! 10053 * <p> 10054 * In order to set the matrix to a lookat transformation without post-multiplying it, 10055 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 10056 * 10057 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 10058 * 10059 * @param eyeX 10060 * the x-coordinate of the eye/camera location 10061 * @param eyeY 10062 * the y-coordinate of the eye/camera location 10063 * @param eyeZ 10064 * the z-coordinate of the eye/camera location 10065 * @param centerX 10066 * the x-coordinate of the point to look at 10067 * @param centerY 10068 * the y-coordinate of the point to look at 10069 * @param centerZ 10070 * the z-coordinate of the point to look at 10071 * @param upX 10072 * the x-coordinate of the up vector 10073 * @param upY 10074 * the y-coordinate of the up vector 10075 * @param upZ 10076 * the z-coordinate of the up vector 10077 * @param dest 10078 * will hold the result 10079 * @return dest 10080 */ 10081 public Matrix4d lookAtPerspective(double eyeX, double eyeY, double eyeZ, 10082 double centerX, double centerY, double centerZ, 10083 double upX, double upY, double upZ, ref Matrix4d dest) { 10084 // Compute direction from position to lookAt 10085 double dirX, dirY, dirZ; 10086 dirX = eyeX - centerX; 10087 dirY = eyeY - centerY; 10088 dirZ = eyeZ - centerZ; 10089 // Normalize direction 10090 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10091 dirX *= invDirLength; 10092 dirY *= invDirLength; 10093 dirZ *= invDirLength; 10094 // left = up x direction 10095 double leftX, leftY, leftZ; 10096 leftX = upY * dirZ - upZ * dirY; 10097 leftY = upZ * dirX - upX * dirZ; 10098 leftZ = upX * dirY - upY * dirX; 10099 // normalize left 10100 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10101 leftX *= invLeftLength; 10102 leftY *= invLeftLength; 10103 leftZ *= invLeftLength; 10104 // up = direction x left 10105 double upnX = dirY * leftZ - dirZ * leftY; 10106 double upnY = dirZ * leftX - dirX * leftZ; 10107 double upnZ = dirX * leftY - dirY * leftX; 10108 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10109 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10110 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10111 double nm10 = m00 * leftY; 10112 double nm20 = m00 * leftZ; 10113 double nm21 = m11 * upnZ; 10114 double nm30 = m00 * rm30; 10115 double nm31 = m11 * rm31; 10116 double nm32 = m22 * rm32 + m32; 10117 double nm33 = m23 * rm32; 10118 return dest 10119 ._m00(m00 * leftX) 10120 ._m01(m11 * upnX) 10121 ._m02(m22 * dirX) 10122 ._m03(m23 * dirX) 10123 ._m10(nm10) 10124 ._m11(m11 * upnY) 10125 ._m12(m22 * dirY) 10126 ._m13(m23 * dirY) 10127 ._m20(nm20) 10128 ._m21(nm21) 10129 ._m22(m22 * dirZ) 10130 ._m23(m23 * dirZ) 10131 ._m30(nm30) 10132 ._m31(nm31) 10133 ._m32(nm32) 10134 ._m33(nm33) 10135 ._properties(0); 10136 } 10137 10138 /** 10139 * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns 10140 * <code>+z</code> with <code>center - eye</code>. 10141 * <p> 10142 * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives, 10143 * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()} 10144 * instead. 10145 * <p> 10146 * In order to apply the lookat transformation to a previous existing transformation, 10147 * use {@link #lookAtLH(ref Vector3d, Vector3d, Vector3d) lookAt()}. 10148 * 10149 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10150 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10151 * 10152 * @param eye 10153 * the position of the camera 10154 * @param center 10155 * the point in space to look at 10156 * @param up 10157 * the direction of 'up' 10158 * @return this 10159 */ 10160 ref public Matrix4d setLookAtLH(ref Vector3d eye, Vector3d center, Vector3d up) return { 10161 return setLookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z); 10162 } 10163 10164 /** 10165 * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, 10166 * that aligns <code>+z</code> with <code>center - eye</code>. 10167 * <p> 10168 * In order to apply the lookat transformation to a previous existing transformation, 10169 * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}. 10170 * 10171 * @see #setLookAtLH(ref Vector3d, Vector3d, Vector3d) 10172 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10173 * 10174 * @param eyeX 10175 * the x-coordinate of the eye/camera location 10176 * @param eyeY 10177 * the y-coordinate of the eye/camera location 10178 * @param eyeZ 10179 * the z-coordinate of the eye/camera location 10180 * @param centerX 10181 * the x-coordinate of the point to look at 10182 * @param centerY 10183 * the y-coordinate of the point to look at 10184 * @param centerZ 10185 * the z-coordinate of the point to look at 10186 * @param upX 10187 * the x-coordinate of the up vector 10188 * @param upY 10189 * the y-coordinate of the up vector 10190 * @param upZ 10191 * the z-coordinate of the up vector 10192 * @return this 10193 */ 10194 ref public Matrix4d setLookAtLH(double eyeX, double eyeY, double eyeZ, 10195 double centerX, double centerY, double centerZ, 10196 double upX, double upY, double upZ) return { 10197 // Compute direction from position to lookAt 10198 double dirX, dirY, dirZ; 10199 dirX = centerX - eyeX; 10200 dirY = centerY - eyeY; 10201 dirZ = centerZ - eyeZ; 10202 // Normalize direction 10203 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10204 dirX *= invDirLength; 10205 dirY *= invDirLength; 10206 dirZ *= invDirLength; 10207 // left = up x direction 10208 double leftX, leftY, leftZ; 10209 leftX = upY * dirZ - upZ * dirY; 10210 leftY = upZ * dirX - upX * dirZ; 10211 leftZ = upX * dirY - upY * dirX; 10212 // normalize left 10213 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10214 leftX *= invLeftLength; 10215 leftY *= invLeftLength; 10216 leftZ *= invLeftLength; 10217 // up = direction x left 10218 double upnX = dirY * leftZ - dirZ * leftY; 10219 double upnY = dirZ * leftX - dirX * leftZ; 10220 double upnZ = dirX * leftY - dirY * leftX; 10221 _m00(leftX). 10222 _m01(upnX). 10223 _m02(dirX). 10224 _m03(0.0). 10225 _m10(leftY). 10226 _m11(upnY). 10227 _m12(dirY). 10228 _m13(0.0). 10229 _m20(leftZ). 10230 _m21(upnZ). 10231 _m22(dirZ). 10232 _m23(0.0). 10233 _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)). 10234 _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)). 10235 _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)). 10236 _m33(1.0). 10237 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 10238 return this; 10239 } 10240 10241 /** 10242 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10243 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10244 * <p> 10245 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10246 * then the new matrix will be <code>M * L</code>. So when transforming a 10247 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10248 * the lookat transformation will be applied first! 10249 * <p> 10250 * In order to set the matrix to a lookat transformation without post-multiplying it, 10251 * use {@link #setLookAtLH(ref Vector3d, Vector3d, Vector3d)}. 10252 * 10253 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10254 * @see #setLookAtLH(ref Vector3d, Vector3d, Vector3d) 10255 * 10256 * @param eye 10257 * the position of the camera 10258 * @param center 10259 * the point in space to look at 10260 * @param up 10261 * the direction of 'up' 10262 * @param dest 10263 * will hold the result 10264 * @return dest 10265 */ 10266 public Matrix4d lookAtLH(ref Vector3d eye, Vector3d center, Vector3d up, ref Matrix4d dest) { 10267 return lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest); 10268 } 10269 10270 /** 10271 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10272 * that aligns <code>+z</code> with <code>center - eye</code>. 10273 * <p> 10274 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10275 * then the new matrix will be <code>M * L</code>. So when transforming a 10276 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10277 * the lookat transformation will be applied first! 10278 * <p> 10279 * In order to set the matrix to a lookat transformation without post-multiplying it, 10280 * use {@link #setLookAtLH(ref Vector3d, Vector3d, Vector3d)}. 10281 * 10282 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10283 * 10284 * @param eye 10285 * the position of the camera 10286 * @param center 10287 * the point in space to look at 10288 * @param up 10289 * the direction of 'up' 10290 * @return this 10291 */ 10292 ref public Matrix4d lookAtLH(ref Vector3d eye, Vector3d center, Vector3d up) return { 10293 lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this); 10294 return this; 10295 } 10296 10297 /** 10298 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10299 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10300 * <p> 10301 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10302 * then the new matrix will be <code>M * L</code>. So when transforming a 10303 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10304 * the lookat transformation will be applied first! 10305 * <p> 10306 * In order to set the matrix to a lookat transformation without post-multiplying it, 10307 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10308 * 10309 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10310 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10311 * 10312 * @param eyeX 10313 * the x-coordinate of the eye/camera location 10314 * @param eyeY 10315 * the y-coordinate of the eye/camera location 10316 * @param eyeZ 10317 * the z-coordinate of the eye/camera location 10318 * @param centerX 10319 * the x-coordinate of the point to look at 10320 * @param centerY 10321 * the y-coordinate of the point to look at 10322 * @param centerZ 10323 * the z-coordinate of the point to look at 10324 * @param upX 10325 * the x-coordinate of the up vector 10326 * @param upY 10327 * the y-coordinate of the up vector 10328 * @param upZ 10329 * the z-coordinate of the up vector 10330 * @param dest 10331 * will hold the result 10332 * @return dest 10333 */ 10334 public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, 10335 double centerX, double centerY, double centerZ, 10336 double upX, double upY, double upZ, ref Matrix4d dest) { 10337 if ((properties & PROPERTY_IDENTITY) != 0) 10338 return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 10339 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 10340 return lookAtPerspectiveLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 10341 return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 10342 } 10343 private Matrix4d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ, 10344 double centerX, double centerY, double centerZ, 10345 double upX, double upY, double upZ, ref Matrix4d dest) { 10346 // Compute direction from position to lookAt 10347 double dirX, dirY, dirZ; 10348 dirX = centerX - eyeX; 10349 dirY = centerY - eyeY; 10350 dirZ = centerZ - eyeZ; 10351 // Normalize direction 10352 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10353 dirX *= invDirLength; 10354 dirY *= invDirLength; 10355 dirZ *= invDirLength; 10356 // left = up x direction 10357 double leftX, leftY, leftZ; 10358 leftX = upY * dirZ - upZ * dirY; 10359 leftY = upZ * dirX - upX * dirZ; 10360 leftZ = upX * dirY - upY * dirX; 10361 // normalize left 10362 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10363 leftX *= invLeftLength; 10364 leftY *= invLeftLength; 10365 leftZ *= invLeftLength; 10366 // up = direction x left 10367 double upnX = dirY * leftZ - dirZ * leftY; 10368 double upnY = dirZ * leftX - dirX * leftZ; 10369 double upnZ = dirX * leftY - dirY * leftX; 10370 // calculate right matrix elements 10371 double rm00 = leftX; 10372 double rm01 = upnX; 10373 double rm02 = dirX; 10374 double rm10 = leftY; 10375 double rm11 = upnY; 10376 double rm12 = dirY; 10377 double rm20 = leftZ; 10378 double rm21 = upnZ; 10379 double rm22 = dirZ; 10380 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10381 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10382 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10383 // introduce temporaries for dependent results 10384 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 10385 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 10386 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 10387 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 10388 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 10389 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 10390 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 10391 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 10392 // perform optimized matrix multiplication 10393 // compute last column first, because others do not depend on it 10394 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 10395 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 10396 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 10397 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 10398 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 10399 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 10400 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 10401 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 10402 // set the rest of the matrix elements 10403 ._m00(nm00) 10404 ._m01(nm01) 10405 ._m02(nm02) 10406 ._m03(nm03) 10407 ._m10(nm10) 10408 ._m11(nm11) 10409 ._m12(nm12) 10410 ._m13(nm13) 10411 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 10412 return dest; 10413 } 10414 10415 /** 10416 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10417 * that aligns <code>+z</code> with <code>center - eye</code>. 10418 * <p> 10419 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10420 * then the new matrix will be <code>M * L</code>. So when transforming a 10421 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10422 * the lookat transformation will be applied first! 10423 * <p> 10424 * In order to set the matrix to a lookat transformation without post-multiplying it, 10425 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10426 * 10427 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10428 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10429 * 10430 * @param eyeX 10431 * the x-coordinate of the eye/camera location 10432 * @param eyeY 10433 * the y-coordinate of the eye/camera location 10434 * @param eyeZ 10435 * the z-coordinate of the eye/camera location 10436 * @param centerX 10437 * the x-coordinate of the point to look at 10438 * @param centerY 10439 * the y-coordinate of the point to look at 10440 * @param centerZ 10441 * the z-coordinate of the point to look at 10442 * @param upX 10443 * the x-coordinate of the up vector 10444 * @param upY 10445 * the y-coordinate of the up vector 10446 * @param upZ 10447 * the z-coordinate of the up vector 10448 * @return this 10449 */ 10450 ref public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, 10451 double centerX, double centerY, double centerZ, 10452 double upX, double upY, double upZ) return { 10453 lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this); 10454 return this; 10455 } 10456 10457 /** 10458 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10459 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10460 * <p> 10461 * This method assumes <code>this</code> to be a perspective transformation, obtained via 10462 * {@link #frustumLH(double, double, double, double, double, double) frustumLH()} or {@link #perspectiveLH(double, double, double, double) perspectiveLH()} or 10463 * one of their overloads. 10464 * <p> 10465 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10466 * then the new matrix will be <code>M * L</code>. So when transforming a 10467 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10468 * the lookat transformation will be applied first! 10469 * <p> 10470 * In order to set the matrix to a lookat transformation without post-multiplying it, 10471 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10472 * 10473 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10474 * 10475 * @param eyeX 10476 * the x-coordinate of the eye/camera location 10477 * @param eyeY 10478 * the y-coordinate of the eye/camera location 10479 * @param eyeZ 10480 * the z-coordinate of the eye/camera location 10481 * @param centerX 10482 * the x-coordinate of the point to look at 10483 * @param centerY 10484 * the y-coordinate of the point to look at 10485 * @param centerZ 10486 * the z-coordinate of the point to look at 10487 * @param upX 10488 * the x-coordinate of the up vector 10489 * @param upY 10490 * the y-coordinate of the up vector 10491 * @param upZ 10492 * the z-coordinate of the up vector 10493 * @param dest 10494 * will hold the result 10495 * @return dest 10496 */ 10497 public Matrix4d lookAtPerspectiveLH(double eyeX, double eyeY, double eyeZ, 10498 double centerX, double centerY, double centerZ, 10499 double upX, double upY, double upZ, ref Matrix4d dest) { 10500 // Compute direction from position to lookAt 10501 double dirX, dirY, dirZ; 10502 dirX = centerX - eyeX; 10503 dirY = centerY - eyeY; 10504 dirZ = centerZ - eyeZ; 10505 // Normalize direction 10506 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10507 dirX *= invDirLength; 10508 dirY *= invDirLength; 10509 dirZ *= invDirLength; 10510 // left = up x direction 10511 double leftX, leftY, leftZ; 10512 leftX = upY * dirZ - upZ * dirY; 10513 leftY = upZ * dirX - upX * dirZ; 10514 leftZ = upX * dirY - upY * dirX; 10515 // normalize left 10516 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10517 leftX *= invLeftLength; 10518 leftY *= invLeftLength; 10519 leftZ *= invLeftLength; 10520 // up = direction x left 10521 double upnX = dirY * leftZ - dirZ * leftY; 10522 double upnY = dirZ * leftX - dirX * leftZ; 10523 double upnZ = dirX * leftY - dirY * leftX; 10524 10525 // calculate right matrix elements 10526 double rm00 = leftX; 10527 double rm01 = upnX; 10528 double rm02 = dirX; 10529 double rm10 = leftY; 10530 double rm11 = upnY; 10531 double rm12 = dirY; 10532 double rm20 = leftZ; 10533 double rm21 = upnZ; 10534 double rm22 = dirZ; 10535 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10536 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10537 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10538 10539 double nm00 = m00 * rm00; 10540 double nm01 = m11 * rm01; 10541 double nm02 = m22 * rm02; 10542 double nm03 = m23 * rm02; 10543 double nm10 = m00 * rm10; 10544 double nm11 = m11 * rm11; 10545 double nm12 = m22 * rm12; 10546 double nm13 = m23 * rm12; 10547 double nm20 = m00 * rm20; 10548 double nm21 = m11 * rm21; 10549 double nm22 = m22 * rm22; 10550 double nm23 = m23 * rm22; 10551 double nm30 = m00 * rm30; 10552 double nm31 = m11 * rm31; 10553 double nm32 = m22 * rm32 + m32; 10554 double nm33 = m23 * rm32; 10555 dest._m00(nm00) 10556 ._m01(nm01) 10557 ._m02(nm02) 10558 ._m03(nm03) 10559 ._m10(nm10) 10560 ._m11(nm11) 10561 ._m12(nm12) 10562 ._m13(nm13) 10563 ._m20(nm20) 10564 ._m21(nm21) 10565 ._m22(nm22) 10566 ._m23(nm23) 10567 ._m30(nm30) 10568 ._m31(nm31) 10569 ._m32(nm32) 10570 ._m33(nm33) 10571 ._properties(0); 10572 10573 return dest; 10574 } 10575 10576 /** 10577 * This method is equivalent to calling: <code>translate(w-1-2*x, h-1-2*y, 0).scale(w, h, 1)</code> 10578 * <p> 10579 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the created transformation matrix, 10580 * then the new matrix will be <code>M * T</code>. So when transforming a 10581 * vector <code>v</code> with the new matrix by using <code>M * T * v</code>, the 10582 * created transformation will be applied first! 10583 * 10584 * @param x 10585 * the tile's x coordinate/index (should be in <code>[0..w)</code>) 10586 * @param y 10587 * the tile's y coordinate/index (should be in <code>[0..h)</code>) 10588 * @param w 10589 * the number of tiles along the x axis 10590 * @param h 10591 * the number of tiles along the y axis 10592 * @return this 10593 */ 10594 ref public Matrix4d tile(int x, int y, int w, int h) return { 10595 tile(x, y, w, h, this); 10596 return this; 10597 } 10598 public Matrix4d tile(int x, int y, int w, int h, ref Matrix4d dest) { 10599 float tx = w - 1 - (x<<1), ty = h - 1 - (y<<1); 10600 return dest 10601 ._m30(Math.fma(m00, tx, Math.fma(m10, ty, m30))) 10602 ._m31(Math.fma(m01, tx, Math.fma(m11, ty, m31))) 10603 ._m32(Math.fma(m02, tx, Math.fma(m12, ty, m32))) 10604 ._m33(Math.fma(m03, tx, Math.fma(m13, ty, m33))) 10605 ._m00(m00 * w) 10606 ._m01(m01 * w) 10607 ._m02(m02 * w) 10608 ._m03(m03 * w) 10609 ._m10(m10 * h) 10610 ._m11(m11 * h) 10611 ._m12(m12 * h) 10612 ._m13(m13 * h) 10613 ._m20(m20) 10614 ._m21(m21) 10615 ._m22(m22) 10616 ._m23(m23) 10617 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10618 } 10619 10620 /** 10621 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10622 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10623 * <p> 10624 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10625 * then the new matrix will be <code>M * P</code>. So when transforming a 10626 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10627 * the perspective projection will be applied first! 10628 * <p> 10629 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10630 * use {@link #setPerspective(double, double, double, double, bool) setPerspective}. 10631 * 10632 * @see #setPerspective(double, double, double, double, bool) 10633 * 10634 * @param fovy 10635 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10636 * @param aspect 10637 * the aspect ratio (i.e. width / height; must be greater than zero) 10638 * @param zNear 10639 * near clipping plane distance. This value must be greater than zero. 10640 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10641 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10642 * @param zFar 10643 * far clipping plane distance. This value must be greater than zero. 10644 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10645 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10646 * @param dest 10647 * will hold the result 10648 * @param zZeroToOne 10649 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10650 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10651 * @return dest 10652 */ 10653 public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10654 if ((properties & PROPERTY_IDENTITY) != 0) 10655 return dest.setPerspective(fovy, aspect, zNear, zFar, zZeroToOne); 10656 return perspectiveGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest); 10657 } 10658 private Matrix4d perspectiveGeneric(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10659 double h = Math.tan(fovy * 0.5); 10660 // calculate right matrix elements 10661 double rm00 = 1.0 / (h * aspect); 10662 double rm11 = 1.0 / h; 10663 double rm22; 10664 double rm32; 10665 bool farInf = zFar > 0 && Math.isInfinite(zFar); 10666 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 10667 if (farInf) { 10668 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 10669 double e = 1E-6; 10670 rm22 = e - 1.0; 10671 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 10672 } else if (nearInf) { 10673 double e = 1E-6; 10674 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 10675 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 10676 } else { 10677 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 10678 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 10679 } 10680 // perform optimized matrix multiplication 10681 double nm20 = m20 * rm22 - m30; 10682 double nm21 = m21 * rm22 - m31; 10683 double nm22 = m22 * rm22 - m32; 10684 double nm23 = m23 * rm22 - m33; 10685 dest._m00(m00 * rm00) 10686 ._m01(m01 * rm00) 10687 ._m02(m02 * rm00) 10688 ._m03(m03 * rm00) 10689 ._m10(m10 * rm11) 10690 ._m11(m11 * rm11) 10691 ._m12(m12 * rm11) 10692 ._m13(m13 * rm11) 10693 ._m30(m20 * rm32) 10694 ._m31(m21 * rm32) 10695 ._m32(m22 * rm32) 10696 ._m33(m23 * rm32) 10697 ._m20(nm20) 10698 ._m21(nm21) 10699 ._m22(nm22) 10700 ._m23(nm23) 10701 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10702 return dest; 10703 } 10704 10705 /** 10706 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10707 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 10708 * <p> 10709 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10710 * then the new matrix will be <code>M * P</code>. So when transforming a 10711 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10712 * the perspective projection will be applied first! 10713 * <p> 10714 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10715 * use {@link #setPerspective(double, double, double, double) setPerspective}. 10716 * 10717 * @see #setPerspective(double, double, double, double) 10718 * 10719 * @param fovy 10720 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10721 * @param aspect 10722 * the aspect ratio (i.e. width / height; must be greater than zero) 10723 * @param zNear 10724 * near clipping plane distance. This value must be greater than zero. 10725 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10726 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10727 * @param zFar 10728 * far clipping plane distance. This value must be greater than zero. 10729 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10730 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10731 * @param dest 10732 * will hold the result 10733 * @return dest 10734 */ 10735 public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, ref Matrix4d dest) { 10736 return perspective(fovy, aspect, zNear, zFar, false, dest); 10737 } 10738 10739 /** 10740 * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system 10741 * using the given NDC z range to this matrix. 10742 * <p> 10743 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10744 * then the new matrix will be <code>M * P</code>. So when transforming a 10745 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10746 * the perspective projection will be applied first! 10747 * <p> 10748 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10749 * use {@link #setPerspective(double, double, double, double, bool) setPerspective}. 10750 * 10751 * @see #setPerspective(double, double, double, double, bool) 10752 * 10753 * @param fovy 10754 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10755 * @param aspect 10756 * the aspect ratio (i.e. width / height; must be greater than zero) 10757 * @param zNear 10758 * near clipping plane distance. This value must be greater than zero. 10759 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10760 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10761 * @param zFar 10762 * far clipping plane distance. This value must be greater than zero. 10763 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10764 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10765 * @param zZeroToOne 10766 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10767 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10768 * @return this 10769 */ 10770 ref public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 10771 perspective(fovy, aspect, zNear, zFar, zZeroToOne, this); 10772 return this; 10773 } 10774 10775 /** 10776 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10777 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 10778 * <p> 10779 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10780 * then the new matrix will be <code>M * P</code>. So when transforming a 10781 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10782 * the perspective projection will be applied first! 10783 * <p> 10784 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10785 * use {@link #setPerspective(double, double, double, double) setPerspective}. 10786 * 10787 * @see #setPerspective(double, double, double, double) 10788 * 10789 * @param fovy 10790 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10791 * @param aspect 10792 * the aspect ratio (i.e. width / height; must be greater than zero) 10793 * @param zNear 10794 * near clipping plane distance. This value must be greater than zero. 10795 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10796 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10797 * @param zFar 10798 * far clipping plane distance. This value must be greater than zero. 10799 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10800 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10801 * @return this 10802 */ 10803 ref public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar) return { 10804 perspective(fovy, aspect, zNear, zFar, this); 10805 return this; 10806 } 10807 10808 /** 10809 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10810 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10811 * <p> 10812 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10813 * then the new matrix will be <code>M * P</code>. So when transforming a 10814 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10815 * the perspective projection will be applied first! 10816 * <p> 10817 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10818 * use {@link #setPerspectiveRect(double, double, double, double, bool) setPerspectiveRect}. 10819 * 10820 * @see #setPerspectiveRect(double, double, double, double, bool) 10821 * 10822 * @param width 10823 * the width of the near frustum plane 10824 * @param height 10825 * the height of the near frustum plane 10826 * @param zNear 10827 * near clipping plane distance. This value must be greater than zero. 10828 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10829 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10830 * @param zFar 10831 * far clipping plane distance. This value must be greater than zero. 10832 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10833 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10834 * @param dest 10835 * will hold the result 10836 * @param zZeroToOne 10837 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10838 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10839 * @return dest 10840 */ 10841 public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10842 if ((properties & PROPERTY_IDENTITY) != 0) 10843 return dest.setPerspectiveRect(width, height, zNear, zFar, zZeroToOne); 10844 return perspectiveRectGeneric(width, height, zNear, zFar, zZeroToOne, dest); 10845 } 10846 private Matrix4d perspectiveRectGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10847 double rm00 = (zNear + zNear) / width; 10848 double rm11 = (zNear + zNear) / height; 10849 double rm22, rm32; 10850 bool farInf = zFar > 0 && Math.isInfinite(zFar); 10851 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 10852 if (farInf) { 10853 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 10854 double e = 1E-6f; 10855 rm22 = e - 1.0; 10856 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 10857 } else if (nearInf) { 10858 double e = 1E-6f; 10859 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 10860 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 10861 } else { 10862 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 10863 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 10864 } 10865 // perform optimized matrix multiplication 10866 double nm20 = m20 * rm22 - m30; 10867 double nm21 = m21 * rm22 - m31; 10868 double nm22 = m22 * rm22 - m32; 10869 double nm23 = m23 * rm22 - m33; 10870 dest._m00(m00 * rm00) 10871 ._m01(m01 * rm00) 10872 ._m02(m02 * rm00) 10873 ._m03(m03 * rm00) 10874 ._m10(m10 * rm11) 10875 ._m11(m11 * rm11) 10876 ._m12(m12 * rm11) 10877 ._m13(m13 * rm11) 10878 ._m30(m20 * rm32) 10879 ._m31(m21 * rm32) 10880 ._m32(m22 * rm32) 10881 ._m33(m23 * rm32) 10882 ._m20(nm20) 10883 ._m21(nm21) 10884 ._m22(nm22) 10885 ._m23(nm23) 10886 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10887 return dest; 10888 } 10889 10890 /** 10891 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10892 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 10893 * <p> 10894 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10895 * then the new matrix will be <code>M * P</code>. So when transforming a 10896 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10897 * the perspective projection will be applied first! 10898 * <p> 10899 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10900 * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}. 10901 * 10902 * @see #setPerspectiveRect(double, double, double, double) 10903 * 10904 * @param width 10905 * the width of the near frustum plane 10906 * @param height 10907 * the height of the near frustum plane 10908 * @param zNear 10909 * near clipping plane distance. This value must be greater than zero. 10910 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10911 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10912 * @param zFar 10913 * far clipping plane distance. This value must be greater than zero. 10914 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10915 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10916 * @param dest 10917 * will hold the result 10918 * @return dest 10919 */ 10920 public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 10921 return perspectiveRect(width, height, zNear, zFar, false, dest); 10922 } 10923 10924 /** 10925 * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system 10926 * using the given NDC z range to this matrix. 10927 * <p> 10928 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10929 * then the new matrix will be <code>M * P</code>. So when transforming a 10930 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10931 * the perspective projection will be applied first! 10932 * <p> 10933 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10934 * use {@link #setPerspectiveRect(double, double, double, double, bool) setPerspectiveRect}. 10935 * 10936 * @see #setPerspectiveRect(double, double, double, double, bool) 10937 * 10938 * @param width 10939 * the width of the near frustum plane 10940 * @param height 10941 * the height of the near frustum plane 10942 * @param zNear 10943 * near clipping plane distance. This value must be greater than zero. 10944 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10945 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10946 * @param zFar 10947 * far clipping plane distance. This value must be greater than zero. 10948 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10949 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10950 * @param zZeroToOne 10951 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10952 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10953 * @return this 10954 */ 10955 ref public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 10956 perspectiveRect(width, height, zNear, zFar, zZeroToOne, this); 10957 return this; 10958 } 10959 10960 /** 10961 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10962 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 10963 * <p> 10964 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10965 * then the new matrix will be <code>M * P</code>. So when transforming a 10966 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10967 * the perspective projection will be applied first! 10968 * <p> 10969 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10970 * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}. 10971 * 10972 * @see #setPerspectiveRect(double, double, double, double) 10973 * 10974 * @param width 10975 * the width of the near frustum plane 10976 * @param height 10977 * the height of the near frustum plane 10978 * @param zNear 10979 * near clipping plane distance. This value must be greater than zero. 10980 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10981 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10982 * @param zFar 10983 * far clipping plane distance. This value must be greater than zero. 10984 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10985 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10986 * @return this 10987 */ 10988 ref public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar) return { 10989 perspectiveRect(width, height, zNear, zFar, this); 10990 return this; 10991 } 10992 10993 /** 10994 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 10995 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10996 * <p> 10997 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 10998 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 10999 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11000 * is parallel to the XZ-plane. 11001 * <p> 11002 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11003 * then the new matrix will be <code>M * P</code>. So when transforming a 11004 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11005 * the perspective projection will be applied first! 11006 * <p> 11007 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11008 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, bool) setPerspectiveOffCenter}. 11009 * 11010 * @see #setPerspectiveOffCenter(double, double, double, double, double, double, bool) 11011 * 11012 * @param fovy 11013 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11014 * @param offAngleX 11015 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11016 * @param offAngleY 11017 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11018 * @param aspect 11019 * the aspect ratio (i.e. width / height; must be greater than zero) 11020 * @param zNear 11021 * near clipping plane distance. This value must be greater than zero. 11022 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11023 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11024 * @param zFar 11025 * far clipping plane distance. This value must be greater than zero. 11026 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11027 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11028 * @param dest 11029 * will hold the result 11030 * @param zZeroToOne 11031 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11032 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11033 * @return dest 11034 */ 11035 public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11036 if ((properties & PROPERTY_IDENTITY) != 0) 11037 return dest.setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne); 11038 return perspectiveOffCenterGeneric(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, dest); 11039 } 11040 private Matrix4d perspectiveOffCenterGeneric(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11041 double h = Math.tan(fovy * 0.5); 11042 // calculate right matrix elements 11043 double xScale = 1.0 / (h * aspect); 11044 double yScale = 1.0 / h; 11045 double rm00 = xScale; 11046 double rm11 = yScale; 11047 double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY); 11048 double rm20 = offX * xScale; 11049 double rm21 = offY * yScale; 11050 double rm22; 11051 double rm32; 11052 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11053 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11054 if (farInf) { 11055 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11056 double e = 1E-6; 11057 rm22 = e - 1.0; 11058 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 11059 } else if (nearInf) { 11060 double e = 1E-6; 11061 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 11062 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 11063 } else { 11064 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 11065 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 11066 } 11067 // perform optimized matrix multiplication 11068 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30; 11069 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31; 11070 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32; 11071 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33; 11072 dest._m00(m00 * rm00) 11073 ._m01(m01 * rm00) 11074 ._m02(m02 * rm00) 11075 ._m03(m03 * rm00) 11076 ._m10(m10 * rm11) 11077 ._m11(m11 * rm11) 11078 ._m12(m12 * rm11) 11079 ._m13(m13 * rm11) 11080 ._m30(m20 * rm32) 11081 ._m31(m21 * rm32) 11082 ._m32(m22 * rm32) 11083 ._m33(m23 * rm32) 11084 ._m20(nm20) 11085 ._m21(nm21) 11086 ._m22(nm22) 11087 ._m23(nm23) 11088 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 11089 | PROPERTY_ORTHONORMAL | (rm20 == 0.0 && rm21 == 0.0 ? 0 : PROPERTY_PERSPECTIVE))); 11090 return dest; 11091 } 11092 11093 /** 11094 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11095 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 11096 * <p> 11097 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11098 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11099 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11100 * is parallel to the XZ-plane. 11101 * <p> 11102 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11103 * then the new matrix will be <code>M * P</code>. So when transforming a 11104 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11105 * the perspective projection will be applied first! 11106 * <p> 11107 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11108 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}. 11109 * 11110 * @see #setPerspectiveOffCenter(double, double, double, double, double, double) 11111 * 11112 * @param fovy 11113 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11114 * @param offAngleX 11115 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11116 * @param offAngleY 11117 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11118 * @param aspect 11119 * the aspect ratio (i.e. width / height; must be greater than zero) 11120 * @param zNear 11121 * near clipping plane distance. This value must be greater than zero. 11122 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11123 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11124 * @param zFar 11125 * far clipping plane distance. This value must be greater than zero. 11126 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11127 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11128 * @param dest 11129 * will hold the result 11130 * @return dest 11131 */ 11132 public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, ref Matrix4d dest) { 11133 return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false, dest); 11134 } 11135 11136 /** 11137 * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system 11138 * using the given NDC z range to this matrix. 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, bool) setPerspectiveOffCenter}. 11152 * 11153 * @see #setPerspectiveOffCenter(double, double, double, double, double, double, bool) 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 zZeroToOne 11172 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11173 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11174 * @return this 11175 */ 11176 ref public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11177 perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, this); 11178 return this; 11179 } 11180 11181 /** 11182 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11183 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11184 * <p> 11185 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11186 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11187 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11188 * is parallel to the XZ-plane. 11189 * <p> 11190 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11191 * then the new matrix will be <code>M * P</code>. So when transforming a 11192 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11193 * the perspective projection will be applied first! 11194 * <p> 11195 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11196 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}. 11197 * 11198 * @see #setPerspectiveOffCenter(double, double, double, double, double, double) 11199 * 11200 * @param fovy 11201 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11202 * @param offAngleX 11203 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11204 * @param offAngleY 11205 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11206 * @param aspect 11207 * the aspect ratio (i.e. width / height; must be greater than zero) 11208 * @param zNear 11209 * near clipping plane distance. This value must be greater than zero. 11210 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11211 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11212 * @param zFar 11213 * far clipping plane distance. This value must be greater than zero. 11214 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11215 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11216 * @return this 11217 */ 11218 ref public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar) return { 11219 perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, this); 11220 return this; 11221 } 11222 11223 /** 11224 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11225 * using the given NDC z range to this matrix. 11226 * <p> 11227 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11228 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11229 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11230 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11231 * <p> 11232 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11233 * then the new matrix will be <code>M * P</code>. So when transforming a 11234 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11235 * the perspective projection will be applied first! 11236 * <p> 11237 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11238 * use {@link #setPerspectiveOffCenterFov(double, double, double, double, double, double, bool) setPerspectiveOffCenterFov}. 11239 * 11240 * @see #setPerspectiveOffCenterFov(double, double, double, double, double, double, bool) 11241 * 11242 * @param angleLeft 11243 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11244 * For a symmetric frustum, this value is negative. 11245 * @param angleRight 11246 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11247 * @param angleDown 11248 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11249 * For a symmetric frustum, this value is negative. 11250 * @param angleUp 11251 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11252 * @param zNear 11253 * near clipping plane distance. This value must be greater than zero. 11254 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11255 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11256 * @param zFar 11257 * far clipping plane distance. This value must be greater than zero. 11258 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11259 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11260 * @param zZeroToOne 11261 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11262 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11263 * @return this 11264 */ 11265 ref public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11266 perspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, zZeroToOne, this); 11267 return this; 11268 } 11269 public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11270 return frustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne, dest); 11271 } 11272 11273 /** 11274 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11275 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11276 * <p> 11277 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11278 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11279 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11280 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11281 * <p> 11282 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11283 * then the new matrix will be <code>M * P</code>. So when transforming a 11284 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11285 * the perspective projection will be applied first! 11286 * <p> 11287 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11288 * use {@link #setPerspectiveOffCenterFov(double, double, double, double, double, double) setPerspectiveOffCenterFov}. 11289 * 11290 * @see #setPerspectiveOffCenterFov(double, double, double, double, double, double) 11291 * 11292 * @param angleLeft 11293 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11294 * For a symmetric frustum, this value is negative. 11295 * @param angleRight 11296 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11297 * @param angleDown 11298 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11299 * For a symmetric frustum, this value is negative. 11300 * @param angleUp 11301 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11302 * @param zNear 11303 * near clipping plane distance. This value must be greater than zero. 11304 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11305 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11306 * @param zFar 11307 * far clipping plane distance. This value must be greater than zero. 11308 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11309 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11310 * @return this 11311 */ 11312 ref public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11313 perspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, this); 11314 return this; 11315 } 11316 public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, ref Matrix4d dest) { 11317 return frustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, dest); 11318 } 11319 11320 /** 11321 * Apply an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11322 * using the given NDC z range to this matrix. 11323 * <p> 11324 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11325 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11326 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11327 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11328 * <p> 11329 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11330 * then the new matrix will be <code>M * P</code>. So when transforming a 11331 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11332 * the perspective projection will be applied first! 11333 * <p> 11334 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11335 * use {@link #setPerspectiveOffCenterFovLH(double, double, double, double, double, double, bool) setPerspectiveOffCenterFovLH}. 11336 * 11337 * @see #setPerspectiveOffCenterFovLH(double, double, double, double, double, double, bool) 11338 * 11339 * @param angleLeft 11340 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11341 * For a symmetric frustum, this value is negative. 11342 * @param angleRight 11343 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11344 * @param angleDown 11345 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11346 * For a symmetric frustum, this value is negative. 11347 * @param angleUp 11348 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11349 * @param zNear 11350 * near clipping plane distance. This value must be greater than zero. 11351 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11352 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11353 * @param zFar 11354 * far clipping plane distance. This value must be greater than zero. 11355 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11356 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11357 * @param zZeroToOne 11358 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11359 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11360 * @return this 11361 */ 11362 ref public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11363 perspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, zZeroToOne, this); 11364 return this; 11365 } 11366 public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11367 return frustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne, dest); 11368 } 11369 11370 /** 11371 * Apply an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11372 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11373 * <p> 11374 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11375 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11376 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11377 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11378 * <p> 11379 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11380 * then the new matrix will be <code>M * P</code>. So when transforming a 11381 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11382 * the perspective projection will be applied first! 11383 * <p> 11384 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11385 * use {@link #setPerspectiveOffCenterFovLH(double, double, double, double, double, double) setPerspectiveOffCenterFovLH}. 11386 * 11387 * @see #setPerspectiveOffCenterFovLH(double, double, double, double, double, double) 11388 * 11389 * @param angleLeft 11390 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11391 * For a symmetric frustum, this value is negative. 11392 * @param angleRight 11393 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11394 * @param angleDown 11395 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11396 * For a symmetric frustum, this value is negative. 11397 * @param angleUp 11398 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11399 * @param zNear 11400 * near clipping plane distance. This value must be greater than zero. 11401 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11402 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11403 * @param zFar 11404 * far clipping plane distance. This value must be greater than zero. 11405 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11406 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11407 * @return this 11408 */ 11409 ref public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11410 perspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, this); 11411 return this; 11412 } 11413 public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, ref Matrix4d dest) { 11414 return frustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, dest); 11415 } 11416 11417 /** 11418 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11419 * using the given NDC z range. 11420 * <p> 11421 * In order to apply the perspective projection transformation to an existing transformation, 11422 * use {@link #perspective(double, double, double, double, bool) perspective()}. 11423 * 11424 * @see #perspective(double, double, double, double, bool) 11425 * 11426 * @param fovy 11427 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11428 * @param aspect 11429 * the aspect ratio (i.e. width / height; must be greater than zero) 11430 * @param zNear 11431 * near clipping plane distance. This value must be greater than zero. 11432 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11433 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11434 * @param zFar 11435 * far clipping plane distance. This value must be greater than zero. 11436 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11437 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11438 * @param zZeroToOne 11439 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11440 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11441 * @return this 11442 */ 11443 ref public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11444 double h = Math.tan(fovy * 0.5); 11445 _m00(1.0 / (h * aspect)). 11446 _m01(0.0). 11447 _m02(0.0). 11448 _m03(0.0). 11449 _m10(0.0). 11450 _m11(1.0 / h). 11451 _m12(0.0). 11452 _m13(0.0). 11453 _m20(0.0). 11454 _m21(0.0); 11455 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11456 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11457 if (farInf) { 11458 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11459 double e = 1E-6; 11460 _m22(e - 1.0). 11461 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11462 } else if (nearInf) { 11463 double e = 1E-6; 11464 _m22((zZeroToOne ? 0.0 : 1.0) - e). 11465 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11466 } else { 11467 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 11468 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11469 } 11470 _m23(-1.0). 11471 _m30(0.0). 11472 _m31(0.0). 11473 _m33(0.0). 11474 properties = PROPERTY_PERSPECTIVE; 11475 return this; 11476 } 11477 11478 /** 11479 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11480 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 11481 * <p> 11482 * In order to apply the perspective projection transformation to an existing transformation, 11483 * use {@link #perspective(double, double, double, double) perspective()}. 11484 * 11485 * @see #perspective(double, double, double, double) 11486 * 11487 * @param fovy 11488 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11489 * @param aspect 11490 * the aspect ratio (i.e. width / height; must be greater than zero) 11491 * @param zNear 11492 * near clipping plane distance. This value must be greater than zero. 11493 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11494 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11495 * @param zFar 11496 * far clipping plane distance. This value must be greater than zero. 11497 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11498 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11499 * @return this 11500 */ 11501 ref public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar) return { 11502 return setPerspective(fovy, aspect, zNear, zFar, false); 11503 } 11504 11505 /** 11506 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11507 * using the given NDC z range. 11508 * <p> 11509 * In order to apply the perspective projection transformation to an existing transformation, 11510 * use {@link #perspectiveRect(double, double, double, double, bool) perspectiveRect()}. 11511 * 11512 * @see #perspectiveRect(double, double, double, double, bool) 11513 * 11514 * @param width 11515 * the width of the near frustum plane 11516 * @param height 11517 * the height of the near frustum plane 11518 * @param zNear 11519 * near clipping plane distance. This value must be greater than zero. 11520 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11521 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11522 * @param zFar 11523 * far clipping plane distance. This value must be greater than zero. 11524 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11525 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11526 * @param zZeroToOne 11527 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11528 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11529 * @return this 11530 */ 11531 ref public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 11532 this.zero(); 11533 this._m00((zNear + zNear) / width); 11534 this._m11((zNear + zNear) / height); 11535 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11536 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11537 if (farInf) { 11538 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11539 double e = 1E-6; 11540 this._m22(e - 1.0); 11541 this._m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11542 } else if (nearInf) { 11543 double e = 1E-6f; 11544 this._m22((zZeroToOne ? 0.0 : 1.0) - e); 11545 this._m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11546 } else { 11547 this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)); 11548 this._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11549 } 11550 this._m23(-1.0); 11551 properties = PROPERTY_PERSPECTIVE; 11552 return this; 11553 } 11554 11555 /** 11556 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11557 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 11558 * <p> 11559 * In order to apply the perspective projection transformation to an existing transformation, 11560 * use {@link #perspectiveRect(double, double, double, double) perspectiveRect()}. 11561 * 11562 * @see #perspectiveRect(double, double, double, double) 11563 * 11564 * @param width 11565 * the width of the near frustum plane 11566 * @param height 11567 * the height of the near frustum plane 11568 * @param zNear 11569 * near clipping plane distance. This value must be greater than zero. 11570 * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11571 * In that case, <code>zFar</code> may not also be {@link Float#POSITIVE_INFINITY}. 11572 * @param zFar 11573 * far clipping plane distance. This value must be greater than zero. 11574 * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11575 * In that case, <code>zNear</code> may not also be {@link Float#POSITIVE_INFINITY}. 11576 * @return this 11577 */ 11578 ref public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar) return { 11579 return setPerspectiveRect(width, height, zNear, zFar, false); 11580 } 11581 11582 /** 11583 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed 11584 * coordinate system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11585 * <p> 11586 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11587 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11588 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11589 * is parallel to the XZ-plane. 11590 * <p> 11591 * In order to apply the perspective projection transformation to an existing transformation, 11592 * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}. 11593 * 11594 * @see #perspectiveOffCenter(double, double, double, double, double, double) 11595 * 11596 * @param fovy 11597 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11598 * @param offAngleX 11599 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11600 * @param offAngleY 11601 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11602 * @param aspect 11603 * the aspect ratio (i.e. width / height; must be greater than zero) 11604 * @param zNear 11605 * near clipping plane distance. This value must be greater than zero. 11606 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11607 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11608 * @param zFar 11609 * far clipping plane distance. This value must be greater than zero. 11610 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11611 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11612 * @return this 11613 */ 11614 ref public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY, 11615 double aspect, double zNear, double zFar) return { 11616 return setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false); 11617 } 11618 /** 11619 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed 11620 * coordinate system using the given NDC z range. 11621 * <p> 11622 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11623 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11624 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11625 * is parallel to the XZ-plane. 11626 * <p> 11627 * In order to apply the perspective projection transformation to an existing transformation, 11628 * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}. 11629 * 11630 * @see #perspectiveOffCenter(double, double, double, double, double, double) 11631 * 11632 * @param fovy 11633 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11634 * @param offAngleX 11635 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11636 * @param offAngleY 11637 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11638 * @param aspect 11639 * the aspect ratio (i.e. width / height; must be greater than zero) 11640 * @param zNear 11641 * near clipping plane distance. This value must be greater than zero. 11642 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11643 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11644 * @param zFar 11645 * far clipping plane distance. This value must be greater than zero. 11646 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11647 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11648 * @param zZeroToOne 11649 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11650 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11651 * @return this 11652 */ 11653 ref public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY, 11654 double aspect, double zNear, double zFar, bool zZeroToOne) return { 11655 this.zero(); 11656 double h = Math.tan(fovy * 0.5); 11657 double xScale = 1.0 / (h * aspect), yScale = 1.0 / h; 11658 _m00(xScale). 11659 _m11(yScale); 11660 double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY); 11661 _m20(offX * xScale). 11662 _m21(offY * yScale); 11663 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11664 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11665 if (farInf) { 11666 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11667 double e = 1E-6; 11668 _m22(e - 1.0). 11669 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11670 } else if (nearInf) { 11671 double e = 1E-6; 11672 _m22((zZeroToOne ? 0.0 : 1.0) - e). 11673 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11674 } else { 11675 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 11676 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11677 } 11678 _m23(-1.0). 11679 _m30(0.0). 11680 _m31(0.0). 11681 _m33(0.0). 11682 properties = offAngleX == 0.0 && offAngleY == 0.0 ? PROPERTY_PERSPECTIVE : 0; 11683 return this; 11684 } 11685 11686 /** 11687 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate 11688 * system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11689 * <p> 11690 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11691 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11692 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11693 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11694 * <p> 11695 * In order to apply the perspective projection transformation to an existing transformation, 11696 * use {@link #perspectiveOffCenterFov(double, double, double, double, double, double) perspectiveOffCenterFov()}. 11697 * 11698 * @see #perspectiveOffCenterFov(double, double, double, double, double, double) 11699 * 11700 * @param angleLeft 11701 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11702 * For a symmetric frustum, this value is negative. 11703 * @param angleRight 11704 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11705 * @param angleDown 11706 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11707 * For a symmetric frustum, this value is negative. 11708 * @param angleUp 11709 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11710 * @param zNear 11711 * near clipping plane distance. This value must be greater than zero. 11712 * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11713 * In that case, <code>zFar</code> may not also be {@link Float#POSITIVE_INFINITY}. 11714 * @param zFar 11715 * far clipping plane distance. This value must be greater than zero. 11716 * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11717 * In that case, <code>zNear</code> may not also be {@link Float#POSITIVE_INFINITY}. 11718 * @return this 11719 */ 11720 ref public Matrix4d setPerspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11721 return setPerspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, false); 11722 } 11723 /** 11724 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11725 * using the given NDC z range. 11726 * <p> 11727 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11728 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11729 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11730 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11731 * <p> 11732 * In order to apply the perspective projection transformation to an existing transformation, 11733 * use {@link #perspectiveOffCenterFov(double, double, double, double, double, double, bool) perspectiveOffCenterFov()}. 11734 * 11735 * @see #perspectiveOffCenterFov(double, double, double, double, double, double, bool) 11736 * 11737 * @param angleLeft 11738 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11739 * For a symmetric frustum, this value is negative. 11740 * @param angleRight 11741 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11742 * @param angleDown 11743 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11744 * For a symmetric frustum, this value is negative. 11745 * @param angleUp 11746 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11747 * @param zNear 11748 * near clipping plane distance. This value must be greater than zero. 11749 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11750 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11751 * @param zFar 11752 * far clipping plane distance. This value must be greater than zero. 11753 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11754 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11755 * @param zZeroToOne 11756 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11757 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11758 * @return this 11759 */ 11760 ref public Matrix4d setPerspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11761 return setFrustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne); 11762 } 11763 11764 /** 11765 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate 11766 * system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11767 * <p> 11768 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11769 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11770 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11771 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11772 * <p> 11773 * In order to apply the perspective projection transformation to an existing transformation, 11774 * use {@link #perspectiveOffCenterFovLH(double, double, double, double, double, double) perspectiveOffCenterFovLH()}. 11775 * 11776 * @see #perspectiveOffCenterFovLH(double, double, double, double, double, double) 11777 * 11778 * @param angleLeft 11779 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11780 * For a symmetric frustum, this value is negative. 11781 * @param angleRight 11782 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11783 * @param angleDown 11784 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11785 * For a symmetric frustum, this value is negative. 11786 * @param angleUp 11787 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11788 * @param zNear 11789 * near clipping plane distance. This value must be greater than zero. 11790 * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11791 * In that case, <code>zFar</code> may not also be {@link Float#POSITIVE_INFINITY}. 11792 * @param zFar 11793 * far clipping plane distance. This value must be greater than zero. 11794 * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11795 * In that case, <code>zNear</code> may not also be {@link Float#POSITIVE_INFINITY}. 11796 * @return this 11797 */ 11798 ref public Matrix4d setPerspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11799 return setPerspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, false); 11800 } 11801 /** 11802 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11803 * using the given NDC z range. 11804 * <p> 11805 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11806 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11807 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11808 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11809 * <p> 11810 * In order to apply the perspective projection transformation to an existing transformation, 11811 * use {@link #perspectiveOffCenterFovLH(double, double, double, double, double, double, bool) perspectiveOffCenterFovLH()}. 11812 * 11813 * @see #perspectiveOffCenterFovLH(double, double, double, double, double, double, bool) 11814 * 11815 * @param angleLeft 11816 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11817 * For a symmetric frustum, this value is negative. 11818 * @param angleRight 11819 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11820 * @param angleDown 11821 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11822 * For a symmetric frustum, this value is negative. 11823 * @param angleUp 11824 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11825 * @param zNear 11826 * near clipping plane distance. This value must be greater than zero. 11827 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11828 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11829 * @param zFar 11830 * far clipping plane distance. This value must be greater than zero. 11831 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11832 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11833 * @param zZeroToOne 11834 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11835 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11836 * @return this 11837 */ 11838 ref public Matrix4d setPerspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11839 return setFrustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne); 11840 } 11841 11842 /** 11843 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11844 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 11845 * <p> 11846 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11847 * then the new matrix will be <code>M * P</code>. So when transforming a 11848 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11849 * the perspective projection will be applied first! 11850 * <p> 11851 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11852 * use {@link #setPerspectiveLH(double, double, double, double, bool) setPerspectiveLH}. 11853 * 11854 * @see #setPerspectiveLH(double, double, double, double, bool) 11855 * 11856 * @param fovy 11857 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11858 * @param aspect 11859 * the aspect ratio (i.e. width / height; must be greater than zero) 11860 * @param zNear 11861 * near clipping plane distance. This value must be greater than zero. 11862 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11863 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11864 * @param zFar 11865 * far clipping plane distance. This value must be greater than zero. 11866 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11867 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11868 * @param zZeroToOne 11869 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11870 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11871 * @param dest 11872 * will hold the result 11873 * @return dest 11874 */ 11875 public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11876 if ((properties & PROPERTY_IDENTITY) != 0) 11877 return dest.setPerspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne); 11878 return perspectiveLHGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest); 11879 } 11880 private Matrix4d perspectiveLHGeneric(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11881 double h = Math.tan(fovy * 0.5); 11882 // calculate right matrix elements 11883 double rm00 = 1.0 / (h * aspect); 11884 double rm11 = 1.0 / h; 11885 double rm22; 11886 double rm32; 11887 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11888 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11889 if (farInf) { 11890 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11891 double e = 1E-6; 11892 rm22 = 1.0 - e; 11893 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 11894 } else if (nearInf) { 11895 double e = 1E-6; 11896 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 11897 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 11898 } else { 11899 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear); 11900 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 11901 } 11902 // perform optimized matrix multiplication 11903 double nm20 = m20 * rm22 + m30; 11904 double nm21 = m21 * rm22 + m31; 11905 double nm22 = m22 * rm22 + m32; 11906 double nm23 = m23 * rm22 + m33; 11907 dest._m00(m00 * rm00) 11908 ._m01(m01 * rm00) 11909 ._m02(m02 * rm00) 11910 ._m03(m03 * rm00) 11911 ._m10(m10 * rm11) 11912 ._m11(m11 * rm11) 11913 ._m12(m12 * rm11) 11914 ._m13(m13 * rm11) 11915 ._m30(m20 * rm32) 11916 ._m31(m21 * rm32) 11917 ._m32(m22 * rm32) 11918 ._m33(m23 * rm32) 11919 ._m20(nm20) 11920 ._m21(nm21) 11921 ._m22(nm22) 11922 ._m23(nm23) 11923 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 11924 return dest; 11925 } 11926 11927 /** 11928 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11929 * using the given NDC z range to this matrix. 11930 * <p> 11931 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11932 * then the new matrix will be <code>M * P</code>. So when transforming a 11933 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11934 * the perspective projection will be applied first! 11935 * <p> 11936 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11937 * use {@link #setPerspectiveLH(double, double, double, double, bool) setPerspectiveLH}. 11938 * 11939 * @see #setPerspectiveLH(double, double, double, double, bool) 11940 * 11941 * @param fovy 11942 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11943 * @param aspect 11944 * the aspect ratio (i.e. width / height; must be greater than zero) 11945 * @param zNear 11946 * near clipping plane distance. This value must be greater than zero. 11947 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11948 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11949 * @param zFar 11950 * far clipping plane distance. This value must be greater than zero. 11951 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11952 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11953 * @param zZeroToOne 11954 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11955 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11956 * @return this 11957 */ 11958 ref public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11959 perspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne, this); 11960 return this; 11961 } 11962 11963 /** 11964 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11965 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 11966 * <p> 11967 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11968 * then the new matrix will be <code>M * P</code>. So when transforming a 11969 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11970 * the perspective projection will be applied first! 11971 * <p> 11972 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11973 * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}. 11974 * 11975 * @see #setPerspectiveLH(double, double, double, double) 11976 * 11977 * @param fovy 11978 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11979 * @param aspect 11980 * the aspect ratio (i.e. width / height; must be greater than zero) 11981 * @param zNear 11982 * near clipping plane distance. This value must be greater than zero. 11983 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11984 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11985 * @param zFar 11986 * far clipping plane distance. This value must be greater than zero. 11987 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11988 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11989 * @param dest 11990 * will hold the result 11991 * @return dest 11992 */ 11993 public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, ref Matrix4d dest) { 11994 return perspectiveLH(fovy, aspect, zNear, zFar, false, dest); 11995 } 11996 11997 /** 11998 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11999 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 12000 * <p> 12001 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 12002 * then the new matrix will be <code>M * P</code>. So when transforming a 12003 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 12004 * the perspective projection will be applied first! 12005 * <p> 12006 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12007 * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}. 12008 * 12009 * @see #setPerspectiveLH(double, double, double, double) 12010 * 12011 * @param fovy 12012 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12013 * @param aspect 12014 * the aspect ratio (i.e. width / height; must be greater than zero) 12015 * @param zNear 12016 * near clipping plane distance. This value must be greater than zero. 12017 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12018 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12019 * @param zFar 12020 * far clipping plane distance. This value must be greater than zero. 12021 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12022 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12023 * @return this 12024 */ 12025 ref public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar) return { 12026 perspectiveLH(fovy, aspect, zNear, zFar, this); 12027 return this; 12028 } 12029 12030 /** 12031 * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system 12032 * using the given NDC z range of <code>[-1..+1]</code>. 12033 * <p> 12034 * In order to apply the perspective projection transformation to an existing transformation, 12035 * use {@link #perspectiveLH(double, double, double, double, bool) perspectiveLH()}. 12036 * 12037 * @see #perspectiveLH(double, double, double, double, bool) 12038 * 12039 * @param fovy 12040 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12041 * @param aspect 12042 * the aspect ratio (i.e. width / height; must be greater than zero) 12043 * @param zNear 12044 * near clipping plane distance. This value must be greater than zero. 12045 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12046 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12047 * @param zFar 12048 * far clipping plane distance. This value must be greater than zero. 12049 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12050 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12051 * @param zZeroToOne 12052 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12053 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12054 * @return this 12055 */ 12056 ref public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 12057 double h = Math.tan(fovy * 0.5); 12058 _m00(1.0 / (h * aspect)). 12059 _m01(0.0). 12060 _m02(0.0). 12061 _m03(0.0). 12062 _m10(0.0). 12063 _m11(1.0 / h). 12064 _m12(0.0). 12065 _m13(0.0). 12066 _m20(0.0). 12067 _m21(0.0); 12068 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12069 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12070 if (farInf) { 12071 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12072 double e = 1E-6; 12073 _m22(1.0 - e). 12074 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12075 } else if (nearInf) { 12076 double e = 1E-6; 12077 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12078 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12079 } else { 12080 _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)). 12081 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12082 } 12083 _m23(1.0). 12084 _m30(0.0). 12085 _m31(0.0). 12086 _m33(0.0). 12087 properties = PROPERTY_PERSPECTIVE; 12088 return this; 12089 } 12090 12091 /** 12092 * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system 12093 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12094 * <p> 12095 * In order to apply the perspective projection transformation to an existing transformation, 12096 * use {@link #perspectiveLH(double, double, double, double) perspectiveLH()}. 12097 * 12098 * @see #perspectiveLH(double, double, double, double) 12099 * 12100 * @param fovy 12101 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12102 * @param aspect 12103 * the aspect ratio (i.e. width / height; must be greater than zero) 12104 * @param zNear 12105 * near clipping plane distance. This value must be greater than zero. 12106 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12107 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12108 * @param zFar 12109 * far clipping plane distance. This value must be greater than zero. 12110 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12111 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12112 * @return this 12113 */ 12114 ref public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar) return { 12115 return setPerspectiveLH(fovy, aspect, zNear, zFar, false); 12116 } 12117 12118 /** 12119 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12120 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 12121 * <p> 12122 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12123 * then the new matrix will be <code>M * F</code>. So when transforming a 12124 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12125 * the frustum transformation will be applied first! 12126 * <p> 12127 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12128 * use {@link #setFrustum(double, double, double, double, double, double, bool) setFrustum()}. 12129 * <p> 12130 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12131 * 12132 * @see #setFrustum(double, double, double, double, double, double, bool) 12133 * 12134 * @param left 12135 * the distance along the x-axis to the left frustum edge 12136 * @param right 12137 * the distance along the x-axis to the right frustum edge 12138 * @param bottom 12139 * the distance along the y-axis to the bottom frustum edge 12140 * @param top 12141 * the distance along the y-axis to the top frustum edge 12142 * @param zNear 12143 * near clipping plane distance. This value must be greater than zero. 12144 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12145 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12146 * @param zFar 12147 * far clipping plane distance. This value must be greater than zero. 12148 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12149 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12150 * @param zZeroToOne 12151 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12152 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12153 * @param dest 12154 * will hold the result 12155 * @return dest 12156 */ 12157 public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12158 if ((properties & PROPERTY_IDENTITY) != 0) 12159 return dest.setFrustum(left, right, bottom, top, zNear, zFar, zZeroToOne); 12160 return frustumGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 12161 } 12162 private Matrix4d frustumGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12163 // calculate right matrix elements 12164 double rm00 = (zNear + zNear) / (right - left); 12165 double rm11 = (zNear + zNear) / (top - bottom); 12166 double rm20 = (right + left) / (right - left); 12167 double rm21 = (top + bottom) / (top - bottom); 12168 double rm22; 12169 double rm32; 12170 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12171 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12172 if (farInf) { 12173 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12174 double e = 1E-6; 12175 rm22 = e - 1.0; 12176 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 12177 } else if (nearInf) { 12178 double e = 1E-6; 12179 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 12180 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 12181 } else { 12182 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 12183 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 12184 } 12185 // perform optimized matrix multiplication 12186 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30; 12187 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31; 12188 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32; 12189 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33; 12190 dest._m00(m00 * rm00) 12191 ._m01(m01 * rm00) 12192 ._m02(m02 * rm00) 12193 ._m03(m03 * rm00) 12194 ._m10(m10 * rm11) 12195 ._m11(m11 * rm11) 12196 ._m12(m12 * rm11) 12197 ._m13(m13 * rm11) 12198 ._m30(m20 * rm32) 12199 ._m31(m21 * rm32) 12200 ._m32(m22 * rm32) 12201 ._m33(m23 * rm32) 12202 ._m20(nm20) 12203 ._m21(nm21) 12204 ._m22(nm22) 12205 ._m23(nm23) 12206 ._properties(0); 12207 return dest; 12208 } 12209 12210 /** 12211 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12212 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12213 * <p> 12214 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12215 * then the new matrix will be <code>M * F</code>. So when transforming a 12216 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12217 * the frustum transformation will be applied first! 12218 * <p> 12219 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12220 * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}. 12221 * <p> 12222 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12223 * 12224 * @see #setFrustum(double, double, double, double, double, double) 12225 * 12226 * @param left 12227 * the distance along the x-axis to the left frustum edge 12228 * @param right 12229 * the distance along the x-axis to the right frustum edge 12230 * @param bottom 12231 * the distance along the y-axis to the bottom frustum edge 12232 * @param top 12233 * the distance along the y-axis to the top frustum edge 12234 * @param zNear 12235 * near clipping plane distance. This value must be greater than zero. 12236 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12237 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12238 * @param zFar 12239 * far clipping plane distance. This value must be greater than zero. 12240 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12241 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12242 * @param dest 12243 * will hold the result 12244 * @return dest 12245 */ 12246 public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 12247 return frustum(left, right, bottom, top, zNear, zFar, false, dest); 12248 } 12249 12250 /** 12251 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12252 * using the given NDC z range to this matrix. 12253 * <p> 12254 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12255 * then the new matrix will be <code>M * F</code>. So when transforming a 12256 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12257 * the frustum transformation will be applied first! 12258 * <p> 12259 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12260 * use {@link #setFrustum(double, double, double, double, double, double, bool) setFrustum()}. 12261 * <p> 12262 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12263 * 12264 * @see #setFrustum(double, double, double, double, double, double, bool) 12265 * 12266 * @param left 12267 * the distance along the x-axis to the left frustum edge 12268 * @param right 12269 * the distance along the x-axis to the right frustum edge 12270 * @param bottom 12271 * the distance along the y-axis to the bottom frustum edge 12272 * @param top 12273 * the distance along the y-axis to the top frustum edge 12274 * @param zNear 12275 * near clipping plane distance. This value must be greater than zero. 12276 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12277 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12278 * @param zFar 12279 * far clipping plane distance. This value must be greater than zero. 12280 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12281 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12282 * @param zZeroToOne 12283 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12284 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12285 * @return this 12286 */ 12287 ref public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12288 frustum(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 12289 return this; 12290 } 12291 12292 /** 12293 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12294 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 12295 * <p> 12296 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12297 * then the new matrix will be <code>M * F</code>. So when transforming a 12298 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12299 * the frustum transformation will be applied first! 12300 * <p> 12301 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12302 * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}. 12303 * <p> 12304 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12305 * 12306 * @see #setFrustum(double, double, double, double, double, double) 12307 * 12308 * @param left 12309 * the distance along the x-axis to the left frustum edge 12310 * @param right 12311 * the distance along the x-axis to the right frustum edge 12312 * @param bottom 12313 * the distance along the y-axis to the bottom frustum edge 12314 * @param top 12315 * the distance along the y-axis to the top frustum edge 12316 * @param zNear 12317 * near clipping plane distance. This value must be greater than zero. 12318 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12319 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12320 * @param zFar 12321 * far clipping plane distance. This value must be greater than zero. 12322 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12323 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12324 * @return this 12325 */ 12326 ref public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar) return { 12327 frustum(left, right, bottom, top, zNear, zFar, this); 12328 return this; 12329 } 12330 12331 /** 12332 * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12333 * using the given NDC z range. 12334 * <p> 12335 * In order to apply the perspective frustum transformation to an existing transformation, 12336 * use {@link #frustum(double, double, double, double, double, double, bool) frustum()}. 12337 * <p> 12338 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12339 * 12340 * @see #frustum(double, double, double, double, double, double, bool) 12341 * 12342 * @param left 12343 * the distance along the x-axis to the left frustum edge 12344 * @param right 12345 * the distance along the x-axis to the right frustum edge 12346 * @param bottom 12347 * the distance along the y-axis to the bottom frustum edge 12348 * @param top 12349 * the distance along the y-axis to the top frustum edge 12350 * @param zNear 12351 * near clipping plane distance. This value must be greater than zero. 12352 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12353 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12354 * @param zFar 12355 * far clipping plane distance. This value must be greater than zero. 12356 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12357 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12358 * @param zZeroToOne 12359 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12360 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12361 * @return this 12362 */ 12363 ref public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12364 if ((properties & PROPERTY_IDENTITY) == 0) 12365 _identity(); 12366 _m00((zNear + zNear) / (right - left)). 12367 _m11((zNear + zNear) / (top - bottom)). 12368 _m20((right + left) / (right - left)). 12369 _m21((top + bottom) / (top - bottom)); 12370 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12371 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12372 if (farInf) { 12373 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12374 double e = 1E-6; 12375 _m22(e - 1.0). 12376 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12377 } else if (nearInf) { 12378 double e = 1E-6; 12379 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12380 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12381 } else { 12382 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 12383 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12384 } 12385 _m23(-1.0). 12386 _m33(0.0). 12387 properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0; 12388 return this; 12389 } 12390 12391 /** 12392 * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12393 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12394 * <p> 12395 * In order to apply the perspective frustum transformation to an existing transformation, 12396 * use {@link #frustum(double, double, double, double, double, double) frustum()}. 12397 * <p> 12398 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12399 * 12400 * @see #frustum(double, double, double, double, double, double) 12401 * 12402 * @param left 12403 * the distance along the x-axis to the left frustum edge 12404 * @param right 12405 * the distance along the x-axis to the right frustum edge 12406 * @param bottom 12407 * the distance along the y-axis to the bottom frustum edge 12408 * @param top 12409 * the distance along the y-axis to the top frustum edge 12410 * @param zNear 12411 * near clipping plane distance. This value must be greater than zero. 12412 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12413 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12414 * @param zFar 12415 * far clipping plane distance. This value must be greater than zero. 12416 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12417 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12418 * @return this 12419 */ 12420 ref public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar) return { 12421 return setFrustum(left, right, bottom, top, zNear, zFar, false); 12422 } 12423 12424 /** 12425 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12426 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 12427 * <p> 12428 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12429 * then the new matrix will be <code>M * F</code>. So when transforming a 12430 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12431 * the frustum transformation will be applied first! 12432 * <p> 12433 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12434 * use {@link #setFrustumLH(double, double, double, double, double, double, bool) setFrustumLH()}. 12435 * <p> 12436 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12437 * 12438 * @see #setFrustumLH(double, double, double, double, double, double, bool) 12439 * 12440 * @param left 12441 * the distance along the x-axis to the left frustum edge 12442 * @param right 12443 * the distance along the x-axis to the right frustum edge 12444 * @param bottom 12445 * the distance along the y-axis to the bottom frustum edge 12446 * @param top 12447 * the distance along the y-axis to the top frustum edge 12448 * @param zNear 12449 * near clipping plane distance. This value must be greater than zero. 12450 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12451 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12452 * @param zFar 12453 * far clipping plane distance. This value must be greater than zero. 12454 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12455 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12456 * @param zZeroToOne 12457 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12458 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12459 * @param dest 12460 * will hold the result 12461 * @return dest 12462 */ 12463 public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12464 if ((properties & PROPERTY_IDENTITY) != 0) 12465 return dest.setFrustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne); 12466 return frustumLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 12467 } 12468 private Matrix4d frustumLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12469 // calculate right matrix elements 12470 double rm00 = (zNear + zNear) / (right - left); 12471 double rm11 = (zNear + zNear) / (top - bottom); 12472 double rm20 = (right + left) / (right - left); 12473 double rm21 = (top + bottom) / (top - bottom); 12474 double rm22; 12475 double rm32; 12476 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12477 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12478 if (farInf) { 12479 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12480 double e = 1E-6; 12481 rm22 = 1.0 - e; 12482 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 12483 } else if (nearInf) { 12484 double e = 1E-6; 12485 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 12486 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 12487 } else { 12488 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear); 12489 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 12490 } 12491 // perform optimized matrix multiplication 12492 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30; 12493 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31; 12494 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32; 12495 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33; 12496 dest._m00(m00 * rm00) 12497 ._m01(m01 * rm00) 12498 ._m02(m02 * rm00) 12499 ._m03(m03 * rm00) 12500 ._m10(m10 * rm11) 12501 ._m11(m11 * rm11) 12502 ._m12(m12 * rm11) 12503 ._m13(m13 * rm11) 12504 ._m30(m20 * rm32) 12505 ._m31(m21 * rm32) 12506 ._m32(m22 * rm32) 12507 ._m33(m23 * rm32) 12508 ._m20(nm20) 12509 ._m21(nm21) 12510 ._m22(nm22) 12511 ._m23(nm23) 12512 ._properties(0); 12513 return dest; 12514 } 12515 12516 /** 12517 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12518 * using the given NDC z range to this matrix. 12519 * <p> 12520 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12521 * then the new matrix will be <code>M * F</code>. So when transforming a 12522 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12523 * the frustum transformation will be applied first! 12524 * <p> 12525 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12526 * use {@link #setFrustumLH(double, double, double, double, double, double, bool) setFrustumLH()}. 12527 * <p> 12528 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12529 * 12530 * @see #setFrustumLH(double, double, double, double, double, double, bool) 12531 * 12532 * @param left 12533 * the distance along the x-axis to the left frustum edge 12534 * @param right 12535 * the distance along the x-axis to the right frustum edge 12536 * @param bottom 12537 * the distance along the y-axis to the bottom frustum edge 12538 * @param top 12539 * the distance along the y-axis to the top frustum edge 12540 * @param zNear 12541 * near clipping plane distance. This value must be greater than zero. 12542 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12543 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12544 * @param zFar 12545 * far clipping plane distance. This value must be greater than zero. 12546 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12547 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12548 * @param zZeroToOne 12549 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12550 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12551 * @return this 12552 */ 12553 ref public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12554 frustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 12555 return this; 12556 } 12557 12558 /** 12559 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12560 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12561 * <p> 12562 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12563 * then the new matrix will be <code>M * F</code>. So when transforming a 12564 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12565 * the frustum transformation will be applied first! 12566 * <p> 12567 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12568 * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}. 12569 * <p> 12570 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12571 * 12572 * @see #setFrustumLH(double, double, double, double, double, double) 12573 * 12574 * @param left 12575 * the distance along the x-axis to the left frustum edge 12576 * @param right 12577 * the distance along the x-axis to the right frustum edge 12578 * @param bottom 12579 * the distance along the y-axis to the bottom frustum edge 12580 * @param top 12581 * the distance along the y-axis to the top frustum edge 12582 * @param zNear 12583 * near clipping plane distance. This value must be greater than zero. 12584 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12585 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12586 * @param zFar 12587 * far clipping plane distance. This value must be greater than zero. 12588 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12589 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12590 * @param dest 12591 * will hold the result 12592 * @return dest 12593 */ 12594 public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 12595 return frustumLH(left, right, bottom, top, zNear, zFar, false, dest); 12596 } 12597 12598 /** 12599 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12600 * using the given NDC z range to this matrix. 12601 * <p> 12602 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12603 * then the new matrix will be <code>M * F</code>. So when transforming a 12604 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12605 * the frustum transformation will be applied first! 12606 * <p> 12607 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12608 * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}. 12609 * <p> 12610 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12611 * 12612 * @see #setFrustumLH(double, double, double, double, double, double) 12613 * 12614 * @param left 12615 * the distance along the x-axis to the left frustum edge 12616 * @param right 12617 * the distance along the x-axis to the right frustum edge 12618 * @param bottom 12619 * the distance along the y-axis to the bottom frustum edge 12620 * @param top 12621 * the distance along the y-axis to the top frustum edge 12622 * @param zNear 12623 * near clipping plane distance. This value must be greater than zero. 12624 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12625 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12626 * @param zFar 12627 * far clipping plane distance. This value must be greater than zero. 12628 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12629 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12630 * @return this 12631 */ 12632 ref public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 12633 frustumLH(left, right, bottom, top, zNear, zFar, this); 12634 return this; 12635 } 12636 12637 /** 12638 * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12639 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12640 * <p> 12641 * In order to apply the perspective frustum transformation to an existing transformation, 12642 * use {@link #frustumLH(double, double, double, double, double, double, bool) frustumLH()}. 12643 * <p> 12644 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12645 * 12646 * @see #frustumLH(double, double, double, double, double, double, bool) 12647 * 12648 * @param left 12649 * the distance along the x-axis to the left frustum edge 12650 * @param right 12651 * the distance along the x-axis to the right frustum edge 12652 * @param bottom 12653 * the distance along the y-axis to the bottom frustum edge 12654 * @param top 12655 * the distance along the y-axis to the top frustum edge 12656 * @param zNear 12657 * near clipping plane distance. This value must be greater than zero. 12658 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12659 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12660 * @param zFar 12661 * far clipping plane distance. This value must be greater than zero. 12662 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12663 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12664 * @param zZeroToOne 12665 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12666 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12667 * @return this 12668 */ 12669 ref public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12670 if ((properties & PROPERTY_IDENTITY) == 0) 12671 _identity(); 12672 _m00((zNear + zNear) / (right - left)). 12673 _m11((zNear + zNear) / (top - bottom)). 12674 _m20((right + left) / (right - left)). 12675 _m21((top + bottom) / (top - bottom)); 12676 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12677 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12678 if (farInf) { 12679 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12680 double e = 1E-6; 12681 _m22(1.0 - e). 12682 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12683 } else if (nearInf) { 12684 double e = 1E-6; 12685 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12686 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12687 } else { 12688 _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)). 12689 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12690 } 12691 _m23(1.0). 12692 _m33(0.0). 12693 properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0; 12694 return this; 12695 } 12696 12697 /** 12698 * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12699 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12700 * <p> 12701 * In order to apply the perspective frustum transformation to an existing transformation, 12702 * use {@link #frustumLH(double, double, double, double, double, double) frustumLH()}. 12703 * <p> 12704 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12705 * 12706 * @see #frustumLH(double, double, double, double, double, double) 12707 * 12708 * @param left 12709 * the distance along the x-axis to the left frustum edge 12710 * @param right 12711 * the distance along the x-axis to the right frustum edge 12712 * @param bottom 12713 * the distance along the y-axis to the bottom frustum edge 12714 * @param top 12715 * the distance along the y-axis to the top frustum edge 12716 * @param zNear 12717 * near clipping plane distance. This value must be greater than zero. 12718 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12719 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12720 * @param zFar 12721 * far clipping plane distance. This value must be greater than zero. 12722 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12723 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12724 * @return this 12725 */ 12726 ref public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 12727 return setFrustumLH(left, right, bottom, top, zNear, zFar, false); 12728 } 12729 12730 /** 12731 * Set this matrix to represent a perspective projection equivalent to the given intrinsic camera calibration parameters. 12732 * The resulting matrix will be suited for a right-handed coordinate system using OpenGL's NDC z range of <code>[-1..+1]</code>. 12733 * <p> 12734 * See: <a href="https://en.wikipedia.org/wiki/Camera_resectioning#Intrinsic_parameters">https://en.wikipedia.org/</a> 12735 * <p> 12736 * Reference: <a href="http://ksimek.github.io/2013/06/03/calibrated_cameras_in_opengl/">http://ksimek.github.io/</a> 12737 * 12738 * @param alphaX 12739 * specifies the focal length and scale along the X axis 12740 * @param alphaY 12741 * specifies the focal length and scale along the Y axis 12742 * @param gamma 12743 * the skew coefficient between the X and Y axis (may be <code>0</code>) 12744 * @param u0 12745 * the X coordinate of the principal point in image/sensor units 12746 * @param v0 12747 * the Y coordinate of the principal point in image/sensor units 12748 * @param imgWidth 12749 * the width of the sensor/image image/sensor units 12750 * @param imgHeight 12751 * the height of the sensor/image image/sensor units 12752 * @param near 12753 * the distance to the near plane 12754 * @param far 12755 * the distance to the far plane 12756 * @return this 12757 */ 12758 ref public Matrix4d setFromIntrinsic(double alphaX, double alphaY, double gamma, double u0, double v0, int imgWidth, int imgHeight, double near, double far) return { 12759 double l00 = 2.0 / imgWidth; 12760 double l11 = 2.0 / imgHeight; 12761 double l22 = 2.0 / (near - far); 12762 setm00(l00 * alphaX); 12763 setm01(0.0); 12764 setm02(0.0); 12765 setm03(0.0); 12766 setm10(l00 * gamma); 12767 setm11(l11 * alphaY); 12768 setm12(0.0); 12769 setm13(0.0); 12770 setm20(l00 * u0 - 1.0); 12771 setm21(l11 * v0 - 1.0); 12772 setm22(l22 * -(near + far) + (far + near) / (near - far)); 12773 setm23(-1.0); 12774 setm30(0.0); 12775 setm31(0.0); 12776 setm32(l22 * -near * far); 12777 setm33(0.0); 12778 this.properties = PROPERTY_PERSPECTIVE; 12779 return this; 12780 } 12781 12782 public Vector4d frustumPlane(int plane, ref Vector4d dest) { 12783 switch (plane) { 12784 case PLANE_NX: 12785 dest.set(m03 + m00, m13 + m10, m23 + m20, m33 + m30).normalize3(); 12786 break; 12787 case PLANE_PX: 12788 dest.set(m03 - m00, m13 - m10, m23 - m20, m33 - m30).normalize3(); 12789 break; 12790 case PLANE_NY: 12791 dest.set(m03 + m01, m13 + m11, m23 + m21, m33 + m31).normalize3(); 12792 break; 12793 case PLANE_PY: 12794 dest.set(m03 - m01, m13 - m11, m23 - m21, m33 - m31).normalize3(); 12795 break; 12796 case PLANE_NZ: 12797 dest.set(m03 + m02, m13 + m12, m23 + m22, m33 + m32).normalize3(); 12798 break; 12799 case PLANE_PZ: 12800 dest.set(m03 - m02, m13 - m12, m23 - m22, m33 - m32).normalize3(); 12801 break; 12802 default: 12803 // do nothing 12804 } 12805 return dest; 12806 } 12807 12808 public Vector3d frustumCorner(int corner, ref Vector3d dest) { 12809 double d1, d2, d3; 12810 double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z; 12811 switch (corner) { 12812 case CORNER_NXNYNZ: // left, bottom, near 12813 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12814 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12815 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12816 break; 12817 case CORNER_PXNYNZ: // right, bottom, near 12818 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12819 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12820 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12821 break; 12822 case CORNER_PXPYNZ: // right, top, near 12823 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12824 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12825 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12826 break; 12827 case CORNER_NXPYNZ: // left, top, near 12828 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12829 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12830 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12831 break; 12832 case CORNER_PXNYPZ: // right, bottom, far 12833 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12834 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12835 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12836 break; 12837 case CORNER_NXNYPZ: // left, bottom, far 12838 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12839 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12840 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12841 break; 12842 case CORNER_NXPYPZ: // left, top, far 12843 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12844 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12845 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12846 break; 12847 case CORNER_PXPYPZ: // right, top, far 12848 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12849 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12850 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12851 break; 12852 default: 12853 // do nothing 12854 } 12855 double c23x, c23y, c23z; 12856 c23x = n2y * n3z - n2z * n3y; 12857 c23y = n2z * n3x - n2x * n3z; 12858 c23z = n2x * n3y - n2y * n3x; 12859 double c31x, c31y, c31z; 12860 c31x = n3y * n1z - n3z * n1y; 12861 c31y = n3z * n1x - n3x * n1z; 12862 c31z = n3x * n1y - n3y * n1x; 12863 double c12x, c12y, c12z; 12864 c12x = n1y * n2z - n1z * n2y; 12865 c12y = n1z * n2x - n1x * n2z; 12866 c12z = n1x * n2y - n1y * n2x; 12867 double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z); 12868 dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot; 12869 dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot; 12870 dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot; 12871 return dest; 12872 } 12873 12874 public Vector3d perspectiveOrigin(ref Vector3d dest) { 12875 /* 12876 * Simply compute the intersection point of the left, right and top frustum plane. 12877 */ 12878 double d1, d2, d3; 12879 double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z; 12880 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12881 n2x = m03 - m00; n2y = m13 - m10; n2z = m23 - m20; d2 = m33 - m30; // right 12882 n3x = m03 - m01; n3y = m13 - m11; n3z = m23 - m21; d3 = m33 - m31; // top 12883 double c23x, c23y, c23z; 12884 c23x = n2y * n3z - n2z * n3y; 12885 c23y = n2z * n3x - n2x * n3z; 12886 c23z = n2x * n3y - n2y * n3x; 12887 double c31x, c31y, c31z; 12888 c31x = n3y * n1z - n3z * n1y; 12889 c31y = n3z * n1x - n3x * n1z; 12890 c31z = n3x * n1y - n3y * n1x; 12891 double c12x, c12y, c12z; 12892 c12x = n1y * n2z - n1z * n2y; 12893 c12y = n1z * n2x - n1x * n2z; 12894 c12z = n1x * n2y - n1y * n2x; 12895 double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z); 12896 dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot; 12897 dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot; 12898 dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot; 12899 return dest; 12900 } 12901 12902 public Vector3d perspectiveInvOrigin(ref Vector3d dest) { 12903 double invW = 1.0 / m23; 12904 dest.x = m20 * invW; 12905 dest.y = m21 * invW; 12906 dest.z = m22 * invW; 12907 return dest; 12908 } 12909 12910 public double perspectiveFov() { 12911 /* 12912 * Compute the angle between the bottom and top frustum plane normals. 12913 */ 12914 double n1x, n1y, n1z, n2x, n2y, n2z; 12915 n1x = m03 + m01; n1y = m13 + m11; n1z = m23 + m21; // bottom 12916 n2x = m01 - m03; n2y = m11 - m13; n2z = m21 - m23; // top 12917 double n1len = Math.sqrt(n1x * n1x + n1y * n1y + n1z * n1z); 12918 double n2len = Math.sqrt(n2x * n2x + n2y * n2y + n2z * n2z); 12919 return Math.acos((n1x * n2x + n1y * n2y + n1z * n2z) / (n1len * n2len)); 12920 } 12921 12922 public double perspectiveNear() { 12923 return m32 / (m23 + m22); 12924 } 12925 12926 public double perspectiveFar() { 12927 return m32 / (m22 - m23); 12928 } 12929 12930 public Vector3d frustumRayDir(double x, double y, ref Vector3d dest) { 12931 /* 12932 * This method works by first obtaining the frustum plane normals, 12933 * then building the cross product to obtain the corner rays, 12934 * and finally bilinearly interpolating to obtain the desired direction. 12935 * The code below uses a condense form of doing all this making use 12936 * of some mathematical identities to simplify the overall expression. 12937 */ 12938 double a = m10 * m23, b = m13 * m21, c = m10 * m21, d = m11 * m23, e = m13 * m20, f = m11 * m20; 12939 double g = m03 * m20, h = m01 * m23, i = m01 * m20, j = m03 * m21, k = m00 * m23, l = m00 * m21; 12940 double m = m00 * m13, n = m03 * m11, o = m00 * m11, p = m01 * m13, q = m03 * m10, r = m01 * m10; 12941 double m1x, m1y, m1z; 12942 m1x = (d + e + f - a - b - c) * (1.0 - y) + (a - b - c + d - e + f) * y; 12943 m1y = (j + k + l - g - h - i) * (1.0 - y) + (g - h - i + j - k + l) * y; 12944 m1z = (p + q + r - m - n - o) * (1.0 - y) + (m - n - o + p - q + r) * y; 12945 double m2x, m2y, m2z; 12946 m2x = (b - c - d + e + f - a) * (1.0 - y) + (a + b - c - d - e + f) * y; 12947 m2y = (h - i - j + k + l - g) * (1.0 - y) + (g + h - i - j - k + l) * y; 12948 m2z = (n - o - p + q + r - m) * (1.0 - y) + (m + n - o - p - q + r) * y; 12949 dest.x = m1x * (1.0 - x) + m2x * x; 12950 dest.y = m1y * (1.0 - x) + m2y * x; 12951 dest.z = m1z * (1.0 - x) + m2z * x; 12952 return dest.normalize(dest); 12953 } 12954 12955 public Vector3d positiveZ(ref Vector3d dir) { 12956 if ((properties & PROPERTY_ORTHONORMAL) != 0) 12957 return normalizedPositiveZ(dir); 12958 return positiveZGeneric(dir); 12959 } 12960 private Vector3d positiveZGeneric(ref Vector3d dir) { 12961 return dir.set(m10 * m21 - m11 * m20, m20 * m01 - m21 * m00, m00 * m11 - m01 * m10).normalize(); 12962 } 12963 12964 public Vector3d normalizedPositiveZ(ref Vector3d dir) { 12965 return dir.set(m02, m12, m22); 12966 } 12967 12968 public Vector3d positiveX(ref Vector3d dir) { 12969 if ((properties & PROPERTY_ORTHONORMAL) != 0) 12970 return normalizedPositiveX(dir); 12971 return positiveXGeneric(dir); 12972 } 12973 private Vector3d positiveXGeneric(ref Vector3d dir) { 12974 return dir.set(m11 * m22 - m12 * m21, m02 * m21 - m01 * m22, m01 * m12 - m02 * m11).normalize(); 12975 } 12976 12977 public Vector3d normalizedPositiveX(ref Vector3d dir) { 12978 return dir.set(m00, m10, m20); 12979 } 12980 12981 public Vector3d positiveY(ref Vector3d dir) { 12982 if ((properties & PROPERTY_ORTHONORMAL) != 0) 12983 return normalizedPositiveY(dir); 12984 return positiveYGeneric(dir); 12985 } 12986 private Vector3d positiveYGeneric(ref Vector3d dir) { 12987 return dir.set(m12 * m20 - m10 * m22, m00 * m22 - m02 * m20, m02 * m10 - m00 * m12).normalize(); 12988 } 12989 12990 public Vector3d normalizedPositiveY(ref Vector3d dir) { 12991 return dir.set(m01, m11, m21); 12992 } 12993 12994 public Vector3d originAffine(ref Vector3d dest) { 12995 double a = m00 * m11 - m01 * m10; 12996 double b = m00 * m12 - m02 * m10; 12997 double d = m01 * m12 - m02 * m11; 12998 double g = m20 * m31 - m21 * m30; 12999 double h = m20 * m32 - m22 * m30; 13000 double j = m21 * m32 - m22 * m31; 13001 dest.x = -m10 * j + m11 * h - m12 * g; 13002 dest.y = m00 * j - m01 * h + m02 * g; 13003 dest.z = -m30 * d + m31 * b - m32 * a; 13004 return dest; 13005 } 13006 13007 public Vector3d origin(ref Vector3d dest) { 13008 if ((properties & PROPERTY_AFFINE) != 0) 13009 return originAffine(dest); 13010 return originGeneric(dest); 13011 } 13012 private Vector3d originGeneric(ref Vector3d dest) { 13013 double a = m00 * m11 - m01 * m10; 13014 double b = m00 * m12 - m02 * m10; 13015 double c = m00 * m13 - m03 * m10; 13016 double d = m01 * m12 - m02 * m11; 13017 double e = m01 * m13 - m03 * m11; 13018 double f = m02 * m13 - m03 * m12; 13019 double g = m20 * m31 - m21 * m30; 13020 double h = m20 * m32 - m22 * m30; 13021 double i = m20 * m33 - m23 * m30; 13022 double j = m21 * m32 - m22 * m31; 13023 double k = m21 * m33 - m23 * m31; 13024 double l = m22 * m33 - m23 * m32; 13025 double det = a * l - b * k + c * j + d * i - e * h + f * g; 13026 double invDet = 1.0 / det; 13027 double nm30 = (-m10 * j + m11 * h - m12 * g) * invDet; 13028 double nm31 = ( m00 * j - m01 * h + m02 * g) * invDet; 13029 double nm32 = (-m30 * d + m31 * b - m32 * a) * invDet; 13030 double nm33 = det / ( m20 * d - m21 * b + m22 * a); 13031 double x = nm30 * nm33; 13032 double y = nm31 * nm33; 13033 double z = nm32 * nm33; 13034 return dest.set(x, y, z); 13035 } 13036 13037 /** 13038 * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation 13039 * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>light</code>. 13040 * <p> 13041 * 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. 13042 * <p> 13043 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13044 * then the new matrix will be <code>M * S</code>. So when transforming a 13045 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13046 * shadow projection will be applied first! 13047 * <p> 13048 * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a> 13049 * 13050 * @param light 13051 * the light's vector 13052 * @param a 13053 * the x factor in the plane equation 13054 * @param b 13055 * the y factor in the plane equation 13056 * @param c 13057 * the z factor in the plane equation 13058 * @param d 13059 * the constant in the plane equation 13060 * @return this 13061 */ 13062 ref public Matrix4d shadow(ref Vector4d light, double a, double b, double c, double d) return { 13063 shadow(light.x, light.y, light.z, light.w, a, b, c, d, this); 13064 return this; 13065 } 13066 13067 public Matrix4d shadow(ref Vector4d light, double a, double b, double c, double d, ref Matrix4d dest) { 13068 return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest); 13069 } 13070 13071 /** 13072 * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation 13073 * <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>. 13074 * <p> 13075 * 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. 13076 * <p> 13077 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13078 * then the new matrix will be <code>M * S</code>. So when transforming a 13079 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13080 * shadow projection will be applied first! 13081 * <p> 13082 * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a> 13083 * 13084 * @param lightX 13085 * the x-component of the light's vector 13086 * @param lightY 13087 * the y-component of the light's vector 13088 * @param lightZ 13089 * the z-component of the light's vector 13090 * @param lightW 13091 * the w-component of the light's vector 13092 * @param a 13093 * the x factor in the plane equation 13094 * @param b 13095 * the y factor in the plane equation 13096 * @param c 13097 * the z factor in the plane equation 13098 * @param d 13099 * the constant in the plane equation 13100 * @return this 13101 */ 13102 ref public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) return { 13103 shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this); 13104 return this; 13105 } 13106 13107 public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, ref Matrix4d dest) { 13108 // normalize plane 13109 double invPlaneLen = Math.invsqrt(a*a + b*b + c*c); 13110 double an = a * invPlaneLen; 13111 double bn = b * invPlaneLen; 13112 double cn = c * invPlaneLen; 13113 double dn = d * invPlaneLen; 13114 13115 double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW; 13116 13117 // compute right matrix elements 13118 double rm00 = dot - an * lightX; 13119 double rm01 = -an * lightY; 13120 double rm02 = -an * lightZ; 13121 double rm03 = -an * lightW; 13122 double rm10 = -bn * lightX; 13123 double rm11 = dot - bn * lightY; 13124 double rm12 = -bn * lightZ; 13125 double rm13 = -bn * lightW; 13126 double rm20 = -cn * lightX; 13127 double rm21 = -cn * lightY; 13128 double rm22 = dot - cn * lightZ; 13129 double rm23 = -cn * lightW; 13130 double rm30 = -dn * lightX; 13131 double rm31 = -dn * lightY; 13132 double rm32 = -dn * lightZ; 13133 double rm33 = dot - dn * lightW; 13134 13135 // matrix multiplication 13136 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03; 13137 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03; 13138 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03; 13139 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02 + m33 * rm03; 13140 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13; 13141 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13; 13142 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13; 13143 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12 + m33 * rm13; 13144 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23; 13145 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23; 13146 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23; 13147 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33 * rm23; 13148 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33) 13149 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33) 13150 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33) 13151 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33 * rm33) 13152 ._m00(nm00) 13153 ._m01(nm01) 13154 ._m02(nm02) 13155 ._m03(nm03) 13156 ._m10(nm10) 13157 ._m11(nm11) 13158 ._m12(nm12) 13159 ._m13(nm13) 13160 ._m20(nm20) 13161 ._m21(nm21) 13162 ._m22(nm22) 13163 ._m23(nm23) 13164 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 13165 return dest; 13166 } 13167 13168 public Matrix4d shadow(ref Vector4d light, Matrix4d planeTransform, ref Matrix4d dest) { 13169 // compute plane equation by transforming (y = 0) 13170 double a = planeTransform.m10; 13171 double b = planeTransform.m11; 13172 double c = planeTransform.m12; 13173 double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32; 13174 return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest); 13175 } 13176 13177 /** 13178 * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation 13179 * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>light</code>. 13180 * <p> 13181 * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>. 13182 * <p> 13183 * 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. 13184 * <p> 13185 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13186 * then the new matrix will be <code>M * S</code>. So when transforming a 13187 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13188 * shadow projection will be applied first! 13189 * 13190 * @param light 13191 * the light's vector 13192 * @param planeTransform 13193 * the transformation to transform the implied plane <code>y = 0</code> before applying the projection 13194 * @return this 13195 */ 13196 ref public Matrix4d shadow(ref Vector4d light, Matrix4d planeTransform) return { 13197 shadow(light, planeTransform, this); 13198 return this; 13199 } 13200 13201 public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4d planeTransform, ref Matrix4d dest) { 13202 // compute plane equation by transforming (y = 0) 13203 double a = planeTransform.m10; 13204 double b = planeTransform.m11; 13205 double c = planeTransform.m12; 13206 double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32; 13207 return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest); 13208 } 13209 13210 /** 13211 * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation 13212 * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>. 13213 * <p> 13214 * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>. 13215 * <p> 13216 * 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. 13217 * <p> 13218 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13219 * then the new matrix will be <code>M * S</code>. So when transforming a 13220 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13221 * shadow projection will be applied first! 13222 * 13223 * @param lightX 13224 * the x-component of the light vector 13225 * @param lightY 13226 * the y-component of the light vector 13227 * @param lightZ 13228 * the z-component of the light vector 13229 * @param lightW 13230 * the w-component of the light vector 13231 * @param planeTransform 13232 * the transformation to transform the implied plane <code>y = 0</code> before applying the projection 13233 * @return this 13234 */ 13235 ref public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4d planeTransform) return { 13236 shadow(lightX, lightY, lightZ, lightW, planeTransform, this); 13237 return this; 13238 } 13239 13240 /** 13241 * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13242 * a target position at <code>targetPos</code> while constraining a cylindrical rotation around the given <code>up</code> vector. 13243 * <p> 13244 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13245 * its position <code>objPos</code>. 13246 * 13247 * @param objPos 13248 * the position of the object to rotate towards <code>targetPos</code> 13249 * @param targetPos 13250 * the position of the target (for example the camera) towards which to rotate the object 13251 * @param up 13252 * the rotation axis (must be {@link Vector3d#normalize() normalized}) 13253 * @return this 13254 */ 13255 ref public Matrix4d billboardCylindrical(ref Vector3d objPos, Vector3d targetPos, Vector3d up) return { 13256 double dirX = targetPos.x - objPos.x; 13257 double dirY = targetPos.y - objPos.y; 13258 double dirZ = targetPos.z - objPos.z; 13259 // left = up x dir 13260 double leftX = up.y * dirZ - up.z * dirY; 13261 double leftY = up.z * dirX - up.x * dirZ; 13262 double leftZ = up.x * dirY - up.y * dirX; 13263 // normalize left 13264 double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 13265 leftX *= invLeftLen; 13266 leftY *= invLeftLen; 13267 leftZ *= invLeftLen; 13268 // recompute dir by constraining rotation around 'up' 13269 // dir = left x up 13270 dirX = leftY * up.z - leftZ * up.y; 13271 dirY = leftZ * up.x - leftX * up.z; 13272 dirZ = leftX * up.y - leftY * up.x; 13273 // normalize dir 13274 double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 13275 dirX *= invDirLen; 13276 dirY *= invDirLen; 13277 dirZ *= invDirLen; 13278 // set matrix elements 13279 _m00(leftX). 13280 _m01(leftY). 13281 _m02(leftZ). 13282 _m03(0.0). 13283 _m10(up.x). 13284 _m11(up.y). 13285 _m12(up.z). 13286 _m13(0.0). 13287 _m20(dirX). 13288 _m21(dirY). 13289 _m22(dirZ). 13290 _m23(0.0). 13291 _m30(objPos.x). 13292 _m31(objPos.y). 13293 _m32(objPos.z). 13294 _m33(1.0). 13295 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13296 return this; 13297 } 13298 13299 /** 13300 * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13301 * a target position at <code>targetPos</code>. 13302 * <p> 13303 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13304 * its position <code>objPos</code>. 13305 * <p> 13306 * If preserving an <i>up</i> vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained 13307 * using {@link #billboardSpherical(ref Vector3d, Vector3d)}. 13308 * 13309 * @see #billboardSpherical(ref Vector3d, Vector3d) 13310 * 13311 * @param objPos 13312 * the position of the object to rotate towards <code>targetPos</code> 13313 * @param targetPos 13314 * the position of the target (for example the camera) towards which to rotate the object 13315 * @param up 13316 * the up axis used to orient the object 13317 * @return this 13318 */ 13319 ref public Matrix4d billboardSpherical(ref Vector3d objPos, Vector3d targetPos, Vector3d up) return { 13320 double dirX = targetPos.x - objPos.x; 13321 double dirY = targetPos.y - objPos.y; 13322 double dirZ = targetPos.z - objPos.z; 13323 // normalize dir 13324 double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 13325 dirX *= invDirLen; 13326 dirY *= invDirLen; 13327 dirZ *= invDirLen; 13328 // left = up x dir 13329 double leftX = up.y * dirZ - up.z * dirY; 13330 double leftY = up.z * dirX - up.x * dirZ; 13331 double leftZ = up.x * dirY - up.y * dirX; 13332 // normalize left 13333 double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 13334 leftX *= invLeftLen; 13335 leftY *= invLeftLen; 13336 leftZ *= invLeftLen; 13337 // up = dir x left 13338 double upX = dirY * leftZ - dirZ * leftY; 13339 double upY = dirZ * leftX - dirX * leftZ; 13340 double upZ = dirX * leftY - dirY * leftX; 13341 // set matrix elements 13342 _m00(leftX). 13343 _m01(leftY). 13344 _m02(leftZ). 13345 _m03(0.0). 13346 _m10(upX). 13347 _m11(upY). 13348 _m12(upZ). 13349 _m13(0.0). 13350 _m20(dirX). 13351 _m21(dirY). 13352 _m22(dirZ). 13353 _m23(0.0). 13354 _m30(objPos.x). 13355 _m31(objPos.y). 13356 _m32(objPos.z). 13357 _m33(1.0). 13358 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13359 return this; 13360 } 13361 13362 /** 13363 * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13364 * a target position at <code>targetPos</code> using a shortest arc rotation by not preserving any <i>up</i> vector of the object. 13365 * <p> 13366 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13367 * its position <code>objPos</code>. 13368 * <p> 13369 * In order to specify an <i>up</i> vector which needs to be maintained when rotating the +Z axis of the object, 13370 * use {@link #billboardSpherical(ref Vector3d, Vector3d, Vector3d)}. 13371 * 13372 * @see #billboardSpherical(ref Vector3d, Vector3d, Vector3d) 13373 * 13374 * @param objPos 13375 * the position of the object to rotate towards <code>targetPos</code> 13376 * @param targetPos 13377 * the position of the target (for example the camera) towards which to rotate the object 13378 * @return this 13379 */ 13380 ref public Matrix4d billboardSpherical(ref Vector3d objPos, Vector3d targetPos) return { 13381 double toDirX = targetPos.x - objPos.x; 13382 double toDirY = targetPos.y - objPos.y; 13383 double toDirZ = targetPos.z - objPos.z; 13384 double x = -toDirY; 13385 double y = toDirX; 13386 double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ; 13387 double invNorm = Math.invsqrt(x * x + y * y + w * w); 13388 x *= invNorm; 13389 y *= invNorm; 13390 w *= invNorm; 13391 double q00 = (x + x) * x; 13392 double q11 = (y + y) * y; 13393 double q01 = (x + x) * y; 13394 double q03 = (x + x) * w; 13395 double q13 = (y + y) * w; 13396 _m00(1.0 - q11). 13397 _m01(q01). 13398 _m02(-q13). 13399 _m03(0.0). 13400 _m10(q01). 13401 _m11(1.0 - q00). 13402 _m12(q03). 13403 _m13(0.0). 13404 _m20(q13). 13405 _m21(-q03). 13406 _m22(1.0 - q11 - q00). 13407 _m23(0.0). 13408 _m30(objPos.x). 13409 _m31(objPos.y). 13410 _m32(objPos.z). 13411 _m33(1.0). 13412 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13413 return this; 13414 } 13415 13416 public int hashCode() { 13417 immutable int prime = 31; 13418 int result = 1; 13419 long temp; 13420 temp = Math.doubleToLongBits(m00); 13421 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13422 temp = Math.doubleToLongBits(m01); 13423 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13424 temp = Math.doubleToLongBits(m02); 13425 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13426 temp = Math.doubleToLongBits(m03); 13427 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13428 temp = Math.doubleToLongBits(m10); 13429 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13430 temp = Math.doubleToLongBits(m11); 13431 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13432 temp = Math.doubleToLongBits(m12); 13433 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13434 temp = Math.doubleToLongBits(m13); 13435 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13436 temp = Math.doubleToLongBits(m20); 13437 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13438 temp = Math.doubleToLongBits(m21); 13439 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13440 temp = Math.doubleToLongBits(m22); 13441 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13442 temp = Math.doubleToLongBits(m23); 13443 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13444 temp = Math.doubleToLongBits(m30); 13445 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13446 temp = Math.doubleToLongBits(m31); 13447 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13448 temp = Math.doubleToLongBits(m32); 13449 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13450 temp = Math.doubleToLongBits(m33); 13451 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13452 return result; 13453 } 13454 13455 public bool equals(Matrix4d m, double delta) { 13456 if (this == m) 13457 return true; 13458 if (!Math.equals(m00, m.m00, delta)) 13459 return false; 13460 if (!Math.equals(m01, m.m01, delta)) 13461 return false; 13462 if (!Math.equals(m02, m.m02, delta)) 13463 return false; 13464 if (!Math.equals(m03, m.m03, delta)) 13465 return false; 13466 if (!Math.equals(m10, m.m10, delta)) 13467 return false; 13468 if (!Math.equals(m11, m.m11, delta)) 13469 return false; 13470 if (!Math.equals(m12, m.m12, delta)) 13471 return false; 13472 if (!Math.equals(m13, m.m13, delta)) 13473 return false; 13474 if (!Math.equals(m20, m.m20, delta)) 13475 return false; 13476 if (!Math.equals(m21, m.m21, delta)) 13477 return false; 13478 if (!Math.equals(m22, m.m22, delta)) 13479 return false; 13480 if (!Math.equals(m23, m.m23, delta)) 13481 return false; 13482 if (!Math.equals(m30, m.m30, delta)) 13483 return false; 13484 if (!Math.equals(m31, m.m31, delta)) 13485 return false; 13486 if (!Math.equals(m32, m.m32, delta)) 13487 return false; 13488 if (!Math.equals(m33, m.m33, delta)) 13489 return false; 13490 return true; 13491 } 13492 13493 public Matrix4d pick(double x, double y, double width, double height, int[] viewport, ref Matrix4d dest) { 13494 double sx = viewport[2] / width; 13495 double sy = viewport[3] / height; 13496 double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width; 13497 double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height; 13498 dest._m30(m00 * tx + m10 * ty + m30) 13499 ._m31(m01 * tx + m11 * ty + m31) 13500 ._m32(m02 * tx + m12 * ty + m32) 13501 ._m33(m03 * tx + m13 * ty + m33) 13502 ._m00(m00 * sx) 13503 ._m01(m01 * sx) 13504 ._m02(m02 * sx) 13505 ._m03(m03 * sx) 13506 ._m10(m10 * sy) 13507 ._m11(m11 * sy) 13508 ._m12(m12 * sy) 13509 ._m13(m13 * sy) 13510 ._properties(0); 13511 return dest; 13512 } 13513 13514 /** 13515 * Apply a picking transformation to this matrix using the given window coordinates <code>(x, y)</code> as the pick center 13516 * and the given <code>(width, height)</code> as the size of the picking region in window coordinates. 13517 * 13518 * @param x 13519 * the x coordinate of the picking region center in window coordinates 13520 * @param y 13521 * the y coordinate of the picking region center in window coordinates 13522 * @param width 13523 * the width of the picking region in window coordinates 13524 * @param height 13525 * the height of the picking region in window coordinates 13526 * @param viewport 13527 * the viewport described by <code>[x, y, width, height]</code> 13528 * @return this 13529 */ 13530 ref public Matrix4d pick(double x, double y, double width, double height, int[] viewport) return { 13531 pick(x, y, width, height, viewport, this); 13532 return this; 13533 } 13534 13535 public bool isAffine() { 13536 return m03 == 0.0 && m13 == 0.0 && m23 == 0.0 && m33 == 1.0; 13537 } 13538 13539 /** 13540 * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix. 13541 * 13542 * @param other 13543 * the other matrix to exchange the values with 13544 * @return this 13545 */ 13546 ref public Matrix4d swap(ref Matrix4d other) return { 13547 double tmp; 13548 tmp = m00; m00 = other.m00; other.m00 = tmp; 13549 tmp = m01; m01 = other.m01; other.m01 = tmp; 13550 tmp = m02; m02 = other.m02; other.m02 = tmp; 13551 tmp = m03; m03 = other.m03; other.m03 = tmp; 13552 tmp = m10; m10 = other.m10; other.m10 = tmp; 13553 tmp = m11; m11 = other.m11; other.m11 = tmp; 13554 tmp = m12; m12 = other.m12; other.m12 = tmp; 13555 tmp = m13; m13 = other.m13; other.m13 = tmp; 13556 tmp = m20; m20 = other.m20; other.m20 = tmp; 13557 tmp = m21; m21 = other.m21; other.m21 = tmp; 13558 tmp = m22; m22 = other.m22; other.m22 = tmp; 13559 tmp = m23; m23 = other.m23; other.m23 = tmp; 13560 tmp = m30; m30 = other.m30; other.m30 = tmp; 13561 tmp = m31; m31 = other.m31; other.m31 = tmp; 13562 tmp = m32; m32 = other.m32; other.m32 = tmp; 13563 tmp = m33; m33 = other.m33; other.m33 = tmp; 13564 int props = properties; 13565 this.properties = other.properties; 13566 other.properties = props; 13567 return this; 13568 } 13569 13570 public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, ref Matrix4d dest) { 13571 double m30 = m20 * -radius + this.m30; 13572 double m31 = m21 * -radius + this.m31; 13573 double m32 = m22 * -radius + this.m32; 13574 double m33 = m23 * -radius + this.m33; 13575 double sin = Math.sin(angleX); 13576 double cos = Math.cosFromSin(sin, angleX); 13577 double nm10 = m10 * cos + m20 * sin; 13578 double nm11 = m11 * cos + m21 * sin; 13579 double nm12 = m12 * cos + m22 * sin; 13580 double nm13 = m13 * cos + m23 * sin; 13581 double m20 = this.m20 * cos - m10 * sin; 13582 double m21 = this.m21 * cos - m11 * sin; 13583 double m22 = this.m22 * cos - m12 * sin; 13584 double m23 = this.m23 * cos - m13 * sin; 13585 sin = Math.sin(angleY); 13586 cos = Math.cosFromSin(sin, angleY); 13587 double nm00 = m00 * cos - m20 * sin; 13588 double nm01 = m01 * cos - m21 * sin; 13589 double nm02 = m02 * cos - m22 * sin; 13590 double nm03 = m03 * cos - m23 * sin; 13591 double nm20 = m00 * sin + m20 * cos; 13592 double nm21 = m01 * sin + m21 * cos; 13593 double nm22 = m02 * sin + m22 * cos; 13594 double nm23 = m03 * sin + m23 * cos; 13595 dest._m30(-nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30) 13596 ._m31(-nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31) 13597 ._m32(-nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32) 13598 ._m33(-nm03 * centerX - nm13 * centerY - nm23 * centerZ + m33) 13599 ._m20(nm20) 13600 ._m21(nm21) 13601 ._m22(nm22) 13602 ._m23(nm23) 13603 ._m10(nm10) 13604 ._m11(nm11) 13605 ._m12(nm12) 13606 ._m13(nm13) 13607 ._m00(nm00) 13608 ._m01(nm01) 13609 ._m02(nm02) 13610 ._m03(nm03) 13611 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 13612 return dest; 13613 } 13614 13615 public Matrix4d arcball(double radius, Vector3d center, double angleX, double angleY, ref Matrix4d dest) { 13616 return arcball(radius, center.x, center.y, center.z, angleX, angleY, dest); 13617 } 13618 13619 /** 13620 * Apply an arcball view transformation to this matrix with the given <code>radius</code> and center <code>(centerX, centerY, centerZ)</code> 13621 * position of the arcball and the specified X and Y rotation angles. 13622 * <p> 13623 * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)</code> 13624 * 13625 * @param radius 13626 * the arcball radius 13627 * @param centerX 13628 * the x coordinate of the center position of the arcball 13629 * @param centerY 13630 * the y coordinate of the center position of the arcball 13631 * @param centerZ 13632 * the z coordinate of the center position of the arcball 13633 * @param angleX 13634 * the rotation angle around the X axis in radians 13635 * @param angleY 13636 * the rotation angle around the Y axis in radians 13637 * @return this 13638 */ 13639 ref public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) return { 13640 arcball(radius, centerX, centerY, centerZ, angleX, angleY, this); 13641 return this; 13642 } 13643 13644 /** 13645 * Apply an arcball view transformation to this matrix with the given <code>radius</code> and <code>center</code> 13646 * position of the arcball and the specified X and Y rotation angles. 13647 * <p> 13648 * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)</code> 13649 * 13650 * @param radius 13651 * the arcball radius 13652 * @param center 13653 * the center position of the arcball 13654 * @param angleX 13655 * the rotation angle around the X axis in radians 13656 * @param angleY 13657 * the rotation angle around the Y axis in radians 13658 * @return this 13659 */ 13660 ref public Matrix4d arcball(double radius, Vector3d center, double angleX, double angleY) return { 13661 arcball(radius, center.x, center.y, center.z, angleX, angleY, this); 13662 return this; 13663 } 13664 13665 /** 13666 * Compute the axis-aligned bounding box of the frustum described by <code>this</code> matrix and store the minimum corner 13667 * coordinates in the given <code>min</code> and the maximum corner coordinates in the given <code>max</code> vector. 13668 * <p> 13669 * The matrix <code>this</code> is assumed to be the {@link #invert() inverse} of the origial view-projection matrix 13670 * for which to compute the axis-aligned bounding box in world-space. 13671 * <p> 13672 * The axis-aligned bounding box of the unit frustum is <code>(-1, -1, -1)</code>, <code>(1, 1, 1)</code>. 13673 * 13674 * @param min 13675 * will hold the minimum corner coordinates of the axis-aligned bounding box 13676 * @param max 13677 * will hold the maximum corner coordinates of the axis-aligned bounding box 13678 * @return this 13679 */ 13680 ref public Matrix4d frustumAabb(ref Vector3d min, Vector3d max) return { 13681 double minX = double.infinity; 13682 double minY = double.infinity; 13683 double minZ = double.infinity; 13684 double maxX = -double.infinity; 13685 double maxY = -double.infinity; 13686 double maxZ = -double.infinity; 13687 for (int t = 0; t < 8; t++) { 13688 double x = ((t & 1) << 1) - 1.0; 13689 double y = (((t >>> 1) & 1) << 1) - 1.0; 13690 double z = (((t >>> 2) & 1) << 1) - 1.0; 13691 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 13692 double nx = (m00 * x + m10 * y + m20 * z + m30) * invW; 13693 double ny = (m01 * x + m11 * y + m21 * z + m31) * invW; 13694 double nz = (m02 * x + m12 * y + m22 * z + m32) * invW; 13695 minX = minX < nx ? minX : nx; 13696 minY = minY < ny ? minY : ny; 13697 minZ = minZ < nz ? minZ : nz; 13698 maxX = maxX > nx ? maxX : nx; 13699 maxY = maxY > ny ? maxY : ny; 13700 maxZ = maxZ > nz ? maxZ : nz; 13701 } 13702 min.x = minX; 13703 min.y = minY; 13704 min.z = minZ; 13705 max.x = maxX; 13706 max.y = maxY; 13707 max.z = maxZ; 13708 return this; 13709 } 13710 13711 public Matrix4d projectedGridRange(Matrix4d projector, double sLower, double sUpper, ref Matrix4d dest) { 13712 // Compute intersection with frustum edges and plane 13713 double minX = double.infinity, minY = double.infinity; 13714 double maxX = -double.infinity, maxY = -double.infinity; 13715 bool intersection = false; 13716 for (int t = 0; t < 3 * 4; t++) { 13717 double c0X, c0Y, c0Z; 13718 double c1X, c1Y, c1Z; 13719 if (t < 4) { 13720 // all x edges 13721 c0X = -1; c1X = +1; 13722 c0Y = c1Y = ((t & 1) << 1) - 1.0; 13723 c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0; 13724 } else if (t < 8) { 13725 // all y edges 13726 c0Y = -1; c1Y = +1; 13727 c0X = c1X = ((t & 1) << 1) - 1.0; 13728 c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0; 13729 } else { 13730 // all z edges 13731 c0Z = -1; c1Z = +1; 13732 c0X = c1X = ((t & 1) << 1) - 1.0; 13733 c0Y = c1Y = (((t >>> 1) & 1) << 1) - 1.0; 13734 } 13735 // unproject corners 13736 double invW = 1.0 / (m03 * c0X + m13 * c0Y + m23 * c0Z + m33); 13737 double p0x = (m00 * c0X + m10 * c0Y + m20 * c0Z + m30) * invW; 13738 double p0y = (m01 * c0X + m11 * c0Y + m21 * c0Z + m31) * invW; 13739 double p0z = (m02 * c0X + m12 * c0Y + m22 * c0Z + m32) * invW; 13740 invW = 1.0 / (m03 * c1X + m13 * c1Y + m23 * c1Z + m33); 13741 double p1x = (m00 * c1X + m10 * c1Y + m20 * c1Z + m30) * invW; 13742 double p1y = (m01 * c1X + m11 * c1Y + m21 * c1Z + m31) * invW; 13743 double p1z = (m02 * c1X + m12 * c1Y + m22 * c1Z + m32) * invW; 13744 double dirX = p1x - p0x; 13745 double dirY = p1y - p0y; 13746 double dirZ = p1z - p0z; 13747 double invDenom = 1.0 / dirY; 13748 // test for intersection 13749 for (int s = 0; s < 2; s++) { 13750 double isectT = -(p0y + (s == 0 ? sLower : sUpper)) * invDenom; 13751 if (isectT >= 0.0 && isectT <= 1.0) { 13752 intersection = true; 13753 // project with projector matrix 13754 double ix = p0x + isectT * dirX; 13755 double iz = p0z + isectT * dirZ; 13756 invW = 1.0 / (projector.m03 * ix + projector.m23 * iz + projector.m33); 13757 double px = (projector.m00 * ix + projector.m20 * iz + projector.m30) * invW; 13758 double py = (projector.m01 * ix + projector.m21 * iz + projector.m31) * invW; 13759 minX = minX < px ? minX : px; 13760 minY = minY < py ? minY : py; 13761 maxX = maxX > px ? maxX : px; 13762 maxY = maxY > py ? maxY : py; 13763 } 13764 } 13765 } 13766 if (!intersection) 13767 return dest; // <- projected grid is not visible 13768 dest.set(maxX - minX, 0, 0, 0, 0, maxY - minY, 0, 0, 0, 0, 1, 0, minX, minY, 0, 1) 13769 ._properties(PROPERTY_AFFINE); 13770 return dest; 13771 } 13772 13773 public Matrix4d perspectiveFrustumSlice(double near, double far, ref Matrix4d dest) { 13774 double invOldNear = (m23 + m22) / m32; 13775 double invNearFar = 1.0 / (near - far); 13776 dest._m00(m00 * invOldNear * near) 13777 ._m01(m01) 13778 ._m02(m02) 13779 ._m03(m03) 13780 ._m10(m10) 13781 ._m11(m11 * invOldNear * near) 13782 ._m12(m12) 13783 ._m13(m13) 13784 ._m20(m20) 13785 ._m21(m21) 13786 ._m22((far + near) * invNearFar) 13787 ._m23(m23) 13788 ._m30(m30) 13789 ._m31(m31) 13790 ._m32((far + far) * near * invNearFar) 13791 ._m33(m33) 13792 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 13793 return dest; 13794 } 13795 13796 public Matrix4d orthoCrop(Matrix4d view, ref Matrix4d dest) { 13797 // determine min/max world z and min/max orthographically view-projected x/y 13798 double minX = double.infinity, maxX = -double.infinity; 13799 double minY = double.infinity, maxY = -double.infinity; 13800 double minZ = double.infinity, maxZ = -double.infinity; 13801 for (int t = 0; t < 8; t++) { 13802 double x = ((t & 1) << 1) - 1.0; 13803 double y = (((t >>> 1) & 1) << 1) - 1.0; 13804 double z = (((t >>> 2) & 1) << 1) - 1.0; 13805 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 13806 double wx = (m00 * x + m10 * y + m20 * z + m30) * invW; 13807 double wy = (m01 * x + m11 * y + m21 * z + m31) * invW; 13808 double wz = (m02 * x + m12 * y + m22 * z + m32) * invW; 13809 invW = 1.0 / (view.m03 * wx + view.m13 * wy + view.m23 * wz + view.m33); 13810 double vx = view.m00 * wx + view.m10 * wy + view.m20 * wz + view.m30; 13811 double vy = view.m01 * wx + view.m11 * wy + view.m21 * wz + view.m31; 13812 double vz = (view.m02 * wx + view.m12 * wy + view.m22 * wz + view.m32) * invW; 13813 minX = minX < vx ? minX : vx; 13814 maxX = maxX > vx ? maxX : vx; 13815 minY = minY < vy ? minY : vy; 13816 maxY = maxY > vy ? maxY : vy; 13817 minZ = minZ < vz ? minZ : vz; 13818 maxZ = maxZ > vz ? maxZ : vz; 13819 } 13820 // build crop projection matrix to fit 'this' frustum into view 13821 return dest.setOrtho(minX, maxX, minY, maxY, -maxZ, -minZ); 13822 } 13823 13824 /** 13825 * Set <code>this</code> matrix to a perspective transformation that maps the trapezoid spanned by the four corner coordinates 13826 * <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>. 13827 * <p> 13828 * The corner coordinates are given in counter-clockwise order starting from the <i>left</i> corner on the smaller parallel side of the trapezoid 13829 * seen when looking at the trapezoid oriented with its shorter parallel edge at the bottom and its longer parallel edge at the top. 13830 * <p> 13831 * Reference: <a href="http://www.comp.nus.edu.sg/~tants/tsm/TSM_recipe.html">Trapezoidal Shadow Maps (TSM) - Recipe</a> 13832 * 13833 * @param p0x 13834 * the x coordinate of the left corner at the shorter edge of the trapezoid 13835 * @param p0y 13836 * the y coordinate of the left corner at the shorter edge of the trapezoid 13837 * @param p1x 13838 * the x coordinate of the right corner at the shorter edge of the trapezoid 13839 * @param p1y 13840 * the y coordinate of the right corner at the shorter edge of the trapezoid 13841 * @param p2x 13842 * the x coordinate of the right corner at the longer edge of the trapezoid 13843 * @param p2y 13844 * the y coordinate of the right corner at the longer edge of the trapezoid 13845 * @param p3x 13846 * the x coordinate of the left corner at the longer edge of the trapezoid 13847 * @param p3y 13848 * the y coordinate of the left corner at the longer edge of the trapezoid 13849 * @return this 13850 */ 13851 ref public Matrix4d trapezoidCrop(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y, double p3x, double p3y) return { 13852 double aX = p1y - p0y, aY = p0x - p1x; 13853 double nm00 = aY; 13854 double nm10 = -aX; 13855 double nm30 = aX * p0y - aY * p0x; 13856 double nm01 = aX; 13857 double nm11 = aY; 13858 double nm31 = -(aX * p0x + aY * p0y); 13859 double c3x = nm00 * p3x + nm10 * p3y + nm30; 13860 double c3y = nm01 * p3x + nm11 * p3y + nm31; 13861 double s = -c3x / c3y; 13862 nm00 += s * nm01; 13863 nm10 += s * nm11; 13864 nm30 += s * nm31; 13865 double d1x = nm00 * p1x + nm10 * p1y + nm30; 13866 double d2x = nm00 * p2x + nm10 * p2y + nm30; 13867 double d = d1x * c3y / (d2x - d1x); 13868 nm31 += d; 13869 double sx = 2.0 / d2x; 13870 double sy = 1.0 / (c3y + d); 13871 double u = (sy + sy) * d / (1.0 - sy * d); 13872 double m03 = nm01 * sy; 13873 double m13 = nm11 * sy; 13874 double m33 = nm31 * sy; 13875 nm01 = (u + 1.0) * m03; 13876 nm11 = (u + 1.0) * m13; 13877 nm31 = (u + 1.0) * m33 - u; 13878 nm00 = sx * nm00 - m03; 13879 nm10 = sx * nm10 - m13; 13880 nm30 = sx * nm30 - m33; 13881 set(nm00, nm01, 0, m03, 13882 nm10, nm11, 0, m13, 13883 0, 0, 1, 0, 13884 nm30, nm31, 0, m33); 13885 properties = 0; 13886 return this; 13887 } 13888 13889 ref public Matrix4d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, ref Vector3d outMin, ref Vector3d outMax) return { 13890 double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX; 13891 double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX; 13892 double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY; 13893 double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY; 13894 double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ; 13895 double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ; 13896 double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz; 13897 double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz; 13898 if (xax < xbx) { 13899 xminx = xax; 13900 xmaxx = xbx; 13901 } else { 13902 xminx = xbx; 13903 xmaxx = xax; 13904 } 13905 if (xay < xby) { 13906 xminy = xay; 13907 xmaxy = xby; 13908 } else { 13909 xminy = xby; 13910 xmaxy = xay; 13911 } 13912 if (xaz < xbz) { 13913 xminz = xaz; 13914 xmaxz = xbz; 13915 } else { 13916 xminz = xbz; 13917 xmaxz = xaz; 13918 } 13919 if (yax < ybx) { 13920 yminx = yax; 13921 ymaxx = ybx; 13922 } else { 13923 yminx = ybx; 13924 ymaxx = yax; 13925 } 13926 if (yay < yby) { 13927 yminy = yay; 13928 ymaxy = yby; 13929 } else { 13930 yminy = yby; 13931 ymaxy = yay; 13932 } 13933 if (yaz < ybz) { 13934 yminz = yaz; 13935 ymaxz = ybz; 13936 } else { 13937 yminz = ybz; 13938 ymaxz = yaz; 13939 } 13940 if (zax < zbx) { 13941 zminx = zax; 13942 zmaxx = zbx; 13943 } else { 13944 zminx = zbx; 13945 zmaxx = zax; 13946 } 13947 if (zay < zby) { 13948 zminy = zay; 13949 zmaxy = zby; 13950 } else { 13951 zminy = zby; 13952 zmaxy = zay; 13953 } 13954 if (zaz < zbz) { 13955 zminz = zaz; 13956 zmaxz = zbz; 13957 } else { 13958 zminz = zbz; 13959 zmaxz = zaz; 13960 } 13961 outMin.x = xminx + yminx + zminx + m30; 13962 outMin.y = xminy + yminy + zminy + m31; 13963 outMin.z = xminz + yminz + zminz + m32; 13964 outMax.x = xmaxx + ymaxx + zmaxx + m30; 13965 outMax.y = xmaxy + ymaxy + zmaxy + m31; 13966 outMax.z = xmaxz + ymaxz + zmaxz + m32; 13967 return this; 13968 } 13969 13970 ref public Matrix4d transformAab(ref Vector3d min, ref Vector3d max, ref Vector3d outMin, ref Vector3d outMax) return { 13971 return transformAab(min.x, min.y, min.z, max.x, max.y, max.z, outMin, outMax); 13972 } 13973 13974 /** 13975 * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code> 13976 * and store the result in <code>this</code>. 13977 * <p> 13978 * 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> 13979 * then the result is <code>other</code>. 13980 * 13981 * @param other 13982 * the other matrix 13983 * @param t 13984 * the interpolation factor between 0.0 and 1.0 13985 * @return this 13986 */ 13987 ref public Matrix4d lerp(Matrix4d other, double t) return { 13988 lerp(other, t, this); 13989 return this; 13990 } 13991 13992 public Matrix4d lerp(Matrix4d other, double t, ref Matrix4d dest) { 13993 dest._m00(Math.fma(other.m00 - m00, t, m00)) 13994 ._m01(Math.fma(other.m01 - m01, t, m01)) 13995 ._m02(Math.fma(other.m02 - m02, t, m02)) 13996 ._m03(Math.fma(other.m03 - m03, t, m03)) 13997 ._m10(Math.fma(other.m10 - m10, t, m10)) 13998 ._m11(Math.fma(other.m11 - m11, t, m11)) 13999 ._m12(Math.fma(other.m12 - m12, t, m12)) 14000 ._m13(Math.fma(other.m13 - m13, t, m13)) 14001 ._m20(Math.fma(other.m20 - m20, t, m20)) 14002 ._m21(Math.fma(other.m21 - m21, t, m21)) 14003 ._m22(Math.fma(other.m22 - m22, t, m22)) 14004 ._m23(Math.fma(other.m23 - m23, t, m23)) 14005 ._m30(Math.fma(other.m30 - m30, t, m30)) 14006 ._m31(Math.fma(other.m31 - m31, t, m31)) 14007 ._m32(Math.fma(other.m32 - m32, t, m32)) 14008 ._m33(Math.fma(other.m33 - m33, t, m33)) 14009 ._properties(properties & other.properties); 14010 return dest; 14011 } 14012 14013 /** 14014 * Apply a model transformation to this matrix for a right-handed coordinate system, 14015 * that aligns the local <code>+Z</code> axis with <code>direction</code> 14016 * and store the result in <code>dest</code>. 14017 * <p> 14018 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14019 * then the new matrix will be <code>M * L</code>. So when transforming a 14020 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14021 * the lookat transformation will be applied first! 14022 * <p> 14023 * In order to set the matrix to a rotation transformation without post-multiplying it, 14024 * use {@link #rotationTowards(ref Vector3d, Vector3d) rotationTowards()}. 14025 * <p> 14026 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine(), dest)</code> 14027 * 14028 * @see #rotateTowards(double, double, double, double, double, double, Matrix4d) 14029 * @see #rotationTowards(ref Vector3d, Vector3d) 14030 * 14031 * @param direction 14032 * the direction to rotate towards 14033 * @param up 14034 * the up vector 14035 * @param dest 14036 * will hold the result 14037 * @return dest 14038 */ 14039 public Matrix4d rotateTowards(ref Vector3d direction, Vector3d up, ref Matrix4d dest) { 14040 return rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, dest); 14041 } 14042 14043 /** 14044 * Apply a model transformation to this matrix for a right-handed coordinate system, 14045 * that aligns the local <code>+Z</code> axis with <code>direction</code>. 14046 * <p> 14047 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14048 * then the new matrix will be <code>M * L</code>. So when transforming a 14049 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14050 * the lookat transformation will be applied first! 14051 * <p> 14052 * In order to set the matrix to a rotation transformation without post-multiplying it, 14053 * use {@link #rotationTowards(ref Vector3d, Vector3d) rotationTowards()}. 14054 * <p> 14055 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine())</code> 14056 * 14057 * @see #rotateTowards(double, double, double, double, double, double) 14058 * @see #rotationTowards(ref Vector3d, Vector3d) 14059 * 14060 * @param direction 14061 * the direction to orient towards 14062 * @param up 14063 * the up vector 14064 * @return this 14065 */ 14066 ref public Matrix4d rotateTowards(ref Vector3d direction, Vector3d up) return { 14067 rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, this); 14068 return this; 14069 } 14070 14071 /** 14072 * Apply a model transformation to this matrix for a right-handed coordinate system, 14073 * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>. 14074 * <p> 14075 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14076 * then the new matrix will be <code>M * L</code>. So when transforming a 14077 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14078 * the lookat transformation will be applied first! 14079 * <p> 14080 * In order to set the matrix to a rotation transformation without post-multiplying it, 14081 * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}. 14082 * <p> 14083 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine())</code> 14084 * 14085 * @see #rotateTowards(ref Vector3d, Vector3d) 14086 * @see #rotationTowards(double, double, double, double, double, double) 14087 * 14088 * @param dirX 14089 * the x-coordinate of the direction to rotate towards 14090 * @param dirY 14091 * the y-coordinate of the direction to rotate towards 14092 * @param dirZ 14093 * the z-coordinate of the direction to rotate towards 14094 * @param upX 14095 * the x-coordinate of the up vector 14096 * @param upY 14097 * the y-coordinate of the up vector 14098 * @param upZ 14099 * the z-coordinate of the up vector 14100 * @return this 14101 */ 14102 ref public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14103 rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this); 14104 return this; 14105 } 14106 14107 /** 14108 * Apply a model transformation to this matrix for a right-handed coordinate system, 14109 * that aligns the local <code>+Z</code> axis with <code>dir</code> 14110 * and store the result in <code>dest</code>. 14111 * <p> 14112 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14113 * then the new matrix will be <code>M * L</code>. So when transforming a 14114 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14115 * the lookat transformation will be applied first! 14116 * <p> 14117 * In order to set the matrix to a rotation transformation without post-multiplying it, 14118 * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}. 14119 * <p> 14120 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)</code> 14121 * 14122 * @see #rotateTowards(ref Vector3d, Vector3d) 14123 * @see #rotationTowards(double, double, double, double, double, double) 14124 * 14125 * @param dirX 14126 * the x-coordinate of the direction to rotate towards 14127 * @param dirY 14128 * the y-coordinate of the direction to rotate towards 14129 * @param dirZ 14130 * the z-coordinate of the direction to rotate towards 14131 * @param upX 14132 * the x-coordinate of the up vector 14133 * @param upY 14134 * the y-coordinate of the up vector 14135 * @param upZ 14136 * the z-coordinate of the up vector 14137 * @param dest 14138 * will hold the result 14139 * @return dest 14140 */ 14141 public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 14142 // Normalize direction 14143 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14144 double ndirX = dirX * invDirLength; 14145 double ndirY = dirY * invDirLength; 14146 double ndirZ = dirZ * invDirLength; 14147 // left = up x direction 14148 double leftX, leftY, leftZ; 14149 leftX = upY * ndirZ - upZ * ndirY; 14150 leftY = upZ * ndirX - upX * ndirZ; 14151 leftZ = upX * ndirY - upY * ndirX; 14152 // normalize left 14153 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14154 leftX *= invLeftLength; 14155 leftY *= invLeftLength; 14156 leftZ *= invLeftLength; 14157 // up = direction x left 14158 double upnX = ndirY * leftZ - ndirZ * leftY; 14159 double upnY = ndirZ * leftX - ndirX * leftZ; 14160 double upnZ = ndirX * leftY - ndirY * leftX; 14161 double rm00 = leftX; 14162 double rm01 = leftY; 14163 double rm02 = leftZ; 14164 double rm10 = upnX; 14165 double rm11 = upnY; 14166 double rm12 = upnZ; 14167 double rm20 = ndirX; 14168 double rm21 = ndirY; 14169 double rm22 = ndirZ; 14170 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 14171 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 14172 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 14173 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 14174 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 14175 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 14176 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 14177 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 14178 dest._m30(m30) 14179 ._m31(m31) 14180 ._m32(m32) 14181 ._m33(m33) 14182 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 14183 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 14184 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 14185 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 14186 ._m00(nm00) 14187 ._m01(nm01) 14188 ._m02(nm02) 14189 ._m03(nm03) 14190 ._m10(nm10) 14191 ._m11(nm11) 14192 ._m12(nm12) 14193 ._m13(nm13) 14194 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 14195 return dest; 14196 } 14197 14198 /** 14199 * Set this matrix to a model transformation for a right-handed coordinate system, 14200 * that aligns the local <code>-z</code> axis with <code>dir</code>. 14201 * <p> 14202 * In order to apply the rotation transformation to a previous existing transformation, 14203 * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}. 14204 * <p> 14205 * This method is equivalent to calling: <code>setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine()</code> 14206 * 14207 * @see #rotationTowards(ref Vector3d, Vector3d) 14208 * @see #rotateTowards(double, double, double, double, double, double) 14209 * 14210 * @param dir 14211 * the direction to orient the local -z axis towards 14212 * @param up 14213 * the up vector 14214 * @return this 14215 */ 14216 ref public Matrix4d rotationTowards(ref Vector3d dir, Vector3d up) return { 14217 return rotationTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z); 14218 } 14219 14220 /** 14221 * Set this matrix to a model transformation for a right-handed coordinate system, 14222 * that aligns the local <code>-z</code> axis with <code>dir</code>. 14223 * <p> 14224 * In order to apply the rotation transformation to a previous existing transformation, 14225 * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}. 14226 * <p> 14227 * This method is equivalent to calling: <code>setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine()</code> 14228 * 14229 * @see #rotateTowards(ref Vector3d, Vector3d) 14230 * @see #rotationTowards(double, double, double, double, double, double) 14231 * 14232 * @param dirX 14233 * the x-coordinate of the direction to rotate towards 14234 * @param dirY 14235 * the y-coordinate of the direction to rotate towards 14236 * @param dirZ 14237 * the z-coordinate of the direction to rotate towards 14238 * @param upX 14239 * the x-coordinate of the up vector 14240 * @param upY 14241 * the y-coordinate of the up vector 14242 * @param upZ 14243 * the z-coordinate of the up vector 14244 * @return this 14245 */ 14246 ref public Matrix4d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14247 // Normalize direction 14248 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14249 double ndirX = dirX * invDirLength; 14250 double ndirY = dirY * invDirLength; 14251 double ndirZ = dirZ * invDirLength; 14252 // left = up x direction 14253 double leftX, leftY, leftZ; 14254 leftX = upY * ndirZ - upZ * ndirY; 14255 leftY = upZ * ndirX - upX * ndirZ; 14256 leftZ = upX * ndirY - upY * ndirX; 14257 // normalize left 14258 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14259 leftX *= invLeftLength; 14260 leftY *= invLeftLength; 14261 leftZ *= invLeftLength; 14262 // up = direction x left 14263 double upnX = ndirY * leftZ - ndirZ * leftY; 14264 double upnY = ndirZ * leftX - ndirX * leftZ; 14265 double upnZ = ndirX * leftY - ndirY * leftX; 14266 if ((properties & PROPERTY_IDENTITY) == 0) 14267 this._identity(); 14268 setm00(leftX); 14269 setm01(leftY); 14270 setm02(leftZ); 14271 setm10(upnX); 14272 setm11(upnY); 14273 setm12(upnZ); 14274 setm20(ndirX); 14275 setm21(ndirY); 14276 setm22(ndirZ); 14277 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 14278 return this; 14279 } 14280 14281 /** 14282 * Set this matrix to a model transformation for a right-handed coordinate system, 14283 * that translates to the given <code>pos</code> and aligns the local <code>-z</code> 14284 * axis with <code>dir</code>. 14285 * <p> 14286 * This method is equivalent to calling: <code>translation(pos).rotateTowards(dir, up)</code> 14287 * 14288 * @see #translation(ref Vector3d) 14289 * @see #rotateTowards(ref Vector3d, Vector3d) 14290 * 14291 * @param pos 14292 * the position to translate to 14293 * @param dir 14294 * the direction to rotate towards 14295 * @param up 14296 * the up vector 14297 * @return this 14298 */ 14299 ref public Matrix4d translationRotateTowards(ref Vector3d pos, Vector3d dir, Vector3d up) return { 14300 return translationRotateTowards(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); 14301 } 14302 14303 /** 14304 * Set this matrix to a model transformation for a right-handed coordinate system, 14305 * that translates to the given <code>(posX, posY, posZ)</code> and aligns the local <code>-z</code> 14306 * axis with <code>(dirX, dirY, dirZ)</code>. 14307 * <p> 14308 * This method is equivalent to calling: <code>translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)</code> 14309 * 14310 * @see #translation(double, double, double) 14311 * @see #rotateTowards(double, double, double, double, double, double) 14312 * 14313 * @param posX 14314 * the x-coordinate of the position to translate to 14315 * @param posY 14316 * the y-coordinate of the position to translate to 14317 * @param posZ 14318 * the z-coordinate of the position to translate to 14319 * @param dirX 14320 * the x-coordinate of the direction to rotate towards 14321 * @param dirY 14322 * the y-coordinate of the direction to rotate towards 14323 * @param dirZ 14324 * the z-coordinate of the direction to rotate towards 14325 * @param upX 14326 * the x-coordinate of the up vector 14327 * @param upY 14328 * the y-coordinate of the up vector 14329 * @param upZ 14330 * the z-coordinate of the up vector 14331 * @return this 14332 */ 14333 ref public Matrix4d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14334 // Normalize direction 14335 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14336 double ndirX = dirX * invDirLength; 14337 double ndirY = dirY * invDirLength; 14338 double ndirZ = dirZ * invDirLength; 14339 // left = up x direction 14340 double leftX, leftY, leftZ; 14341 leftX = upY * ndirZ - upZ * ndirY; 14342 leftY = upZ * ndirX - upX * ndirZ; 14343 leftZ = upX * ndirY - upY * ndirX; 14344 // normalize left 14345 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14346 leftX *= invLeftLength; 14347 leftY *= invLeftLength; 14348 leftZ *= invLeftLength; 14349 // up = direction x left 14350 double upnX = ndirY * leftZ - ndirZ * leftY; 14351 double upnY = ndirZ * leftX - ndirX * leftZ; 14352 double upnZ = ndirX * leftY - ndirY * leftX; 14353 setm00(leftX); 14354 setm01(leftY); 14355 setm02(leftZ); 14356 setm03(0.0); 14357 setm10(upnX); 14358 setm11(upnY); 14359 setm12(upnZ); 14360 setm13(0.0); 14361 setm20(ndirX); 14362 setm21(ndirY); 14363 setm22(ndirZ); 14364 setm23(0.0); 14365 setm30(posX); 14366 setm31(posY); 14367 setm32(posZ); 14368 setm33(1.0); 14369 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 14370 return this; 14371 } 14372 14373 public Vector3d getEulerAnglesZYX(ref Vector3d dest) { 14374 dest.x = Math.atan2(m12, m22); 14375 dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02)); 14376 dest.z = Math.atan2(m01, m00); 14377 return dest; 14378 } 14379 14380 public Vector3d getEulerAnglesXYZ(ref Vector3d dest) { 14381 dest.x = Math.atan2(-m21, m22); 14382 dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20)); 14383 dest.z = Math.atan2(-m10, m00); 14384 return dest; 14385 } 14386 14387 /** 14388 * Compute the extents of the coordinate system before this {@link #isAffine() affine} transformation was applied 14389 * and store the resulting corner coordinates in <code>corner</code> and the span vectors in 14390 * <code>xDir</code>, <code>yDir</code> and <code>zDir</code>. 14391 * <p> 14392 * That means, given the maximum extents of the coordinate system between <code>[-1..+1]</code> in all dimensions, 14393 * this method returns one corner and the length and direction of the three base axis vectors in the coordinate 14394 * system before this transformation is applied, which transforms into the corner coordinates <code>[-1, +1]</code>. 14395 * <p> 14396 * This method is equivalent to computing at least three adjacent corners using {@link #frustumCorner(int, Vector3d)} 14397 * and subtracting them to obtain the length and direction of the span vectors. 14398 * 14399 * @param corner 14400 * will hold one corner of the span (usually the corner {@link Matrix4d#CORNER_NXNYNZ}) 14401 * @param xDir 14402 * will hold the direction and length of the span along the positive X axis 14403 * @param yDir 14404 * will hold the direction and length of the span along the positive Y axis 14405 * @param zDir 14406 * will hold the direction and length of the span along the positive z axis 14407 * @return this 14408 */ 14409 ref public Matrix4d affineSpan(ref Vector3d corner, ref Vector3d xDir, ref Vector3d yDir, ref Vector3d zDir) return { 14410 double a = m10 * m22, b = m10 * m21, c = m10 * m02, d = m10 * m01; 14411 double e = m11 * m22, f = m11 * m20, g = m11 * m02, h = m11 * m00; 14412 double i = m12 * m21, j = m12 * m20, k = m12 * m01, l = m12 * m00; 14413 double m = m20 * m02, n = m20 * m01, o = m21 * m02, p = m21 * m00; 14414 double q = m22 * m01, r = m22 * m00; 14415 double s = 1.0 / (m00 * m11 - m01 * m10) * m22 + (m02 * m10 - m00 * m12) * m21 + (m01 * m12 - m02 * m11) * m20; 14416 double nm00 = (e - i) * s, nm01 = (o - q) * s, nm02 = (k - g) * s; 14417 double nm10 = (j - a) * s, nm11 = (r - m) * s, nm12 = (c - l) * s; 14418 double nm20 = (b - f) * s, nm21 = (n - p) * s, nm22 = (h - d) * s; 14419 corner.x = -nm00 - nm10 - nm20 + (a * m31 - b * m32 + f * m32 - e * m30 + i * m30 - j * m31) * s; 14420 corner.y = -nm01 - nm11 - nm21 + (m * m31 - n * m32 + p * m32 - o * m30 + q * m30 - r * m31) * s; 14421 corner.z = -nm02 - nm12 - nm22 + (g * m30 - k * m30 + l * m31 - c * m31 + d * m32 - h * m32) * s; 14422 xDir.x = 2.0 * nm00; xDir.y = 2.0 * nm01; xDir.z = 2.0 * nm02; 14423 yDir.x = 2.0 * nm10; yDir.y = 2.0 * nm11; yDir.z = 2.0 * nm12; 14424 zDir.x = 2.0 * nm20; zDir.y = 2.0 * nm21; zDir.z = 2.0 * nm22; 14425 return this; 14426 } 14427 14428 public bool testPoint(double x, double y, double z) { 14429 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14430 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14431 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14432 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14433 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14434 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14435 return nxX * x + nxY * y + nxZ * z + nxW >= 0 && pxX * x + pxY * y + pxZ * z + pxW >= 0 && 14436 nyX * x + nyY * y + nyZ * z + nyW >= 0 && pyX * x + pyY * y + pyZ * z + pyW >= 0 && 14437 nzX * x + nzY * y + nzZ * z + nzW >= 0 && pzX * x + pzY * y + pzZ * z + pzW >= 0; 14438 } 14439 14440 public bool testSphere(double x, double y, double z, double r) { 14441 double invl; 14442 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14443 invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ); 14444 nxX *= invl; nxY *= invl; nxZ *= invl; nxW *= invl; 14445 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14446 invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ); 14447 pxX *= invl; pxY *= invl; pxZ *= invl; pxW *= invl; 14448 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14449 invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ); 14450 nyX *= invl; nyY *= invl; nyZ *= invl; nyW *= invl; 14451 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14452 invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ); 14453 pyX *= invl; pyY *= invl; pyZ *= invl; pyW *= invl; 14454 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14455 invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ); 14456 nzX *= invl; nzY *= invl; nzZ *= invl; nzW *= invl; 14457 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14458 invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ); 14459 pzX *= invl; pzY *= invl; pzZ *= invl; pzW *= invl; 14460 return nxX * x + nxY * y + nxZ * z + nxW >= -r && pxX * x + pxY * y + pxZ * z + pxW >= -r && 14461 nyX * x + nyY * y + nyZ * z + nyW >= -r && pyX * x + pyY * y + pyZ * z + pyW >= -r && 14462 nzX * x + nzY * y + nzZ * z + nzW >= -r && pzX * x + pzY * y + pzZ * z + pzW >= -r; 14463 } 14464 14465 public bool testAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { 14466 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14467 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14468 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14469 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14470 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14471 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14472 /* 14473 * This is an implementation of the "2.4 Basic intersection test" of the mentioned site. 14474 * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted. 14475 */ 14476 return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW && 14477 pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW && 14478 nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW && 14479 pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW && 14480 nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW && 14481 pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW; 14482 } 14483 14484 /** 14485 * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and 14486 * <code>b</code>. 14487 * <p> 14488 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix, 14489 * then the new matrix will be <code>M * O</code>. So when transforming a 14490 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 14491 * oblique transformation will be applied first! 14492 * <p> 14493 * The oblique transformation is defined as: 14494 * <pre> 14495 * x' = x + a*z 14496 * y' = y + a*z 14497 * z' = z 14498 * </pre> 14499 * or in matrix form: 14500 * <pre> 14501 * 1 0 a 0 14502 * 0 1 b 0 14503 * 0 0 1 0 14504 * 0 0 0 1 14505 * </pre> 14506 * 14507 * @param a 14508 * the value for the z factor that applies to x 14509 * @param b 14510 * the value for the z factor that applies to y 14511 * @return this 14512 */ 14513 ref public Matrix4d obliqueZ(double a, double b) return { 14514 setm20(m00 * a + m10 * b + m20); 14515 setm21(m01 * a + m11 * b + m21); 14516 setm22(m02 * a + m12 * b + m22); 14517 this.properties &= PROPERTY_AFFINE; 14518 return this; 14519 } 14520 14521 /** 14522 * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and 14523 * <code>b</code> and store the result in <code>dest</code>. 14524 * <p> 14525 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix, 14526 * then the new matrix will be <code>M * O</code>. So when transforming a 14527 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 14528 * oblique transformation will be applied first! 14529 * <p> 14530 * The oblique transformation is defined as: 14531 * <pre> 14532 * x' = x + a*z 14533 * y' = y + a*z 14534 * z' = z 14535 * </pre> 14536 * or in matrix form: 14537 * <pre> 14538 * 1 0 a 0 14539 * 0 1 b 0 14540 * 0 0 1 0 14541 * 0 0 0 1 14542 * </pre> 14543 * 14544 * @param a 14545 * the value for the z factor that applies to x 14546 * @param b 14547 * the value for the z factor that applies to y 14548 * @param dest 14549 * will hold the result 14550 * @return dest 14551 */ 14552 public Matrix4d obliqueZ(double a, double b, ref Matrix4d dest) { 14553 dest._m00(m00) 14554 ._m01(m01) 14555 ._m02(m02) 14556 ._m03(m03) 14557 ._m10(m10) 14558 ._m11(m11) 14559 ._m12(m12) 14560 ._m13(m13) 14561 ._m20(m00 * a + m10 * b + m20) 14562 ._m21(m01 * a + m11 * b + m21) 14563 ._m22(m02 * a + m12 * b + m22) 14564 ._m23(m23) 14565 ._m30(m30) 14566 ._m31(m31) 14567 ._m32(m32) 14568 ._m33(m33) 14569 ._properties(properties & PROPERTY_AFFINE); 14570 return dest; 14571 } 14572 14573 /** 14574 * 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 14575 * and the extents of the near plane rectangle along its local <code>x</code> and <code>y</code> axes, and store the resulting matrices 14576 * in <code>projDest</code> and <code>viewDest</code>. 14577 * <p> 14578 * This method creates a view and perspective projection matrix assuming that there is a pinhole camera at position <code>eye</code> 14579 * projecting the scene onto the near plane defined by the rectangle. 14580 * <p> 14581 * All positions and lengths are in the same (world) unit. 14582 * 14583 * @param eye 14584 * the position of the camera 14585 * @param p 14586 * the bottom left corner of the near plane rectangle (will map to the bottom left corner in window coordinates) 14587 * @param x 14588 * the direction and length of the local "bottom/top" X axis/side of the near plane rectangle 14589 * @param y 14590 * the direction and length of the local "left/right" Y axis/side of the near plane rectangle 14591 * @param nearFarDist 14592 * the distance between the far and near plane (the near plane will be calculated by this method). 14593 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 14594 * If the special value {@link Double#NEGATIVE_INFINITY} is used, the near and far planes will be swapped and 14595 * the near clipping plane will be at positive infinity. 14596 * If a negative value is used (except for {@link Double#NEGATIVE_INFINITY}) the near and far planes will be swapped 14597 * @param zeroToOne 14598 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 14599 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 14600 * @param projDest 14601 * will hold the resulting projection matrix 14602 * @param viewDest 14603 * will hold the resulting view matrix 14604 */ 14605 public static void projViewFromRectangle( 14606 Vector3d eye, Vector3d p, Vector3d x, Vector3d y, double nearFarDist, bool zeroToOne, 14607 ref Matrix4d projDest, ref Matrix4d viewDest) { 14608 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; 14609 double zd = zx * (p.x - eye.x) + zy * (p.y - eye.y) + zz * (p.z - eye.z); 14610 double zs = zd >= 0 ? 1 : -1; zx *= zs; zy *= zs; zz *= zs; zd *= zs; 14611 viewDest.setLookAt(eye.x, eye.y, eye.z, eye.x + zx, eye.y + zy, eye.z + zz, y.x, y.y, y.z); 14612 double px = viewDest.m00 * p.x + viewDest.m10 * p.y + viewDest.m20 * p.z + viewDest.m30; 14613 double py = viewDest.m01 * p.x + viewDest.m11 * p.y + viewDest.m21 * p.z + viewDest.m31; 14614 double tx = viewDest.m00 * x.x + viewDest.m10 * x.y + viewDest.m20 * x.z; 14615 double ty = viewDest.m01 * y.x + viewDest.m11 * y.y + viewDest.m21 * y.z; 14616 double len = Math.sqrt(zx * zx + zy * zy + zz * zz); 14617 double near = zd / len, far; 14618 if (Math.isInfinite(nearFarDist) && nearFarDist < 0.0) { 14619 far = near; 14620 near = double.infinity; 14621 } else if (Math.isInfinite(nearFarDist) && nearFarDist > 0.0) { 14622 far = double.infinity; 14623 } else if (nearFarDist < 0.0) { 14624 far = near; 14625 near = near + nearFarDist; 14626 } else { 14627 far = near + nearFarDist; 14628 } 14629 projDest.setFrustum(px, px + tx, py, py + ty, near, far, zeroToOne); 14630 } 14631 14632 /** 14633 * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(ref Vector3d)}) 14634 * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(ref Vector3d)}) and the 14635 * given vector <code>up</code>. 14636 * <p> 14637 * This effectively ensures that the resulting matrix will be equal to the one obtained from 14638 * {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)} called with the current 14639 * local origin of this matrix (as obtained by {@link #originAffine(ref Vector3d)}), the sum of this position and the 14640 * negated local Z axis as well as the given vector <code>up</code>. 14641 * <p> 14642 * This method must only be called on {@link #isAffine()} matrices. 14643 * 14644 * @param up 14645 * the up vector 14646 * @return this 14647 */ 14648 ref public Matrix4d withLookAtUp(ref Vector3d up) return { 14649 withLookAtUp(up.x, up.y, up.z, this); 14650 return this; 14651 } 14652 14653 public Matrix4d withLookAtUp(ref Vector3d up, ref Matrix4d dest) { 14654 return dest.withLookAtUp(up.x, up.y, up.z); 14655 } 14656 14657 /** 14658 * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(ref Vector3d)}) 14659 * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(ref Vector3d)}) and the 14660 * given vector <code>(upX, upY, upZ)</code>. 14661 * <p> 14662 * This effectively ensures that the resulting matrix will be equal to the one obtained from 14663 * {@link #setLookAt(double, double, double, double, double, double, double, double, double)} called with the current 14664 * local origin of this matrix (as obtained by {@link #originAffine(ref Vector3d)}), the sum of this position and the 14665 * negated local Z axis as well as the given vector <code>(upX, upY, upZ)</code>. 14666 * <p> 14667 * This method must only be called on {@link #isAffine()} matrices. 14668 * 14669 * @param upX 14670 * the x coordinate of the up vector 14671 * @param upY 14672 * the y coordinate of the up vector 14673 * @param upZ 14674 * the z coordinate of the up vector 14675 * @return this 14676 */ 14677 ref public Matrix4d withLookAtUp(double upX, double upY, double upZ) return { 14678 withLookAtUp(upX, upY, upZ, this); 14679 return this; 14680 } 14681 14682 public Matrix4d withLookAtUp(double upX, double upY, double upZ, ref Matrix4d dest) { 14683 double y = (upY * m21 - upZ * m11) * m02 + 14684 (upZ * m01 - upX * m21) * m12 + 14685 (upX * m11 - upY * m01) * m22; 14686 double x = upX * m01 + upY * m11 + upZ * m21; 14687 if ((properties & PROPERTY_ORTHONORMAL) == 0) 14688 x *= Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21); 14689 double invsqrt = Math.invsqrt(y * y + x * x); 14690 double c = x * invsqrt, s = y * invsqrt; 14691 double nm00 = c * m00 - s * m01, nm10 = c * m10 - s * m11, nm20 = c * m20 - s * m21, nm31 = s * m30 + c * m31; 14692 double nm01 = s * m00 + c * m01, nm11 = s * m10 + c * m11, nm21 = s * m20 + c * m21, nm30 = c * m30 - s * m31; 14693 dest._m00(nm00)._m10(nm10)._m20(nm20)._m30(nm30) 14694 ._m01(nm01)._m11(nm11)._m21(nm21)._m31(nm31); 14695 if (dest != this) { 14696 dest 14697 ._m02(m02)._m12(m12)._m22(m22)._m32(m32) 14698 ._m03(m03)._m13(m13)._m23(m23)._m33(m33); 14699 } 14700 dest._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 14701 return dest; 14702 } 14703 14704 /** 14705 * Multiply <code>this</code> by the matrix 14706 * <pre> 14707 * 1 0 0 0 14708 * 0 0 1 0 14709 * 0 1 0 0 14710 * 0 0 0 1 14711 * </pre> 14712 * 14713 * @return this 14714 */ 14715 ref public Matrix4d mapXZY() return { 14716 mapXZY(this); 14717 return this; 14718 } 14719 public Matrix4d mapXZY(ref Matrix4d dest) { 14720 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14721 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)); 14722 } 14723 /** 14724 * Multiply <code>this</code> by the matrix 14725 * <pre> 14726 * 1 0 0 0 14727 * 0 0 -1 0 14728 * 0 1 0 0 14729 * 0 0 0 1 14730 * </pre> 14731 * 14732 * @return this 14733 */ 14734 ref public Matrix4d mapXZnY() return { 14735 mapXZnY(this); 14736 return this; 14737 } 14738 public Matrix4d mapXZnY(ref Matrix4d dest) { 14739 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14740 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)); 14741 } 14742 /** 14743 * Multiply <code>this</code> by the matrix 14744 * <pre> 14745 * 1 0 0 0 14746 * 0 -1 0 0 14747 * 0 0 -1 0 14748 * 0 0 0 1 14749 * </pre> 14750 * 14751 * @return this 14752 */ 14753 ref public Matrix4d mapXnYnZ() return { 14754 mapXnYnZ(this); 14755 return this; 14756 } 14757 public Matrix4d mapXnYnZ(ref Matrix4d dest) { 14758 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)); 14759 } 14760 /** 14761 * Multiply <code>this</code> by the matrix 14762 * <pre> 14763 * 1 0 0 0 14764 * 0 0 1 0 14765 * 0 -1 0 0 14766 * 0 0 0 1 14767 * </pre> 14768 * 14769 * @return this 14770 */ 14771 ref public Matrix4d mapXnZY() return { 14772 mapXnZY(this); 14773 return this; 14774 } 14775 public Matrix4d mapXnZY(ref Matrix4d dest) { 14776 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14777 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)); 14778 } 14779 /** 14780 * Multiply <code>this</code> by the matrix 14781 * <pre> 14782 * 1 0 0 0 14783 * 0 0 -1 0 14784 * 0 -1 0 0 14785 * 0 0 0 1 14786 * </pre> 14787 * 14788 * @return this 14789 */ 14790 ref public Matrix4d mapXnZnY() return { 14791 mapXnZnY(this); 14792 return this; 14793 } 14794 public Matrix4d mapXnZnY(ref Matrix4d dest) { 14795 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14796 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)); 14797 } 14798 /** 14799 * Multiply <code>this</code> by the matrix 14800 * <pre> 14801 * 0 1 0 0 14802 * 1 0 0 0 14803 * 0 0 1 0 14804 * 0 0 0 1 14805 * </pre> 14806 * 14807 * @return this 14808 */ 14809 ref public Matrix4d mapYXZ() return { 14810 mapYXZ(this); 14811 return this; 14812 } 14813 public Matrix4d mapYXZ(ref Matrix4d dest) { 14814 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14815 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)); 14816 } 14817 /** 14818 * Multiply <code>this</code> by the matrix 14819 * <pre> 14820 * 0 1 0 0 14821 * 1 0 0 0 14822 * 0 0 -1 0 14823 * 0 0 0 1 14824 * </pre> 14825 * 14826 * @return this 14827 */ 14828 ref public Matrix4d mapYXnZ() return { 14829 mapYXnZ(this); 14830 return this; 14831 } 14832 public Matrix4d mapYXnZ(ref Matrix4d dest) { 14833 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14834 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)); 14835 } 14836 /** 14837 * Multiply <code>this</code> by the matrix 14838 * <pre> 14839 * 0 0 1 0 14840 * 1 0 0 0 14841 * 0 1 0 0 14842 * 0 0 0 1 14843 * </pre> 14844 * 14845 * @return this 14846 */ 14847 ref public Matrix4d mapYZX() return { 14848 mapYZX(this); 14849 return this; 14850 } 14851 public Matrix4d mapYZX(ref Matrix4d dest) { 14852 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14853 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)); 14854 } 14855 /** 14856 * Multiply <code>this</code> by the matrix 14857 * <pre> 14858 * 0 0 -1 0 14859 * 1 0 0 0 14860 * 0 1 0 0 14861 * 0 0 0 1 14862 * </pre> 14863 * 14864 * @return this 14865 */ 14866 ref public Matrix4d mapYZnX() return { 14867 mapYZnX(this); 14868 return this; 14869 } 14870 public Matrix4d mapYZnX(ref Matrix4d dest) { 14871 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14872 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)); 14873 } 14874 /** 14875 * Multiply <code>this</code> by the matrix 14876 * <pre> 14877 * 0 -1 0 0 14878 * 1 0 0 0 14879 * 0 0 1 0 14880 * 0 0 0 1 14881 * </pre> 14882 * 14883 * @return this 14884 */ 14885 ref public Matrix4d mapYnXZ() return { 14886 mapYnXZ(this); 14887 return this; 14888 } 14889 public Matrix4d mapYnXZ(ref Matrix4d dest) { 14890 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14891 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)); 14892 } 14893 /** 14894 * Multiply <code>this</code> by the matrix 14895 * <pre> 14896 * 0 -1 0 0 14897 * 1 0 0 0 14898 * 0 0 -1 0 14899 * 0 0 0 1 14900 * </pre> 14901 * 14902 * @return this 14903 */ 14904 ref public Matrix4d mapYnXnZ() return { 14905 mapYnXnZ(this); 14906 return this; 14907 } 14908 public Matrix4d mapYnXnZ(ref Matrix4d dest) { 14909 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14910 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)); 14911 } 14912 /** 14913 * Multiply <code>this</code> by the matrix 14914 * <pre> 14915 * 0 0 1 0 14916 * 1 0 0 0 14917 * 0 -1 0 0 14918 * 0 0 0 1 14919 * </pre> 14920 * 14921 * @return this 14922 */ 14923 ref public Matrix4d mapYnZX() return { 14924 mapYnZX(this); 14925 return this; 14926 } 14927 public Matrix4d mapYnZX(ref Matrix4d dest) { 14928 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14929 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)); 14930 } 14931 /** 14932 * Multiply <code>this</code> by the matrix 14933 * <pre> 14934 * 0 0 -1 0 14935 * 1 0 0 0 14936 * 0 -1 0 0 14937 * 0 0 0 1 14938 * </pre> 14939 * 14940 * @return this 14941 */ 14942 ref public Matrix4d mapYnZnX() return { 14943 mapYnZnX(this); 14944 return this; 14945 } 14946 public Matrix4d mapYnZnX(ref Matrix4d dest) { 14947 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14948 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)); 14949 } 14950 /** 14951 * Multiply <code>this</code> by the matrix 14952 * <pre> 14953 * 0 1 0 0 14954 * 0 0 1 0 14955 * 1 0 0 0 14956 * 0 0 0 1 14957 * </pre> 14958 * 14959 * @return this 14960 */ 14961 ref public Matrix4d mapZXY() return { 14962 mapZXY(this); 14963 return this; 14964 } 14965 public Matrix4d mapZXY(ref Matrix4d dest) { 14966 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14967 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14968 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)); 14969 } 14970 /** 14971 * Multiply <code>this</code> by the matrix 14972 * <pre> 14973 * 0 1 0 0 14974 * 0 0 -1 0 14975 * 1 0 0 0 14976 * 0 0 0 1 14977 * </pre> 14978 * 14979 * @return this 14980 */ 14981 ref public Matrix4d mapZXnY() return { 14982 mapZXnY(this); 14983 return this; 14984 } 14985 public Matrix4d mapZXnY(ref Matrix4d dest) { 14986 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14987 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14988 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)); 14989 } 14990 /** 14991 * Multiply <code>this</code> by the matrix 14992 * <pre> 14993 * 0 0 1 0 14994 * 0 1 0 0 14995 * 1 0 0 0 14996 * 0 0 0 1 14997 * </pre> 14998 * 14999 * @return this 15000 */ 15001 ref public Matrix4d mapZYX() return { 15002 mapZYX(this); 15003 return this; 15004 } 15005 public Matrix4d mapZYX(ref Matrix4d dest) { 15006 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15007 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)); 15008 } 15009 /** 15010 * Multiply <code>this</code> by the matrix 15011 * <pre> 15012 * 0 0 -1 0 15013 * 0 1 0 0 15014 * 1 0 0 0 15015 * 0 0 0 1 15016 * </pre> 15017 * 15018 * @return this 15019 */ 15020 ref public Matrix4d mapZYnX() return { 15021 mapZYnX(this); 15022 return this; 15023 } 15024 public Matrix4d mapZYnX(ref Matrix4d dest) { 15025 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15026 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)); 15027 } 15028 /** 15029 * Multiply <code>this</code> by the matrix 15030 * <pre> 15031 * 0 -1 0 0 15032 * 0 0 1 0 15033 * 1 0 0 0 15034 * 0 0 0 1 15035 * </pre> 15036 * 15037 * @return this 15038 */ 15039 ref public Matrix4d mapZnXY() return { 15040 mapZnXY(this); 15041 return this; 15042 } 15043 public Matrix4d mapZnXY(ref Matrix4d dest) { 15044 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15045 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15046 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)); 15047 } 15048 /** 15049 * Multiply <code>this</code> by the matrix 15050 * <pre> 15051 * 0 -1 0 0 15052 * 0 0 -1 0 15053 * 1 0 0 0 15054 * 0 0 0 1 15055 * </pre> 15056 * 15057 * @return this 15058 */ 15059 ref public Matrix4d mapZnXnY() return { 15060 mapZnXnY(this); 15061 return this; 15062 } 15063 public Matrix4d mapZnXnY(ref Matrix4d dest) { 15064 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15065 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15066 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)); 15067 } 15068 /** 15069 * Multiply <code>this</code> by the matrix 15070 * <pre> 15071 * 0 0 1 0 15072 * 0 -1 0 0 15073 * 1 0 0 0 15074 * 0 0 0 1 15075 * </pre> 15076 * 15077 * @return this 15078 */ 15079 ref public Matrix4d mapZnYX() return { 15080 mapZnYX(this); 15081 return this; 15082 } 15083 public Matrix4d mapZnYX(ref Matrix4d dest) { 15084 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15085 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)); 15086 } 15087 /** 15088 * Multiply <code>this</code> by the matrix 15089 * <pre> 15090 * 0 0 -1 0 15091 * 0 -1 0 0 15092 * 1 0 0 0 15093 * 0 0 0 1 15094 * </pre> 15095 * 15096 * @return this 15097 */ 15098 ref public Matrix4d mapZnYnX() return { 15099 mapZnYnX(this); 15100 return this; 15101 } 15102 public Matrix4d mapZnYnX(ref Matrix4d dest) { 15103 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15104 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)); 15105 } 15106 /** 15107 * Multiply <code>this</code> by the matrix 15108 * <pre> 15109 * -1 0 0 0 15110 * 0 1 0 0 15111 * 0 0 -1 0 15112 * 0 0 0 1 15113 * </pre> 15114 * 15115 * @return this 15116 */ 15117 ref public Matrix4d mapnXYnZ() return { 15118 mapnXYnZ(this); 15119 return this; 15120 } 15121 public Matrix4d mapnXYnZ(ref Matrix4d dest) { 15122 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)); 15123 } 15124 /** 15125 * Multiply <code>this</code> by the matrix 15126 * <pre> 15127 * -1 0 0 0 15128 * 0 0 1 0 15129 * 0 1 0 0 15130 * 0 0 0 1 15131 * </pre> 15132 * 15133 * @return this 15134 */ 15135 ref public Matrix4d mapnXZY() return { 15136 mapnXZY(this); 15137 return this; 15138 } 15139 public Matrix4d mapnXZY(ref Matrix4d dest) { 15140 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15141 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)); 15142 } 15143 /** 15144 * Multiply <code>this</code> by the matrix 15145 * <pre> 15146 * -1 0 0 0 15147 * 0 0 -1 0 15148 * 0 1 0 0 15149 * 0 0 0 1 15150 * </pre> 15151 * 15152 * @return this 15153 */ 15154 ref public Matrix4d mapnXZnY() return { 15155 mapnXZnY(this); 15156 return this; 15157 } 15158 public Matrix4d mapnXZnY(ref Matrix4d dest) { 15159 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15160 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)); 15161 } 15162 /** 15163 * Multiply <code>this</code> by the matrix 15164 * <pre> 15165 * -1 0 0 0 15166 * 0 -1 0 0 15167 * 0 0 1 0 15168 * 0 0 0 1 15169 * </pre> 15170 * 15171 * @return this 15172 */ 15173 ref public Matrix4d mapnXnYZ() return { 15174 mapnXnYZ(this); 15175 return this; 15176 } 15177 public Matrix4d mapnXnYZ(ref Matrix4d dest) { 15178 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)); 15179 } 15180 /** 15181 * Multiply <code>this</code> by the matrix 15182 * <pre> 15183 * -1 0 0 0 15184 * 0 -1 0 0 15185 * 0 0 -1 0 15186 * 0 0 0 1 15187 * </pre> 15188 * 15189 * @return this 15190 */ 15191 ref public Matrix4d mapnXnYnZ() return { 15192 mapnXnYnZ(this); 15193 return this; 15194 } 15195 public Matrix4d mapnXnYnZ(ref Matrix4d dest) { 15196 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)); 15197 } 15198 /** 15199 * Multiply <code>this</code> by the matrix 15200 * <pre> 15201 * -1 0 0 0 15202 * 0 0 1 0 15203 * 0 -1 0 0 15204 * 0 0 0 1 15205 * </pre> 15206 * 15207 * @return this 15208 */ 15209 ref public Matrix4d mapnXnZY() return { 15210 mapnXnZY(this); 15211 return this; 15212 } 15213 public Matrix4d mapnXnZY(ref Matrix4d dest) { 15214 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15215 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)); 15216 } 15217 /** 15218 * Multiply <code>this</code> by the matrix 15219 * <pre> 15220 * -1 0 0 0 15221 * 0 0 -1 0 15222 * 0 -1 0 0 15223 * 0 0 0 1 15224 * </pre> 15225 * 15226 * @return this 15227 */ 15228 ref public Matrix4d mapnXnZnY() return { 15229 mapnXnZnY(this); 15230 return this; 15231 } 15232 public Matrix4d mapnXnZnY(ref Matrix4d dest) { 15233 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15234 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)); 15235 } 15236 /** 15237 * Multiply <code>this</code> by the matrix 15238 * <pre> 15239 * 0 1 0 0 15240 * -1 0 0 0 15241 * 0 0 1 0 15242 * 0 0 0 1 15243 * </pre> 15244 * 15245 * @return this 15246 */ 15247 ref public Matrix4d mapnYXZ() return { 15248 mapnYXZ(this); 15249 return this; 15250 } 15251 public Matrix4d mapnYXZ(ref Matrix4d dest) { 15252 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15253 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)); 15254 } 15255 /** 15256 * Multiply <code>this</code> by the matrix 15257 * <pre> 15258 * 0 1 0 0 15259 * -1 0 0 0 15260 * 0 0 -1 0 15261 * 0 0 0 1 15262 * </pre> 15263 * 15264 * @return this 15265 */ 15266 ref public Matrix4d mapnYXnZ() return { 15267 mapnYXnZ(this); 15268 return this; 15269 } 15270 public Matrix4d mapnYXnZ(ref Matrix4d dest) { 15271 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15272 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)); 15273 } 15274 /** 15275 * Multiply <code>this</code> by the matrix 15276 * <pre> 15277 * 0 0 1 0 15278 * -1 0 0 0 15279 * 0 1 0 0 15280 * 0 0 0 1 15281 * </pre> 15282 * 15283 * @return this 15284 */ 15285 ref public Matrix4d mapnYZX() return { 15286 mapnYZX(this); 15287 return this; 15288 } 15289 public Matrix4d mapnYZX(ref Matrix4d dest) { 15290 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15291 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)); 15292 } 15293 /** 15294 * Multiply <code>this</code> by the matrix 15295 * <pre> 15296 * 0 0 -1 0 15297 * -1 0 0 0 15298 * 0 1 0 0 15299 * 0 0 0 1 15300 * </pre> 15301 * 15302 * @return this 15303 */ 15304 ref public Matrix4d mapnYZnX() return { 15305 mapnYZnX(this); 15306 return this; 15307 } 15308 public Matrix4d mapnYZnX(ref Matrix4d dest) { 15309 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15310 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)); 15311 } 15312 /** 15313 * Multiply <code>this</code> by the matrix 15314 * <pre> 15315 * 0 -1 0 0 15316 * -1 0 0 0 15317 * 0 0 1 0 15318 * 0 0 0 1 15319 * </pre> 15320 * 15321 * @return this 15322 */ 15323 ref public Matrix4d mapnYnXZ() return { 15324 mapnYnXZ(this); 15325 return this; 15326 } 15327 public Matrix4d mapnYnXZ(ref Matrix4d dest) { 15328 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15329 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)); 15330 } 15331 /** 15332 * Multiply <code>this</code> by the matrix 15333 * <pre> 15334 * 0 -1 0 0 15335 * -1 0 0 0 15336 * 0 0 -1 0 15337 * 0 0 0 1 15338 * </pre> 15339 * 15340 * @return this 15341 */ 15342 ref public Matrix4d mapnYnXnZ() return { 15343 mapnYnXnZ(this); 15344 return this; 15345 } 15346 public Matrix4d mapnYnXnZ(ref Matrix4d dest) { 15347 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15348 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)); 15349 } 15350 /** 15351 * Multiply <code>this</code> by the matrix 15352 * <pre> 15353 * 0 0 1 0 15354 * -1 0 0 0 15355 * 0 -1 0 0 15356 * 0 0 0 1 15357 * </pre> 15358 * 15359 * @return this 15360 */ 15361 ref public Matrix4d mapnYnZX() return { 15362 mapnYnZX(this); 15363 return this; 15364 } 15365 public Matrix4d mapnYnZX(ref Matrix4d dest) { 15366 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15367 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)); 15368 } 15369 /** 15370 * Multiply <code>this</code> by the matrix 15371 * <pre> 15372 * 0 0 -1 0 15373 * -1 0 0 0 15374 * 0 -1 0 0 15375 * 0 0 0 1 15376 * </pre> 15377 * 15378 * @return this 15379 */ 15380 ref public Matrix4d mapnYnZnX() return { 15381 mapnYnZnX(this); 15382 return this; 15383 } 15384 public Matrix4d mapnYnZnX(ref Matrix4d dest) { 15385 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15386 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)); 15387 } 15388 /** 15389 * Multiply <code>this</code> by the matrix 15390 * <pre> 15391 * 0 1 0 0 15392 * 0 0 1 0 15393 * -1 0 0 0 15394 * 0 0 0 1 15395 * </pre> 15396 * 15397 * @return this 15398 */ 15399 ref public Matrix4d mapnZXY() return { 15400 mapnZXY(this); 15401 return this; 15402 } 15403 public Matrix4d mapnZXY(ref Matrix4d dest) { 15404 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15405 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15406 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)); 15407 } 15408 /** 15409 * Multiply <code>this</code> by the matrix 15410 * <pre> 15411 * 0 1 0 0 15412 * 0 0 -1 0 15413 * -1 0 0 0 15414 * 0 0 0 1 15415 * </pre> 15416 * 15417 * @return this 15418 */ 15419 ref public Matrix4d mapnZXnY() return { 15420 mapnZXnY(this); 15421 return this; 15422 } 15423 public Matrix4d mapnZXnY(ref Matrix4d dest) { 15424 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15425 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15426 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)); 15427 } 15428 /** 15429 * Multiply <code>this</code> by the matrix 15430 * <pre> 15431 * 0 0 1 0 15432 * 0 1 0 0 15433 * -1 0 0 0 15434 * 0 0 0 1 15435 * </pre> 15436 * 15437 * @return this 15438 */ 15439 ref public Matrix4d mapnZYX() return { 15440 mapnZYX(this); 15441 return this; 15442 } 15443 public Matrix4d mapnZYX(ref Matrix4d dest) { 15444 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15445 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)); 15446 } 15447 /** 15448 * Multiply <code>this</code> by the matrix 15449 * <pre> 15450 * 0 0 -1 0 15451 * 0 1 0 0 15452 * -1 0 0 0 15453 * 0 0 0 1 15454 * </pre> 15455 * 15456 * @return this 15457 */ 15458 ref public Matrix4d mapnZYnX() return { 15459 mapnZYnX(this); 15460 return this; 15461 } 15462 public Matrix4d mapnZYnX(ref Matrix4d dest) { 15463 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15464 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)); 15465 } 15466 /** 15467 * Multiply <code>this</code> by the matrix 15468 * <pre> 15469 * 0 -1 0 0 15470 * 0 0 1 0 15471 * -1 0 0 0 15472 * 0 0 0 1 15473 * </pre> 15474 * 15475 * @return this 15476 */ 15477 ref public Matrix4d mapnZnXY() return { 15478 mapnZnXY(this); 15479 return this; 15480 } 15481 public Matrix4d mapnZnXY(ref Matrix4d dest) { 15482 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15483 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15484 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)); 15485 } 15486 /** 15487 * Multiply <code>this</code> by the matrix 15488 * <pre> 15489 * 0 -1 0 0 15490 * 0 0 -1 0 15491 * -1 0 0 0 15492 * 0 0 0 1 15493 * </pre> 15494 * 15495 * @return this 15496 */ 15497 ref public Matrix4d mapnZnXnY() return { 15498 mapnZnXnY(this); 15499 return this; 15500 } 15501 public Matrix4d mapnZnXnY(ref Matrix4d dest) { 15502 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15503 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15504 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)); 15505 } 15506 /** 15507 * Multiply <code>this</code> by the matrix 15508 * <pre> 15509 * 0 0 1 0 15510 * 0 -1 0 0 15511 * -1 0 0 0 15512 * 0 0 0 1 15513 * </pre> 15514 * 15515 * @return this 15516 */ 15517 ref public Matrix4d mapnZnYX() return { 15518 mapnZnYX(this); 15519 return this; 15520 } 15521 public Matrix4d mapnZnYX(ref Matrix4d dest) { 15522 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15523 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)); 15524 } 15525 /** 15526 * Multiply <code>this</code> by the matrix 15527 * <pre> 15528 * 0 0 -1 0 15529 * 0 -1 0 0 15530 * -1 0 0 0 15531 * 0 0 0 1 15532 * </pre> 15533 * 15534 * @return this 15535 */ 15536 ref public Matrix4d mapnZnYnX() return { 15537 mapnZnYnX(this); 15538 return this; 15539 } 15540 public Matrix4d mapnZnYnX(ref Matrix4d dest) { 15541 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15542 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)); 15543 } 15544 15545 /** 15546 * Multiply <code>this</code> by the matrix 15547 * <pre> 15548 * -1 0 0 0 15549 * 0 1 0 0 15550 * 0 0 1 0 15551 * 0 0 0 1 15552 * </pre> 15553 * 15554 * @return this 15555 */ 15556 ref public Matrix4d negateX() return { 15557 return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15558 } 15559 public Matrix4d negateX(ref Matrix4d dest) { 15560 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)); 15561 } 15562 15563 /** 15564 * Multiply <code>this</code> by the matrix 15565 * <pre> 15566 * 1 0 0 0 15567 * 0 -1 0 0 15568 * 0 0 1 0 15569 * 0 0 0 1 15570 * </pre> 15571 * 15572 * @return this 15573 */ 15574 ref public Matrix4d negateY() return { 15575 return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15576 } 15577 public Matrix4d negateY(ref Matrix4d dest) { 15578 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)); 15579 } 15580 15581 /** 15582 * Multiply <code>this</code> by the matrix 15583 * <pre> 15584 * 1 0 0 0 15585 * 0 1 0 0 15586 * 0 0 -1 0 15587 * 0 0 0 1 15588 * </pre> 15589 * 15590 * @return this 15591 */ 15592 ref public Matrix4d negateZ() return { 15593 return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15594 } 15595 public Matrix4d negateZ(ref Matrix4d dest) { 15596 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)); 15597 } 15598 15599 public bool isFinite() { 15600 return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) && Math.isFinite(m03) && 15601 Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) && Math.isFinite(m13) && 15602 Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) && Math.isFinite(m23) && 15603 Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32) && Math.isFinite(m33); 15604 } 15605 15606 }