1 /** 2 * Contains the definition of a 4x4 Matrix of doubles, and associated functions to transform 3 * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this: 4 * <p> 5 * m00 m10 m20 m30<br> 6 * m01 m11 m21 m31<br> 7 * m02 m12 m22 m32<br> 8 * m03 m13 m23 m33<br> 9 * 10 * @author Richard Greenlees 11 * @author Kai Burjack 12 */ 13 module doml.matrix_4d; 14 15 import Math = doml.math; 16 import MemUtil = doml.mem_util; 17 18 import doml.matrix_3d; 19 import doml.matrix_4x3d; 20 import doml.matrix_3x2d; 21 22 import doml.vector_2d; 23 import doml.vector_3d; 24 import doml.vector_4d; 25 26 import doml.axis_angle_4d; 27 import doml.quaternion_d; 28 29 /* 30 * The MIT License 31 $!#@$@ Translated by jordan4ibanez 32 * 33 * Copyright (c) 2015-2021 Richard Greenlees 34 * 35 * Permission is hereby granted, free of charge, to any person obtaining a copy 36 * of this software and associated documentation files (the "Software"), to deal 37 * in the Software without restriction, including without limitation the rights 38 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 39 * copies of the Software, and to permit persons to whom the Software is 40 * furnished to do so, subject to the following conditions: 41 * 42 * The above copyright notice and this permission notice shall be included in 43 * all copies or substantial portions of the Software. 44 * 45 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 51 * THE SOFTWARE. 52 */ 53 54 /** 55 * Contains the definition of a 4x4 Matrix of doubles, and associated functions to transform 56 * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this: 57 * <p> 58 * m00 m10 m20 m30<br> 59 * m01 m11 m21 m31<br> 60 * m02 m12 m22 m32<br> 61 * m03 m13 m23 m33<br> 62 * 63 * @author Richard Greenlees 64 * @author Kai Burjack 65 */ 66 struct Matrix4d { 67 68 double m00 = 1.0; 69 double m01 = 0.0; 70 double m02 = 0.0; 71 double m03 = 0.0; 72 73 double m10 = 0.0; 74 double m11 = 1.0; 75 double m12 = 0.0; 76 double m13 = 0.0; 77 78 double m20 = 0.0; 79 double m21 = 0.0; 80 double m22 = 1.0; 81 double m23 = 0.0; 82 83 double m30 = 0.0; 84 double m31 = 0.0; 85 double m32 = 0.0; 86 double m33 = 1.0; 87 88 /** 89 90 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 91 * identifying the plane with equation <code>x=-1</code> when using the identity matrix. 92 */ 93 static immutable int PLANE_NX = 0; 94 /** 95 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 96 * identifying the plane with equation <code>x=1</code> when using the identity matrix. 97 */ 98 static immutable int PLANE_PX = 1; 99 /** 100 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 101 * identifying the plane with equation <code>y=-1</code> when using the identity matrix. 102 */ 103 static immutable int PLANE_NY = 2; 104 /** 105 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 106 * identifying the plane with equation <code>y=1</code> when using the identity matrix. 107 */ 108 static immutable int PLANE_PY = 3; 109 /** 110 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 111 * identifying the plane with equation <code>z=-1</code> when using the identity matrix. 112 */ 113 static immutable int PLANE_NZ = 4; 114 /** 115 * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)} 116 * identifying the plane with equation <code>z=1</code> when using the identity matrix. 117 */ 118 static immutable int PLANE_PZ = 5; 119 /** 120 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 121 * identifying the corner <code>(-1, -1, -1)</code> when using the identity matrix. 122 */ 123 static immutable int CORNER_NXNYNZ = 0; 124 /** 125 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 126 * identifying the corner <code>(1, -1, -1)</code> when using the identity matrix. 127 */ 128 static immutable int CORNER_PXNYNZ = 1; 129 /** 130 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 131 * identifying the corner <code>(1, 1, -1)</code> when using the identity matrix. 132 */ 133 static immutable int CORNER_PXPYNZ = 2; 134 /** 135 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 136 * identifying the corner <code>(-1, 1, -1)</code> when using the identity matrix. 137 */ 138 static immutable int CORNER_NXPYNZ = 3; 139 /** 140 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 141 * identifying the corner <code>(1, -1, 1)</code> when using the identity matrix. 142 */ 143 static immutable int CORNER_PXNYPZ = 4; 144 /** 145 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 146 * identifying the corner <code>(-1, -1, 1)</code> when using the identity matrix. 147 */ 148 static immutable int CORNER_NXNYPZ = 5; 149 /** 150 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 151 * identifying the corner <code>(-1, 1, 1)</code> when using the identity matrix. 152 */ 153 static immutable int CORNER_NXPYPZ = 6; 154 /** 155 * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)} 156 * identifying the corner <code>(1, 1, 1)</code> when using the identity matrix. 157 */ 158 static immutable int CORNER_PXPYPZ = 7; 159 160 /** 161 * Bit returned by {@link #properties()} to indicate that the matrix represents a perspective transformation. 162 */ 163 static immutable byte PROPERTY_PERSPECTIVE = 1<<0; 164 /** 165 * Bit returned by {@link #properties()} to indicate that the matrix represents an affine transformation. 166 */ 167 static immutable byte PROPERTY_AFFINE = 1<<1; 168 /** 169 * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation. 170 */ 171 static immutable byte PROPERTY_IDENTITY = 1<<2; 172 /** 173 * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation. 174 */ 175 static immutable byte PROPERTY_TRANSLATION = 1<<3; 176 /** 177 * Bit returned by {@link #properties()} to indicate that the upper-left 3x3 submatrix represents an orthogonal 178 * matrix (i.e. orthonormal basis). For practical reasons, this property also always implies 179 * {@link #PROPERTY_AFFINE} in this implementation. 180 */ 181 static immutable byte PROPERTY_ORTHONORMAL = 1<<4; 182 183 184 185 int properties = PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL; 186 187 /** 188 * Create a new {@link Matrix4d} and make it a copy of the given matrix. 189 * 190 * @param mat 191 * the {@link Matrix4d} to copy the values from 192 */ 193 this(Matrix4d mat) { 194 set(mat); 195 } 196 197 /** 198 * Create a new {@link Matrix4d} and set its upper 4x3 submatrix to the given matrix <code>mat</code> 199 * and all other elements to identity. 200 * 201 * @param mat 202 * the {@link Matrix4x3d} to copy the values from 203 */ 204 this(Matrix4x3d mat) { 205 set(mat); 206 } 207 208 /** 209 * Create a new {@link Matrix4d} by setting its uppper left 3x3 submatrix to the values of the given {@link Matrix3d} 210 * and the rest to identity. 211 * 212 * @param mat 213 * the {@link Matrix3d} 214 */ 215 this(Matrix3d mat) { 216 set(mat); 217 } 218 219 /** 220 * Create a new 4x4 matrix using the supplied double values. 221 * <p> 222 * The matrix layout will be:<br><br> 223 * m00, m10, m20, m30<br> 224 * m01, m11, m21, m31<br> 225 * m02, m12, m22, m32<br> 226 * m03, m13, m23, m33 227 * 228 * @param m00 229 * the value of m00 230 * @param m01 231 * the value of m01 232 * @param m02 233 * the value of m02 234 * @param m03 235 * the value of m03 236 * @param m10 237 * the value of m10 238 * @param m11 239 * the value of m11 240 * @param m12 241 * the value of m12 242 * @param m13 243 * the value of m13 244 * @param m20 245 * the value of m20 246 * @param m21 247 * the value of m21 248 * @param m22 249 * the value of m22 250 * @param m23 251 * the value of m23 252 * @param m30 253 * the value of m30 254 * @param m31 255 * the value of m31 256 * @param m32 257 * the value of m32 258 * @param m33 259 * the value of m33 260 */ 261 this(double m00, double m01, double m02, double m03, 262 double m10, double m11, double m12, double m13, 263 double m20, double m21, double m22, double m23, 264 double m30, double m31, double m32, double m33) { 265 setm00(m00); 266 setm01(m01); 267 setm02(m02); 268 setm03(m03); 269 setm10(m10); 270 setm11(m11); 271 setm12(m12); 272 setm13(m13); 273 setm20(m20); 274 setm21(m21); 275 setm22(m22); 276 setm23(m23); 277 setm30(m30); 278 setm31(m31); 279 setm32(m32); 280 setm33(m33); 281 determineProperties(); 282 } 283 284 /** 285 * Create a new {@link Matrix4d} and initialize its four columns using the supplied vectors. 286 * 287 * @param col0 288 * the first column 289 * @param col1 290 * the second column 291 * @param col2 292 * the third column 293 * @param col3 294 * the fourth column 295 */ 296 this(ref Vector4d col0, Vector4d col1, Vector4d col2, Vector4d col3) { 297 set(col0, col1, col2, col3); 298 } 299 300 /** 301 * Assume the given properties about this matrix. 302 * <p> 303 * Use one or multiple of 0, {@link Matrix4d#PROPERTY_IDENTITY}, 304 * {@link Matrix4d#PROPERTY_TRANSLATION}, {@link Matrix4d#PROPERTY_AFFINE}, 305 * {@link Matrix4d#PROPERTY_PERSPECTIVE}, {@link Matrix4fc#PROPERTY_ORTHONORMAL}. 306 * 307 * @param properties 308 * bitset of the properties to assume about this matrix 309 * @return this 310 */ 311 ref public Matrix4d assume(int properties) return { 312 this.properties = cast(byte) properties; 313 return this; 314 } 315 316 /** 317 * Compute and set the matrix properties returned by {@link #properties()} based 318 * on the current matrix element values. 319 * 320 * @return this 321 */ 322 ref public Matrix4d determineProperties() return { 323 int __properties = 0; 324 if (m03 == 0.0 && m13 == 0.0) { 325 if (m23 == 0.0 && m33 == 1.0) { 326 __properties |= PROPERTY_AFFINE; 327 if (m00 == 1.0 && m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m11 == 1.0 && m12 == 0.0 && m20 == 0.0 328 && m21 == 0.0 && m22 == 1.0) { 329 __properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL; 330 if (m30 == 0.0 && m31 == 0.0 && m32 == 0.0) 331 __properties |= PROPERTY_IDENTITY; 332 } 333 /* 334 * We do not determine orthogonality, since it would require arbitrary epsilons 335 * and is rather expensive (6 dot products) in the worst case. 336 */ 337 } else if (m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m12 == 0.0 && m20 == 0.0 && m21 == 0.0 && m30 == 0.0 338 && m31 == 0.0 && m33 == 0.0) { 339 __properties |= PROPERTY_PERSPECTIVE; 340 } 341 } 342 this.properties = __properties; 343 return this; 344 } 345 346 public int getProperties() { 347 return this.properties; 348 } 349 350 /** 351 * Set the value of the matrix element at column 0 and row 0. 352 * 353 * @param m00 354 * the new value 355 * @return this 356 */ 357 ref public Matrix4d setm00(double m00) return { 358 this.m00 = m00; 359 properties &= ~PROPERTY_ORTHONORMAL; 360 if (m00 != 1.0) 361 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 362 return this; 363 } 364 /** 365 * Set the value of the matrix element at column 0 and row 1. 366 * 367 * @param m01 368 * the new value 369 * @return this 370 */ 371 ref public Matrix4d setm01(double m01) return { 372 this.m01 = m01; 373 properties &= ~PROPERTY_ORTHONORMAL; 374 if (m01 != 0.0) 375 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 376 return this; 377 } 378 /** 379 * Set the value of the matrix element at column 0 and row 2. 380 * 381 * @param m02 382 * the new value 383 * @return this 384 */ 385 ref public Matrix4d setm02(double m02) return { 386 this.m02 = m02; 387 properties &= ~PROPERTY_ORTHONORMAL; 388 if (m02 != 0.0) 389 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 390 return this; 391 } 392 /** 393 * Set the value of the matrix element at column 0 and row 3. 394 * 395 * @param m03 396 * the new value 397 * @return this 398 */ 399 ref public Matrix4d setm03(double m03) return { 400 this.m03 = m03; 401 if (m03 != 0.0) 402 properties = 0; 403 return this; 404 } 405 /** 406 * Set the value of the matrix element at column 1 and row 0. 407 * 408 * @param m10 409 * the new value 410 * @return this 411 */ 412 ref public Matrix4d setm10(double m10) return { 413 this.m10 = m10; 414 properties &= ~PROPERTY_ORTHONORMAL; 415 if (m10 != 0.0) 416 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 417 return this; 418 } 419 /** 420 * Set the value of the matrix element at column 1 and row 1. 421 * 422 * @param m11 423 * the new value 424 * @return this 425 */ 426 ref public Matrix4d setm11(double m11) return { 427 this.m11 = m11; 428 properties &= ~PROPERTY_ORTHONORMAL; 429 if (m11 != 1.0) 430 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 431 return this; 432 } 433 /** 434 * Set the value of the matrix element at column 1 and row 2. 435 * 436 * @param m12 437 * the new value 438 * @return this 439 */ 440 ref public Matrix4d setm12(double m12) return { 441 this.m12 = m12; 442 properties &= ~PROPERTY_ORTHONORMAL; 443 if (m12 != 0.0) 444 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 445 return this; 446 } 447 /** 448 * Set the value of the matrix element at column 1 and row 3. 449 * 450 * @param m13 451 * the new value 452 * @return this 453 */ 454 ref public Matrix4d setm13(double m13) return { 455 this.m13 = m13; 456 if (m03 != 0.0) 457 properties = 0; 458 return this; 459 } 460 /** 461 * Set the value of the matrix element at column 2 and row 0. 462 * 463 * @param m20 464 * the new value 465 * @return this 466 */ 467 ref public Matrix4d setm20(double m20) return { 468 this.m20 = m20; 469 properties &= ~PROPERTY_ORTHONORMAL; 470 if (m20 != 0.0) 471 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 472 return this; 473 } 474 /** 475 * Set the value of the matrix element at column 2 and row 1. 476 * 477 * @param m21 478 * the new value 479 * @return this 480 */ 481 ref public Matrix4d setm21(double m21) return { 482 this.m21 = m21; 483 properties &= ~PROPERTY_ORTHONORMAL; 484 if (m21 != 0.0) 485 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION); 486 return this; 487 } 488 /** 489 * Set the value of the matrix element at column 2 and row 2. 490 * 491 * @param m22 492 * the new value 493 * @return this 494 */ 495 ref public Matrix4d setm22(double m22) return { 496 this.m22 = m22; 497 properties &= ~PROPERTY_ORTHONORMAL; 498 if (m22 != 1.0) 499 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 500 return this; 501 } 502 /** 503 * Set the value of the matrix element at column 2 and row 3. 504 * 505 * @param m23 506 * the new value 507 * @return this 508 */ 509 ref public Matrix4d setm23(double m23) return { 510 this.m23 = m23; 511 if (m23 != 0.0) 512 properties &= ~(PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL); 513 return this; 514 } 515 /** 516 * Set the value of the matrix element at column 3 and row 0. 517 * 518 * @param m30 519 * the new value 520 * @return this 521 */ 522 ref public Matrix4d setm30(double m30) return { 523 this.m30 = m30; 524 if (m30 != 0.0) 525 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE); 526 return this; 527 } 528 /** 529 * Set the value of the matrix element at column 3 and row 1. 530 * 531 * @param m31 532 * the new value 533 * @return this 534 */ 535 ref public Matrix4d setm31(double m31) return { 536 this.m31 = m31; 537 if (m31 != 0.0) 538 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE); 539 return this; 540 } 541 /** 542 * Set the value of the matrix element at column 3 and row 2. 543 * 544 * @param m32 545 * the new value 546 * @return this 547 */ 548 ref public Matrix4d setm32(double m32) return { 549 this.m32 = m32; 550 if (m32 != 0.0) 551 properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE); 552 return this; 553 } 554 /** 555 * Set the value of the matrix element at column 3 and row 3. 556 * 557 * @param m33 558 * the new value 559 * @return this 560 */ 561 ref public Matrix4d setm33(double m33) return { 562 this.m33 = m33; 563 if (m33 != 0.0) 564 properties &= ~(PROPERTY_PERSPECTIVE); 565 if (m33 != 1.0) 566 properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL | PROPERTY_AFFINE); 567 return this; 568 } 569 570 ref Matrix4d _properties(int properties) return { 571 this.properties = properties; 572 return this; 573 } 574 575 /** 576 * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix. 577 * 578 * @param m00 579 * the new value 580 * @return this 581 */ 582 ref Matrix4d _m00(double m00) return { 583 setm00(m00); 584 return this; 585 } 586 /** 587 * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix. 588 * 589 * @param m01 590 * the new value 591 * @return this 592 */ 593 ref Matrix4d _m01(double m01) return { 594 setm01(m01); 595 return this; 596 } 597 /** 598 * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix. 599 * 600 * @param m02 601 * the new value 602 * @return this 603 */ 604 ref Matrix4d _m02(double m02) return { 605 setm02(m02); 606 return this; 607 } 608 /** 609 * Set the value of the matrix element at column 0 and row 3 without updating the properties of the matrix. 610 * 611 * @param m03 612 * the new value 613 * @return this 614 */ 615 ref Matrix4d _m03(double m03) return { 616 setm03(m03); 617 return this; 618 } 619 /** 620 * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix. 621 * 622 * @param m10 623 * the new value 624 * @return this 625 */ 626 ref Matrix4d _m10(double m10) return { 627 setm10(m10); 628 return this; 629 } 630 /** 631 * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix. 632 * 633 * @param m11 634 * the new value 635 * @return this 636 */ 637 ref Matrix4d _m11(double m11) return { 638 setm11(m11); 639 return this; 640 } 641 /** 642 * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix. 643 * 644 * @param m12 645 * the new value 646 * @return this 647 */ 648 ref Matrix4d _m12(double m12) return { 649 setm12(m12); 650 return this; 651 } 652 /** 653 * Set the value of the matrix element at column 1 and row 3 without updating the properties of the matrix. 654 * 655 * @param m13 656 * the new value 657 * @return this 658 */ 659 ref Matrix4d _m13(double m13) return { 660 setm13(m13); 661 return this; 662 } 663 /** 664 * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix. 665 * 666 * @param m20 667 * the new value 668 * @return this 669 */ 670 ref Matrix4d _m20(double m20) return { 671 setm20(m20); 672 return this; 673 } 674 /** 675 * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix. 676 * 677 * @param m21 678 * the new value 679 * @return this 680 */ 681 ref Matrix4d _m21(double m21) return { 682 setm21(m21); 683 return this; 684 } 685 /** 686 * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix. 687 * 688 * @param m22 689 * the new value 690 * @return this 691 */ 692 ref Matrix4d _m22(double m22) return { 693 setm22(m22); 694 return this; 695 } 696 /** 697 * Set the value of the matrix element at column 2 and row 3 without updating the properties of the matrix. 698 * 699 * @param m23 700 * the new value 701 * @return this 702 */ 703 ref Matrix4d _m23(double m23) return { 704 setm23(m23); 705 return this; 706 } 707 /** 708 * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix. 709 * 710 * @param m30 711 * the new value 712 * @return this 713 */ 714 ref Matrix4d _m30(double m30) return { 715 setm30(m30); 716 return this; 717 } 718 /** 719 * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix. 720 * 721 * @param m31 722 * the new value 723 * @return this 724 */ 725 ref Matrix4d _m31(double m31) return { 726 setm31(m31); 727 return this; 728 } 729 /** 730 * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix. 731 * 732 * @param m32 733 * the new value 734 * @return this 735 */ 736 ref Matrix4d _m32(double m32) return { 737 setm32(m32); 738 return this; 739 } 740 /** 741 * Set the value of the matrix element at column 3 and row 3 without updating the properties of the matrix. 742 * 743 * @param m33 744 * the new value 745 * @return this 746 */ 747 ref Matrix4d _m33(double m33) return { 748 setm33(m33); 749 return this; 750 } 751 752 /** 753 * Reset this matrix to the identity. 754 * <p> 755 * Please note that if a call to {@link #identity()} is immediately followed by a call to: 756 * {@link #translate(double, double, double) translate}, 757 * {@link #rotate(double, double, double, double) rotate}, 758 * {@link #scale(double, double, double) scale}, 759 * {@link #perspective(double, double, double, double) perspective}, 760 * {@link #frustum(double, double, double, double, double, double) frustum}, 761 * {@link #ortho(double, double, double, double, double, double) ortho}, 762 * {@link #ortho2D(double, double, double, double) ortho2D}, 763 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}, 764 * {@link #lookAlong(double, double, double, double, double, double) lookAlong}, 765 * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with: 766 * {@link #translation(double, double, double) translation}, 767 * {@link #rotation(double, double, double, double) rotation}, 768 * {@link #scaling(double, double, double) scaling}, 769 * {@link #setPerspective(double, double, double, double) setPerspective}, 770 * {@link #setFrustum(double, double, double, double, double, double) setFrustum}, 771 * {@link #setOrtho(double, double, double, double, double, double) setOrtho}, 772 * {@link #setOrtho2D(double, double, double, double) setOrtho2D}, 773 * {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt}, 774 * {@link #setLookAlong(double, double, double, double, double, double) setLookAlong}, 775 * or any of their overloads. 776 * 777 * @return this 778 */ 779 ref public Matrix4d identity() return { 780 if ((properties & PROPERTY_IDENTITY) != 0) 781 return this; 782 _identity(); 783 properties = PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL; 784 return this; 785 } 786 private void _identity() { 787 _m00(1.0). 788 _m10(0.0). 789 _m20(0.0). 790 _m30(0.0). 791 _m01(0.0). 792 _m11(1.0). 793 _m21(0.0). 794 _m31(0.0). 795 _m02(0.0). 796 _m12(0.0). 797 _m22(1.0). 798 _m32(0.0). 799 _m03(0.0). 800 _m13(0.0). 801 _m23(0.0). 802 _m33(1.0); 803 } 804 805 /** 806 * Store the values of the given matrix <code>m</code> into <code>this</code> matrix. 807 * 808 * @see #Matrix4d(Matrix4d) 809 * @see #get(Matrix4d) 810 * 811 * @param m 812 * the matrix to copy the values from 813 * @return this 814 */ 815 ref public Matrix4d set(Matrix4d m) return { 816 return 817 _m00(m.m00). 818 _m01(m.m01). 819 _m02(m.m02). 820 _m03(m.m03). 821 _m10(m.m10). 822 _m11(m.m11). 823 _m12(m.m12). 824 _m13(m.m13). 825 _m20(m.m20). 826 _m21(m.m21). 827 _m22(m.m22). 828 _m23(m.m23). 829 _m30(m.m30). 830 _m31(m.m31). 831 _m32(m.m32). 832 _m33(m.m33). 833 _properties(m.properties); 834 } 835 836 837 /** 838 * Store the values of the transpose of the given matrix <code>m</code> into <code>this</code> matrix. 839 * 840 * @param m 841 * the matrix to copy the transposed values from 842 * @return this 843 */ 844 ref public Matrix4d setTransposed(Matrix4d m) return { 845 if ((m.properties & PROPERTY_IDENTITY) != 0) 846 return this.identity(); 847 return setTransposedInternal(m); 848 } 849 ref private Matrix4d setTransposedInternal(Matrix4d m) return { 850 double nm10 = m.m01, nm12 = m.m21, nm13 = m.m31; 851 double nm20 = m.m02, nm21 = m.m12, nm30 = m.m03; 852 double nm31 = m.m13, nm32 = m.m23; 853 return this 854 ._m00(m.m00)._m01(m.m10)._m02(m.m20)._m03(m.m30) 855 ._m10(nm10)._m11(m.m11)._m12(nm12)._m13(nm13) 856 ._m20(nm20)._m21(nm21)._m22(m.m22)._m23(m.m32) 857 ._m30(nm30)._m31(nm31)._m32(nm32)._m33(m.m33) 858 ._properties(m.properties & PROPERTY_IDENTITY); 859 } 860 861 /** 862 * Store the values of the given matrix <code>m</code> into <code>this</code> matrix 863 * and set the other matrix elements to identity. 864 * 865 * @see #Matrix4d(Matrix4x3d) 866 * 867 * @param m 868 * the matrix to copy the values from 869 * @return this 870 */ 871 ref public Matrix4d set(Matrix4x3d m) return { 872 return 873 _m00(m.m00). 874 _m01(m.m01). 875 _m02(m.m02). 876 _m03(0.0). 877 _m10(m.m10). 878 _m11(m.m11). 879 _m12(m.m12). 880 _m13(0.0). 881 _m20(m.m20). 882 _m21(m.m21). 883 _m22(m.m22). 884 _m23(0.0). 885 _m30(m.m30). 886 _m31(m.m31). 887 _m32(m.m32). 888 _m33(1.0). 889 _properties(m.properties | PROPERTY_AFFINE); 890 } 891 892 893 /** 894 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3d} 895 * and the rest to identity. 896 * 897 * @see #Matrix4d(Matrix3d) 898 * 899 * @param mat 900 * the {@link Matrix3d} 901 * @return this 902 */ 903 ref public Matrix4d set(Matrix3d mat) return { 904 return 905 _m00(mat.m00). 906 _m01(mat.m01). 907 _m02(mat.m02). 908 _m03(0.0). 909 _m10(mat.m10). 910 _m11(mat.m11). 911 _m12(mat.m12). 912 _m13(0.0). 913 _m20(mat.m20). 914 _m21(mat.m21). 915 _m22(mat.m22). 916 _m23(0.0). 917 _m30(0.0). 918 _m31(0.0). 919 _m32(0.0). 920 _m33(1.0). 921 _properties(PROPERTY_AFFINE); 922 } 923 924 /** 925 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to that of the given {@link Matrix4d} 926 * and don't change the other elements. 927 * 928 * @param mat 929 * the {@link Matrix4d} 930 * @return this 931 */ 932 ref public Matrix4d set3x3(Matrix4d mat) return { 933 return 934 _m00(mat.m00). 935 _m01(mat.m01). 936 _m02(mat.m02). 937 _m10(mat.m10). 938 _m11(mat.m11). 939 _m12(mat.m12). 940 _m20(mat.m20). 941 _m21(mat.m21). 942 _m22(mat.m22). 943 _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE)); 944 } 945 946 /** 947 * Set the upper 4x3 submatrix of this {@link Matrix4d} to the given {@link Matrix4x3d} 948 * and don't change the other elements. 949 * 950 * @see Matrix4x3d#get(Matrix4d) 951 * 952 * @param mat 953 * the {@link Matrix4x3d} 954 * @return this 955 */ 956 ref public Matrix4d set4x3(Matrix4x3d mat) return { 957 return 958 _m00(mat.m00). 959 _m01(mat.m01). 960 _m02(mat.m02). 961 _m10(mat.m10). 962 _m11(mat.m11). 963 _m12(mat.m12). 964 _m20(mat.m20). 965 _m21(mat.m21). 966 _m22(mat.m22). 967 _m30(mat.m30). 968 _m31(mat.m31). 969 _m32(mat.m32). 970 _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE)); 971 } 972 973 974 /** 975 * Set the upper 4x3 submatrix of this {@link Matrix4d} to the upper 4x3 submatrix of the given {@link Matrix4d} 976 * and don't change the other elements. 977 * 978 * @param mat 979 * the {@link Matrix4d} 980 * @return this 981 */ 982 ref public Matrix4d set4x3(Matrix4d mat) return { 983 return 984 _m00(mat.m00). 985 _m01(mat.m01). 986 _m02(mat.m02). 987 _m10(mat.m10). 988 _m11(mat.m11). 989 _m12(mat.m12). 990 _m20(mat.m20). 991 _m21(mat.m21). 992 _m22(mat.m22). 993 _m30(mat.m30). 994 _m31(mat.m31). 995 _m32(mat.m32). 996 _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE)); 997 } 998 999 /** 1000 * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}. 1001 * 1002 * @param axisAngle 1003 * the {@link AxisAngle4d} 1004 * @return this 1005 */ 1006 ref public Matrix4d set(ref AxisAngle4d axisAngle) return { 1007 double x = axisAngle.x; 1008 double y = axisAngle.y; 1009 double z = axisAngle.z; 1010 double angle = axisAngle.angle; 1011 double invLength = Math.invsqrt(x*x + y*y + z*z); 1012 x *= invLength; 1013 y *= invLength; 1014 z *= invLength; 1015 double s = Math.sin(angle); 1016 double c = Math.cosFromSin(s, angle); 1017 double omc = 1.0 - c; 1018 _m00(c + x*x*omc). 1019 _m11(c + y*y*omc). 1020 _m22(c + z*z*omc); 1021 double tmp1 = x*y*omc; 1022 double tmp2 = z*s; 1023 _m10(tmp1 - tmp2). 1024 _m01(tmp1 + tmp2); 1025 tmp1 = x*z*omc; 1026 tmp2 = y*s; 1027 _m20(tmp1 + tmp2). 1028 _m02(tmp1 - tmp2); 1029 tmp1 = y*z*omc; 1030 tmp2 = x*s; 1031 _m21(tmp1 - tmp2). 1032 _m12(tmp1 + tmp2). 1033 _m03(0.0). 1034 _m13(0.0). 1035 _m23(0.0). 1036 _m30(0.0). 1037 _m31(0.0). 1038 _m32(0.0). 1039 _m33(1.0). 1040 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 1041 return this; 1042 } 1043 1044 1045 /** 1046 * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniond}. 1047 * <p> 1048 * This method is equivalent to calling: <code>rotation(q)</code> 1049 * <p> 1050 * Reference: <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/">http://www.euclideanspace.com/</a> 1051 * 1052 * @see #rotation(ref Quaterniond) 1053 * 1054 * @param q 1055 * the {@link Quaterniond} 1056 * @return this 1057 */ 1058 ref public Matrix4d set(ref Quaterniond q) return { 1059 return rotation(q); 1060 } 1061 1062 /** 1063 * Multiply this matrix by the supplied <code>right</code> matrix. 1064 * <p> 1065 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1066 * then the new matrix will be <code>M * R</code>. So when transforming a 1067 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1068 * transformation of the right matrix will be applied first! 1069 * 1070 * @param right 1071 * the right operand of the multiplication 1072 * @return this 1073 */ 1074 ref public Matrix4d mul(Matrix4d right) return { 1075 mul(right, this); 1076 return this; 1077 } 1078 1079 public Matrix4d mul(Matrix4d right, ref Matrix4d dest) { 1080 if ((properties & PROPERTY_IDENTITY) != 0) 1081 return dest.set(right); 1082 else if ((right.properties & PROPERTY_IDENTITY) != 0) 1083 return dest.set(this); 1084 else if ((properties & PROPERTY_TRANSLATION) != 0 && (right.properties & PROPERTY_AFFINE) != 0) 1085 return mulTranslationAffine(right, dest); 1086 else if ((properties & PROPERTY_AFFINE) != 0 && (right.properties & PROPERTY_AFFINE) != 0) 1087 return mulAffine(right, dest); 1088 else if ((properties & PROPERTY_PERSPECTIVE) != 0 && (right.properties & PROPERTY_AFFINE) != 0) 1089 return mulPerspectiveAffine(right, dest); 1090 else if ((right.properties & PROPERTY_AFFINE) != 0) 1091 return mulAffineR(right, dest); 1092 return mul0(right, dest); 1093 } 1094 1095 /** 1096 * Multiply this matrix by the supplied <code>right</code> matrix. 1097 * <p> 1098 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1099 * then the new matrix will be <code>M * R</code>. So when transforming a 1100 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1101 * transformation of the right matrix will be applied first! 1102 * <p> 1103 * This method neither assumes nor checks for any matrix properties of <code>this</code> or <code>right</code> 1104 * and will always perform a complete 4x4 matrix multiplication. This method should only be used whenever the 1105 * multiplied matrices do not have any properties for which there are optimized multiplication methods available. 1106 * 1107 * @param right 1108 * the right operand of the matrix multiplication 1109 * @return this 1110 */ 1111 ref public Matrix4d mul0(Matrix4d right) return { 1112 mul0(right, this); 1113 return this; 1114 } 1115 1116 public Matrix4d mul0(Matrix4d right, ref Matrix4d dest) { 1117 double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, Math.fma(m20, right.m02, m30 * right.m03))); 1118 double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, Math.fma(m21, right.m02, m31 * right.m03))); 1119 double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, Math.fma(m22, right.m02, m32 * right.m03))); 1120 double nm03 = Math.fma(m03, right.m00, Math.fma(m13, right.m01, Math.fma(m23, right.m02, m33 * right.m03))); 1121 double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, Math.fma(m20, right.m12, m30 * right.m13))); 1122 double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, Math.fma(m21, right.m12, m31 * right.m13))); 1123 double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, Math.fma(m22, right.m12, m32 * right.m13))); 1124 double nm13 = Math.fma(m03, right.m10, Math.fma(m13, right.m11, Math.fma(m23, right.m12, m33 * right.m13))); 1125 double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, Math.fma(m20, right.m22, m30 * right.m23))); 1126 double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, Math.fma(m21, right.m22, m31 * right.m23))); 1127 double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, Math.fma(m22, right.m22, m32 * right.m23))); 1128 double nm23 = Math.fma(m03, right.m20, Math.fma(m13, right.m21, Math.fma(m23, right.m22, m33 * right.m23))); 1129 double nm30 = Math.fma(m00, right.m30, Math.fma(m10, right.m31, Math.fma(m20, right.m32, m30 * right.m33))); 1130 double nm31 = Math.fma(m01, right.m30, Math.fma(m11, right.m31, Math.fma(m21, right.m32, m31 * right.m33))); 1131 double nm32 = Math.fma(m02, right.m30, Math.fma(m12, right.m31, Math.fma(m22, right.m32, m32 * right.m33))); 1132 double nm33 = Math.fma(m03, right.m30, Math.fma(m13, right.m31, Math.fma(m23, right.m32, m33 * right.m33))); 1133 return dest 1134 ._m00(nm00) 1135 ._m01(nm01) 1136 ._m02(nm02) 1137 ._m03(nm03) 1138 ._m10(nm10) 1139 ._m11(nm11) 1140 ._m12(nm12) 1141 ._m13(nm13) 1142 ._m20(nm20) 1143 ._m21(nm21) 1144 ._m22(nm22) 1145 ._m23(nm23) 1146 ._m30(nm30) 1147 ._m31(nm31) 1148 ._m32(nm32) 1149 ._m33(nm33) 1150 ._properties(0); 1151 } 1152 1153 /** 1154 * Multiply this matrix by the matrix with the supplied elements. 1155 * <p> 1156 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix whose 1157 * elements are supplied via the parameters, then the new matrix will be <code>M * R</code>. 1158 * So when transforming a vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1159 * transformation of the right matrix will be applied first! 1160 * 1161 * @param r00 1162 * the m00 element of the right matrix 1163 * @param r01 1164 * the m01 element of the right matrix 1165 * @param r02 1166 * the m02 element of the right matrix 1167 * @param r03 1168 * the m03 element of the right matrix 1169 * @param r10 1170 * the m10 element of the right matrix 1171 * @param r11 1172 * the m11 element of the right matrix 1173 * @param r12 1174 * the m12 element of the right matrix 1175 * @param r13 1176 * the m13 element of the right matrix 1177 * @param r20 1178 * the m20 element of the right matrix 1179 * @param r21 1180 * the m21 element of the right matrix 1181 * @param r22 1182 * the m22 element of the right matrix 1183 * @param r23 1184 * the m23 element of the right matrix 1185 * @param r30 1186 * the m30 element of the right matrix 1187 * @param r31 1188 * the m31 element of the right matrix 1189 * @param r32 1190 * the m32 element of the right matrix 1191 * @param r33 1192 * the m33 element of the right matrix 1193 * @return this 1194 */ 1195 ref 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) return { 1200 mul(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, this); 1201 return this; 1202 } 1203 1204 public Matrix4d mul( 1205 double r00, double r01, double r02, double r03, 1206 double r10, double r11, double r12, double r13, 1207 double r20, double r21, double r22, double r23, 1208 double r30, double r31, double r32, double r33, ref Matrix4d dest) { 1209 if ((properties & PROPERTY_IDENTITY) != 0) 1210 return dest.set(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33); 1211 else if ((properties & PROPERTY_AFFINE) != 0) 1212 return mulAffineL(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest); 1213 return mulGeneric(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest); 1214 } 1215 private Matrix4d mulAffineL( 1216 double r00, double r01, double r02, double r03, 1217 double r10, double r11, double r12, double r13, 1218 double r20, double r21, double r22, double r23, 1219 double r30, double r31, double r32, double r33, ref Matrix4d dest) { 1220 double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03))); 1221 double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03))); 1222 double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03))); 1223 double nm03 = r03; 1224 double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13))); 1225 double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13))); 1226 double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13))); 1227 double nm13 = r13; 1228 double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23))); 1229 double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23))); 1230 double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23))); 1231 double nm23 = r23; 1232 double nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33))); 1233 double nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33))); 1234 double nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33))); 1235 double nm33 = r33; 1236 return dest 1237 ._m00(nm00) 1238 ._m01(nm01) 1239 ._m02(nm02) 1240 ._m03(nm03) 1241 ._m10(nm10) 1242 ._m11(nm11) 1243 ._m12(nm12) 1244 ._m13(nm13) 1245 ._m20(nm20) 1246 ._m21(nm21) 1247 ._m22(nm22) 1248 ._m23(nm23) 1249 ._m30(nm30) 1250 ._m31(nm31) 1251 ._m32(nm32) 1252 ._m33(nm33) 1253 ._properties(PROPERTY_AFFINE); 1254 } 1255 private Matrix4d mulGeneric( 1256 double r00, double r01, double r02, double r03, 1257 double r10, double r11, double r12, double r13, 1258 double r20, double r21, double r22, double r23, 1259 double r30, double r31, double r32, double r33, ref Matrix4d dest) { 1260 double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03))); 1261 double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03))); 1262 double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03))); 1263 double nm03 = Math.fma(m03, r00, Math.fma(m13, r01, Math.fma(m23, r02, m33 * r03))); 1264 double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13))); 1265 double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13))); 1266 double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13))); 1267 double nm13 = Math.fma(m03, r10, Math.fma(m13, r11, Math.fma(m23, r12, m33 * r13))); 1268 double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23))); 1269 double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23))); 1270 double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23))); 1271 double nm23 = Math.fma(m03, r20, Math.fma(m13, r21, Math.fma(m23, r22, m33 * r23))); 1272 double nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33))); 1273 double nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33))); 1274 double nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33))); 1275 double nm33 = Math.fma(m03, r30, Math.fma(m13, r31, Math.fma(m23, r32, m33 * r33))); 1276 return dest 1277 ._m00(nm00) 1278 ._m01(nm01) 1279 ._m02(nm02) 1280 ._m03(nm03) 1281 ._m10(nm10) 1282 ._m11(nm11) 1283 ._m12(nm12) 1284 ._m13(nm13) 1285 ._m20(nm20) 1286 ._m21(nm21) 1287 ._m22(nm22) 1288 ._m23(nm23) 1289 ._m30(nm30) 1290 ._m31(nm31) 1291 ._m32(nm32) 1292 ._m33(nm33) 1293 ._properties(0); 1294 } 1295 1296 /** 1297 * Multiply this matrix by the 3x3 matrix with the supplied elements expanded to a 4x4 matrix with 1298 * all other matrix elements set to identity. 1299 * <p> 1300 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix whose 1301 * elements are supplied via the parameters, then the new matrix will be <code>M * R</code>. 1302 * So when transforming a vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1303 * transformation of the right matrix will be applied first! 1304 * 1305 * @param r00 1306 * the m00 element of the right matrix 1307 * @param r01 1308 * the m01 element of the right matrix 1309 * @param r02 1310 * the m02 element of the right matrix 1311 * @param r10 1312 * the m10 element of the right matrix 1313 * @param r11 1314 * the m11 element of the right matrix 1315 * @param r12 1316 * the m12 element of the right matrix 1317 * @param r20 1318 * the m20 element of the right matrix 1319 * @param r21 1320 * the m21 element of the right matrix 1321 * @param r22 1322 * the m22 element of the right matrix 1323 * @return this 1324 */ 1325 ref public Matrix4d mul3x3( 1326 double r00, double r01, double r02, 1327 double r10, double r11, double r12, 1328 double r20, double r21, double r22) return { 1329 mul3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, this); 1330 return this; 1331 } 1332 public Matrix4d mul3x3( 1333 double r00, double r01, double r02, 1334 double r10, double r11, double r12, 1335 double r20, double r21, double r22, ref Matrix4d dest) { 1336 if ((properties & PROPERTY_IDENTITY) != 0) 1337 return dest.set(r00, r01, r02, 0, r10, r11, r12, 0, r20, r21, r22, 0, 0, 0, 0, 1); 1338 return mulGeneric3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, dest); 1339 } 1340 private Matrix4d mulGeneric3x3( 1341 double r00, double r01, double r02, 1342 double r10, double r11, double r12, 1343 double r20, double r21, double r22, ref Matrix4d dest) { 1344 double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, m20 * r02)); 1345 double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, m21 * r02)); 1346 double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, m22 * r02)); 1347 double nm03 = Math.fma(m03, r00, Math.fma(m13, r01, m23 * r02)); 1348 double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, m20 * r12)); 1349 double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, m21 * r12)); 1350 double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, m22 * r12)); 1351 double nm13 = Math.fma(m03, r10, Math.fma(m13, r11, m23 * r12)); 1352 double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, m20 * r22)); 1353 double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, m21 * r22)); 1354 double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, m22 * r22)); 1355 double nm23 = Math.fma(m03, r20, Math.fma(m13, r21, m23 * r22)); 1356 return dest 1357 ._m00(nm00) 1358 ._m01(nm01) 1359 ._m02(nm02) 1360 ._m03(nm03) 1361 ._m10(nm10) 1362 ._m11(nm11) 1363 ._m12(nm12) 1364 ._m13(nm13) 1365 ._m20(nm20) 1366 ._m21(nm21) 1367 ._m22(nm22) 1368 ._m23(nm23) 1369 ._m30(m30) 1370 ._m31(m31) 1371 ._m32(m32) 1372 ._m33(m33) 1373 ._properties(this.properties & PROPERTY_AFFINE); 1374 } 1375 1376 /** 1377 * Pre-multiply this matrix by the supplied <code>left</code> matrix and store the result in <code>this</code>. 1378 * <p> 1379 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix, 1380 * then the new matrix will be <code>L * M</code>. So when transforming a 1381 * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the 1382 * transformation of <code>this</code> matrix will be applied first! 1383 * 1384 * @param left 1385 * the left operand of the matrix multiplication 1386 * @return this 1387 */ 1388 ref public Matrix4d mulLocal(Matrix4d left) return { 1389 mulLocal(left, this); 1390 return this; 1391 } 1392 1393 public Matrix4d mulLocal(Matrix4d left, ref Matrix4d dest) { 1394 if ((properties & PROPERTY_IDENTITY) != 0) 1395 return dest.set(left); 1396 else if ((left.properties & PROPERTY_IDENTITY) != 0) 1397 return dest.set(this); 1398 else if ((properties & PROPERTY_AFFINE) != 0 && (left.properties & PROPERTY_AFFINE) != 0) 1399 return mulLocalAffine(left, dest); 1400 return mulLocalGeneric(left, dest); 1401 } 1402 private Matrix4d mulLocalGeneric(Matrix4d left, ref Matrix4d dest) { 1403 double nm00 = Math.fma(left.m00, m00, Math.fma(left.m10, m01, Math.fma(left.m20, m02, left.m30 * m03))); 1404 double nm01 = Math.fma(left.m01, m00, Math.fma(left.m11, m01, Math.fma(left.m21, m02, left.m31 * m03))); 1405 double nm02 = Math.fma(left.m02, m00, Math.fma(left.m12, m01, Math.fma(left.m22, m02, left.m32 * m03))); 1406 double nm03 = Math.fma(left.m03, m00, Math.fma(left.m13, m01, Math.fma(left.m23, m02, left.m33 * m03))); 1407 double nm10 = Math.fma(left.m00, m10, Math.fma(left.m10, m11, Math.fma(left.m20, m12, left.m30 * m13))); 1408 double nm11 = Math.fma(left.m01, m10, Math.fma(left.m11, m11, Math.fma(left.m21, m12, left.m31 * m13))); 1409 double nm12 = Math.fma(left.m02, m10, Math.fma(left.m12, m11, Math.fma(left.m22, m12, left.m32 * m13))); 1410 double nm13 = Math.fma(left.m03, m10, Math.fma(left.m13, m11, Math.fma(left.m23, m12, left.m33 * m13))); 1411 double nm20 = Math.fma(left.m00, m20, Math.fma(left.m10, m21, Math.fma(left.m20, m22, left.m30 * m23))); 1412 double nm21 = Math.fma(left.m01, m20, Math.fma(left.m11, m21, Math.fma(left.m21, m22, left.m31 * m23))); 1413 double nm22 = Math.fma(left.m02, m20, Math.fma(left.m12, m21, Math.fma(left.m22, m22, left.m32 * m23))); 1414 double nm23 = Math.fma(left.m03, m20, Math.fma(left.m13, m21, Math.fma(left.m23, m22, left.m33 * m23))); 1415 double nm30 = Math.fma(left.m00, m30, Math.fma(left.m10, m31, Math.fma(left.m20, m32, left.m30 * m33))); 1416 double nm31 = Math.fma(left.m01, m30, Math.fma(left.m11, m31, Math.fma(left.m21, m32, left.m31 * m33))); 1417 double nm32 = Math.fma(left.m02, m30, Math.fma(left.m12, m31, Math.fma(left.m22, m32, left.m32 * m33))); 1418 double nm33 = Math.fma(left.m03, m30, Math.fma(left.m13, m31, Math.fma(left.m23, m32, left.m33 * m33))); 1419 return dest 1420 ._m00(nm00) 1421 ._m01(nm01) 1422 ._m02(nm02) 1423 ._m03(nm03) 1424 ._m10(nm10) 1425 ._m11(nm11) 1426 ._m12(nm12) 1427 ._m13(nm13) 1428 ._m20(nm20) 1429 ._m21(nm21) 1430 ._m22(nm22) 1431 ._m23(nm23) 1432 ._m30(nm30) 1433 ._m31(nm31) 1434 ._m32(nm32) 1435 ._m33(nm33) 1436 ._properties(0); 1437 } 1438 1439 /** 1440 * 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>. 1441 * <p> 1442 * This method assumes that <code>this</code> matrix and the given <code>left</code> matrix both represent an {@link #isAffine() affine} transformation 1443 * (i.e. their last rows are equal to <code>(0, 0, 0, 1)</code>) 1444 * 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). 1445 * <p> 1446 * This method will not modify either the last row of <code>this</code> or the last row of <code>left</code>. 1447 * <p> 1448 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix, 1449 * then the new matrix will be <code>L * M</code>. So when transforming a 1450 * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the 1451 * transformation of <code>this</code> matrix will be applied first! 1452 * 1453 * @param left 1454 * the left operand of the matrix multiplication (the last row is assumed to be <code>(0, 0, 0, 1)</code>) 1455 * @return this 1456 */ 1457 ref public Matrix4d mulLocalAffine(Matrix4d left) return { 1458 mulLocalAffine(left, this); 1459 return this; 1460 } 1461 1462 public Matrix4d mulLocalAffine(Matrix4d left, ref Matrix4d dest) { 1463 double nm00 = left.m00 * m00 + left.m10 * m01 + left.m20 * m02; 1464 double nm01 = left.m01 * m00 + left.m11 * m01 + left.m21 * m02; 1465 double nm02 = left.m02 * m00 + left.m12 * m01 + left.m22 * m02; 1466 double nm03 = left.m03; 1467 double nm10 = left.m00 * m10 + left.m10 * m11 + left.m20 * m12; 1468 double nm11 = left.m01 * m10 + left.m11 * m11 + left.m21 * m12; 1469 double nm12 = left.m02 * m10 + left.m12 * m11 + left.m22 * m12; 1470 double nm13 = left.m13; 1471 double nm20 = left.m00 * m20 + left.m10 * m21 + left.m20 * m22; 1472 double nm21 = left.m01 * m20 + left.m11 * m21 + left.m21 * m22; 1473 double nm22 = left.m02 * m20 + left.m12 * m21 + left.m22 * m22; 1474 double nm23 = left.m23; 1475 double nm30 = left.m00 * m30 + left.m10 * m31 + left.m20 * m32 + left.m30; 1476 double nm31 = left.m01 * m30 + left.m11 * m31 + left.m21 * m32 + left.m31; 1477 double nm32 = left.m02 * m30 + left.m12 * m31 + left.m22 * m32 + left.m32; 1478 double nm33 = left.m33; 1479 dest._m00(nm00) 1480 ._m01(nm01) 1481 ._m02(nm02) 1482 ._m03(nm03) 1483 ._m10(nm10) 1484 ._m11(nm11) 1485 ._m12(nm12) 1486 ._m13(nm13) 1487 ._m20(nm20) 1488 ._m21(nm21) 1489 ._m22(nm22) 1490 ._m23(nm23) 1491 ._m30(nm30) 1492 ._m31(nm31) 1493 ._m32(nm32) 1494 ._m33(nm33) 1495 ._properties(PROPERTY_AFFINE); 1496 return dest; 1497 } 1498 1499 /** 1500 * Multiply this matrix by the supplied <code>right</code> matrix. 1501 * <p> 1502 * The last row of the <code>right</code> matrix is assumed to be <code>(0, 0, 0, 1)</code>. 1503 * <p> 1504 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1505 * then the new matrix will be <code>M * R</code>. So when transforming a 1506 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1507 * transformation of the right matrix will be applied first! 1508 * 1509 * @param right 1510 * the right operand of the matrix multiplication 1511 * @return this 1512 */ 1513 ref public Matrix4d mul(Matrix4x3d right) return { 1514 mul(right, this); 1515 return this; 1516 } 1517 1518 public Matrix4d mul(Matrix4x3d right, ref Matrix4d dest) { 1519 if ((properties & PROPERTY_IDENTITY) != 0) 1520 return dest.set(right); 1521 else if ((right.properties & PROPERTY_IDENTITY) != 0) 1522 return dest.set(this); 1523 else if ((properties & PROPERTY_TRANSLATION) != 0) 1524 return mulTranslation(right, dest); 1525 else if ((properties & PROPERTY_AFFINE) != 0) 1526 return mulAffine(right, dest); 1527 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 1528 return mulPerspectiveAffine(right, dest); 1529 return mulGeneric(right, dest); 1530 } 1531 private Matrix4d mulTranslation(Matrix4x3d right, ref Matrix4d dest) { 1532 return dest 1533 ._m00(right.m00) 1534 ._m01(right.m01) 1535 ._m02(right.m02) 1536 ._m03(m03) 1537 ._m10(right.m10) 1538 ._m11(right.m11) 1539 ._m12(right.m12) 1540 ._m13(m13) 1541 ._m20(right.m20) 1542 ._m21(right.m21) 1543 ._m22(right.m22) 1544 ._m23(m23) 1545 ._m30(right.m30 + m30) 1546 ._m31(right.m31 + m31) 1547 ._m32(right.m32 + m32) 1548 ._m33(m33) 1549 ._properties(PROPERTY_AFFINE | (right.properties & PROPERTY_ORTHONORMAL)); 1550 } 1551 private Matrix4d mulAffine(Matrix4x3d right, ref Matrix4d dest) { 1552 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 1553 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 1554 double m20 = this.m20, m21 = this.m21, m22 = this.m22; 1555 double rm00 = right.m00, rm01 = right.m01, rm02 = right.m02; 1556 double rm10 = right.m10, rm11 = right.m11, rm12 = right.m12; 1557 double rm20 = right.m20, rm21 = right.m21, rm22 = right.m22; 1558 double rm30 = right.m30, rm31 = right.m31, rm32 = right.m32; 1559 return dest 1560 ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02))) 1561 ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02))) 1562 ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02))) 1563 ._m03(m03) 1564 ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12))) 1565 ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12))) 1566 ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12))) 1567 ._m13(m13) 1568 ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22))) 1569 ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22))) 1570 ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22))) 1571 ._m23(m23) 1572 ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30)))) 1573 ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31)))) 1574 ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32)))) 1575 ._m33(m33) 1576 ._properties(PROPERTY_AFFINE | (this.properties & right.properties & PROPERTY_ORTHONORMAL)); 1577 } 1578 private Matrix4d mulGeneric(Matrix4x3d right, ref Matrix4d dest) { 1579 double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, m20 * right.m02)); 1580 double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, m21 * right.m02)); 1581 double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, m22 * right.m02)); 1582 double nm03 = Math.fma(m03, right.m00, Math.fma(m13, right.m01, m23 * right.m02)); 1583 double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, m20 * right.m12)); 1584 double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, m21 * right.m12)); 1585 double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, m22 * right.m12)); 1586 double nm13 = Math.fma(m03, right.m10, Math.fma(m13, right.m11, m23 * right.m12)); 1587 double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, m20 * right.m22)); 1588 double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, m21 * right.m22)); 1589 double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, m22 * right.m22)); 1590 double nm23 = Math.fma(m03, right.m20, Math.fma(m13, right.m21, m23 * right.m22)); 1591 double nm30 = Math.fma(m00, right.m30, Math.fma(m10, right.m31, Math.fma(m20, right.m32, m30))); 1592 double nm31 = Math.fma(m01, right.m30, Math.fma(m11, right.m31, Math.fma(m21, right.m32, m31))); 1593 double nm32 = Math.fma(m02, right.m30, Math.fma(m12, right.m31, Math.fma(m22, right.m32, m32))); 1594 double nm33 = Math.fma(m03, right.m30, Math.fma(m13, right.m31, Math.fma(m23, right.m32, m33))); 1595 dest._m00(nm00) 1596 ._m01(nm01) 1597 ._m02(nm02) 1598 ._m03(nm03) 1599 ._m10(nm10) 1600 ._m11(nm11) 1601 ._m12(nm12) 1602 ._m13(nm13) 1603 ._m20(nm20) 1604 ._m21(nm21) 1605 ._m22(nm22) 1606 ._m23(nm23) 1607 ._m30(nm30) 1608 ._m31(nm31) 1609 ._m32(nm32) 1610 ._m33(nm33) 1611 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 1612 return dest; 1613 } 1614 public Matrix4d mulPerspectiveAffine(Matrix4x3d view, ref Matrix4d dest) { 1615 double lm00 = m00, lm11 = m11, lm22 = m22, lm23 = m23; 1616 dest._m00(lm00 * view.m00)._m01(lm11 * view.m01)._m02(lm22 * view.m02)._m03(lm23 * view.m02). 1617 _m10(lm00 * view.m10)._m11(lm11 * view.m11)._m12(lm22 * view.m12)._m13(lm23 * view.m12). 1618 _m20(lm00 * view.m20)._m21(lm11 * view.m21)._m22(lm22 * view.m22)._m23(lm23 * view.m22). 1619 _m30(lm00 * view.m30)._m31(lm11 * view.m31)._m32(lm22 * view.m32 + m32)._m33(lm23 * view.m32) 1620 ._properties(0); 1621 return dest; 1622 } 1623 1624 1625 /** 1626 * Multiply this matrix by the supplied <code>right</code> matrix and store the result in <code>this</code>. 1627 * <p> 1628 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1629 * then the new matrix will be <code>M * R</code>. So when transforming a 1630 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1631 * transformation of the right matrix will be applied first! 1632 * 1633 * @param right 1634 * the right operand of the matrix multiplication 1635 * @return this 1636 */ 1637 ref public Matrix4d mul(Matrix3x2d right) return { 1638 mul(right, this); 1639 return this; 1640 } 1641 1642 public Matrix4d mul(Matrix3x2d right, ref Matrix4d dest) { 1643 double nm00 = m00 * right.m00 + m10 * right.m01; 1644 double nm01 = m01 * right.m00 + m11 * right.m01; 1645 double nm02 = m02 * right.m00 + m12 * right.m01; 1646 double nm03 = m03 * right.m00 + m13 * right.m01; 1647 double nm10 = m00 * right.m10 + m10 * right.m11; 1648 double nm11 = m01 * right.m10 + m11 * right.m11; 1649 double nm12 = m02 * right.m10 + m12 * right.m11; 1650 double nm13 = m03 * right.m10 + m13 * right.m11; 1651 double nm30 = m00 * right.m20 + m10 * right.m21 + m30; 1652 double nm31 = m01 * right.m20 + m11 * right.m21 + m31; 1653 double nm32 = m02 * right.m20 + m12 * right.m21 + m32; 1654 double nm33 = m03 * right.m20 + m13 * right.m21 + m33; 1655 dest._m00(nm00) 1656 ._m01(nm01) 1657 ._m02(nm02) 1658 ._m03(nm03) 1659 ._m10(nm10) 1660 ._m11(nm11) 1661 ._m12(nm12) 1662 ._m13(nm13) 1663 ._m20(m20) 1664 ._m21(m21) 1665 ._m22(m22) 1666 ._m23(m23) 1667 ._m30(nm30) 1668 ._m31(nm31) 1669 ._m32(nm32) 1670 ._m33(nm33) 1671 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 1672 return dest; 1673 } 1674 1675 1676 1677 1678 /** 1679 * Multiply <code>this</code> symmetric perspective projection matrix by the supplied {@link #isAffine() affine} <code>view</code> matrix. 1680 * <p> 1681 * If <code>P</code> is <code>this</code> matrix and <code>V</code> the <code>view</code> matrix, 1682 * then the new matrix will be <code>P * V</code>. So when transforming a 1683 * vector <code>v</code> with the new matrix by using <code>P * V * v</code>, the 1684 * transformation of the <code>view</code> matrix will be applied first! 1685 * 1686 * @param view 1687 * the {@link #isAffine() affine} matrix to multiply <code>this</code> symmetric perspective projection matrix by 1688 * @return this 1689 */ 1690 ref public Matrix4d mulPerspectiveAffine(Matrix4d view) return { 1691 mulPerspectiveAffine(view, this); 1692 return this; 1693 } 1694 1695 public Matrix4d mulPerspectiveAffine(Matrix4d view, ref Matrix4d dest) { 1696 double nm00 = m00 * view.m00, nm01 = m11 * view.m01, nm02 = m22 * view.m02, nm03 = m23 * view.m02; 1697 double nm10 = m00 * view.m10, nm11 = m11 * view.m11, nm12 = m22 * view.m12, nm13 = m23 * view.m12; 1698 double nm20 = m00 * view.m20, nm21 = m11 * view.m21, nm22 = m22 * view.m22, nm23 = m23 * view.m22; 1699 double nm30 = m00 * view.m30, nm31 = m11 * view.m31, nm32 = m22 * view.m32 + m32, nm33 = m23 * view.m32; 1700 return dest 1701 ._m00(nm00)._m01(nm01)._m02(nm02)._m03(nm03) 1702 ._m10(nm10)._m11(nm11)._m12(nm12)._m13(nm13) 1703 ._m20(nm20)._m21(nm21)._m22(nm22)._m23(nm23) 1704 ._m30(nm30)._m31(nm31)._m32(nm32)._m33(nm33) 1705 ._properties(0); 1706 } 1707 1708 /** 1709 * 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>. 1710 * <p> 1711 * 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>) 1712 * 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). 1713 * <p> 1714 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1715 * then the new matrix will be <code>M * R</code>. So when transforming a 1716 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1717 * transformation of the right matrix will be applied first! 1718 * 1719 * @param right 1720 * the right operand of the matrix multiplication (the last row is assumed to be <code>(0, 0, 0, 1)</code>) 1721 * @return this 1722 */ 1723 ref public Matrix4d mulAffineR(Matrix4d right) return { 1724 mulAffineR(right, this); 1725 return this; 1726 } 1727 1728 public Matrix4d mulAffineR(Matrix4d right, ref Matrix4d dest) { 1729 double nm00 = Math.fma(m00, right.m00, Math.fma(m10, right.m01, m20 * right.m02)); 1730 double nm01 = Math.fma(m01, right.m00, Math.fma(m11, right.m01, m21 * right.m02)); 1731 double nm02 = Math.fma(m02, right.m00, Math.fma(m12, right.m01, m22 * right.m02)); 1732 double nm03 = Math.fma(m03, right.m00, Math.fma(m13, right.m01, m23 * right.m02)); 1733 double nm10 = Math.fma(m00, right.m10, Math.fma(m10, right.m11, m20 * right.m12)); 1734 double nm11 = Math.fma(m01, right.m10, Math.fma(m11, right.m11, m21 * right.m12)); 1735 double nm12 = Math.fma(m02, right.m10, Math.fma(m12, right.m11, m22 * right.m12)); 1736 double nm13 = Math.fma(m03, right.m10, Math.fma(m13, right.m11, m23 * right.m12)); 1737 double nm20 = Math.fma(m00, right.m20, Math.fma(m10, right.m21, m20 * right.m22)); 1738 double nm21 = Math.fma(m01, right.m20, Math.fma(m11, right.m21, m21 * right.m22)); 1739 double nm22 = Math.fma(m02, right.m20, Math.fma(m12, right.m21, m22 * right.m22)); 1740 double nm23 = Math.fma(m03, right.m20, Math.fma(m13, right.m21, m23 * right.m22)); 1741 double nm30 = Math.fma(m00, right.m30, Math.fma(m10, right.m31, Math.fma(m20, right.m32, m30))); 1742 double nm31 = Math.fma(m01, right.m30, Math.fma(m11, right.m31, Math.fma(m21, right.m32, m31))); 1743 double nm32 = Math.fma(m02, right.m30, Math.fma(m12, right.m31, Math.fma(m22, right.m32, m32))); 1744 double nm33 = Math.fma(m03, right.m30, Math.fma(m13, right.m31, Math.fma(m23, right.m32, m33))); 1745 dest._m00(nm00) 1746 ._m01(nm01) 1747 ._m02(nm02) 1748 ._m03(nm03) 1749 ._m10(nm10) 1750 ._m11(nm11) 1751 ._m12(nm12) 1752 ._m13(nm13) 1753 ._m20(nm20) 1754 ._m21(nm21) 1755 ._m22(nm22) 1756 ._m23(nm23) 1757 ._m30(nm30) 1758 ._m31(nm31) 1759 ._m32(nm32) 1760 ._m33(nm33) 1761 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 1762 return dest; 1763 } 1764 1765 /** 1766 * 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>. 1767 * <p> 1768 * This method assumes that <code>this</code> matrix and the given <code>right</code> matrix both represent an {@link #isAffine() affine} transformation 1769 * (i.e. their last rows are equal to <code>(0, 0, 0, 1)</code>) 1770 * 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). 1771 * <p> 1772 * This method will not modify either the last row of <code>this</code> or the last row of <code>right</code>. 1773 * <p> 1774 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 1775 * then the new matrix will be <code>M * R</code>. So when transforming a 1776 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 1777 * transformation of the right matrix will be applied first! 1778 * 1779 * @param right 1780 * the right operand of the matrix multiplication (the last row is assumed to be <code>(0, 0, 0, 1)</code>) 1781 * @return this 1782 */ 1783 ref public Matrix4d mulAffine(Matrix4d right) return { 1784 mulAffine(right, this); 1785 return this; 1786 } 1787 1788 public Matrix4d mulAffine(Matrix4d right, ref Matrix4d dest) { 1789 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 1790 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 1791 double m20 = this.m20, m21 = this.m21, m22 = this.m22; 1792 double rm00 = right.m00, rm01 = right.m01, rm02 = right.m02; 1793 double rm10 = right.m10, rm11 = right.m11, rm12 = right.m12; 1794 double rm20 = right.m20, rm21 = right.m21, rm22 = right.m22; 1795 double rm30 = right.m30, rm31 = right.m31, rm32 = right.m32; 1796 return dest 1797 ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02))) 1798 ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02))) 1799 ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02))) 1800 ._m03(m03) 1801 ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12))) 1802 ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12))) 1803 ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12))) 1804 ._m13(m13) 1805 ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22))) 1806 ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22))) 1807 ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22))) 1808 ._m23(m23) 1809 ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30)))) 1810 ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31)))) 1811 ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32)))) 1812 ._m33(m33) 1813 ._properties(PROPERTY_AFFINE | (this.properties & right.properties & PROPERTY_ORTHONORMAL)); 1814 } 1815 1816 public Matrix4d mulTranslationAffine(Matrix4d right, ref Matrix4d dest) { 1817 return dest 1818 ._m00(right.m00) 1819 ._m01(right.m01) 1820 ._m02(right.m02) 1821 ._m03(m03) 1822 ._m10(right.m10) 1823 ._m11(right.m11) 1824 ._m12(right.m12) 1825 ._m13(m13) 1826 ._m20(right.m20) 1827 ._m21(right.m21) 1828 ._m22(right.m22) 1829 ._m23(m23) 1830 ._m30(right.m30 + m30) 1831 ._m31(right.m31 + m31) 1832 ._m32(right.m32 + m32) 1833 ._m33(m33) 1834 ._properties(PROPERTY_AFFINE | (right.properties & PROPERTY_ORTHONORMAL)); 1835 } 1836 1837 /** 1838 * Multiply <code>this</code> orthographic projection matrix by the supplied {@link #isAffine() affine} <code>view</code> matrix. 1839 * <p> 1840 * If <code>M</code> is <code>this</code> matrix and <code>V</code> the <code>view</code> matrix, 1841 * then the new matrix will be <code>M * V</code>. So when transforming a 1842 * vector <code>v</code> with the new matrix by using <code>M * V * v</code>, the 1843 * transformation of the <code>view</code> matrix will be applied first! 1844 * 1845 * @param view 1846 * the affine matrix which to multiply <code>this</code> with 1847 * @return this 1848 */ 1849 ref public Matrix4d mulOrthoAffine(Matrix4d view) return { 1850 mulOrthoAffine(view, this); 1851 return this; 1852 } 1853 1854 public Matrix4d mulOrthoAffine(Matrix4d view, ref Matrix4d dest) { 1855 double nm00 = m00 * view.m00; 1856 double nm01 = m11 * view.m01; 1857 double nm02 = m22 * view.m02; 1858 double nm03 = 0.0; 1859 double nm10 = m00 * view.m10; 1860 double nm11 = m11 * view.m11; 1861 double nm12 = m22 * view.m12; 1862 double nm13 = 0.0; 1863 double nm20 = m00 * view.m20; 1864 double nm21 = m11 * view.m21; 1865 double nm22 = m22 * view.m22; 1866 double nm23 = 0.0; 1867 double nm30 = m00 * view.m30 + m30; 1868 double nm31 = m11 * view.m31 + m31; 1869 double nm32 = m22 * view.m32 + m32; 1870 double nm33 = 1.0; 1871 dest._m00(nm00) 1872 ._m01(nm01) 1873 ._m02(nm02) 1874 ._m03(nm03) 1875 ._m10(nm10) 1876 ._m11(nm11) 1877 ._m12(nm12) 1878 ._m13(nm13) 1879 ._m20(nm20) 1880 ._m21(nm21) 1881 ._m22(nm22) 1882 ._m23(nm23) 1883 ._m30(nm30) 1884 ._m31(nm31) 1885 ._m32(nm32) 1886 ._m33(nm33) 1887 ._properties(PROPERTY_AFFINE); 1888 return dest; 1889 } 1890 1891 /** 1892 * Component-wise add the upper 4x3 submatrices of <code>this</code> and <code>other</code> 1893 * by first multiplying each component of <code>other</code>'s 4x3 submatrix by <code>otherFactor</code> and 1894 * adding that result to <code>this</code>. 1895 * <p> 1896 * The matrix <code>other</code> will not be changed. 1897 * 1898 * @param other 1899 * the other matrix 1900 * @param otherFactor 1901 * the factor to multiply each of the other matrix's 4x3 components 1902 * @return this 1903 */ 1904 ref public Matrix4d fma4x3(Matrix4d other, double otherFactor) return { 1905 fma4x3(other, otherFactor, this); 1906 return this; 1907 } 1908 1909 public Matrix4d fma4x3(Matrix4d other, double otherFactor, ref Matrix4d dest) { 1910 dest._m00(Math.fma(other.m00, otherFactor, m00)) 1911 ._m01(Math.fma(other.m01, otherFactor, m01)) 1912 ._m02(Math.fma(other.m02, otherFactor, m02)) 1913 ._m03(m03) 1914 ._m10(Math.fma(other.m10, otherFactor, m10)) 1915 ._m11(Math.fma(other.m11, otherFactor, m11)) 1916 ._m12(Math.fma(other.m12, otherFactor, m12)) 1917 ._m13(m13) 1918 ._m20(Math.fma(other.m20, otherFactor, m20)) 1919 ._m21(Math.fma(other.m21, otherFactor, m21)) 1920 ._m22(Math.fma(other.m22, otherFactor, m22)) 1921 ._m23(m23) 1922 ._m30(Math.fma(other.m30, otherFactor, m30)) 1923 ._m31(Math.fma(other.m31, otherFactor, m31)) 1924 ._m32(Math.fma(other.m32, otherFactor, m32)) 1925 ._m33(m33) 1926 ._properties(0); 1927 return dest; 1928 } 1929 1930 /** 1931 * Component-wise add <code>this</code> and <code>other</code>. 1932 * 1933 * @param other 1934 * the other addend 1935 * @return this 1936 */ 1937 ref public Matrix4d add(Matrix4d other) return { 1938 add(other, this); 1939 return this; 1940 } 1941 1942 public Matrix4d add(Matrix4d other, ref Matrix4d dest) { 1943 dest._m00(m00 + other.m00) 1944 ._m01(m01 + other.m01) 1945 ._m02(m02 + other.m02) 1946 ._m03(m03 + other.m03) 1947 ._m10(m10 + other.m10) 1948 ._m11(m11 + other.m11) 1949 ._m12(m12 + other.m12) 1950 ._m13(m13 + other.m13) 1951 ._m20(m20 + other.m20) 1952 ._m21(m21 + other.m21) 1953 ._m22(m22 + other.m22) 1954 ._m23(m23 + other.m23) 1955 ._m30(m30 + other.m30) 1956 ._m31(m31 + other.m31) 1957 ._m32(m32 + other.m32) 1958 ._m33(m33 + other.m33) 1959 ._properties(0); 1960 return dest; 1961 } 1962 1963 /** 1964 * Component-wise subtract <code>subtrahend</code> from <code>this</code>. 1965 * 1966 * @param subtrahend 1967 * the subtrahend 1968 * @return this 1969 */ 1970 ref public Matrix4d sub(Matrix4d subtrahend) return { 1971 sub(subtrahend, this); 1972 return this; 1973 } 1974 1975 public Matrix4d sub(Matrix4d subtrahend, ref Matrix4d dest) { 1976 dest._m00(m00 - subtrahend.m00) 1977 ._m01(m01 - subtrahend.m01) 1978 ._m02(m02 - subtrahend.m02) 1979 ._m03(m03 - subtrahend.m03) 1980 ._m10(m10 - subtrahend.m10) 1981 ._m11(m11 - subtrahend.m11) 1982 ._m12(m12 - subtrahend.m12) 1983 ._m13(m13 - subtrahend.m13) 1984 ._m20(m20 - subtrahend.m20) 1985 ._m21(m21 - subtrahend.m21) 1986 ._m22(m22 - subtrahend.m22) 1987 ._m23(m23 - subtrahend.m23) 1988 ._m30(m30 - subtrahend.m30) 1989 ._m31(m31 - subtrahend.m31) 1990 ._m32(m32 - subtrahend.m32) 1991 ._m33(m33 - subtrahend.m33) 1992 ._properties(0); 1993 return dest; 1994 } 1995 1996 /** 1997 * Component-wise multiply <code>this</code> by <code>other</code>. 1998 * 1999 * @param other 2000 * the other matrix 2001 * @return this 2002 */ 2003 ref public Matrix4d mulComponentWise(Matrix4d other) return { 2004 mulComponentWise(other, this); 2005 return this; 2006 } 2007 2008 public Matrix4d mulComponentWise(Matrix4d other, ref Matrix4d dest) { 2009 dest._m00(m00 * other.m00) 2010 ._m01(m01 * other.m01) 2011 ._m02(m02 * other.m02) 2012 ._m03(m03 * other.m03) 2013 ._m10(m10 * other.m10) 2014 ._m11(m11 * other.m11) 2015 ._m12(m12 * other.m12) 2016 ._m13(m13 * other.m13) 2017 ._m20(m20 * other.m20) 2018 ._m21(m21 * other.m21) 2019 ._m22(m22 * other.m22) 2020 ._m23(m23 * other.m23) 2021 ._m30(m30 * other.m30) 2022 ._m31(m31 * other.m31) 2023 ._m32(m32 * other.m32) 2024 ._m33(m33 * other.m33) 2025 ._properties(0); 2026 return dest; 2027 } 2028 2029 /** 2030 * Component-wise add the upper 4x3 submatrices of <code>this</code> and <code>other</code>. 2031 * 2032 * @param other 2033 * the other addend 2034 * @return this 2035 */ 2036 ref public Matrix4d add4x3(Matrix4d other) return { 2037 add4x3(other, this); 2038 return this; 2039 } 2040 2041 public Matrix4d add4x3(Matrix4d other, ref Matrix4d dest) { 2042 dest._m00(m00 + other.m00) 2043 ._m01(m01 + other.m01) 2044 ._m02(m02 + other.m02) 2045 ._m03(m03) 2046 ._m10(m10 + other.m10) 2047 ._m11(m11 + other.m11) 2048 ._m12(m12 + other.m12) 2049 ._m13(m13) 2050 ._m20(m20 + other.m20) 2051 ._m21(m21 + other.m21) 2052 ._m22(m22 + other.m22) 2053 ._m23(m23) 2054 ._m30(m30 + other.m30) 2055 ._m31(m31 + other.m31) 2056 ._m32(m32 + other.m32) 2057 ._m33(m33) 2058 ._properties(0); 2059 return dest; 2060 } 2061 2062 /** 2063 * Component-wise subtract the upper 4x3 submatrices of <code>subtrahend</code> from <code>this</code>. 2064 * 2065 * @param subtrahend 2066 * the subtrahend 2067 * @return this 2068 */ 2069 ref public Matrix4d sub4x3(Matrix4d subtrahend) return { 2070 sub4x3(subtrahend, this); 2071 return this; 2072 } 2073 2074 public Matrix4d sub4x3(Matrix4d subtrahend, ref Matrix4d dest) { 2075 dest._m00(m00 - subtrahend.m00) 2076 ._m01(m01 - subtrahend.m01) 2077 ._m02(m02 - subtrahend.m02) 2078 ._m03(m03) 2079 ._m10(m10 - subtrahend.m10) 2080 ._m11(m11 - subtrahend.m11) 2081 ._m12(m12 - subtrahend.m12) 2082 ._m13(m13) 2083 ._m20(m20 - subtrahend.m20) 2084 ._m21(m21 - subtrahend.m21) 2085 ._m22(m22 - subtrahend.m22) 2086 ._m23(m23) 2087 ._m30(m30 - subtrahend.m30) 2088 ._m31(m31 - subtrahend.m31) 2089 ._m32(m32 - subtrahend.m32) 2090 ._m33(m33) 2091 ._properties(0); 2092 return dest; 2093 } 2094 2095 /** 2096 * Component-wise multiply the upper 4x3 submatrices of <code>this</code> by <code>other</code>. 2097 * 2098 * @param other 2099 * the other matrix 2100 * @return this 2101 */ 2102 ref public Matrix4d mul4x3ComponentWise(Matrix4d other) return { 2103 mul4x3ComponentWise(other, this); 2104 return this; 2105 } 2106 2107 public Matrix4d mul4x3ComponentWise(Matrix4d other, ref Matrix4d dest) { 2108 dest._m00(m00 * other.m00) 2109 ._m01(m01 * other.m01) 2110 ._m02(m02 * other.m02) 2111 ._m03(m03) 2112 ._m10(m10 * other.m10) 2113 ._m11(m11 * other.m11) 2114 ._m12(m12 * other.m12) 2115 ._m13(m13) 2116 ._m20(m20 * other.m20) 2117 ._m21(m21 * other.m21) 2118 ._m22(m22 * other.m22) 2119 ._m23(m23) 2120 ._m30(m30 * other.m30) 2121 ._m31(m31 * other.m31) 2122 ._m32(m32 * other.m32) 2123 ._m33(m33) 2124 ._properties(0); 2125 return dest; 2126 } 2127 2128 /** Set the values within this matrix to the supplied double values. The matrix will look like this:<br><br> 2129 * 2130 * m00, m10, m20, m30<br> 2131 * m01, m11, m21, m31<br> 2132 * m02, m12, m22, m32<br> 2133 * m03, m13, m23, m33 2134 * 2135 * @param m00 2136 * the new value of m00 2137 * @param m01 2138 * the new value of m01 2139 * @param m02 2140 * the new value of m02 2141 * @param m03 2142 * the new value of m03 2143 * @param m10 2144 * the new value of m10 2145 * @param m11 2146 * the new value of m11 2147 * @param m12 2148 * the new value of m12 2149 * @param m13 2150 * the new value of m13 2151 * @param m20 2152 * the new value of m20 2153 * @param m21 2154 * the new value of m21 2155 * @param m22 2156 * the new value of m22 2157 * @param m23 2158 * the new value of m23 2159 * @param m30 2160 * the new value of m30 2161 * @param m31 2162 * the new value of m31 2163 * @param m32 2164 * the new value of m32 2165 * @param m33 2166 * the new value of m33 2167 * @return this 2168 */ 2169 ref public Matrix4d set(double m00, double m01, double m02,double m03, 2170 double m10, double m11, double m12, double m13, 2171 double m20, double m21, double m22, double m23, 2172 double m30, double m31, double m32, double m33) return { 2173 setm00(m00); 2174 setm10(m10); 2175 setm20(m20); 2176 setm30(m30); 2177 setm01(m01); 2178 setm11(m11); 2179 setm21(m21); 2180 setm31(m31); 2181 setm02(m02); 2182 setm12(m12); 2183 setm22(m22); 2184 setm32(m32); 2185 setm03(m03); 2186 setm13(m13); 2187 setm23(m23); 2188 setm33(m33); 2189 return determineProperties(); 2190 } 2191 2192 2193 /** 2194 * Set the values in the matrix using a double array that contains the matrix elements in column-major order. 2195 * <p> 2196 * The results will look like this:<br><br> 2197 * 2198 * 0, 4, 8, 12<br> 2199 * 1, 5, 9, 13<br> 2200 * 2, 6, 10, 14<br> 2201 * 3, 7, 11, 15<br> 2202 * 2203 * @see #set(double[], int) 2204 * 2205 * @param m 2206 * the array to read the matrix values from 2207 * @return this 2208 */ 2209 ref public Matrix4d set(double[] m) return { 2210 return set(m, 0); 2211 } 2212 2213 /** 2214 * Set the values in the matrix using a double array that contains the matrix elements in column-major order. 2215 * <p> 2216 * The results will look like this:<br><br> 2217 * 2218 * 0, 4, 8, 12<br> 2219 * 1, 5, 9, 13<br> 2220 * 2, 6, 10, 14<br> 2221 * 3, 7, 11, 15<br> 2222 * 2223 * @see #set(double[]) 2224 * 2225 * @param m 2226 * the array to read the matrix values from 2227 * @param off 2228 * the offset into the array 2229 * @return this 2230 */ 2231 ref public Matrix4d set(double[] m, int off) return { 2232 return 2233 _m00(m[off+0]). 2234 _m01(m[off+1]). 2235 _m02(m[off+2]). 2236 _m03(m[off+3]). 2237 _m10(m[off+4]). 2238 _m11(m[off+5]). 2239 _m12(m[off+6]). 2240 _m13(m[off+7]). 2241 _m20(m[off+8]). 2242 _m21(m[off+9]). 2243 _m22(m[off+10]). 2244 _m23(m[off+11]). 2245 _m30(m[off+12]). 2246 _m31(m[off+13]). 2247 _m32(m[off+14]). 2248 _m33(m[off+15]). 2249 determineProperties(); 2250 } 2251 2252 2253 /** 2254 * Set the four columns of this matrix to the supplied vectors, respectively. 2255 * 2256 * @param col0 2257 * the first column 2258 * @param col1 2259 * the second column 2260 * @param col2 2261 * the third column 2262 * @param col3 2263 * the fourth column 2264 * @return this 2265 */ 2266 ref public Matrix4d set(ref Vector4d col0, Vector4d col1, Vector4d col2, Vector4d col3) return { 2267 return 2268 _m00(col0.x). 2269 _m01(col0.y). 2270 _m02(col0.z). 2271 _m03(col0.w). 2272 _m10(col1.x). 2273 _m11(col1.y). 2274 _m12(col1.z). 2275 _m13(col1.w). 2276 _m20(col2.x). 2277 _m21(col2.y). 2278 _m22(col2.z). 2279 _m23(col2.w). 2280 _m30(col3.x). 2281 _m31(col3.y). 2282 _m32(col3.z). 2283 _m33(col3.w). 2284 determineProperties(); 2285 } 2286 2287 public double determinant() { 2288 if ((properties & PROPERTY_AFFINE) != 0) 2289 return determinantAffine(); 2290 return (m00 * m11 - m01 * m10) * (m22 * m33 - m23 * m32) 2291 + (m02 * m10 - m00 * m12) * (m21 * m33 - m23 * m31) 2292 + (m00 * m13 - m03 * m10) * (m21 * m32 - m22 * m31) 2293 + (m01 * m12 - m02 * m11) * (m20 * m33 - m23 * m30) 2294 + (m03 * m11 - m01 * m13) * (m20 * m32 - m22 * m30) 2295 + (m02 * m13 - m03 * m12) * (m20 * m31 - m21 * m30); 2296 } 2297 2298 public double determinant3x3() { 2299 return (m00 * m11 - m01 * m10) * m22 2300 + (m02 * m10 - m00 * m12) * m21 2301 + (m01 * m12 - m02 * m11) * m20; 2302 } 2303 2304 public double determinantAffine() { 2305 return (m00 * m11 - m01 * m10) * m22 2306 + (m02 * m10 - m00 * m12) * m21 2307 + (m01 * m12 - m02 * m11) * m20; 2308 } 2309 2310 /** 2311 * Invert this matrix. 2312 * <p> 2313 * If <code>this</code> matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing, 2314 * and thus its last row is equal to <code>(0, 0, 0, 1)</code>, then {@link #invertAffine()} can be used instead of this method. 2315 * 2316 * @see #invertAffine() 2317 * 2318 * @return this 2319 */ 2320 ref public Matrix4d invert() return { 2321 invert(this); 2322 return this; 2323 } 2324 2325 public Matrix4d invert(ref Matrix4d dest) { 2326 if ((properties & PROPERTY_IDENTITY) != 0) 2327 return dest.identity(); 2328 else if ((properties & PROPERTY_TRANSLATION) != 0) 2329 return invertTranslation(dest); 2330 else if ((properties & PROPERTY_ORTHONORMAL) != 0) 2331 return invertOrthonormal(dest); 2332 else if ((properties & PROPERTY_AFFINE) != 0) 2333 return invertAffine(dest); 2334 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 2335 return invertPerspective(dest); 2336 return invertGeneric(dest); 2337 } 2338 private Matrix4d invertTranslation(ref Matrix4d dest) { 2339 if (dest != this) 2340 dest.set(this); 2341 dest._m30(-m30) 2342 ._m31(-m31) 2343 ._m32(-m32) 2344 ._properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL); 2345 return dest; 2346 } 2347 private Matrix4d invertOrthonormal(ref Matrix4d dest) { 2348 double nm30 = -(m00 * m30 + m01 * m31 + m02 * m32); 2349 double nm31 = -(m10 * m30 + m11 * m31 + m12 * m32); 2350 double nm32 = -(m20 * m30 + m21 * m31 + m22 * m32); 2351 double m01 = this.m01; 2352 double m02 = this.m02; 2353 double m12 = this.m12; 2354 dest._m00(m00) 2355 ._m01(m10) 2356 ._m02(m20) 2357 ._m03(0.0) 2358 ._m10(m01) 2359 ._m11(m11) 2360 ._m12(m21) 2361 ._m13(0.0) 2362 ._m20(m02) 2363 ._m21(m12) 2364 ._m22(m22) 2365 ._m23(0.0) 2366 ._m30(nm30) 2367 ._m31(nm31) 2368 ._m32(nm32) 2369 ._m33(1.0) 2370 ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 2371 return dest; 2372 } 2373 private Matrix4d invertGeneric(ref Matrix4d dest) { 2374 if (this != dest) 2375 return invertGenericNonThis(dest); 2376 return invertGenericThis(dest); 2377 } 2378 private Matrix4d invertGenericNonThis(ref Matrix4d dest) { 2379 double a = m00 * m11 - m01 * m10; 2380 double b = m00 * m12 - m02 * m10; 2381 double c = m00 * m13 - m03 * m10; 2382 double d = m01 * m12 - m02 * m11; 2383 double e = m01 * m13 - m03 * m11; 2384 double f = m02 * m13 - m03 * m12; 2385 double g = m20 * m31 - m21 * m30; 2386 double h = m20 * m32 - m22 * m30; 2387 double i = m20 * m33 - m23 * m30; 2388 double j = m21 * m32 - m22 * m31; 2389 double k = m21 * m33 - m23 * m31; 2390 double l = m22 * m33 - m23 * m32; 2391 double det = a * l - b * k + c * j + d * i - e * h + f * g; 2392 det = 1.0 / det; 2393 return dest 2394 ._m00(Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det) 2395 ._m01(Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det) 2396 ._m02(Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det) 2397 ._m03(Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det) 2398 ._m10(Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det) 2399 ._m11(Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det) 2400 ._m12(Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det) 2401 ._m13(Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det) 2402 ._m20(Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det) 2403 ._m21(Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det) 2404 ._m22(Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det) 2405 ._m23(Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det) 2406 ._m30(Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det) 2407 ._m31(Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det) 2408 ._m32(Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det) 2409 ._m33(Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det) 2410 ._properties(0); 2411 } 2412 private Matrix4d invertGenericThis(ref Matrix4d dest) { 2413 double a = m00 * m11 - m01 * m10; 2414 double b = m00 * m12 - m02 * m10; 2415 double c = m00 * m13 - m03 * m10; 2416 double d = m01 * m12 - m02 * m11; 2417 double e = m01 * m13 - m03 * m11; 2418 double f = m02 * m13 - m03 * m12; 2419 double g = m20 * m31 - m21 * m30; 2420 double h = m20 * m32 - m22 * m30; 2421 double i = m20 * m33 - m23 * m30; 2422 double j = m21 * m32 - m22 * m31; 2423 double k = m21 * m33 - m23 * m31; 2424 double l = m22 * m33 - m23 * m32; 2425 double det = a * l - b * k + c * j + d * i - e * h + f * g; 2426 det = 1.0 / det; 2427 double nm00 = Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det; 2428 double nm01 = Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det; 2429 double nm02 = Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det; 2430 double nm03 = Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det; 2431 double nm10 = Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det; 2432 double nm11 = Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det; 2433 double nm12 = Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det; 2434 double nm13 = Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det; 2435 double nm20 = Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det; 2436 double nm21 = Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det; 2437 double nm22 = Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det; 2438 double nm23 = Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det; 2439 double nm30 = Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det; 2440 double nm31 = Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det; 2441 double nm32 = Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det; 2442 double nm33 = Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det; 2443 return dest 2444 ._m00(nm00) 2445 ._m01(nm01) 2446 ._m02(nm02) 2447 ._m03(nm03) 2448 ._m10(nm10) 2449 ._m11(nm11) 2450 ._m12(nm12) 2451 ._m13(nm13) 2452 ._m20(nm20) 2453 ._m21(nm21) 2454 ._m22(nm22) 2455 ._m23(nm23) 2456 ._m30(nm30) 2457 ._m31(nm31) 2458 ._m32(nm32) 2459 ._m33(nm33) 2460 ._properties(0); 2461 } 2462 2463 public Matrix4d invertPerspective(ref Matrix4d dest) { 2464 double a = 1.0 / (m00 * m11); 2465 double l = -1.0 / (m23 * m32); 2466 dest.set(m11 * a, 0, 0, 0, 2467 0, m00 * a, 0, 0, 2468 0, 0, 0, -m23 * l, 2469 0, 0, -m32 * l, m22 * l); 2470 return dest; 2471 } 2472 2473 /** 2474 * If <code>this</code> is a perspective projection matrix obtained via one of the {@link #perspective(double, double, double, double) perspective()} methods 2475 * or via {@link #setPerspective(double, double, double, double) setPerspective()}, that is, if <code>this</code> is a symmetrical perspective frustum transformation, 2476 * then this method builds the inverse of <code>this</code>. 2477 * <p> 2478 * 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()}. 2479 * 2480 * @see #perspective(double, double, double, double) 2481 * 2482 * @return this 2483 */ 2484 ref public Matrix4d invertPerspective() return { 2485 invertPerspective(this); 2486 return this; 2487 } 2488 2489 public Matrix4d invertFrustum(ref Matrix4d dest) { 2490 double invM00 = 1.0 / m00; 2491 double invM11 = 1.0 / m11; 2492 double invM23 = 1.0 / m23; 2493 double invM32 = 1.0 / m32; 2494 dest.set(invM00, 0, 0, 0, 2495 0, invM11, 0, 0, 2496 0, 0, 0, invM32, 2497 -m20 * invM00 * invM23, -m21 * invM11 * invM23, invM23, -m22 * invM23 * invM32); 2498 return dest; 2499 } 2500 2501 /** 2502 * 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 2503 * or via {@link #setFrustum(double, double, double, double, double, double) setFrustum()}, 2504 * then this method builds the inverse of <code>this</code>. 2505 * <p> 2506 * This method can be used to quickly obtain the inverse of a perspective projection matrix. 2507 * <p> 2508 * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(double, double, double, double) perspective()}, then 2509 * {@link #invertPerspective()} should be used instead. 2510 * 2511 * @see #frustum(double, double, double, double, double, double) 2512 * @see #invertPerspective() 2513 * 2514 * @return this 2515 */ 2516 ref public Matrix4d invertFrustum() return { 2517 invertFrustum(this); 2518 return this; 2519 } 2520 2521 public Matrix4d invertOrtho(ref Matrix4d dest) { 2522 double invM00 = 1.0 / m00; 2523 double invM11 = 1.0 / m11; 2524 double invM22 = 1.0 / m22; 2525 dest.set(invM00, 0, 0, 0, 2526 0, invM11, 0, 0, 2527 0, 0, invM22, 0, 2528 -m30 * invM00, -m31 * invM11, -m32 * invM22, 1) 2529 ._properties(PROPERTY_AFFINE | (this.properties & PROPERTY_ORTHONORMAL)); 2530 return dest; 2531 } 2532 2533 /** 2534 * Invert <code>this</code> orthographic projection matrix. 2535 * <p> 2536 * This method can be used to quickly obtain the inverse of an orthographic projection matrix. 2537 * 2538 * @return this 2539 */ 2540 ref public Matrix4d invertOrtho() return { 2541 invertOrtho(this); 2542 return this; 2543 } 2544 2545 public Matrix4d invertPerspectiveView(Matrix4d view, ref Matrix4d dest) { 2546 double a = 1.0 / (m00 * m11); 2547 double l = -1.0 / (m23 * m32); 2548 double pm00 = m11 * a; 2549 double pm11 = m00 * a; 2550 double pm23 = -m23 * l; 2551 double pm32 = -m32 * l; 2552 double pm33 = m22 * l; 2553 double vm30 = -view.m00 * view.m30 - view.m01 * view.m31 - view.m02 * view.m32; 2554 double vm31 = -view.m10 * view.m30 - view.m11 * view.m31 - view.m12 * view.m32; 2555 double vm32 = -view.m20 * view.m30 - view.m21 * view.m31 - view.m22 * view.m32; 2556 double nm10 = view.m01 * pm11; 2557 double nm30 = view.m02 * pm32 + vm30 * pm33; 2558 double nm31 = view.m12 * pm32 + vm31 * pm33; 2559 double nm32 = view.m22 * pm32 + vm32 * pm33; 2560 return dest 2561 ._m00(view.m00 * pm00) 2562 ._m01(view.m10 * pm00) 2563 ._m02(view.m20 * pm00) 2564 ._m03(0.0) 2565 ._m10(nm10) 2566 ._m11(view.m11 * pm11) 2567 ._m12(view.m21 * pm11) 2568 ._m13(0.0) 2569 ._m20(vm30 * pm23) 2570 ._m21(vm31 * pm23) 2571 ._m22(vm32 * pm23) 2572 ._m23(pm23) 2573 ._m30(nm30) 2574 ._m31(nm31) 2575 ._m32(nm32) 2576 ._m33(pm33) 2577 ._properties(0); 2578 } 2579 2580 public Matrix4d invertPerspectiveView(Matrix4x3d view, ref Matrix4d dest) { 2581 double a = 1.0 / (m00 * m11); 2582 double l = -1.0 / (m23 * m32); 2583 double pm00 = m11 * a; 2584 double pm11 = m00 * a; 2585 double pm23 = -m23 * l; 2586 double pm32 = -m32 * l; 2587 double pm33 = m22 * l; 2588 double vm30 = -view.m00 * view.m30 - view.m01 * view.m31 - view.m02 * view.m32; 2589 double vm31 = -view.m10 * view.m30 - view.m11 * view.m31 - view.m12 * view.m32; 2590 double vm32 = -view.m20 * view.m30 - view.m21 * view.m31 - view.m22 * view.m32; 2591 return dest 2592 ._m00(view.m00 * pm00) 2593 ._m01(view.m10 * pm00) 2594 ._m02(view.m20 * pm00) 2595 ._m03(0.0) 2596 ._m10(view.m01 * pm11) 2597 ._m11(view.m11 * pm11) 2598 ._m12(view.m21 * pm11) 2599 ._m13(0.0) 2600 ._m20(vm30 * pm23) 2601 ._m21(vm31 * pm23) 2602 ._m22(vm32 * pm23) 2603 ._m23(pm23) 2604 ._m30(view.m02 * pm32 + vm30 * pm33) 2605 ._m31(view.m12 * pm32 + vm31 * pm33) 2606 ._m32(view.m22 * pm32 + vm32 * pm33) 2607 ._m33(pm33) 2608 ._properties(0); 2609 } 2610 2611 public Matrix4d invertAffine(ref Matrix4d dest) { 2612 double m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10; 2613 double m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11; 2614 double s = 1.0 / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20); 2615 double m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22; 2616 double m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20; 2617 double m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02; 2618 double m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00; 2619 double nm00 = (m11m22 - m12m21) * s; 2620 double nm01 = (m21m02 - m22m01) * s; 2621 double nm02 = (m12m01 - m11m02) * s; 2622 double nm10 = (m12m20 - m10m22) * s; 2623 double nm11 = (m22m00 - m20m02) * s; 2624 double nm12 = (m10m02 - m12m00) * s; 2625 double nm20 = (m10m21 - m11m20) * s; 2626 double nm21 = (m20m01 - m21m00) * s; 2627 double nm22 = (m11m00 - m10m01) * s; 2628 double nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s; 2629 double nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s; 2630 double nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s; 2631 dest._m00(nm00) 2632 ._m01(nm01) 2633 ._m02(nm02) 2634 ._m03(0.0) 2635 ._m10(nm10) 2636 ._m11(nm11) 2637 ._m12(nm12) 2638 ._m13(0.0) 2639 ._m20(nm20) 2640 ._m21(nm21) 2641 ._m22(nm22) 2642 ._m23(0.0) 2643 ._m30(nm30) 2644 ._m31(nm31) 2645 ._m32(nm32) 2646 ._m33(1.0) 2647 ._properties(PROPERTY_AFFINE); 2648 return dest; 2649 } 2650 2651 /** 2652 * 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>). 2653 * 2654 * @return this 2655 */ 2656 ref public Matrix4d invertAffine() return { 2657 invertAffine(this); 2658 return this; 2659 } 2660 2661 /** 2662 * Transpose this matrix. 2663 * 2664 * @return this 2665 */ 2666 ref public Matrix4d transpose() return { 2667 transpose(this); 2668 return this; 2669 } 2670 2671 public Matrix4d transpose(ref Matrix4d dest) { 2672 if ((properties & PROPERTY_IDENTITY) != 0) 2673 return dest.identity(); 2674 else if (this != dest) 2675 return transposeNonThisGeneric(dest); 2676 return transposeThisGeneric(dest); 2677 } 2678 private Matrix4d transposeNonThisGeneric(ref Matrix4d dest) { 2679 return dest 2680 ._m00(m00) 2681 ._m01(m10) 2682 ._m02(m20) 2683 ._m03(m30) 2684 ._m10(m01) 2685 ._m11(m11) 2686 ._m12(m21) 2687 ._m13(m31) 2688 ._m20(m02) 2689 ._m21(m12) 2690 ._m22(m22) 2691 ._m23(m32) 2692 ._m30(m03) 2693 ._m31(m13) 2694 ._m32(m23) 2695 ._m33(m33) 2696 ._properties(0); 2697 } 2698 private Matrix4d transposeThisGeneric(ref Matrix4d dest) { 2699 double nm10 = m01; 2700 double nm20 = m02; 2701 double nm21 = m12; 2702 double nm30 = m03; 2703 double nm31 = m13; 2704 double nm32 = m23; 2705 return dest 2706 ._m01(m10) 2707 ._m02(m20) 2708 ._m03(m30) 2709 ._m10(nm10) 2710 ._m12(m21) 2711 ._m13(m31) 2712 ._m20(nm20) 2713 ._m21(nm21) 2714 ._m23(m32) 2715 ._m30(nm30) 2716 ._m31(nm31) 2717 ._m32(nm32) 2718 ._properties(0); 2719 } 2720 2721 /** 2722 * Transpose only the upper left 3x3 submatrix of this matrix. 2723 * <p> 2724 * All other matrix elements are left unchanged. 2725 * 2726 * @return this 2727 */ 2728 ref public Matrix4d transpose3x3() return { 2729 transpose3x3(this); 2730 return this; 2731 } 2732 2733 public Matrix4d transpose3x3(ref Matrix4d dest) { 2734 double nm10 = m01, nm20 = m02, nm21 = m12; 2735 return dest 2736 ._m00(m00) 2737 ._m01(m10) 2738 ._m02(m20) 2739 ._m10(nm10) 2740 ._m11(m11) 2741 ._m12(m21) 2742 ._m20(nm20) 2743 ._m21(nm21) 2744 ._m22(m22) 2745 ._properties(this.properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 2746 } 2747 2748 public Matrix3d transpose3x3(ref Matrix3d dest) { 2749 return dest 2750 ._m00(m00) 2751 ._m01(m10) 2752 ._m02(m20) 2753 ._m10(m01) 2754 ._m11(m11) 2755 ._m12(m21) 2756 ._m20(m02) 2757 ._m21(m12) 2758 ._m22(m22); 2759 } 2760 2761 /** 2762 * Set this matrix to be a simple translation matrix. 2763 * <p> 2764 * The resulting matrix can be multiplied against another transformation 2765 * matrix to obtain an additional translation. 2766 * 2767 * @param x 2768 * the offset to translate in x 2769 * @param y 2770 * the offset to translate in y 2771 * @param z 2772 * the offset to translate in z 2773 * @return this 2774 */ 2775 ref public Matrix4d translation(double x, double y, double z) return { 2776 if ((properties & PROPERTY_IDENTITY) == 0) 2777 this._identity(); 2778 return this. 2779 _m30(x). 2780 _m31(y). 2781 _m32(z). 2782 _m33(1.0). 2783 _properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL); 2784 } 2785 2786 2787 /** 2788 * Set this matrix to be a simple translation matrix. 2789 * <p> 2790 * The resulting matrix can be multiplied against another transformation 2791 * matrix to obtain an additional translation. 2792 * 2793 * @param offset 2794 * the offsets in x, y and z to translate 2795 * @return this 2796 */ 2797 ref public Matrix4d translation(ref Vector3d offset) return { 2798 return translation(offset.x, offset.y, offset.z); 2799 } 2800 2801 /** 2802 * Set only the translation components <code>(m30, m31, m32)</code> of this matrix to the given values <code>(x, y, z)</code>. 2803 * <p> 2804 * To build a translation matrix instead, use {@link #translation(double, double, double)}. 2805 * To apply a translation, use {@link #translate(double, double, double)}. 2806 * 2807 * @see #translation(double, double, double) 2808 * @see #translate(double, double, double) 2809 * 2810 * @param x 2811 * the units to translate in x 2812 * @param y 2813 * the units to translate in y 2814 * @param z 2815 * the units to translate in z 2816 * @return this 2817 */ 2818 ref public Matrix4d setTranslation(double x, double y, double z) return { 2819 _m30(x). 2820 _m31(y). 2821 _m32(z). 2822 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY); 2823 return this; 2824 } 2825 2826 /** 2827 * 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>. 2828 * <p> 2829 * To build a translation matrix instead, use {@link #translation(ref Vector3d)}. 2830 * To apply a translation, use {@link #translate(ref Vector3d)}. 2831 * 2832 * @see #translation(ref Vector3d) 2833 * @see #translate(ref Vector3d) 2834 * 2835 * @param xyz 2836 * the units to translate in <code>(x, y, z)</code> 2837 * @return this 2838 */ 2839 ref public Matrix4d setTranslation(ref Vector3d xyz) return { 2840 return setTranslation(xyz.x, xyz.y, xyz.z); 2841 } 2842 2843 public Vector3d getTranslation(ref Vector3d dest) { 2844 dest.x = m30; 2845 dest.y = m31; 2846 dest.z = m32; 2847 return dest; 2848 } 2849 2850 public Vector3d getScale(ref Vector3d dest) { 2851 dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02); 2852 dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12); 2853 dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22); 2854 return dest; 2855 } 2856 2857 public Matrix4d get(ref Matrix4d dest) { 2858 return dest.set(this); 2859 } 2860 2861 public Matrix4x3d get4x3(ref Matrix4x3d dest) { 2862 return dest.set(this); 2863 } 2864 2865 public Matrix3d get3x3(ref Matrix3d dest) { 2866 return dest.set(this); 2867 } 2868 2869 public Quaterniond getUnnormalizedRotation(ref Quaterniond dest) { 2870 return dest.setFromUnnormalized(this); 2871 } 2872 2873 public Quaterniond getNormalizedRotation(ref Quaterniond dest) { 2874 return dest.setFromNormalized(this); 2875 } 2876 2877 // Additional functionality for D (becomes a DoubleBuffer) 2878 public double[16] getDoubleArray() { 2879 double[16] dest; 2880 dest[0] = m00; 2881 dest[1] = m01; 2882 dest[2] = m02; 2883 dest[3] = m03; 2884 dest[4] = m10; 2885 dest[5] = m11; 2886 dest[6] = m12; 2887 dest[7] = m13; 2888 dest[8] = m20; 2889 dest[9] = m21; 2890 dest[10] = m22; 2891 dest[11] = m23; 2892 dest[12] = m30; 2893 dest[13] = m31; 2894 dest[14] = m32; 2895 dest[15] = m33; 2896 return dest; 2897 } 2898 2899 // Additional functionality for D (becomes a DoubleBuffer) 2900 public double[16] getDoubleArray(ref double[16] dest, int offset) { 2901 dest[offset+0] = m00; 2902 dest[offset+1] = m01; 2903 dest[offset+2] = m02; 2904 dest[offset+3] = m03; 2905 dest[offset+4] = m10; 2906 dest[offset+5] = m11; 2907 dest[offset+6] = m12; 2908 dest[offset+7] = m13; 2909 dest[offset+8] = m20; 2910 dest[offset+9] = m21; 2911 dest[offset+10] = m22; 2912 dest[offset+11] = m23; 2913 dest[offset+12] = m30; 2914 dest[offset+13] = m31; 2915 dest[offset+14] = m32; 2916 dest[offset+15] = m33; 2917 return dest; 2918 } 2919 2920 public double[] get(ref double[] dest, int offset) { 2921 dest[offset+0] = m00; 2922 dest[offset+1] = m01; 2923 dest[offset+2] = m02; 2924 dest[offset+3] = m03; 2925 dest[offset+4] = m10; 2926 dest[offset+5] = m11; 2927 dest[offset+6] = m12; 2928 dest[offset+7] = m13; 2929 dest[offset+8] = m20; 2930 dest[offset+9] = m21; 2931 dest[offset+10] = m22; 2932 dest[offset+11] = m23; 2933 dest[offset+12] = m30; 2934 dest[offset+13] = m31; 2935 dest[offset+14] = m32; 2936 dest[offset+15] = m33; 2937 return dest; 2938 } 2939 2940 public double[] get(ref double[] dest) { 2941 return get(dest, 0); 2942 } 2943 2944 /** 2945 * Set all the values within this matrix to 0. 2946 * 2947 * @return this 2948 */ 2949 ref public Matrix4d zero() return { 2950 return 2951 _m00(0.0). 2952 _m01(0.0). 2953 _m02(0.0). 2954 _m03(0.0). 2955 _m10(0.0). 2956 _m11(0.0). 2957 _m12(0.0). 2958 _m13(0.0). 2959 _m20(0.0). 2960 _m21(0.0). 2961 _m22(0.0). 2962 _m23(0.0). 2963 _m30(0.0). 2964 _m31(0.0). 2965 _m32(0.0). 2966 _m33(0.0). 2967 _properties(0); 2968 } 2969 2970 /** 2971 * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor. 2972 * <p> 2973 * The resulting matrix can be multiplied against another transformation 2974 * matrix to obtain an additional scaling. 2975 * <p> 2976 * In order to post-multiply a scaling transformation directly to a 2977 * matrix, use {@link #scale(double) scale()} instead. 2978 * 2979 * @see #scale(double) 2980 * 2981 * @param factor 2982 * the scale factor in x, y and z 2983 * @return this 2984 */ 2985 ref public Matrix4d scaling(double factor) return { 2986 return scaling(factor, factor, factor); 2987 } 2988 2989 /** 2990 * Set this matrix to be a simple scale matrix. 2991 * 2992 * @param x 2993 * the scale in x 2994 * @param y 2995 * the scale in y 2996 * @param z 2997 * the scale in z 2998 * @return this 2999 */ 3000 ref public Matrix4d scaling(double x, double y, double z) return { 3001 if ((properties & PROPERTY_IDENTITY) == 0) 3002 identity(); 3003 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3004 _m00(x). 3005 _m11(y). 3006 _m22(z). 3007 properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0); 3008 return this; 3009 } 3010 3011 /** 3012 * Set this matrix to be a simple scale matrix which scales the base axes by 3013 * <code>xyz.x</code>, <code>xyz.y</code> and <code>xyz.z</code>, respectively. 3014 * <p> 3015 * The resulting matrix can be multiplied against another transformation 3016 * matrix to obtain an additional scaling. 3017 * <p> 3018 * In order to post-multiply a scaling transformation directly to a 3019 * matrix use {@link #scale(ref Vector3d) scale()} instead. 3020 * 3021 * @see #scale(ref Vector3d) 3022 * 3023 * @param xyz 3024 * the scale in x, y and z, respectively 3025 * @return this 3026 */ 3027 ref public Matrix4d scaling(ref Vector3d xyz) return { 3028 return scaling(xyz.x, xyz.y, xyz.z); 3029 } 3030 3031 /** 3032 * Set this matrix to a rotation matrix which rotates the given radians about a given axis. 3033 * <p> 3034 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3035 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3036 * When used with a left-handed coordinate system, the rotation is clockwise. 3037 * <p> 3038 * From <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">Wikipedia</a> 3039 * 3040 * @param angle 3041 * the angle in radians 3042 * @param x 3043 * the x-coordinate of the axis to rotate about 3044 * @param y 3045 * the y-coordinate of the axis to rotate about 3046 * @param z 3047 * the z-coordinate of the axis to rotate about 3048 * @return this 3049 */ 3050 ref public Matrix4d rotation(double angle, double x, double y, double z) return { 3051 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 3052 rotationX(x * angle); 3053 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 3054 rotationY(y * angle); 3055 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 3056 rotationZ(z * angle); 3057 else 3058 rotationInternal(angle, x, y, z); 3059 return this; 3060 } 3061 private Matrix4d rotationInternal(double angle, double x, double y, double z) { 3062 double sin = Math.sin(angle); 3063 double cos = Math.cosFromSin(sin, angle); 3064 double C = 1.0 - cos; 3065 double xy = x * y, xz = x * z, yz = y * z; 3066 if ((properties & PROPERTY_IDENTITY) == 0) 3067 this._identity(); 3068 _m00(cos + x * x * C). 3069 _m10(xy * C - z * sin). 3070 _m20(xz * C + y * sin). 3071 _m01(xy * C + z * sin). 3072 _m11(cos + y * y * C). 3073 _m21(yz * C - x * sin). 3074 _m02(xz * C - y * sin). 3075 _m12(yz * C + x * sin). 3076 _m22(cos + z * z * C). 3077 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3078 return this; 3079 } 3080 3081 /** 3082 * Set this matrix to a rotation transformation about the X axis. 3083 * <p> 3084 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3085 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3086 * When used with a left-handed coordinate system, the rotation is clockwise. 3087 * <p> 3088 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3089 * 3090 * @param ang 3091 * the angle in radians 3092 * @return this 3093 */ 3094 ref public Matrix4d rotationX(double ang) return { 3095 double sin, cos; 3096 sin = Math.sin(ang); 3097 cos = Math.cosFromSin(sin, ang); 3098 if ((properties & PROPERTY_IDENTITY) == 0) 3099 this._identity(); 3100 _m11(cos). 3101 _m12(sin). 3102 _m21(-sin). 3103 _m22(cos). 3104 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3105 return this; 3106 } 3107 3108 /** 3109 * Set this matrix to a rotation transformation about the Y axis. 3110 * <p> 3111 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3112 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3113 * When used with a left-handed coordinate system, the rotation is clockwise. 3114 * <p> 3115 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3116 * 3117 * @param ang 3118 * the angle in radians 3119 * @return this 3120 */ 3121 ref public Matrix4d rotationY(double ang) return { 3122 double sin, cos; 3123 sin = Math.sin(ang); 3124 cos = Math.cosFromSin(sin, ang); 3125 if ((properties & PROPERTY_IDENTITY) == 0) 3126 this._identity(); 3127 _m00(cos). 3128 _m02(-sin). 3129 _m20(sin). 3130 _m22(cos). 3131 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3132 return this; 3133 } 3134 3135 /** 3136 * Set this matrix to a rotation transformation about the Z axis. 3137 * <p> 3138 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3139 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3140 * When used with a left-handed coordinate system, the rotation is clockwise. 3141 * <p> 3142 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 3143 * 3144 * @param ang 3145 * the angle in radians 3146 * @return this 3147 */ 3148 ref public Matrix4d rotationZ(double ang) return { 3149 double sin, cos; 3150 sin = Math.sin(ang); 3151 cos = Math.cosFromSin(sin, ang); 3152 if ((properties & PROPERTY_IDENTITY) == 0) 3153 this._identity(); 3154 _m00(cos). 3155 _m01(sin). 3156 _m10(-sin). 3157 _m11(cos). 3158 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3159 return this; 3160 } 3161 3162 /** 3163 * Set this matrix to a rotation transformation about the Z axis to align the local <code>+X</code> towards <code>(dirX, dirY)</code>. 3164 * <p> 3165 * The vector <code>(dirX, dirY)</code> must be a unit vector. 3166 * 3167 * @param dirX 3168 * the x component of the normalized direction 3169 * @param dirY 3170 * the y component of the normalized direction 3171 * @return this 3172 */ 3173 ref public Matrix4d rotationTowardsXY(double dirX, double dirY) return { 3174 if ((properties & PROPERTY_IDENTITY) == 0) 3175 this._identity(); 3176 setm00(dirY); 3177 setm01(dirX); 3178 setm10(-dirX); 3179 setm11(dirY); 3180 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3181 return this; 3182 } 3183 3184 /** 3185 * Set this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation 3186 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3187 * <p> 3188 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3189 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3190 * When used with a left-handed coordinate system, the rotation is clockwise. 3191 * <p> 3192 * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 3193 * 3194 * @param angleX 3195 * the angle to rotate about X 3196 * @param angleY 3197 * the angle to rotate about Y 3198 * @param angleZ 3199 * the angle to rotate about Z 3200 * @return this 3201 */ 3202 ref public Matrix4d rotationXYZ(double angleX, double angleY, double angleZ) return { 3203 double sinX = Math.sin(angleX); 3204 double cosX = Math.cosFromSin(sinX, angleX); 3205 double sinY = Math.sin(angleY); 3206 double cosY = Math.cosFromSin(sinY, angleY); 3207 double sinZ = Math.sin(angleZ); 3208 double cosZ = Math.cosFromSin(sinZ, angleZ); 3209 double m_sinX = -sinX; 3210 double m_sinY = -sinY; 3211 double m_sinZ = -sinZ; 3212 if ((properties & PROPERTY_IDENTITY) == 0) 3213 this._identity(); 3214 3215 // rotateX 3216 double nm11 = cosX; 3217 double nm12 = sinX; 3218 double nm21 = m_sinX; 3219 double nm22 = cosX; 3220 // rotateY 3221 double nm00 = cosY; 3222 double nm01 = nm21 * m_sinY; 3223 double nm02 = nm22 * m_sinY; 3224 _m20(sinY). 3225 _m21(nm21 * cosY). 3226 _m22(nm22 * cosY). 3227 // rotateZ 3228 _m00(nm00 * cosZ). 3229 _m01(nm01 * cosZ + nm11 * sinZ). 3230 _m02(nm02 * cosZ + nm12 * sinZ). 3231 _m10(nm00 * m_sinZ). 3232 _m11(nm01 * m_sinZ + nm11 * cosZ). 3233 _m12(nm02 * m_sinZ + nm12 * cosZ). 3234 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3235 return this; 3236 } 3237 3238 /** 3239 * Set this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation 3240 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis. 3241 * <p> 3242 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3243 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3244 * When used with a left-handed coordinate system, the rotation is clockwise. 3245 * <p> 3246 * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 3247 * 3248 * @param angleZ 3249 * the angle to rotate about Z 3250 * @param angleY 3251 * the angle to rotate about Y 3252 * @param angleX 3253 * the angle to rotate about X 3254 * @return this 3255 */ 3256 ref public Matrix4d rotationZYX(double angleZ, double angleY, double angleX) return { 3257 double sinX = Math.sin(angleX); 3258 double cosX = Math.cosFromSin(sinX, angleX); 3259 double sinY = Math.sin(angleY); 3260 double cosY = Math.cosFromSin(sinY, angleY); 3261 double sinZ = Math.sin(angleZ); 3262 double cosZ = Math.cosFromSin(sinZ, angleZ); 3263 double m_sinZ = -sinZ; 3264 double m_sinY = -sinY; 3265 double m_sinX = -sinX; 3266 if ((properties & PROPERTY_IDENTITY) == 0) 3267 this._identity(); 3268 3269 // rotateZ 3270 double nm00 = cosZ; 3271 double nm01 = sinZ; 3272 double nm10 = m_sinZ; 3273 double nm11 = cosZ; 3274 // rotateY 3275 double nm20 = nm00 * sinY; 3276 double nm21 = nm01 * sinY; 3277 double nm22 = cosY; 3278 _m00(nm00 * cosY). 3279 _m01(nm01 * cosY). 3280 _m02(m_sinY). 3281 // rotateX 3282 _m10(nm10 * cosX + nm20 * sinX). 3283 _m11(nm11 * cosX + nm21 * sinX). 3284 _m12(nm22 * sinX). 3285 _m20(nm10 * m_sinX + nm20 * cosX). 3286 _m21(nm11 * m_sinX + nm21 * cosX). 3287 _m22(nm22 * cosX). 3288 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3289 return this; 3290 } 3291 3292 /** 3293 * Set this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation 3294 * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3295 * <p> 3296 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3297 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3298 * When used with a left-handed coordinate system, the rotation is clockwise. 3299 * <p> 3300 * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 3301 * 3302 * @param angleY 3303 * the angle to rotate about Y 3304 * @param angleX 3305 * the angle to rotate about X 3306 * @param angleZ 3307 * the angle to rotate about Z 3308 * @return this 3309 */ 3310 ref public Matrix4d rotationYXZ(double angleY, double angleX, double angleZ) return { 3311 double sinX = Math.sin(angleX); 3312 double cosX = Math.cosFromSin(sinX, angleX); 3313 double sinY = Math.sin(angleY); 3314 double cosY = Math.cosFromSin(sinY, angleY); 3315 double sinZ = Math.sin(angleZ); 3316 double cosZ = Math.cosFromSin(sinZ, angleZ); 3317 double m_sinY = -sinY; 3318 double m_sinX = -sinX; 3319 double m_sinZ = -sinZ; 3320 3321 // rotateY 3322 double nm00 = cosY; 3323 double nm02 = m_sinY; 3324 double nm20 = sinY; 3325 double nm22 = cosY; 3326 // rotateX 3327 double nm10 = nm20 * sinX; 3328 double nm11 = cosX; 3329 double nm12 = nm22 * sinX; 3330 _m20(nm20 * cosX). 3331 _m21(m_sinX). 3332 _m22(nm22 * cosX). 3333 _m23(0.0). 3334 // rotateZ 3335 _m00(nm00 * cosZ + nm10 * sinZ). 3336 _m01(nm11 * sinZ). 3337 _m02(nm02 * cosZ + nm12 * sinZ). 3338 _m03(0.0). 3339 _m10(nm00 * m_sinZ + nm10 * cosZ). 3340 _m11(nm11 * cosZ). 3341 _m12(nm02 * m_sinZ + nm12 * cosZ). 3342 _m13(0.0). 3343 // set last column to identity 3344 _m30(0.0). 3345 _m31(0.0). 3346 _m32(0.0). 3347 _m33(1.0). 3348 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 3349 return this; 3350 } 3351 3352 /** 3353 * 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 3354 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3355 * <p> 3356 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3357 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3358 * When used with a left-handed coordinate system, the rotation is clockwise. 3359 * 3360 * @param angleX 3361 * the angle to rotate about X 3362 * @param angleY 3363 * the angle to rotate about Y 3364 * @param angleZ 3365 * the angle to rotate about Z 3366 * @return this 3367 */ 3368 ref public Matrix4d setRotationXYZ(double angleX, double angleY, double angleZ) return { 3369 double sinX = Math.sin(angleX); 3370 double cosX = Math.cosFromSin(sinX, angleX); 3371 double sinY = Math.sin(angleY); 3372 double cosY = Math.cosFromSin(sinY, angleY); 3373 double sinZ = Math.sin(angleZ); 3374 double cosZ = Math.cosFromSin(sinZ, angleZ); 3375 double m_sinX = -sinX; 3376 double m_sinY = -sinY; 3377 double m_sinZ = -sinZ; 3378 3379 // rotateX 3380 double nm11 = cosX; 3381 double nm12 = sinX; 3382 double nm21 = m_sinX; 3383 double nm22 = cosX; 3384 // rotateY 3385 double nm00 = cosY; 3386 double nm01 = nm21 * m_sinY; 3387 double nm02 = nm22 * m_sinY; 3388 _m20(sinY). 3389 _m21(nm21 * cosY). 3390 _m22(nm22 * cosY). 3391 // rotateZ 3392 _m00(nm00 * cosZ). 3393 _m01(nm01 * cosZ + nm11 * sinZ). 3394 _m02(nm02 * cosZ + nm12 * sinZ). 3395 _m10(nm00 * m_sinZ). 3396 _m11(nm01 * m_sinZ + nm11 * cosZ). 3397 _m12(nm02 * m_sinZ + nm12 * cosZ). 3398 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3399 return this; 3400 } 3401 3402 /** 3403 * 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 3404 * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis. 3405 * <p> 3406 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3407 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3408 * When used with a left-handed coordinate system, the rotation is clockwise. 3409 * 3410 * @param angleZ 3411 * the angle to rotate about Z 3412 * @param angleY 3413 * the angle to rotate about Y 3414 * @param angleX 3415 * the angle to rotate about X 3416 * @return this 3417 */ 3418 ref public Matrix4d setRotationZYX(double angleZ, double angleY, double angleX) return { 3419 double sinX = Math.sin(angleX); 3420 double cosX = Math.cosFromSin(sinX, angleX); 3421 double sinY = Math.sin(angleY); 3422 double cosY = Math.cosFromSin(sinY, angleY); 3423 double sinZ = Math.sin(angleZ); 3424 double cosZ = Math.cosFromSin(sinZ, angleZ); 3425 double m_sinZ = -sinZ; 3426 double m_sinY = -sinY; 3427 double m_sinX = -sinX; 3428 3429 // rotateZ 3430 double nm00 = cosZ; 3431 double nm01 = sinZ; 3432 double nm10 = m_sinZ; 3433 double nm11 = cosZ; 3434 // rotateY 3435 double nm20 = nm00 * sinY; 3436 double nm21 = nm01 * sinY; 3437 double nm22 = cosY; 3438 _m00(nm00 * cosY). 3439 _m01(nm01 * cosY). 3440 _m02(m_sinY). 3441 // rotateX 3442 _m10(nm10 * cosX + nm20 * sinX). 3443 _m11(nm11 * cosX + nm21 * sinX). 3444 _m12(nm22 * sinX). 3445 _m20(nm10 * m_sinX + nm20 * cosX). 3446 _m21(nm11 * m_sinX + nm21 * cosX). 3447 _m22(nm22 * cosX). 3448 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3449 return this; 3450 } 3451 3452 /** 3453 * 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 3454 * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis. 3455 * <p> 3456 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3457 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3458 * When used with a left-handed coordinate system, the rotation is clockwise. 3459 * 3460 * @param angleY 3461 * the angle to rotate about Y 3462 * @param angleX 3463 * the angle to rotate about X 3464 * @param angleZ 3465 * the angle to rotate about Z 3466 * @return this 3467 */ 3468 ref public Matrix4d setRotationYXZ(double angleY, double angleX, double angleZ) return { 3469 double sinX = Math.sin(angleX); 3470 double cosX = Math.cosFromSin(sinX, angleX); 3471 double sinY = Math.sin(angleY); 3472 double cosY = Math.cosFromSin(sinY, angleY); 3473 double sinZ = Math.sin(angleZ); 3474 double cosZ = Math.cosFromSin(sinZ, angleZ); 3475 double m_sinY = -sinY; 3476 double m_sinX = -sinX; 3477 double m_sinZ = -sinZ; 3478 3479 // rotateY 3480 double nm00 = cosY; 3481 double nm02 = m_sinY; 3482 double nm20 = sinY; 3483 double nm22 = cosY; 3484 // rotateX 3485 double nm10 = nm20 * sinX; 3486 double nm11 = cosX; 3487 double nm12 = nm22 * sinX; 3488 _m20(nm20 * cosX). 3489 _m21(m_sinX). 3490 _m22(nm22 * cosX). 3491 // rotateZ 3492 _m00(nm00 * cosZ + nm10 * sinZ). 3493 _m01(nm11 * sinZ). 3494 _m02(nm02 * cosZ + nm12 * sinZ). 3495 _m10(nm00 * m_sinZ + nm10 * cosZ). 3496 _m11(nm11 * cosZ). 3497 _m12(nm02 * m_sinZ + nm12 * cosZ). 3498 properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION); 3499 return this; 3500 } 3501 3502 /** 3503 * Set this matrix to a rotation matrix which rotates the given radians about a given axis. 3504 * <p> 3505 * The axis described by the <code>axis</code> vector needs to be a unit vector. 3506 * <p> 3507 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 3508 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 3509 * When used with a left-handed coordinate system, the rotation is clockwise. 3510 * 3511 * @param angle 3512 * the angle in radians 3513 * @param axis 3514 * the axis to rotate about 3515 * @return this 3516 */ 3517 ref public Matrix4d rotation(double angle, Vector3d axis) return { 3518 return rotation(angle, axis.x, axis.y, axis.z); 3519 } 3520 3521 3522 public Vector4d transform(ref Vector4d v) { 3523 return v.mul(this); 3524 } 3525 3526 public Vector4d transform(ref Vector4d v, ref Vector4d dest) { 3527 return v.mul(this, dest); 3528 } 3529 3530 public Vector4d transform(double x, double y, double z, double w, ref Vector4d dest) { 3531 return dest.set(m00 * x + m10 * y + m20 * z + m30 * w, 3532 m01 * x + m11 * y + m21 * z + m31 * w, 3533 m02 * x + m12 * y + m22 * z + m32 * w, 3534 m03 * x + m13 * y + m23 * z + m33 * w); 3535 } 3536 3537 public Vector4d transformTranspose(ref Vector4d v) { 3538 return v.mulTranspose(this); 3539 } 3540 public Vector4d transformTranspose(ref Vector4d v, ref Vector4d dest) { 3541 return v.mulTranspose(this, dest); 3542 } 3543 public Vector4d transformTranspose(double x, double y, double z, double w, ref Vector4d dest) { 3544 return dest.set(x, y, z, w).mulTranspose(this); 3545 } 3546 3547 public Vector4d transformProject(ref Vector4d v) { 3548 return v.mulProject(this); 3549 } 3550 3551 public Vector4d transformProject(ref Vector4d v, ref Vector4d dest) { 3552 return v.mulProject(this, dest); 3553 } 3554 3555 public Vector4d transformProject(double x, double y, double z, double w, ref Vector4d dest) { 3556 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33 * w); 3557 return dest.set((m00 * x + m10 * y + m20 * z + m30 * w) * invW, 3558 (m01 * x + m11 * y + m21 * z + m31 * w) * invW, 3559 (m02 * x + m12 * y + m22 * z + m32 * w) * invW, 3560 1.0); 3561 } 3562 3563 public Vector3d transformProject(ref Vector3d v) { 3564 return v.mulProject(this); 3565 } 3566 3567 public Vector3d transformProject(ref Vector3d v, ref Vector3d dest) { 3568 return v.mulProject(this, dest); 3569 } 3570 3571 public Vector3d transformProject(double x, double y, double z, ref Vector3d dest) { 3572 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 3573 return dest.set((m00 * x + m10 * y + m20 * z + m30) * invW, 3574 (m01 * x + m11 * y + m21 * z + m31) * invW, 3575 (m02 * x + m12 * y + m22 * z + m32) * invW); 3576 } 3577 3578 public Vector3d transformProject(ref Vector4d v, ref Vector3d dest) { 3579 return v.mulProject(this, dest); 3580 } 3581 3582 public Vector3d transformProject(double x, double y, double z, double w, ref Vector3d dest) { 3583 dest.x = x; 3584 dest.y = y; 3585 dest.z = z; 3586 return dest.mulProject(this, w, dest); 3587 } 3588 3589 public Vector3d transformPosition(ref Vector3d dest) { 3590 return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z + m30, 3591 m01 * dest.x + m11 * dest.y + m21 * dest.z + m31, 3592 m02 * dest.x + m12 * dest.y + m22 * dest.z + m32); 3593 } 3594 3595 public Vector3d transformPosition(ref Vector3d v, ref Vector3d dest) { 3596 return transformPosition(v.x, v.y, v.z, dest); 3597 } 3598 3599 public Vector3d transformPosition(double x, double y, double z, ref Vector3d dest) { 3600 return dest.set(m00 * x + m10 * y + m20 * z + m30, 3601 m01 * x + m11 * y + m21 * z + m31, 3602 m02 * x + m12 * y + m22 * z + m32); 3603 } 3604 3605 public Vector3d transformDirection(ref Vector3d dest) { 3606 return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z, 3607 m01 * dest.x + m11 * dest.y + m21 * dest.z, 3608 m02 * dest.x + m12 * dest.y + m22 * dest.z); 3609 } 3610 3611 public Vector3d transformDirection(ref Vector3d v, ref Vector3d dest) { 3612 return dest.set(m00 * v.x + m10 * v.y + m20 * v.z, 3613 m01 * v.x + m11 * v.y + m21 * v.z, 3614 m02 * v.x + m12 * v.y + m22 * v.z); 3615 } 3616 3617 public Vector3d transformDirection(double x, double y, double z, ref Vector3d dest) { 3618 return dest.set(m00 * x + m10 * y + m20 * z, 3619 m01 * x + m11 * y + m21 * z, 3620 m02 * x + m12 * y + m22 * z); 3621 } 3622 3623 public Vector4d transformAffine(ref Vector4d dest) { 3624 return dest.mulAffine(this, dest); 3625 } 3626 3627 public Vector4d transformAffine(ref Vector4d v, ref Vector4d dest) { 3628 return transformAffine(v.x, v.y, v.z, v.w, dest); 3629 } 3630 3631 public Vector4d transformAffine(double x, double y, double z, double w, ref Vector4d dest) { 3632 double rx = m00 * x + m10 * y + m20 * z + m30 * w; 3633 double ry = m01 * x + m11 * y + m21 * z + m31 * w; 3634 double rz = m02 * x + m12 * y + m22 * z + m32 * w; 3635 dest.x = rx; 3636 dest.y = ry; 3637 dest.z = rz; 3638 dest.w = w; 3639 return dest; 3640 } 3641 3642 /** 3643 * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3d} and don't change the other elements. 3644 * 3645 * @param mat 3646 * the 3x3 matrix 3647 * @return this 3648 */ 3649 ref public Matrix4d set3x3(Matrix3d mat) return { 3650 return 3651 _m00(mat.m00). 3652 _m01(mat.m01). 3653 _m02(mat.m02). 3654 _m10(mat.m10). 3655 _m11(mat.m11). 3656 _m12(mat.m12). 3657 _m20(mat.m20). 3658 _m21(mat.m21). 3659 _m22(mat.m22). 3660 _properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 3661 } 3662 3663 public Matrix4d scale(ref Vector3d xyz, ref Matrix4d dest) { 3664 return scale(xyz.x, xyz.y, xyz.z, dest); 3665 } 3666 3667 /** 3668 * Apply scaling to this matrix by scaling the base axes by the given <code>xyz.x</code>, 3669 * <code>xyz.y</code> and <code>xyz.z</code> factors, respectively. 3670 * <p> 3671 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3672 * then the new matrix will be <code>M * S</code>. So when transforming a 3673 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3674 * scaling will be applied first! 3675 * 3676 * @param xyz 3677 * the factors of the x, y and z component, respectively 3678 * @return this 3679 */ 3680 ref public Matrix4d scale(ref Vector3d xyz) return { 3681 scale(xyz.x, xyz.y, xyz.z, this); 3682 return this; 3683 } 3684 3685 public Matrix4d scale(double x, double y, double z, ref Matrix4d dest) { 3686 if ((properties & PROPERTY_IDENTITY) != 0) 3687 return dest.scaling(x, y, z); 3688 return scaleGeneric(x, y, z, dest); 3689 } 3690 private Matrix4d scaleGeneric(double x, double y, double z, ref Matrix4d dest) { 3691 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3692 dest._m00(m00 * x) 3693 ._m01(m01 * x) 3694 ._m02(m02 * x) 3695 ._m03(m03 * x) 3696 ._m10(m10 * y) 3697 ._m11(m11 * y) 3698 ._m12(m12 * y) 3699 ._m13(m13 * y) 3700 ._m20(m20 * z) 3701 ._m21(m21 * z) 3702 ._m22(m22 * z) 3703 ._m23(m23 * z) 3704 ._m30(m30) 3705 ._m31(m31) 3706 ._m32(m32) 3707 ._m33(m33) 3708 ._properties(properties 3709 & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL))); 3710 return dest; 3711 } 3712 3713 /** 3714 * Apply scaling to <code>this</code> matrix by scaling the base axes by the given x, 3715 * y and z factors. 3716 * <p> 3717 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3718 * then the new matrix will be <code>M * S</code>. So when transforming a 3719 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 3720 * , the scaling will be applied first! 3721 * 3722 * @param x 3723 * the factor of the x component 3724 * @param y 3725 * the factor of the y component 3726 * @param z 3727 * the factor of the z component 3728 * @return this 3729 */ 3730 ref public Matrix4d scale(double x, double y, double z) return { 3731 scale(x, y, z, this); 3732 return this; 3733 } 3734 3735 public Matrix4d scale(double xyz, ref Matrix4d dest) { 3736 return scale(xyz, xyz, xyz, dest); 3737 } 3738 3739 /** 3740 * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor. 3741 * <p> 3742 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3743 * then the new matrix will be <code>M * S</code>. So when transforming a 3744 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 3745 * , the scaling will be applied first! 3746 * 3747 * @see #scale(double, double, double) 3748 * 3749 * @param xyz 3750 * the factor for all components 3751 * @return this 3752 */ 3753 ref public Matrix4d scale(double xyz) return { 3754 return scale(xyz, xyz, xyz); 3755 } 3756 3757 public Matrix4d scaleXY(double x, double y, ref Matrix4d dest) { 3758 return scale(x, y, 1.0, dest); 3759 } 3760 3761 /** 3762 * Apply scaling to this matrix by scaling the X axis by <code>x</code> and the Y axis by <code>y</code>. 3763 * <p> 3764 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3765 * then the new matrix will be <code>M * S</code>. So when transforming a 3766 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3767 * scaling will be applied first! 3768 * 3769 * @param x 3770 * the factor of the x component 3771 * @param y 3772 * the factor of the y component 3773 * @return this 3774 */ 3775 ref public Matrix4d scaleXY(double x, double y) return { 3776 return scale(x, y, 1.0); 3777 } 3778 3779 public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4d dest) { 3780 double nm30 = m00 * ox + m10 * oy + m20 * oz + m30; 3781 double nm31 = m01 * ox + m11 * oy + m21 * oz + m31; 3782 double nm32 = m02 * ox + m12 * oy + m22 * oz + m32; 3783 double nm33 = m03 * ox + m13 * oy + m23 * oz + m33; 3784 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 3785 return dest 3786 ._m00(m00 * sx) 3787 ._m01(m01 * sx) 3788 ._m02(m02 * sx) 3789 ._m03(m03 * sx) 3790 ._m10(m10 * sy) 3791 ._m11(m11 * sy) 3792 ._m12(m12 * sy) 3793 ._m13(m13 * sy) 3794 ._m20(m20 * sz) 3795 ._m21(m21 * sz) 3796 ._m22(m22 * sz) 3797 ._m23(m23 * sz) 3798 ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30) 3799 ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31) 3800 ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32) 3801 ._m33(-dest.m03 * ox - dest.m13 * oy - dest.m23 * oz + nm33) 3802 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3803 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3804 } 3805 3806 /** 3807 * Apply scaling to this matrix by scaling the base axes by the given sx, 3808 * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin. 3809 * <p> 3810 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3811 * then the new matrix will be <code>M * S</code>. So when transforming a 3812 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3813 * scaling will be applied first! 3814 * <p> 3815 * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)</code> 3816 * 3817 * @param sx 3818 * the scaling factor of the x component 3819 * @param sy 3820 * the scaling factor of the y component 3821 * @param sz 3822 * the scaling factor of the z component 3823 * @param ox 3824 * the x coordinate of the scaling origin 3825 * @param oy 3826 * the y coordinate of the scaling origin 3827 * @param oz 3828 * the z coordinate of the scaling origin 3829 * @return this 3830 */ 3831 ref public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) return { 3832 scaleAround(sx, sy, sz, ox, oy, oz, this); 3833 return this; 3834 } 3835 3836 /** 3837 * Apply scaling to this matrix by scaling all three base axes by the given <code>factor</code> 3838 * while using <code>(ox, oy, oz)</code> as the scaling origin. 3839 * <p> 3840 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3841 * then the new matrix will be <code>M * S</code>. So when transforming a 3842 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 3843 * scaling will be applied first! 3844 * <p> 3845 * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)</code> 3846 * 3847 * @param factor 3848 * the scaling factor for all three axes 3849 * @param ox 3850 * the x coordinate of the scaling origin 3851 * @param oy 3852 * the y coordinate of the scaling origin 3853 * @param oz 3854 * the z coordinate of the scaling origin 3855 * @return this 3856 */ 3857 ref public Matrix4d scaleAround(double factor, double ox, double oy, double oz) return { 3858 scaleAround(factor, factor, factor, ox, oy, oz, this); 3859 return this; 3860 } 3861 3862 public Matrix4d scaleAround(double factor, double ox, double oy, double oz, ref Matrix4d dest) { 3863 return scaleAround(factor, factor, factor, ox, oy, oz, dest); 3864 } 3865 3866 public Matrix4d scaleLocal(double x, double y, double z, ref Matrix4d dest) { 3867 if ((properties & PROPERTY_IDENTITY) != 0) 3868 return dest.scaling(x, y, z); 3869 return scaleLocalGeneric(x, y, z, dest); 3870 } 3871 private Matrix4d scaleLocalGeneric(double x, double y, double z, ref Matrix4d dest) { 3872 double nm00 = x * m00; 3873 double nm01 = y * m01; 3874 double nm02 = z * m02; 3875 double nm10 = x * m10; 3876 double nm11 = y * m11; 3877 double nm12 = z * m12; 3878 double nm20 = x * m20; 3879 double nm21 = y * m21; 3880 double nm22 = z * m22; 3881 double nm30 = x * m30; 3882 double nm31 = y * m31; 3883 double nm32 = z * m32; 3884 bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z); 3885 dest._m00(nm00) 3886 ._m01(nm01) 3887 ._m02(nm02) 3888 ._m03(m03) 3889 ._m10(nm10) 3890 ._m11(nm11) 3891 ._m12(nm12) 3892 ._m13(m13) 3893 ._m20(nm20) 3894 ._m21(nm21) 3895 ._m22(nm22) 3896 ._m23(m23) 3897 ._m30(nm30) 3898 ._m31(nm31) 3899 ._m32(nm32) 3900 ._m33(m33) 3901 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3902 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3903 return dest; 3904 } 3905 3906 public Matrix4d scaleLocal(double xyz, ref Matrix4d dest) { 3907 return scaleLocal(xyz, xyz, xyz, dest); 3908 } 3909 3910 /** 3911 * Pre-multiply scaling to this matrix by scaling the base axes by the given xyz factor. 3912 * <p> 3913 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3914 * then the new matrix will be <code>S * M</code>. So when transforming a 3915 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3916 * scaling will be applied last! 3917 * 3918 * @param xyz 3919 * the factor of the x, y and z component 3920 * @return this 3921 */ 3922 ref public Matrix4d scaleLocal(double xyz) return { 3923 scaleLocal(xyz, this); 3924 return this; 3925 } 3926 3927 /** 3928 * Pre-multiply scaling to this matrix by scaling the base axes by the given x, 3929 * y and z factors. 3930 * <p> 3931 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3932 * then the new matrix will be <code>S * M</code>. So when transforming a 3933 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3934 * scaling will be applied last! 3935 * 3936 * @param x 3937 * the factor of the x component 3938 * @param y 3939 * the factor of the y component 3940 * @param z 3941 * the factor of the z component 3942 * @return this 3943 */ 3944 ref public Matrix4d scaleLocal(double x, double y, double z) return { 3945 scaleLocal(x, y, z, this); 3946 return this; 3947 } 3948 3949 public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4d dest) { 3950 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 3951 dest._m00(sx * (m00 - ox * m03) + ox * m03) 3952 ._m01(sy * (m01 - oy * m03) + oy * m03) 3953 ._m02(sz * (m02 - oz * m03) + oz * m03) 3954 ._m03(m03) 3955 ._m10(sx * (m10 - ox * m13) + ox * m13) 3956 ._m11(sy * (m11 - oy * m13) + oy * m13) 3957 ._m12(sz * (m12 - oz * m13) + oz * m13) 3958 ._m13(m13) 3959 ._m20(sx * (m20 - ox * m23) + ox * m23) 3960 ._m21(sy * (m21 - oy * m23) + oy * m23) 3961 ._m22(sz * (m22 - oz * m23) + oz * m23) 3962 ._m23(m23) 3963 ._m30(sx * (m30 - ox * m33) + ox * m33) 3964 ._m31(sy * (m31 - oy * m33) + oy * m33) 3965 ._m32(sz * (m32 - oz * m33) + oz * m33) 3966 ._m33(m33) 3967 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 3968 | (one ? 0 : PROPERTY_ORTHONORMAL))); 3969 return dest; 3970 } 3971 3972 /** 3973 * Pre-multiply scaling to this matrix by scaling the base axes by the given sx, 3974 * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin. 3975 * <p> 3976 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 3977 * then the new matrix will be <code>S * M</code>. So when transforming a 3978 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 3979 * scaling will be applied last! 3980 * <p> 3981 * 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> 3982 * 3983 * @param sx 3984 * the scaling factor of the x component 3985 * @param sy 3986 * the scaling factor of the y component 3987 * @param sz 3988 * the scaling factor of the z component 3989 * @param ox 3990 * the x coordinate of the scaling origin 3991 * @param oy 3992 * the y coordinate of the scaling origin 3993 * @param oz 3994 * the z coordinate of the scaling origin 3995 * @return this 3996 */ 3997 ref public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz) return { 3998 scaleAroundLocal(sx, sy, sz, ox, oy, oz, this); 3999 return this; 4000 } 4001 4002 /** 4003 * Pre-multiply scaling to this matrix by scaling all three base axes by the given <code>factor</code> 4004 * while using <code>(ox, oy, oz)</code> as the scaling origin. 4005 * <p> 4006 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 4007 * then the new matrix will be <code>S * M</code>. So when transforming a 4008 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 4009 * scaling will be applied last! 4010 * <p> 4011 * This method is equivalent to calling: <code>new Matrix4d().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, this)</code> 4012 * 4013 * @param factor 4014 * the scaling factor for all three axes 4015 * @param ox 4016 * the x coordinate of the scaling origin 4017 * @param oy 4018 * the y coordinate of the scaling origin 4019 * @param oz 4020 * the z coordinate of the scaling origin 4021 * @return this 4022 */ 4023 ref public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz) return { 4024 scaleAroundLocal(factor, factor, factor, ox, oy, oz, this); 4025 return this; 4026 } 4027 4028 public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz, ref Matrix4d dest) { 4029 return scaleAroundLocal(factor, factor, factor, ox, oy, oz, dest); 4030 } 4031 4032 public Matrix4d rotate(double ang, double x, double y, double z, ref Matrix4d dest) { 4033 if ((properties & PROPERTY_IDENTITY) != 0) 4034 return dest.rotation(ang, x, y, z); 4035 else if ((properties & PROPERTY_TRANSLATION) != 0) 4036 return rotateTranslation(ang, x, y, z, dest); 4037 else if ((properties & PROPERTY_AFFINE) != 0) 4038 return rotateAffine(ang, x, y, z, dest); 4039 return rotateGeneric(ang, x, y, z, dest); 4040 } 4041 private Matrix4d rotateGeneric(double ang, double x, double y, double z, ref Matrix4d dest) { 4042 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4043 return rotateX(x * ang, dest); 4044 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4045 return rotateY(y * ang, dest); 4046 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4047 return rotateZ(z * ang, dest); 4048 return rotateGenericInternal(ang, x, y, z, dest); 4049 } 4050 private Matrix4d rotateGenericInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4051 double s = Math.sin(ang); 4052 double c = Math.cosFromSin(s, ang); 4053 double C = 1.0 - c; 4054 double xx = x * x, xy = x * y, xz = x * z; 4055 double yy = y * y, yz = y * z; 4056 double zz = z * z; 4057 double rm00 = xx * C + c; 4058 double rm01 = xy * C + z * s; 4059 double rm02 = xz * C - y * s; 4060 double rm10 = xy * C - z * s; 4061 double rm11 = yy * C + c; 4062 double rm12 = yz * C + x * s; 4063 double rm20 = xz * C + y * s; 4064 double rm21 = yz * C - x * s; 4065 double rm22 = zz * C + c; 4066 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4067 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4068 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4069 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 4070 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4071 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4072 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4073 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 4074 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4075 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4076 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4077 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 4078 ._m00(nm00) 4079 ._m01(nm01) 4080 ._m02(nm02) 4081 ._m03(nm03) 4082 ._m10(nm10) 4083 ._m11(nm11) 4084 ._m12(nm12) 4085 ._m13(nm13) 4086 ._m30(m30) 4087 ._m31(m31) 4088 ._m32(m32) 4089 ._m33(m33) 4090 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4091 return dest; 4092 } 4093 4094 /** 4095 * Apply rotation to this matrix by rotating the given amount of radians 4096 * about the given axis specified as x, y and z components. 4097 * <p> 4098 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4099 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4100 * When used with a left-handed coordinate system, the rotation is clockwise. 4101 * <p> 4102 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4103 * then the new matrix will be <code>M * R</code>. So when transforming a 4104 * vector <code>v</code> with the new matrix by using <code>M * R * v</code> 4105 * , the rotation will be applied first! 4106 * <p> 4107 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4108 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4109 * 4110 * @see #rotation(double, double, double, double) 4111 * 4112 * @param ang 4113 * the angle is in radians 4114 * @param x 4115 * the x component of the axis 4116 * @param y 4117 * the y component of the axis 4118 * @param z 4119 * the z component of the axis 4120 * @return this 4121 */ 4122 ref public Matrix4d rotate(double ang, double x, double y, double z) return { 4123 rotate(ang, x, y, z, this); 4124 return this; 4125 } 4126 4127 /** 4128 * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians 4129 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4130 * <p> 4131 * This method assumes <code>this</code> to only contain a translation. 4132 * <p> 4133 * The axis described by the three components needs to be a unit vector. 4134 * <p> 4135 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4136 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4137 * When used with a left-handed coordinate system, the rotation is clockwise. 4138 * <p> 4139 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4140 * then the new matrix will be <code>M * R</code>. So when transforming a 4141 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4142 * rotation will be applied first! 4143 * <p> 4144 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4145 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4146 * <p> 4147 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4148 * 4149 * @see #rotation(double, double, double, double) 4150 * 4151 * @param ang 4152 * the angle in radians 4153 * @param x 4154 * the x component of the axis 4155 * @param y 4156 * the y component of the axis 4157 * @param z 4158 * the z component of the axis 4159 * @param dest 4160 * will hold the result 4161 * @return dest 4162 */ 4163 public Matrix4d rotateTranslation(double ang, double x, double y, double z, ref Matrix4d dest) { 4164 double tx = m30, ty = m31, tz = m32; 4165 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4166 return dest.rotationX(x * ang).setTranslation(tx, ty, tz); 4167 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4168 return dest.rotationY(y * ang).setTranslation(tx, ty, tz); 4169 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4170 return dest.rotationZ(z * ang).setTranslation(tx, ty, tz); 4171 return rotateTranslationInternal(ang, x, y, z, dest); 4172 } 4173 private Matrix4d rotateTranslationInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4174 double s = Math.sin(ang); 4175 double c = Math.cosFromSin(s, ang); 4176 double C = 1.0 - c; 4177 double xx = x * x, xy = x * y, xz = x * z; 4178 double yy = y * y, yz = y * z; 4179 double zz = z * z; 4180 double rm00 = xx * C + c; 4181 double rm01 = xy * C + z * s; 4182 double rm02 = xz * C - y * s; 4183 double rm10 = xy * C - z * s; 4184 double rm11 = yy * C + c; 4185 double rm12 = yz * C + x * s; 4186 double rm20 = xz * C + y * s; 4187 double rm21 = yz * C - x * s; 4188 double rm22 = zz * C + c; 4189 return dest 4190 ._m20(rm20) 4191 ._m21(rm21) 4192 ._m22(rm22) 4193 ._m23(0.0) 4194 ._m00(rm00) 4195 ._m01(rm01) 4196 ._m02(rm02) 4197 ._m03(0.0) 4198 ._m10(rm10) 4199 ._m11(rm11) 4200 ._m12(rm12) 4201 ._m13(0.0) 4202 ._m30(m30) 4203 ._m31(m31) 4204 ._m32(m32) 4205 ._m33(1.0) 4206 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4207 } 4208 4209 /** 4210 * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians 4211 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4212 * <p> 4213 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 4214 * <p> 4215 * The axis described by the three components needs to be a unit vector. 4216 * <p> 4217 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4218 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4219 * When used with a left-handed coordinate system, the rotation is clockwise. 4220 * <p> 4221 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4222 * then the new matrix will be <code>M * R</code>. So when transforming a 4223 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4224 * rotation will be applied first! 4225 * <p> 4226 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4227 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4228 * <p> 4229 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4230 * 4231 * @see #rotation(double, double, double, double) 4232 * 4233 * @param ang 4234 * the angle in radians 4235 * @param x 4236 * the x component of the axis 4237 * @param y 4238 * the y component of the axis 4239 * @param z 4240 * the z component of the axis 4241 * @param dest 4242 * will hold the result 4243 * @return dest 4244 */ 4245 public Matrix4d rotateAffine(double ang, double x, double y, double z, ref Matrix4d dest) { 4246 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4247 return rotateX(x * ang, dest); 4248 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4249 return rotateY(y * ang, dest); 4250 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4251 return rotateZ(z * ang, dest); 4252 return rotateAffineInternal(ang, x, y, z, dest); 4253 } 4254 private Matrix4d rotateAffineInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4255 double s = Math.sin(ang); 4256 double c = Math.cosFromSin(s, ang); 4257 double C = 1.0 - c; 4258 double xx = x * x, xy = x * y, xz = x * z; 4259 double yy = y * y, yz = y * z; 4260 double zz = z * z; 4261 double rm00 = xx * C + c; 4262 double rm01 = xy * C + z * s; 4263 double rm02 = xz * C - y * s; 4264 double rm10 = xy * C - z * s; 4265 double rm11 = yy * C + c; 4266 double rm12 = yz * C + x * s; 4267 double rm20 = xz * C + y * s; 4268 double rm21 = yz * C - x * s; 4269 double rm22 = zz * C + c; 4270 // add temporaries for dependent values 4271 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4272 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4273 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4274 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4275 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4276 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4277 // set non-dependent values directly 4278 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4279 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4280 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4281 ._m23(0.0) 4282 // set other values 4283 ._m00(nm00) 4284 ._m01(nm01) 4285 ._m02(nm02) 4286 ._m03(0.0) 4287 ._m10(nm10) 4288 ._m11(nm11) 4289 ._m12(nm12) 4290 ._m13(0.0) 4291 ._m30(m30) 4292 ._m31(m31) 4293 ._m32(m32) 4294 ._m33(m33) 4295 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4296 return dest; 4297 } 4298 4299 /** 4300 * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians 4301 * about the specified <code>(x, y, z)</code> axis. 4302 * <p> 4303 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 4304 * <p> 4305 * The axis described by the three components needs to be a unit vector. 4306 * <p> 4307 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4308 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4309 * When used with a left-handed coordinate system, the rotation is clockwise. 4310 * <p> 4311 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4312 * then the new matrix will be <code>M * R</code>. So when transforming a 4313 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 4314 * rotation will be applied first! 4315 * <p> 4316 * In order to set the matrix to a rotation matrix without post-multiplying the rotation 4317 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4318 * <p> 4319 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4320 * 4321 * @see #rotation(double, double, double, double) 4322 * 4323 * @param ang 4324 * the angle in radians 4325 * @param x 4326 * the x component of the axis 4327 * @param y 4328 * the y component of the axis 4329 * @param z 4330 * the z component of the axis 4331 * @return this 4332 */ 4333 ref public Matrix4d rotateAffine(double ang, double x, double y, double z) return { 4334 rotateAffine(ang, x, y, z, this); 4335 return this; 4336 } 4337 4338 /** 4339 * Apply the rotation transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> as the rotation origin. 4340 * <p> 4341 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4342 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4343 * When used with a left-handed coordinate system, the rotation is clockwise. 4344 * <p> 4345 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 4346 * then the new matrix will be <code>M * Q</code>. So when transforming a 4347 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 4348 * the quaternion rotation will be applied first! 4349 * <p> 4350 * This method is equivalent to calling: <code>translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code> 4351 * <p> 4352 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4353 * 4354 * @param quat 4355 * the {@link Quaterniond} 4356 * @param ox 4357 * the x coordinate of the rotation origin 4358 * @param oy 4359 * the y coordinate of the rotation origin 4360 * @param oz 4361 * the z coordinate of the rotation origin 4362 * @return this 4363 */ 4364 ref public Matrix4d rotateAround(ref Quaterniond quat, double ox, double oy, double oz) return { 4365 rotateAround(quat, ox, oy, oz, this); 4366 return this; 4367 } 4368 4369 public Matrix4d rotateAroundAffine(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4370 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4371 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4372 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4373 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4374 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4375 double rm00 = w2 + x2 - z2 - y2; 4376 double rm01 = dxy + dzw; 4377 double rm02 = dxz - dyw; 4378 double rm10 = -dzw + dxy; 4379 double rm11 = y2 - z2 + w2 - x2; 4380 double rm12 = dyz + dxw; 4381 double rm20 = dyw + dxz; 4382 double rm21 = dyz - dxw; 4383 double rm22 = z2 - y2 - x2 + w2; 4384 double tm30 = m00 * ox + m10 * oy + m20 * oz + m30; 4385 double tm31 = m01 * ox + m11 * oy + m21 * oz + m31; 4386 double tm32 = m02 * ox + m12 * oy + m22 * oz + m32; 4387 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4388 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4389 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4390 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4391 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4392 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4393 dest 4394 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4395 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4396 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4397 ._m23(0.0) 4398 ._m00(nm00) 4399 ._m01(nm01) 4400 ._m02(nm02) 4401 ._m03(0.0) 4402 ._m10(nm10) 4403 ._m11(nm11) 4404 ._m12(nm12) 4405 ._m13(0.0) 4406 ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30) 4407 ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31) 4408 ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32) 4409 ._m33(1.0) 4410 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4411 return dest; 4412 } 4413 4414 public Matrix4d rotateAround(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4415 if ((properties & PROPERTY_IDENTITY) != 0) 4416 return rotationAround(quat, ox, oy, oz); 4417 else if ((properties & PROPERTY_AFFINE) != 0) 4418 return rotateAroundAffine(quat, ox, oy, oz, this); 4419 return rotateAroundGeneric(quat, ox, oy, oz, this); 4420 } 4421 private Matrix4d rotateAroundGeneric(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4422 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4423 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4424 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4425 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4426 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4427 double rm00 = w2 + x2 - z2 - y2; 4428 double rm01 = dxy + dzw; 4429 double rm02 = dxz - dyw; 4430 double rm10 = -dzw + dxy; 4431 double rm11 = y2 - z2 + w2 - x2; 4432 double rm12 = dyz + dxw; 4433 double rm20 = dyw + dxz; 4434 double rm21 = dyz - dxw; 4435 double rm22 = z2 - y2 - x2 + w2; 4436 double tm30 = m00 * ox + m10 * oy + m20 * oz + m30; 4437 double tm31 = m01 * ox + m11 * oy + m21 * oz + m31; 4438 double tm32 = m02 * ox + m12 * oy + m22 * oz + m32; 4439 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 4440 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 4441 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 4442 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 4443 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 4444 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 4445 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 4446 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 4447 dest 4448 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 4449 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 4450 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 4451 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 4452 ._m00(nm00) 4453 ._m01(nm01) 4454 ._m02(nm02) 4455 ._m03(nm03) 4456 ._m10(nm10) 4457 ._m11(nm11) 4458 ._m12(nm12) 4459 ._m13(nm13) 4460 ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30) 4461 ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31) 4462 ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32) 4463 ._m33(m33) 4464 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4465 return dest; 4466 } 4467 4468 /** 4469 * 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. 4470 * <p> 4471 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4472 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4473 * When used with a left-handed coordinate system, the rotation is clockwise. 4474 * <p> 4475 * This method is equivalent to calling: <code>translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code> 4476 * <p> 4477 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4478 * 4479 * @param quat 4480 * the {@link Quaterniond} 4481 * @param ox 4482 * the x coordinate of the rotation origin 4483 * @param oy 4484 * the y coordinate of the rotation origin 4485 * @param oz 4486 * the z coordinate of the rotation origin 4487 * @return this 4488 */ 4489 ref public Matrix4d rotationAround(ref Quaterniond quat, double ox, double oy, double oz) return { 4490 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 4491 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 4492 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 4493 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 4494 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 4495 this._m20(dyw + dxz); 4496 this._m21(dyz - dxw); 4497 this._m22(z2 - y2 - x2 + w2); 4498 this._m23(0.0); 4499 this._m00(w2 + x2 - z2 - y2); 4500 this._m01(dxy + dzw); 4501 this._m02(dxz - dyw); 4502 this._m03(0.0); 4503 this._m10(-dzw + dxy); 4504 this._m11(y2 - z2 + w2 - x2); 4505 this._m12(dyz + dxw); 4506 this._m13(0.0); 4507 this._m30(-m00 * ox - m10 * oy - m20 * oz + ox); 4508 this._m31(-m01 * ox - m11 * oy - m21 * oz + oy); 4509 this._m32(-m02 * ox - m12 * oy - m22 * oz + oz); 4510 this._m33(1.0); 4511 this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 4512 return this; 4513 } 4514 4515 /** 4516 * Pre-multiply a rotation to this matrix by rotating the given amount of radians 4517 * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>. 4518 * <p> 4519 * The axis described by the three components needs to be a unit vector. 4520 * <p> 4521 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4522 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4523 * When used with a left-handed coordinate system, the rotation is clockwise. 4524 * <p> 4525 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4526 * then the new matrix will be <code>R * M</code>. So when transforming a 4527 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 4528 * rotation will be applied last! 4529 * <p> 4530 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 4531 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4532 * <p> 4533 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4534 * 4535 * @see #rotation(double, double, double, double) 4536 * 4537 * @param ang 4538 * the angle in radians 4539 * @param x 4540 * the x component of the axis 4541 * @param y 4542 * the y component of the axis 4543 * @param z 4544 * the z component of the axis 4545 * @param dest 4546 * will hold the result 4547 * @return dest 4548 */ 4549 public Matrix4d rotateLocal(double ang, double x, double y, double z, ref Matrix4d dest) { 4550 if ((properties & PROPERTY_IDENTITY) != 0) 4551 return dest.rotation(ang, x, y, z); 4552 return rotateLocalGeneric(ang, x, y, z, dest); 4553 } 4554 private Matrix4d rotateLocalGeneric(double ang, double x, double y, double z, ref Matrix4d dest) { 4555 if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x)) 4556 return rotateLocalX(x * ang, dest); 4557 else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y)) 4558 return rotateLocalY(y * ang, dest); 4559 else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z)) 4560 return rotateLocalZ(z * ang, dest); 4561 return rotateLocalGenericInternal(ang, x, y, z, dest); 4562 } 4563 private Matrix4d rotateLocalGenericInternal(double ang, double x, double y, double z, ref Matrix4d dest) { 4564 double s = Math.sin(ang); 4565 double c = Math.cosFromSin(s, ang); 4566 double C = 1.0 - c; 4567 double xx = x * x, xy = x * y, xz = x * z; 4568 double yy = y * y, yz = y * z; 4569 double zz = z * z; 4570 double lm00 = xx * C + c; 4571 double lm01 = xy * C + z * s; 4572 double lm02 = xz * C - y * s; 4573 double lm10 = xy * C - z * s; 4574 double lm11 = yy * C + c; 4575 double lm12 = yz * C + x * s; 4576 double lm20 = xz * C + y * s; 4577 double lm21 = yz * C - x * s; 4578 double lm22 = zz * C + c; 4579 double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; 4580 double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; 4581 double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; 4582 double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; 4583 double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; 4584 double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; 4585 double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; 4586 double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; 4587 double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; 4588 double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32; 4589 double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32; 4590 double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32; 4591 dest._m00(nm00) 4592 ._m01(nm01) 4593 ._m02(nm02) 4594 ._m03(m03) 4595 ._m10(nm10) 4596 ._m11(nm11) 4597 ._m12(nm12) 4598 ._m13(m13) 4599 ._m20(nm20) 4600 ._m21(nm21) 4601 ._m22(nm22) 4602 ._m23(m23) 4603 ._m30(nm30) 4604 ._m31(nm31) 4605 ._m32(nm32) 4606 ._m33(m33) 4607 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4608 return dest; 4609 } 4610 4611 /** 4612 * Pre-multiply a rotation to this matrix by rotating the given amount of radians 4613 * about the specified <code>(x, y, z)</code> axis. 4614 * <p> 4615 * The axis described by the three components needs to be a unit vector. 4616 * <p> 4617 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4618 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4619 * When used with a left-handed coordinate system, the rotation is clockwise. 4620 * <p> 4621 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 4622 * then the new matrix will be <code>R * M</code>. So when transforming a 4623 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 4624 * rotation will be applied last! 4625 * <p> 4626 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 4627 * transformation, use {@link #rotation(double, double, double, double) rotation()}. 4628 * <p> 4629 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 4630 * 4631 * @see #rotation(double, double, double, double) 4632 * 4633 * @param ang 4634 * the angle in radians 4635 * @param x 4636 * the x component of the axis 4637 * @param y 4638 * the y component of the axis 4639 * @param z 4640 * the z component of the axis 4641 * @return this 4642 */ 4643 ref public Matrix4d rotateLocal(double ang, double x, double y, double z) return { 4644 rotateLocal(ang, x, y, z, this); 4645 return this; 4646 } 4647 4648 public Matrix4d rotateAroundLocal(ref Quaterniond quat, double ox, double oy, double oz, ref Matrix4d dest) { 4649 double w2 = quat.w * quat.w; 4650 double x2 = quat.x * quat.x; 4651 double y2 = quat.y * quat.y; 4652 double z2 = quat.z * quat.z; 4653 double zw = quat.z * quat.w; 4654 double xy = quat.x * quat.y; 4655 double xz = quat.x * quat.z; 4656 double yw = quat.y * quat.w; 4657 double yz = quat.y * quat.z; 4658 double xw = quat.x * quat.w; 4659 double lm00 = w2 + x2 - z2 - y2; 4660 double lm01 = xy + zw + zw + xy; 4661 double lm02 = xz - yw + xz - yw; 4662 double lm10 = -zw + xy - zw + xy; 4663 double lm11 = y2 - z2 + w2 - x2; 4664 double lm12 = yz + yz + xw + xw; 4665 double lm20 = yw + xz + xz + yw; 4666 double lm21 = yz + yz - xw - xw; 4667 double lm22 = z2 - y2 - x2 + w2; 4668 double tm00 = m00 - ox * m03; 4669 double tm01 = m01 - oy * m03; 4670 double tm02 = m02 - oz * m03; 4671 double tm10 = m10 - ox * m13; 4672 double tm11 = m11 - oy * m13; 4673 double tm12 = m12 - oz * m13; 4674 double tm20 = m20 - ox * m23; 4675 double tm21 = m21 - oy * m23; 4676 double tm22 = m22 - oz * m23; 4677 double tm30 = m30 - ox * m33; 4678 double tm31 = m31 - oy * m33; 4679 double tm32 = m32 - oz * m33; 4680 dest._m00(lm00 * tm00 + lm10 * tm01 + lm20 * tm02 + ox * m03) 4681 ._m01(lm01 * tm00 + lm11 * tm01 + lm21 * tm02 + oy * m03) 4682 ._m02(lm02 * tm00 + lm12 * tm01 + lm22 * tm02 + oz * m03) 4683 ._m03(m03) 4684 ._m10(lm00 * tm10 + lm10 * tm11 + lm20 * tm12 + ox * m13) 4685 ._m11(lm01 * tm10 + lm11 * tm11 + lm21 * tm12 + oy * m13) 4686 ._m12(lm02 * tm10 + lm12 * tm11 + lm22 * tm12 + oz * m13) 4687 ._m13(m13) 4688 ._m20(lm00 * tm20 + lm10 * tm21 + lm20 * tm22 + ox * m23) 4689 ._m21(lm01 * tm20 + lm11 * tm21 + lm21 * tm22 + oy * m23) 4690 ._m22(lm02 * tm20 + lm12 * tm21 + lm22 * tm22 + oz * m23) 4691 ._m23(m23) 4692 ._m30(lm00 * tm30 + lm10 * tm31 + lm20 * tm32 + ox * m33) 4693 ._m31(lm01 * tm30 + lm11 * tm31 + lm21 * tm32 + oy * m33) 4694 ._m32(lm02 * tm30 + lm12 * tm31 + lm22 * tm32 + oz * m33) 4695 ._m33(m33) 4696 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 4697 return dest; 4698 } 4699 4700 /** 4701 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> 4702 * as the rotation origin. 4703 * <p> 4704 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 4705 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 4706 * When used with a left-handed coordinate system, the rotation is clockwise. 4707 * <p> 4708 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 4709 * then the new matrix will be <code>Q * M</code>. So when transforming a 4710 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 4711 * the quaternion rotation will be applied last! 4712 * <p> 4713 * This method is equivalent to calling: <code>translateLocal(-ox, -oy, -oz).rotateLocal(quat).translateLocal(ox, oy, oz)</code> 4714 * <p> 4715 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 4716 * 4717 * @param quat 4718 * the {@link Quaterniond} 4719 * @param ox 4720 * the x coordinate of the rotation origin 4721 * @param oy 4722 * the y coordinate of the rotation origin 4723 * @param oz 4724 * the z coordinate of the rotation origin 4725 * @return this 4726 */ 4727 ref public Matrix4d rotateAroundLocal(ref Quaterniond quat, double ox, double oy, double oz) return { 4728 rotateAroundLocal(quat, ox, oy, oz, this); 4729 return this; 4730 } 4731 4732 /** 4733 * Apply a translation to this matrix by translating by the given number of 4734 * units in x, y and z. 4735 * <p> 4736 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4737 * matrix, then the new matrix will be <code>M * T</code>. So when 4738 * transforming a vector <code>v</code> with the new matrix by using 4739 * <code>M * T * v</code>, the translation will be applied first! 4740 * <p> 4741 * In order to set the matrix to a translation transformation without post-multiplying 4742 * it, use {@link #translation(ref Vector3d)}. 4743 * 4744 * @see #translation(ref Vector3d) 4745 * 4746 * @param offset 4747 * the number of units in x, y and z by which to translate 4748 * @return this 4749 */ 4750 ref public Matrix4d translate(ref Vector3d offset) return { 4751 return translate(offset.x, offset.y, offset.z); 4752 } 4753 4754 /** 4755 * Apply a translation to this matrix by translating by the given number of 4756 * units in x, y and z and store the result in <code>dest</code>. 4757 * <p> 4758 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4759 * matrix, then the new matrix will be <code>M * T</code>. So when 4760 * transforming a vector <code>v</code> with the new matrix by using 4761 * <code>M * T * v</code>, the translation will be applied first! 4762 * <p> 4763 * In order to set the matrix to a translation transformation without post-multiplying 4764 * it, use {@link #translation(ref Vector3d)}. 4765 * 4766 * @see #translation(ref Vector3d) 4767 * 4768 * @param offset 4769 * the number of units in x, y and z by which to translate 4770 * @param dest 4771 * will hold the result 4772 * @return dest 4773 */ 4774 public Matrix4d translate(ref Vector3d offset, ref Matrix4d dest) { 4775 return translate(offset.x, offset.y, offset.z, dest); 4776 } 4777 4778 4779 4780 /** 4781 * Apply a translation to this matrix by translating by the given number of 4782 * units in x, y and z and store the result in <code>dest</code>. 4783 * <p> 4784 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4785 * matrix, then the new matrix will be <code>M * T</code>. So when 4786 * transforming a vector <code>v</code> with the new matrix by using 4787 * <code>M * T * v</code>, the translation will be applied first! 4788 * <p> 4789 * In order to set the matrix to a translation transformation without post-multiplying 4790 * it, use {@link #translation(double, double, double)}. 4791 * 4792 * @see #translation(double, double, double) 4793 * 4794 * @param x 4795 * the offset to translate in x 4796 * @param y 4797 * the offset to translate in y 4798 * @param z 4799 * the offset to translate in z 4800 * @param dest 4801 * will hold the result 4802 * @return dest 4803 */ 4804 public Matrix4d translate(double x, double y, double z, ref Matrix4d dest) { 4805 if ((properties & PROPERTY_IDENTITY) != 0) 4806 return dest.translation(x, y, z); 4807 return translateGeneric(x, y, z, dest); 4808 } 4809 private Matrix4d translateGeneric(double x, double y, double z, ref Matrix4d dest) { 4810 dest._m00(m00) 4811 ._m01(m01) 4812 ._m02(m02) 4813 ._m03(m03) 4814 ._m10(m10) 4815 ._m11(m11) 4816 ._m12(m12) 4817 ._m13(m13) 4818 ._m20(m20) 4819 ._m21(m21) 4820 ._m22(m22) 4821 ._m23(m23) 4822 ._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30)))) 4823 ._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31)))) 4824 ._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32)))) 4825 ._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)))) 4826 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY)); 4827 return dest; 4828 } 4829 4830 /** 4831 * Apply a translation to this matrix by translating by the given number of 4832 * units in x, y and z. 4833 * <p> 4834 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4835 * matrix, then the new matrix will be <code>M * T</code>. So when 4836 * transforming a vector <code>v</code> with the new matrix by using 4837 * <code>M * T * v</code>, the translation will be applied first! 4838 * <p> 4839 * In order to set the matrix to a translation transformation without post-multiplying 4840 * it, use {@link #translation(double, double, double)}. 4841 * 4842 * @see #translation(double, double, double) 4843 * 4844 * @param x 4845 * the offset to translate in x 4846 * @param y 4847 * the offset to translate in y 4848 * @param z 4849 * the offset to translate in z 4850 * @return this 4851 */ 4852 ref public Matrix4d translate(double x, double y, double z) return { 4853 if ((properties & PROPERTY_IDENTITY) != 0) 4854 return translation(x, y, z); 4855 this._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30)))); 4856 this._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31)))); 4857 this._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32)))); 4858 this._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)))); 4859 this.properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY); 4860 return this; 4861 } 4862 4863 /** 4864 * Pre-multiply a translation to this matrix by translating by the given number of 4865 * units in x, y and z. 4866 * <p> 4867 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4868 * matrix, then the new matrix will be <code>T * M</code>. So when 4869 * transforming a vector <code>v</code> with the new matrix by using 4870 * <code>T * M * v</code>, the translation will be applied last! 4871 * <p> 4872 * In order to set the matrix to a translation transformation without pre-multiplying 4873 * it, use {@link #translation(ref Vector3d)}. 4874 * 4875 * @see #translation(ref Vector3d) 4876 * 4877 * @param offset 4878 * the number of units in x, y and z by which to translate 4879 * @return this 4880 */ 4881 ref public Matrix4d translateLocal(ref Vector3d offset) return { 4882 return translateLocal(offset.x, offset.y, offset.z); 4883 } 4884 4885 /** 4886 * Pre-multiply a translation to this matrix by translating by the given number of 4887 * units in x, y and z and store the result in <code>dest</code>. 4888 * <p> 4889 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4890 * matrix, then the new matrix will be <code>T * M</code>. So when 4891 * transforming a vector <code>v</code> with the new matrix by using 4892 * <code>T * M * v</code>, the translation will be applied last! 4893 * <p> 4894 * In order to set the matrix to a translation transformation without pre-multiplying 4895 * it, use {@link #translation(ref Vector3d)}. 4896 * 4897 * @see #translation(ref Vector3d) 4898 * 4899 * @param offset 4900 * the number of units in x, y and z by which to translate 4901 * @param dest 4902 * will hold the result 4903 * @return dest 4904 */ 4905 public Matrix4d translateLocal(ref Vector3d offset, ref Matrix4d dest) { 4906 return translateLocal(offset.x, offset.y, offset.z, dest); 4907 } 4908 4909 /** 4910 * Pre-multiply a translation to this matrix by translating by the given number of 4911 * units in x, y and z and store the result in <code>dest</code>. 4912 * <p> 4913 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4914 * matrix, then the new matrix will be <code>T * M</code>. So when 4915 * transforming a vector <code>v</code> with the new matrix by using 4916 * <code>T * M * v</code>, the translation will be applied last! 4917 * <p> 4918 * In order to set the matrix to a translation transformation without pre-multiplying 4919 * it, use {@link #translation(double, double, double)}. 4920 * 4921 * @see #translation(double, double, double) 4922 * 4923 * @param x 4924 * the offset to translate in x 4925 * @param y 4926 * the offset to translate in y 4927 * @param z 4928 * the offset to translate in z 4929 * @param dest 4930 * will hold the result 4931 * @return dest 4932 */ 4933 public Matrix4d translateLocal(double x, double y, double z, ref Matrix4d dest) { 4934 if ((properties & PROPERTY_IDENTITY) != 0) 4935 return dest.translation(x, y, z); 4936 return translateLocalGeneric(x, y, z, dest); 4937 } 4938 private Matrix4d translateLocalGeneric(double x, double y, double z, ref Matrix4d dest) { 4939 double nm00 = m00 + x * m03; 4940 double nm01 = m01 + y * m03; 4941 double nm02 = m02 + z * m03; 4942 double nm10 = m10 + x * m13; 4943 double nm11 = m11 + y * m13; 4944 double nm12 = m12 + z * m13; 4945 double nm20 = m20 + x * m23; 4946 double nm21 = m21 + y * m23; 4947 double nm22 = m22 + z * m23; 4948 double nm30 = m30 + x * m33; 4949 double nm31 = m31 + y * m33; 4950 double nm32 = m32 + z * m33; 4951 return dest 4952 ._m00(nm00) 4953 ._m01(nm01) 4954 ._m02(nm02) 4955 ._m03(m03) 4956 ._m10(nm10) 4957 ._m11(nm11) 4958 ._m12(nm12) 4959 ._m13(m13) 4960 ._m20(nm20) 4961 ._m21(nm21) 4962 ._m22(nm22) 4963 ._m23(m23) 4964 ._m30(nm30) 4965 ._m31(nm31) 4966 ._m32(nm32) 4967 ._m33(m33) 4968 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY)); 4969 } 4970 4971 /** 4972 * Pre-multiply a translation to this matrix by translating by the given number of 4973 * units in x, y and z. 4974 * <p> 4975 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation 4976 * matrix, then the new matrix will be <code>T * M</code>. So when 4977 * transforming a vector <code>v</code> with the new matrix by using 4978 * <code>T * M * v</code>, the translation will be applied last! 4979 * <p> 4980 * In order to set the matrix to a translation transformation without pre-multiplying 4981 * it, use {@link #translation(double, double, double)}. 4982 * 4983 * @see #translation(double, double, double) 4984 * 4985 * @param x 4986 * the offset to translate in x 4987 * @param y 4988 * the offset to translate in y 4989 * @param z 4990 * the offset to translate in z 4991 * @return this 4992 */ 4993 ref public Matrix4d translateLocal(double x, double y, double z) return { 4994 translateLocal(x, y, z, this); 4995 return this; 4996 } 4997 4998 /** 4999 * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians 5000 * about the X axis and store the result in <code>dest</code>. 5001 * <p> 5002 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5003 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5004 * When used with a left-handed coordinate system, the rotation is clockwise. 5005 * <p> 5006 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5007 * then the new matrix will be <code>R * M</code>. So when transforming a 5008 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5009 * rotation will be applied last! 5010 * <p> 5011 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5012 * transformation, use {@link #rotationX(double) rotationX()}. 5013 * <p> 5014 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5015 * 5016 * @see #rotationX(double) 5017 * 5018 * @param ang 5019 * the angle in radians to rotate about the X axis 5020 * @param dest 5021 * will hold the result 5022 * @return dest 5023 */ 5024 public Matrix4d rotateLocalX(double ang, ref Matrix4d dest) { 5025 double sin = Math.sin(ang); 5026 double cos = Math.cosFromSin(sin, ang); 5027 double nm02 = sin * m01 + cos * m02; 5028 double nm12 = sin * m11 + cos * m12; 5029 double nm22 = sin * m21 + cos * m22; 5030 double nm32 = sin * m31 + cos * m32; 5031 dest 5032 ._m00(m00) 5033 ._m01(cos * m01 - sin * m02) 5034 ._m02(nm02) 5035 ._m03(m03) 5036 ._m10(m10) 5037 ._m11(cos * m11 - sin * m12) 5038 ._m12(nm12) 5039 ._m13(m13) 5040 ._m20(m20) 5041 ._m21(cos * m21 - sin * m22) 5042 ._m22(nm22) 5043 ._m23(m23) 5044 ._m30(m30) 5045 ._m31(cos * m31 - sin * m32) 5046 ._m32(nm32) 5047 ._m33(m33) 5048 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5049 return dest; 5050 } 5051 5052 /** 5053 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis. 5054 * <p> 5055 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5056 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5057 * When used with a left-handed coordinate system, the rotation is clockwise. 5058 * <p> 5059 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5060 * then the new matrix will be <code>R * M</code>. So when transforming a 5061 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5062 * rotation will be applied last! 5063 * <p> 5064 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5065 * transformation, use {@link #rotationX(double) rotationX()}. 5066 * <p> 5067 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5068 * 5069 * @see #rotationX(double) 5070 * 5071 * @param ang 5072 * the angle in radians to rotate about the X axis 5073 * @return this 5074 */ 5075 ref public Matrix4d rotateLocalX(double ang) return { 5076 rotateLocalX(ang, this); 5077 return this; 5078 } 5079 5080 /** 5081 * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians 5082 * about the Y axis and store the result in <code>dest</code>. 5083 * <p> 5084 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5085 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5086 * When used with a left-handed coordinate system, the rotation is clockwise. 5087 * <p> 5088 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5089 * then the new matrix will be <code>R * M</code>. So when transforming a 5090 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5091 * rotation will be applied last! 5092 * <p> 5093 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5094 * transformation, use {@link #rotationY(double) rotationY()}. 5095 * <p> 5096 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5097 * 5098 * @see #rotationY(double) 5099 * 5100 * @param ang 5101 * the angle in radians to rotate about the Y axis 5102 * @param dest 5103 * will hold the result 5104 * @return dest 5105 */ 5106 public Matrix4d rotateLocalY(double ang, ref Matrix4d dest) { 5107 double sin = Math.sin(ang); 5108 double cos = Math.cosFromSin(sin, ang); 5109 double nm02 = -sin * m00 + cos * m02; 5110 double nm12 = -sin * m10 + cos * m12; 5111 double nm22 = -sin * m20 + cos * m22; 5112 double nm32 = -sin * m30 + cos * m32; 5113 dest 5114 ._m00(cos * m00 + sin * m02) 5115 ._m01(m01) 5116 ._m02(nm02) 5117 ._m03(m03) 5118 ._m10(cos * m10 + sin * m12) 5119 ._m11(m11) 5120 ._m12(nm12) 5121 ._m13(m13) 5122 ._m20(cos * m20 + sin * m22) 5123 ._m21(m21) 5124 ._m22(nm22) 5125 ._m23(m23) 5126 ._m30(cos * m30 + sin * m32) 5127 ._m31(m31) 5128 ._m32(nm32) 5129 ._m33(m33) 5130 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5131 return dest; 5132 } 5133 5134 /** 5135 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis. 5136 * <p> 5137 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5138 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5139 * When used with a left-handed coordinate system, the rotation is clockwise. 5140 * <p> 5141 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5142 * then the new matrix will be <code>R * M</code>. So when transforming a 5143 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5144 * rotation will be applied last! 5145 * <p> 5146 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5147 * transformation, use {@link #rotationY(double) rotationY()}. 5148 * <p> 5149 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5150 * 5151 * @see #rotationY(double) 5152 * 5153 * @param ang 5154 * the angle in radians to rotate about the Y axis 5155 * @return this 5156 */ 5157 ref public Matrix4d rotateLocalY(double ang) return { 5158 rotateLocalY(ang, this); 5159 return this; 5160 } 5161 5162 /** 5163 * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians 5164 * about the Z axis and store the result in <code>dest</code>. 5165 * <p> 5166 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5167 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5168 * When used with a left-handed coordinate system, the rotation is clockwise. 5169 * <p> 5170 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5171 * then the new matrix will be <code>R * M</code>. So when transforming a 5172 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5173 * rotation will be applied last! 5174 * <p> 5175 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5176 * transformation, use {@link #rotationZ(double) rotationZ()}. 5177 * <p> 5178 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5179 * 5180 * @see #rotationZ(double) 5181 * 5182 * @param ang 5183 * the angle in radians to rotate about the Z axis 5184 * @param dest 5185 * will hold the result 5186 * @return dest 5187 */ 5188 public Matrix4d rotateLocalZ(double ang, ref Matrix4d dest) { 5189 double sin = Math.sin(ang); 5190 double cos = Math.cosFromSin(sin, ang); 5191 double nm01 = sin * m00 + cos * m01; 5192 double nm11 = sin * m10 + cos * m11; 5193 double nm21 = sin * m20 + cos * m21; 5194 double nm31 = sin * m30 + cos * m31; 5195 dest 5196 ._m00(cos * m00 - sin * m01) 5197 ._m01(nm01) 5198 ._m02(m02) 5199 ._m03(m03) 5200 ._m10(cos * m10 - sin * m11) 5201 ._m11(nm11) 5202 ._m12(m12) 5203 ._m13(m13) 5204 ._m20(cos * m20 - sin * m21) 5205 ._m21(nm21) 5206 ._m22(m22) 5207 ._m23(m23) 5208 ._m30(cos * m30 - sin * m31) 5209 ._m31(nm31) 5210 ._m32(m32) 5211 ._m33(m33) 5212 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5213 return dest; 5214 } 5215 5216 /** 5217 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis. 5218 * <p> 5219 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5220 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5221 * When used with a left-handed coordinate system, the rotation is clockwise. 5222 * <p> 5223 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5224 * then the new matrix will be <code>R * M</code>. So when transforming a 5225 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 5226 * rotation will be applied last! 5227 * <p> 5228 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 5229 * transformation, use {@link #rotationZ(double) rotationY()}. 5230 * <p> 5231 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a> 5232 * 5233 * @see #rotationY(double) 5234 * 5235 * @param ang 5236 * the angle in radians to rotate about the Z axis 5237 * @return this 5238 */ 5239 ref public Matrix4d rotateLocalZ(double ang) return { 5240 rotateLocalZ(ang, this); 5241 return this; 5242 } 5243 5244 public Matrix4d rotateX(double ang, ref Matrix4d dest) { 5245 if ((properties & PROPERTY_IDENTITY) != 0) 5246 return dest.rotationX(ang); 5247 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5248 double x = m30, y = m31, z = m32; 5249 return dest.rotationX(ang).setTranslation(x, y, z); 5250 } 5251 return rotateXInternal(ang, dest); 5252 } 5253 private Matrix4d rotateXInternal(double ang, ref Matrix4d dest) { 5254 double sin, cos; 5255 sin = Math.sin(ang); 5256 cos = Math.cosFromSin(sin, ang); 5257 double rm11 = cos; 5258 double rm12 = sin; 5259 double rm21 = -sin; 5260 double rm22 = cos; 5261 5262 // add temporaries for dependent values 5263 double nm10 = m10 * rm11 + m20 * rm12; 5264 double nm11 = m11 * rm11 + m21 * rm12; 5265 double nm12 = m12 * rm11 + m22 * rm12; 5266 double nm13 = m13 * rm11 + m23 * rm12; 5267 // set non-dependent values directly 5268 dest._m20(m10 * rm21 + m20 * rm22) 5269 ._m21(m11 * rm21 + m21 * rm22) 5270 ._m22(m12 * rm21 + m22 * rm22) 5271 ._m23(m13 * rm21 + m23 * rm22) 5272 // set other values 5273 ._m10(nm10) 5274 ._m11(nm11) 5275 ._m12(nm12) 5276 ._m13(nm13) 5277 ._m00(m00) 5278 ._m01(m01) 5279 ._m02(m02) 5280 ._m03(m03) 5281 ._m30(m30) 5282 ._m31(m31) 5283 ._m32(m32) 5284 ._m33(m33) 5285 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5286 return dest; 5287 } 5288 5289 /** 5290 * Apply rotation about the X axis to this matrix by rotating the given amount of radians. 5291 * <p> 5292 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5293 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5294 * When used with a left-handed coordinate system, the rotation is clockwise. 5295 * <p> 5296 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5297 * then the new matrix will be <code>M * R</code>. So when transforming a 5298 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5299 * rotation will be applied first! 5300 * <p> 5301 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5302 * 5303 * @param ang 5304 * the angle in radians 5305 * @return this 5306 */ 5307 ref public Matrix4d rotateX(double ang) return { 5308 rotateX(ang, this); 5309 return this; 5310 } 5311 5312 public Matrix4d rotateY(double ang, ref Matrix4d dest) { 5313 if ((properties & PROPERTY_IDENTITY) != 0) 5314 return dest.rotationY(ang); 5315 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5316 double x = m30, y = m31, z = m32; 5317 return dest.rotationY(ang).setTranslation(x, y, z); 5318 } 5319 return rotateYInternal(ang, dest); 5320 } 5321 private Matrix4d rotateYInternal(double ang, ref Matrix4d dest) { 5322 double sin, cos; 5323 sin = Math.sin(ang); 5324 cos = Math.cosFromSin(sin, ang); 5325 double rm00 = cos; 5326 double rm02 = -sin; 5327 double rm20 = sin; 5328 double rm22 = cos; 5329 5330 // add temporaries for dependent values 5331 double nm00 = m00 * rm00 + m20 * rm02; 5332 double nm01 = m01 * rm00 + m21 * rm02; 5333 double nm02 = m02 * rm00 + m22 * rm02; 5334 double nm03 = m03 * rm00 + m23 * rm02; 5335 // set non-dependent values directly 5336 dest._m20(m00 * rm20 + m20 * rm22) 5337 ._m21(m01 * rm20 + m21 * rm22) 5338 ._m22(m02 * rm20 + m22 * rm22) 5339 ._m23(m03 * rm20 + m23 * rm22) 5340 // set other values 5341 ._m00(nm00) 5342 ._m01(nm01) 5343 ._m02(nm02) 5344 ._m03(nm03) 5345 ._m10(m10) 5346 ._m11(m11) 5347 ._m12(m12) 5348 ._m13(m13) 5349 ._m30(m30) 5350 ._m31(m31) 5351 ._m32(m32) 5352 ._m33(m33) 5353 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5354 return dest; 5355 } 5356 5357 /** 5358 * Apply rotation about the Y axis to this matrix by rotating the given amount of radians. 5359 * <p> 5360 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5361 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5362 * When used with a left-handed coordinate system, the rotation is clockwise. 5363 * <p> 5364 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5365 * then the new matrix will be <code>M * R</code>. So when transforming a 5366 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5367 * rotation will be applied first! 5368 * <p> 5369 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5370 * 5371 * @param ang 5372 * the angle in radians 5373 * @return this 5374 */ 5375 ref public Matrix4d rotateY(double ang) return { 5376 rotateY(ang, this); 5377 return this; 5378 } 5379 5380 public Matrix4d rotateZ(double ang, ref Matrix4d dest) { 5381 if ((properties & PROPERTY_IDENTITY) != 0) 5382 return dest.rotationZ(ang); 5383 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5384 double x = m30, y = m31, z = m32; 5385 return dest.rotationZ(ang).setTranslation(x, y, z); 5386 } 5387 return rotateZInternal(ang, dest); 5388 } 5389 private Matrix4d rotateZInternal(double ang, ref Matrix4d dest) { 5390 double sin = Math.sin(ang); 5391 double cos = Math.cosFromSin(sin, ang); 5392 return rotateTowardsXY(sin, cos, dest); 5393 } 5394 5395 /** 5396 * Apply rotation about the Z axis to this matrix by rotating the given amount of radians. 5397 * <p> 5398 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5399 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5400 * When used with a left-handed coordinate system, the rotation is clockwise. 5401 * <p> 5402 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5403 * then the new matrix will be <code>M * R</code>. So when transforming a 5404 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5405 * rotation will be applied first! 5406 * <p> 5407 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a> 5408 * 5409 * @param ang 5410 * the angle in radians 5411 * @return this 5412 */ 5413 ref public Matrix4d rotateZ(double ang) return { 5414 rotateZ(ang, this); 5415 return this; 5416 } 5417 5418 /** 5419 * Apply rotation about the Z axis to align the local <code>+X</code> towards <code>(dirX, dirY)</code>. 5420 * <p> 5421 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5422 * then the new matrix will be <code>M * R</code>. So when transforming a 5423 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5424 * rotation will be applied first! 5425 * <p> 5426 * The vector <code>(dirX, dirY)</code> must be a unit vector. 5427 * 5428 * @param dirX 5429 * the x component of the normalized direction 5430 * @param dirY 5431 * the y component of the normalized direction 5432 * @return this 5433 */ 5434 ref public Matrix4d rotateTowardsXY(double dirX, double dirY) return { 5435 rotateTowardsXY(dirX, dirY, this); 5436 return this; 5437 } 5438 5439 public Matrix4d rotateTowardsXY(double dirX, double dirY, ref Matrix4d dest) { 5440 if ((properties & PROPERTY_IDENTITY) != 0) 5441 return dest.rotationTowardsXY(dirX, dirY); 5442 double rm00 = dirY; 5443 double rm01 = dirX; 5444 double rm10 = -dirX; 5445 double rm11 = dirY; 5446 double nm00 = m00 * rm00 + m10 * rm01; 5447 double nm01 = m01 * rm00 + m11 * rm01; 5448 double nm02 = m02 * rm00 + m12 * rm01; 5449 double nm03 = m03 * rm00 + m13 * rm01; 5450 dest._m10(m00 * rm10 + m10 * rm11) 5451 ._m11(m01 * rm10 + m11 * rm11) 5452 ._m12(m02 * rm10 + m12 * rm11) 5453 ._m13(m03 * rm10 + m13 * rm11) 5454 ._m00(nm00) 5455 ._m01(nm01) 5456 ._m02(nm02) 5457 ._m03(nm03) 5458 ._m20(m20) 5459 ._m21(m21) 5460 ._m22(m22) 5461 ._m23(m23) 5462 ._m30(m30) 5463 ._m31(m31) 5464 ._m32(m32) 5465 ._m33(m33) 5466 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5467 return dest; 5468 } 5469 5470 /** 5471 * 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 5472 * followed by a rotation of <code>angles.z</code> radians about the Z axis. 5473 * <p> 5474 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5475 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5476 * When used with a left-handed coordinate system, the rotation is clockwise. 5477 * <p> 5478 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5479 * then the new matrix will be <code>M * R</code>. So when transforming a 5480 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5481 * rotation will be applied first! 5482 * <p> 5483 * This method is equivalent to calling: <code>rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)</code> 5484 * 5485 * @param angles 5486 * the Euler angles 5487 * @return this 5488 */ 5489 ref public Matrix4d rotateXYZ(ref Vector3d angles) return { 5490 return rotateXYZ(angles.x, angles.y, angles.z); 5491 } 5492 5493 /** 5494 * 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 5495 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5496 * <p> 5497 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5498 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5499 * When used with a left-handed coordinate system, the rotation is clockwise. 5500 * <p> 5501 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5502 * then the new matrix will be <code>M * R</code>. So when transforming a 5503 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5504 * rotation will be applied first! 5505 * <p> 5506 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 5507 * 5508 * @param angleX 5509 * the angle to rotate about X 5510 * @param angleY 5511 * the angle to rotate about Y 5512 * @param angleZ 5513 * the angle to rotate about Z 5514 * @return this 5515 */ 5516 ref public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ) return { 5517 rotateXYZ(angleX, angleY, angleZ, this); 5518 return this; 5519 } 5520 5521 public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5522 if ((properties & PROPERTY_IDENTITY) != 0) 5523 return dest.rotationXYZ(angleX, angleY, angleZ); 5524 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5525 double tx = m30, ty = m31, tz = m32; 5526 return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz); 5527 } else if ((properties & PROPERTY_AFFINE) != 0) 5528 return dest.rotateAffineXYZ(angleX, angleY, angleZ); 5529 return rotateXYZInternal(angleX, angleY, angleZ, dest); 5530 } 5531 private Matrix4d rotateXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5532 double sinX = Math.sin(angleX); 5533 double cosX = Math.cosFromSin(sinX, angleX); 5534 double sinY = Math.sin(angleY); 5535 double cosY = Math.cosFromSin(sinY, angleY); 5536 double sinZ = Math.sin(angleZ); 5537 double cosZ = Math.cosFromSin(sinZ, angleZ); 5538 double m_sinX = -sinX; 5539 double m_sinY = -sinY; 5540 double m_sinZ = -sinZ; 5541 5542 // rotateX 5543 double nm10 = m10 * cosX + m20 * sinX; 5544 double nm11 = m11 * cosX + m21 * sinX; 5545 double nm12 = m12 * cosX + m22 * sinX; 5546 double nm13 = m13 * cosX + m23 * sinX; 5547 double nm20 = m10 * m_sinX + m20 * cosX; 5548 double nm21 = m11 * m_sinX + m21 * cosX; 5549 double nm22 = m12 * m_sinX + m22 * cosX; 5550 double nm23 = m13 * m_sinX + m23 * cosX; 5551 // rotateY 5552 double nm00 = m00 * cosY + nm20 * m_sinY; 5553 double nm01 = m01 * cosY + nm21 * m_sinY; 5554 double nm02 = m02 * cosY + nm22 * m_sinY; 5555 double nm03 = m03 * cosY + nm23 * m_sinY; 5556 dest._m20(m00 * sinY + nm20 * cosY) 5557 ._m21(m01 * sinY + nm21 * cosY) 5558 ._m22(m02 * sinY + nm22 * cosY) 5559 ._m23(m03 * sinY + nm23 * cosY) 5560 // rotateZ 5561 ._m00(nm00 * cosZ + nm10 * sinZ) 5562 ._m01(nm01 * cosZ + nm11 * sinZ) 5563 ._m02(nm02 * cosZ + nm12 * sinZ) 5564 ._m03(nm03 * cosZ + nm13 * sinZ) 5565 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5566 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5567 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5568 ._m13(nm03 * m_sinZ + nm13 * cosZ) 5569 // copy last column from 'this' 5570 ._m30(m30) 5571 ._m31(m31) 5572 ._m32(m32) 5573 ._m33(m33) 5574 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5575 return dest; 5576 } 5577 5578 /** 5579 * 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 5580 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5581 * <p> 5582 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5583 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5584 * When used with a left-handed coordinate system, the rotation is clockwise. 5585 * <p> 5586 * 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>) 5587 * 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). 5588 * <p> 5589 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5590 * then the new matrix will be <code>M * R</code>. So when transforming a 5591 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5592 * rotation will be applied first! 5593 * <p> 5594 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 5595 * 5596 * @param angleX 5597 * the angle to rotate about X 5598 * @param angleY 5599 * the angle to rotate about Y 5600 * @param angleZ 5601 * the angle to rotate about Z 5602 * @return this 5603 */ 5604 ref public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ) return { 5605 rotateAffineXYZ(angleX, angleY, angleZ, this); 5606 return this; 5607 } 5608 5609 public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5610 if ((properties & PROPERTY_IDENTITY) != 0) 5611 return dest.rotationXYZ(angleX, angleY, angleZ); 5612 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5613 double tx = m30, ty = m31, tz = m32; 5614 return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz); 5615 } 5616 return rotateAffineXYZInternal(angleX, angleY, angleZ, dest); 5617 } 5618 private Matrix4d rotateAffineXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4d dest) { 5619 double sinX = Math.sin(angleX); 5620 double cosX = Math.cosFromSin(sinX, angleX); 5621 double sinY = Math.sin(angleY); 5622 double cosY = Math.cosFromSin(sinY, angleY); 5623 double sinZ = Math.sin(angleZ); 5624 double cosZ = Math.cosFromSin(sinZ, angleZ); 5625 double m_sinX = -sinX; 5626 double m_sinY = -sinY; 5627 double m_sinZ = -sinZ; 5628 5629 // rotateX 5630 double nm10 = m10 * cosX + m20 * sinX; 5631 double nm11 = m11 * cosX + m21 * sinX; 5632 double nm12 = m12 * cosX + m22 * sinX; 5633 double nm20 = m10 * m_sinX + m20 * cosX; 5634 double nm21 = m11 * m_sinX + m21 * cosX; 5635 double nm22 = m12 * m_sinX + m22 * cosX; 5636 // rotateY 5637 double nm00 = m00 * cosY + nm20 * m_sinY; 5638 double nm01 = m01 * cosY + nm21 * m_sinY; 5639 double nm02 = m02 * cosY + nm22 * m_sinY; 5640 dest._m20(m00 * sinY + nm20 * cosY) 5641 ._m21(m01 * sinY + nm21 * cosY) 5642 ._m22(m02 * sinY + nm22 * cosY) 5643 ._m23(0.0) 5644 // rotateZ 5645 ._m00(nm00 * cosZ + nm10 * sinZ) 5646 ._m01(nm01 * cosZ + nm11 * sinZ) 5647 ._m02(nm02 * cosZ + nm12 * sinZ) 5648 ._m03(0.0) 5649 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5650 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5651 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5652 ._m13(0.0) 5653 // copy last column from 'this' 5654 ._m30(m30) 5655 ._m31(m31) 5656 ._m32(m32) 5657 ._m33(m33) 5658 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5659 return dest; 5660 } 5661 5662 /** 5663 * 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 5664 * followed by a rotation of <code>angles.x</code> radians about the X axis. 5665 * <p> 5666 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5667 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5668 * When used with a left-handed coordinate system, the rotation is clockwise. 5669 * <p> 5670 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5671 * then the new matrix will be <code>M * R</code>. So when transforming a 5672 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5673 * rotation will be applied first! 5674 * <p> 5675 * This method is equivalent to calling: <code>rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)</code> 5676 * 5677 * @param angles 5678 * the Euler angles 5679 * @return this 5680 */ 5681 ref public Matrix4d rotateZYX(ref Vector3d angles) return { 5682 return rotateZYX(angles.z, angles.y, angles.x); 5683 } 5684 5685 /** 5686 * 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 5687 * followed by a rotation of <code>angleX</code> radians about the X axis. 5688 * <p> 5689 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5690 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5691 * When used with a left-handed coordinate system, the rotation is clockwise. 5692 * <p> 5693 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5694 * then the new matrix will be <code>M * R</code>. So when transforming a 5695 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5696 * rotation will be applied first! 5697 * <p> 5698 * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 5699 * 5700 * @param angleZ 5701 * the angle to rotate about Z 5702 * @param angleY 5703 * the angle to rotate about Y 5704 * @param angleX 5705 * the angle to rotate about X 5706 * @return this 5707 */ 5708 ref public Matrix4d rotateZYX(double angleZ, double angleY, double angleX) return { 5709 rotateZYX(angleZ, angleY, angleX, this); 5710 return this; 5711 } 5712 5713 public Matrix4d rotateZYX(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5714 if ((properties & PROPERTY_IDENTITY) != 0) 5715 return dest.rotationZYX(angleZ, angleY, angleX); 5716 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5717 double tx = m30, ty = m31, tz = m32; 5718 return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz); 5719 } else if ((properties & PROPERTY_AFFINE) != 0) 5720 return dest.rotateAffineZYX(angleZ, angleY, angleX); 5721 return rotateZYXInternal(angleZ, angleY, angleX, dest); 5722 } 5723 private Matrix4d rotateZYXInternal(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5724 double sinX = Math.sin(angleX); 5725 double cosX = Math.cosFromSin(sinX, angleX); 5726 double sinY = Math.sin(angleY); 5727 double cosY = Math.cosFromSin(sinY, angleY); 5728 double sinZ = Math.sin(angleZ); 5729 double cosZ = Math.cosFromSin(sinZ, angleZ); 5730 double m_sinZ = -sinZ; 5731 double m_sinY = -sinY; 5732 double m_sinX = -sinX; 5733 5734 // rotateZ 5735 double nm00 = m00 * cosZ + m10 * sinZ; 5736 double nm01 = m01 * cosZ + m11 * sinZ; 5737 double nm02 = m02 * cosZ + m12 * sinZ; 5738 double nm03 = m03 * cosZ + m13 * sinZ; 5739 double nm10 = m00 * m_sinZ + m10 * cosZ; 5740 double nm11 = m01 * m_sinZ + m11 * cosZ; 5741 double nm12 = m02 * m_sinZ + m12 * cosZ; 5742 double nm13 = m03 * m_sinZ + m13 * cosZ; 5743 // rotateY 5744 double nm20 = nm00 * sinY + m20 * cosY; 5745 double nm21 = nm01 * sinY + m21 * cosY; 5746 double nm22 = nm02 * sinY + m22 * cosY; 5747 double nm23 = nm03 * sinY + m23 * cosY; 5748 dest._m00(nm00 * cosY + m20 * m_sinY) 5749 ._m01(nm01 * cosY + m21 * m_sinY) 5750 ._m02(nm02 * cosY + m22 * m_sinY) 5751 ._m03(nm03 * cosY + m23 * m_sinY) 5752 // rotateX 5753 ._m10(nm10 * cosX + nm20 * sinX) 5754 ._m11(nm11 * cosX + nm21 * sinX) 5755 ._m12(nm12 * cosX + nm22 * sinX) 5756 ._m13(nm13 * cosX + nm23 * sinX) 5757 ._m20(nm10 * m_sinX + nm20 * cosX) 5758 ._m21(nm11 * m_sinX + nm21 * cosX) 5759 ._m22(nm12 * m_sinX + nm22 * cosX) 5760 ._m23(nm13 * m_sinX + nm23 * cosX) 5761 // copy last column from 'this' 5762 ._m30(m30) 5763 ._m31(m31) 5764 ._m32(m32) 5765 ._m33(m33) 5766 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5767 return dest; 5768 } 5769 5770 /** 5771 * 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 5772 * followed by a rotation of <code>angleX</code> radians about the X axis. 5773 * <p> 5774 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5775 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5776 * When used with a left-handed coordinate system, the rotation is clockwise. 5777 * <p> 5778 * 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>) 5779 * 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). 5780 * <p> 5781 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5782 * then the new matrix will be <code>M * R</code>. So when transforming a 5783 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5784 * rotation will be applied first! 5785 * 5786 * @param angleZ 5787 * the angle to rotate about Z 5788 * @param angleY 5789 * the angle to rotate about Y 5790 * @param angleX 5791 * the angle to rotate about X 5792 * @return this 5793 */ 5794 ref public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX) return { 5795 rotateAffineZYX(angleZ, angleY, angleX, this); 5796 return this; 5797 } 5798 5799 public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX, ref Matrix4d dest) { 5800 double sinX = Math.sin(angleX); 5801 double cosX = Math.cosFromSin(sinX, angleX); 5802 double sinY = Math.sin(angleY); 5803 double cosY = Math.cosFromSin(sinY, angleY); 5804 double sinZ = Math.sin(angleZ); 5805 double cosZ = Math.cosFromSin(sinZ, angleZ); 5806 double m_sinZ = -sinZ; 5807 double m_sinY = -sinY; 5808 double m_sinX = -sinX; 5809 5810 // rotateZ 5811 double nm00 = m00 * cosZ + m10 * sinZ; 5812 double nm01 = m01 * cosZ + m11 * sinZ; 5813 double nm02 = m02 * cosZ + m12 * sinZ; 5814 double nm10 = m00 * m_sinZ + m10 * cosZ; 5815 double nm11 = m01 * m_sinZ + m11 * cosZ; 5816 double nm12 = m02 * m_sinZ + m12 * cosZ; 5817 // rotateY 5818 double nm20 = nm00 * sinY + m20 * cosY; 5819 double nm21 = nm01 * sinY + m21 * cosY; 5820 double nm22 = nm02 * sinY + m22 * cosY; 5821 dest._m00(nm00 * cosY + m20 * m_sinY) 5822 ._m01(nm01 * cosY + m21 * m_sinY) 5823 ._m02(nm02 * cosY + m22 * m_sinY) 5824 ._m03(0.0) 5825 // rotateX 5826 ._m10(nm10 * cosX + nm20 * sinX) 5827 ._m11(nm11 * cosX + nm21 * sinX) 5828 ._m12(nm12 * cosX + nm22 * sinX) 5829 ._m13(0.0) 5830 ._m20(nm10 * m_sinX + nm20 * cosX) 5831 ._m21(nm11 * m_sinX + nm21 * cosX) 5832 ._m22(nm12 * m_sinX + nm22 * cosX) 5833 ._m23(0.0) 5834 // copy last column from 'this' 5835 ._m30(m30) 5836 ._m31(m31) 5837 ._m32(m32) 5838 ._m33(m33) 5839 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5840 return dest; 5841 } 5842 5843 /** 5844 * 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 5845 * followed by a rotation of <code>angles.z</code> radians about the Z axis. 5846 * <p> 5847 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5848 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5849 * When used with a left-handed coordinate system, the rotation is clockwise. 5850 * <p> 5851 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5852 * then the new matrix will be <code>M * R</code>. So when transforming a 5853 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5854 * rotation will be applied first! 5855 * <p> 5856 * This method is equivalent to calling: <code>rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)</code> 5857 * 5858 * @param angles 5859 * the Euler angles 5860 * @return this 5861 */ 5862 ref public Matrix4d rotateYXZ(ref Vector3d angles) return { 5863 return rotateYXZ(angles.y, angles.x, angles.z); 5864 } 5865 5866 /** 5867 * 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 5868 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5869 * <p> 5870 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5871 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5872 * When used with a left-handed coordinate system, the rotation is clockwise. 5873 * <p> 5874 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5875 * then the new matrix will be <code>M * R</code>. So when transforming a 5876 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5877 * rotation will be applied first! 5878 * <p> 5879 * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 5880 * 5881 * @param angleY 5882 * the angle to rotate about Y 5883 * @param angleX 5884 * the angle to rotate about X 5885 * @param angleZ 5886 * the angle to rotate about Z 5887 * @return this 5888 */ 5889 ref public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ) return { 5890 rotateYXZ(angleY, angleX, angleZ, this); 5891 return this; 5892 } 5893 5894 public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5895 if ((properties & PROPERTY_IDENTITY) != 0) 5896 return dest.rotationYXZ(angleY, angleX, angleZ); 5897 else if ((properties & PROPERTY_TRANSLATION) != 0) { 5898 double tx = m30, ty = m31, tz = m32; 5899 return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz); 5900 } else if ((properties & PROPERTY_AFFINE) != 0) 5901 return dest.rotateAffineYXZ(angleY, angleX, angleZ); 5902 return rotateYXZInternal(angleY, angleX, angleZ, dest); 5903 } 5904 private Matrix4d rotateYXZInternal(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5905 double sinX = Math.sin(angleX); 5906 double cosX = Math.cosFromSin(sinX, angleX); 5907 double sinY = Math.sin(angleY); 5908 double cosY = Math.cosFromSin(sinY, angleY); 5909 double sinZ = Math.sin(angleZ); 5910 double cosZ = Math.cosFromSin(sinZ, angleZ); 5911 double m_sinY = -sinY; 5912 double m_sinX = -sinX; 5913 double m_sinZ = -sinZ; 5914 5915 // rotateY 5916 double nm20 = m00 * sinY + m20 * cosY; 5917 double nm21 = m01 * sinY + m21 * cosY; 5918 double nm22 = m02 * sinY + m22 * cosY; 5919 double nm23 = m03 * sinY + m23 * cosY; 5920 double nm00 = m00 * cosY + m20 * m_sinY; 5921 double nm01 = m01 * cosY + m21 * m_sinY; 5922 double nm02 = m02 * cosY + m22 * m_sinY; 5923 double nm03 = m03 * cosY + m23 * m_sinY; 5924 // rotateX 5925 double nm10 = m10 * cosX + nm20 * sinX; 5926 double nm11 = m11 * cosX + nm21 * sinX; 5927 double nm12 = m12 * cosX + nm22 * sinX; 5928 double nm13 = m13 * cosX + nm23 * sinX; 5929 dest._m20(m10 * m_sinX + nm20 * cosX) 5930 ._m21(m11 * m_sinX + nm21 * cosX) 5931 ._m22(m12 * m_sinX + nm22 * cosX) 5932 ._m23(m13 * m_sinX + nm23 * cosX) 5933 // rotateZ 5934 ._m00(nm00 * cosZ + nm10 * sinZ) 5935 ._m01(nm01 * cosZ + nm11 * sinZ) 5936 ._m02(nm02 * cosZ + nm12 * sinZ) 5937 ._m03(nm03 * cosZ + nm13 * sinZ) 5938 ._m10(nm00 * m_sinZ + nm10 * cosZ) 5939 ._m11(nm01 * m_sinZ + nm11 * cosZ) 5940 ._m12(nm02 * m_sinZ + nm12 * cosZ) 5941 ._m13(nm03 * m_sinZ + nm13 * cosZ) 5942 // copy last column from 'this' 5943 ._m30(m30) 5944 ._m31(m31) 5945 ._m32(m32) 5946 ._m33(m33) 5947 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 5948 return dest; 5949 } 5950 5951 /** 5952 * 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 5953 * followed by a rotation of <code>angleZ</code> radians about the Z axis. 5954 * <p> 5955 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 5956 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 5957 * When used with a left-handed coordinate system, the rotation is clockwise. 5958 * <p> 5959 * 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>) 5960 * 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). 5961 * <p> 5962 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 5963 * then the new matrix will be <code>M * R</code>. So when transforming a 5964 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 5965 * rotation will be applied first! 5966 * 5967 * @param angleY 5968 * the angle to rotate about Y 5969 * @param angleX 5970 * the angle to rotate about X 5971 * @param angleZ 5972 * the angle to rotate about Z 5973 * @return this 5974 */ 5975 ref public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ) return { 5976 rotateAffineYXZ(angleY, angleX, angleZ, this); 5977 return this; 5978 } 5979 5980 public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ, ref Matrix4d dest) { 5981 double sinX = Math.sin(angleX); 5982 double cosX = Math.cosFromSin(sinX, angleX); 5983 double sinY = Math.sin(angleY); 5984 double cosY = Math.cosFromSin(sinY, angleY); 5985 double sinZ = Math.sin(angleZ); 5986 double cosZ = Math.cosFromSin(sinZ, angleZ); 5987 double m_sinY = -sinY; 5988 double m_sinX = -sinX; 5989 double m_sinZ = -sinZ; 5990 5991 // rotateY 5992 double nm20 = m00 * sinY + m20 * cosY; 5993 double nm21 = m01 * sinY + m21 * cosY; 5994 double nm22 = m02 * sinY + m22 * cosY; 5995 double nm00 = m00 * cosY + m20 * m_sinY; 5996 double nm01 = m01 * cosY + m21 * m_sinY; 5997 double nm02 = m02 * cosY + m22 * m_sinY; 5998 // rotateX 5999 double nm10 = m10 * cosX + nm20 * sinX; 6000 double nm11 = m11 * cosX + nm21 * sinX; 6001 double nm12 = m12 * cosX + nm22 * sinX; 6002 dest._m20(m10 * m_sinX + nm20 * cosX) 6003 ._m21(m11 * m_sinX + nm21 * cosX) 6004 ._m22(m12 * m_sinX + nm22 * cosX) 6005 ._m23(0.0) 6006 // rotateZ 6007 ._m00(nm00 * cosZ + nm10 * sinZ) 6008 ._m01(nm01 * cosZ + nm11 * sinZ) 6009 ._m02(nm02 * cosZ + nm12 * sinZ) 6010 ._m03(0.0) 6011 ._m10(nm00 * m_sinZ + nm10 * cosZ) 6012 ._m11(nm01 * m_sinZ + nm11 * cosZ) 6013 ._m12(nm02 * m_sinZ + nm12 * cosZ) 6014 ._m13(0.0) 6015 // copy last column from 'this' 6016 ._m30(m30) 6017 ._m31(m31) 6018 ._m32(m32) 6019 ._m33(m33) 6020 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6021 return dest; 6022 } 6023 6024 /** 6025 * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}. 6026 * <p> 6027 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6028 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6029 * When used with a left-handed coordinate system, the rotation is clockwise. 6030 * <p> 6031 * The resulting matrix can be multiplied against another transformation 6032 * matrix to obtain an additional rotation. 6033 * <p> 6034 * In order to apply the rotation transformation to an existing transformation, 6035 * use {@link #rotate(ref AxisAngle4d) rotate()} instead. 6036 * <p> 6037 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 6038 * 6039 * @see #rotate(ref AxisAngle4d) 6040 * 6041 * @param angleAxis 6042 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 6043 * @return this 6044 */ 6045 ref public Matrix4d rotation(ref AxisAngle4d angleAxis) return { 6046 return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z); 6047 } 6048 6049 /** 6050 * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniond}. 6051 * <p> 6052 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6053 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6054 * When used with a left-handed coordinate system, the rotation is clockwise. 6055 * <p> 6056 * The resulting matrix can be multiplied against another transformation 6057 * matrix to obtain an additional rotation. 6058 * <p> 6059 * In order to apply the rotation transformation to an existing transformation, 6060 * use {@link #rotate(ref Quaterniond) rotate()} instead. 6061 * <p> 6062 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6063 * 6064 * @see #rotate(ref Quaterniond) 6065 * 6066 * @param quat 6067 * the {@link Quaterniond} 6068 * @return this 6069 */ 6070 ref public Matrix4d rotation(ref Quaterniond quat) return { 6071 double w2 = quat.w * quat.w; 6072 double x2 = quat.x * quat.x; 6073 double y2 = quat.y * quat.y; 6074 double z2 = quat.z * quat.z; 6075 double zw = quat.z * quat.w, dzw = zw + zw; 6076 double xy = quat.x * quat.y, dxy = xy + xy; 6077 double xz = quat.x * quat.z, dxz = xz + xz; 6078 double yw = quat.y * quat.w, dyw = yw + yw; 6079 double yz = quat.y * quat.z, dyz = yz + yz; 6080 double xw = quat.x * quat.w, dxw = xw + xw; 6081 if ((properties & PROPERTY_IDENTITY) == 0) 6082 this._identity(); 6083 _m00(w2 + x2 - z2 - y2). 6084 _m01(dxy + dzw). 6085 _m02(dxz - dyw). 6086 _m10(-dzw + dxy). 6087 _m11(y2 - z2 + w2 - x2). 6088 _m12(dyz + dxw). 6089 _m20(dyw + dxz). 6090 _m21(dyz - dxw). 6091 _m22(z2 - y2 - x2 + w2). 6092 _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 6093 return this; 6094 } 6095 6096 6097 /** 6098 * 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>, 6099 * <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 6100 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>. 6101 * <p> 6102 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6103 * at last the translation. 6104 * <p> 6105 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6106 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6107 * When used with a left-handed coordinate system, the rotation is clockwise. 6108 * <p> 6109 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)</code> 6110 * 6111 * @see #translation(double, double, double) 6112 * @see #rotate(ref Quaterniond) 6113 * @see #scale(double, double, double) 6114 * 6115 * @param tx 6116 * the number of units by which to translate the x-component 6117 * @param ty 6118 * the number of units by which to translate the y-component 6119 * @param tz 6120 * the number of units by which to translate the z-component 6121 * @param qx 6122 * the x-coordinate of the vector part of the quaternion 6123 * @param qy 6124 * the y-coordinate of the vector part of the quaternion 6125 * @param qz 6126 * the z-coordinate of the vector part of the quaternion 6127 * @param qw 6128 * the scalar part of the quaternion 6129 * @param sx 6130 * the scaling factor for the x-axis 6131 * @param sy 6132 * the scaling factor for the y-axis 6133 * @param sz 6134 * the scaling factor for the z-axis 6135 * @return this 6136 */ 6137 ref public Matrix4d translationRotateScale(double tx, double ty, double tz, 6138 double qx, double qy, double qz, double qw, 6139 double sx, double sy, double sz) return { 6140 double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz; 6141 double q00 = dqx * qx; 6142 double q11 = dqy * qy; 6143 double q22 = dqz * qz; 6144 double q01 = dqx * qy; 6145 double q02 = dqx * qz; 6146 double q03 = dqx * qw; 6147 double q12 = dqy * qz; 6148 double q13 = dqy * qw; 6149 double q23 = dqz * qw; 6150 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6151 _m00(sx - (q11 + q22) * sx). 6152 _m01((q01 + q23) * sx). 6153 _m02((q02 - q13) * sx). 6154 _m03(0.0). 6155 _m10((q01 - q23) * sy). 6156 _m11(sy - (q22 + q00) * sy). 6157 _m12((q12 + q03) * sy). 6158 _m13(0.0). 6159 _m20((q02 + q13) * sz). 6160 _m21((q12 - q03) * sz). 6161 _m22(sz - (q11 + q00) * sz). 6162 _m23(0.0). 6163 _m30(tx). 6164 _m31(ty). 6165 _m32(tz). 6166 _m33(1.0). 6167 properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0); 6168 return this; 6169 } 6170 6171 /** 6172 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>, 6173 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6174 * which scales the axes by <code>scale</code>. 6175 * <p> 6176 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6177 * at last the translation. 6178 * <p> 6179 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6180 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6181 * When used with a left-handed coordinate system, the rotation is clockwise. 6182 * <p> 6183 * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code> 6184 * 6185 * @see #translation(ref Vector3d) 6186 * @see #rotate(ref Quaterniond) 6187 * @see #scale(ref Vector3d) 6188 * 6189 * @param translation 6190 * the translation 6191 * @param quat 6192 * the quaternion representing a rotation 6193 * @param scale 6194 * the scaling factors 6195 * @return this 6196 */ 6197 ref public Matrix4d translationRotateScale(ref Vector3d translation, 6198 Quaterniond quat, 6199 Vector3d scale) return { 6200 return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale.x, scale.y, scale.z); 6201 } 6202 6203 /** 6204 * 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>, 6205 * <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 6206 * which scales all three axes by <code>scale</code>. 6207 * <p> 6208 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6209 * at last the translation. 6210 * <p> 6211 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6212 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6213 * When used with a left-handed coordinate system, the rotation is clockwise. 6214 * <p> 6215 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(scale)</code> 6216 * 6217 * @see #translation(double, double, double) 6218 * @see #rotate(ref Quaterniond) 6219 * @see #scale(double) 6220 * 6221 * @param tx 6222 * the number of units by which to translate the x-component 6223 * @param ty 6224 * the number of units by which to translate the y-component 6225 * @param tz 6226 * the number of units by which to translate the z-component 6227 * @param qx 6228 * the x-coordinate of the vector part of the quaternion 6229 * @param qy 6230 * the y-coordinate of the vector part of the quaternion 6231 * @param qz 6232 * the z-coordinate of the vector part of the quaternion 6233 * @param qw 6234 * the scalar part of the quaternion 6235 * @param scale 6236 * the scaling factor for all three axes 6237 * @return this 6238 */ 6239 ref public Matrix4d translationRotateScale(double tx, double ty, double tz, 6240 double qx, double qy, double qz, double qw, 6241 double scale) return { 6242 return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, scale, scale, scale); 6243 } 6244 6245 /** 6246 * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>, 6247 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6248 * which scales all three axes by <code>scale</code>. 6249 * <p> 6250 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6251 * at last the translation. 6252 * <p> 6253 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6254 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6255 * When used with a left-handed coordinate system, the rotation is clockwise. 6256 * <p> 6257 * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code> 6258 * 6259 * @see #translation(ref Vector3d) 6260 * @see #rotate(ref Quaterniond) 6261 * @see #scale(double) 6262 * 6263 * @param translation 6264 * the translation 6265 * @param quat 6266 * the quaternion representing a rotation 6267 * @param scale 6268 * the scaling factors 6269 * @return this 6270 */ 6271 ref public Matrix4d translationRotateScale(ref Vector3d translation, 6272 Quaterniond quat, 6273 double scale) return { 6274 return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale, scale, scale); 6275 } 6276 6277 6278 /** 6279 * 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>, 6280 * <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 6281 * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>. 6282 * <p> 6283 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6284 * 6285 * @see #translationRotateScale(double, double, double, double, double, double, double, double, double, double) 6286 * @see #invert() 6287 * 6288 * @param tx 6289 * the number of units by which to translate the x-component 6290 * @param ty 6291 * the number of units by which to translate the y-component 6292 * @param tz 6293 * the number of units by which to translate the z-component 6294 * @param qx 6295 * the x-coordinate of the vector part of the quaternion 6296 * @param qy 6297 * the y-coordinate of the vector part of the quaternion 6298 * @param qz 6299 * the z-coordinate of the vector part of the quaternion 6300 * @param qw 6301 * the scalar part of the quaternion 6302 * @param sx 6303 * the scaling factor for the x-axis 6304 * @param sy 6305 * the scaling factor for the y-axis 6306 * @param sz 6307 * the scaling factor for the z-axis 6308 * @return this 6309 */ 6310 ref public Matrix4d translationRotateScaleInvert(double tx, double ty, double tz, 6311 double qx, double qy, double qz, double qw, 6312 double sx, double sy, double sz) return { 6313 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6314 if (one) 6315 return translationRotateInvert(tx, ty, tz, qx, qy, qz, qw); 6316 double nqx = -qx, nqy = -qy, nqz = -qz; 6317 double dqx = nqx + nqx; 6318 double dqy = nqy + nqy; 6319 double dqz = nqz + nqz; 6320 double q00 = dqx * nqx; 6321 double q11 = dqy * nqy; 6322 double q22 = dqz * nqz; 6323 double q01 = dqx * nqy; 6324 double q02 = dqx * nqz; 6325 double q03 = dqx * qw; 6326 double q12 = dqy * nqz; 6327 double q13 = dqy * qw; 6328 double q23 = dqz * qw; 6329 double isx = 1/sx, isy = 1/sy, isz = 1/sz; 6330 _m00(isx * (1.0 - q11 - q22)). 6331 _m01(isy * (q01 + q23)). 6332 _m02(isz * (q02 - q13)). 6333 _m03(0.0). 6334 _m10(isx * (q01 - q23)). 6335 _m11(isy * (1.0 - q22 - q00)). 6336 _m12(isz * (q12 + q03)). 6337 _m13(0.0). 6338 _m20(isx * (q02 + q13)). 6339 _m21(isy * (q12 - q03)). 6340 _m22(isz * (1.0 - q11 - q00)). 6341 _m23(0.0). 6342 _m30(-m00 * tx - m10 * ty - m20 * tz). 6343 _m31(-m01 * tx - m11 * ty - m21 * tz). 6344 _m32(-m02 * tx - m12 * ty - m22 * tz). 6345 _m33(1.0). 6346 properties = PROPERTY_AFFINE; 6347 return this; 6348 } 6349 6350 /** 6351 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code>, 6352 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6353 * which scales the axes by <code>scale</code>. 6354 * <p> 6355 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6356 * 6357 * @see #translationRotateScale(ref Vector3d, Quaterniond, Vector3d) 6358 * @see #invert() 6359 * 6360 * @param translation 6361 * the translation 6362 * @param quat 6363 * the quaternion representing a rotation 6364 * @param scale 6365 * the scaling factors 6366 * @return this 6367 */ 6368 ref public Matrix4d translationRotateScaleInvert(ref Vector3d translation, 6369 Quaterniond quat, 6370 Vector3d scale) return { 6371 return translationRotateScaleInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale.x, scale.y, scale.z); 6372 } 6373 6374 6375 /** 6376 * Set <code>this</code> matrix to <code>(T * R * S)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code>, 6377 * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation 6378 * which scales all three axes by <code>scale</code>. 6379 * <p> 6380 * This method is equivalent to calling: <code>translationRotateScale(...).invert()</code> 6381 * 6382 * @see #translationRotateScale(ref Vector3d, Quaterniond, double) 6383 * @see #invert() 6384 * 6385 * @param translation 6386 * the translation 6387 * @param quat 6388 * the quaternion representing a rotation 6389 * @param scale 6390 * the scaling factors 6391 * @return this 6392 */ 6393 ref public Matrix4d translationRotateScaleInvert(ref Vector3d translation, 6394 Quaterniond quat, 6395 double scale) return { 6396 return translationRotateScaleInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w, scale, scale, scale); 6397 } 6398 6399 6400 /** 6401 * 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>, 6402 * <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 6403 * 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. 6404 * <p> 6405 * 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 6406 * at last the translation. 6407 * <p> 6408 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6409 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6410 * When used with a left-handed coordinate system, the rotation is clockwise. 6411 * <p> 6412 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mulAffine(m)</code> 6413 * 6414 * @see #translation(double, double, double) 6415 * @see #rotate(ref Quaterniond) 6416 * @see #scale(double, double, double) 6417 * @see #mulAffine(Matrix4d) 6418 * 6419 * @param tx 6420 * the number of units by which to translate the x-component 6421 * @param ty 6422 * the number of units by which to translate the y-component 6423 * @param tz 6424 * the number of units by which to translate the z-component 6425 * @param qx 6426 * the x-coordinate of the vector part of the quaternion 6427 * @param qy 6428 * the y-coordinate of the vector part of the quaternion 6429 * @param qz 6430 * the z-coordinate of the vector part of the quaternion 6431 * @param qw 6432 * the scalar part of the quaternion 6433 * @param sx 6434 * the scaling factor for the x-axis 6435 * @param sy 6436 * the scaling factor for the y-axis 6437 * @param sz 6438 * the scaling factor for the z-axis 6439 * @param m 6440 * the {@link #isAffine() affine} matrix to multiply by 6441 * @return this 6442 */ 6443 ref public Matrix4d translationRotateScaleMulAffine(double tx, double ty, double tz, 6444 double qx, double qy, double qz, double qw, 6445 double sx, double sy, double sz, 6446 Matrix4d m) return { 6447 double w2 = qw * qw; 6448 double x2 = qx * qx; 6449 double y2 = qy * qy; 6450 double z2 = qz * qz; 6451 double zw = qz * qw; 6452 double xy = qx * qy; 6453 double xz = qx * qz; 6454 double yw = qy * qw; 6455 double yz = qy * qz; 6456 double xw = qx * qw; 6457 double nm00 = w2 + x2 - z2 - y2; 6458 double nm01 = xy + zw + zw + xy; 6459 double nm02 = xz - yw + xz - yw; 6460 double nm10 = -zw + xy - zw + xy; 6461 double nm11 = y2 - z2 + w2 - x2; 6462 double nm12 = yz + yz + xw + xw; 6463 double nm20 = yw + xz + xz + yw; 6464 double nm21 = yz + yz - xw - xw; 6465 double nm22 = z2 - y2 - x2 + w2; 6466 double m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02; 6467 double m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02; 6468 setm02(nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02); 6469 setm00(m00); 6470 setm01(m01); 6471 setm03(0.0); 6472 double m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12; 6473 double m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12; 6474 setm12(nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12); 6475 setm10(m10); 6476 setm11(m11); 6477 setm13(0.0); 6478 double m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22; 6479 double m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22; 6480 setm22(nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22); 6481 setm20(m20); 6482 setm21(m21); 6483 setm23(0.0); 6484 double m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx; 6485 double m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty; 6486 setm32(nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz); 6487 setm30(m30); 6488 setm31(m31); 6489 setm33(1.0); 6490 bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz); 6491 properties = PROPERTY_AFFINE | (one && (m.properties & PROPERTY_ORTHONORMAL) != 0 ? PROPERTY_ORTHONORMAL : 0); 6492 return this; 6493 } 6494 6495 6496 6497 /** 6498 * 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 6499 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>. 6500 * <p> 6501 * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation. 6502 * <p> 6503 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6504 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6505 * When used with a left-handed coordinate system, the rotation is clockwise. 6506 * <p> 6507 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code> 6508 * 6509 * @see #translation(double, double, double) 6510 * @see #rotate(ref Quaterniond) 6511 * 6512 * @param tx 6513 * the number of units by which to translate the x-component 6514 * @param ty 6515 * the number of units by which to translate the y-component 6516 * @param tz 6517 * the number of units by which to translate the z-component 6518 * @param qx 6519 * the x-coordinate of the vector part of the quaternion 6520 * @param qy 6521 * the y-coordinate of the vector part of the quaternion 6522 * @param qz 6523 * the z-coordinate of the vector part of the quaternion 6524 * @param qw 6525 * the scalar part of the quaternion 6526 * @return this 6527 */ 6528 ref public Matrix4d translationRotate(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return { 6529 double w2 = qw * qw; 6530 double x2 = qx * qx; 6531 double y2 = qy * qy; 6532 double z2 = qz * qz; 6533 double zw = qz * qw; 6534 double xy = qx * qy; 6535 double xz = qx * qz; 6536 double yw = qy * qw; 6537 double yz = qy * qz; 6538 double xw = qx * qw; 6539 setm00(w2 + x2 - z2 - y2); 6540 setm01(xy + zw + zw + xy); 6541 setm02(xz - yw + xz - yw); 6542 setm10(-zw + xy - zw + xy); 6543 setm11(y2 - z2 + w2 - x2); 6544 setm12(yz + yz + xw + xw); 6545 setm20(yw + xz + xz + yw); 6546 setm21(yz + yz - xw - xw); 6547 setm22(z2 - y2 - x2 + w2); 6548 setm30(tx); 6549 setm31(ty); 6550 setm32(tz); 6551 setm33(1.0); 6552 this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 6553 return this; 6554 } 6555 6556 /** 6557 * 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 6558 * <code>R</code> is a rotation - and possibly scaling - transformation specified by the given quaternion. 6559 * <p> 6560 * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation. 6561 * <p> 6562 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6563 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6564 * When used with a left-handed coordinate system, the rotation is clockwise. 6565 * <p> 6566 * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code> 6567 * 6568 * @see #translation(double, double, double) 6569 * @see #rotate(ref Quaterniond) 6570 * 6571 * @param tx 6572 * the number of units by which to translate the x-component 6573 * @param ty 6574 * the number of units by which to translate the y-component 6575 * @param tz 6576 * the number of units by which to translate the z-component 6577 * @param quat 6578 * the quaternion representing a rotation 6579 * @return this 6580 */ 6581 ref public Matrix4d translationRotate(double tx, double ty, double tz, Quaterniond quat) return { 6582 return translationRotate(tx, ty, tz, quat.x, quat.y, quat.z, quat.w); 6583 } 6584 6585 /** 6586 * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is the given <code>translation</code> and 6587 * <code>R</code> is a rotation transformation specified by the given quaternion. 6588 * <p> 6589 * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and 6590 * at last the translation. 6591 * <p> 6592 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6593 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6594 * When used with a left-handed coordinate system, the rotation is clockwise. 6595 * <p> 6596 * This method is equivalent to calling: <code>translation(translation).rotate(quat)</code> 6597 * 6598 * @see #translation(ref Vector3d) 6599 * @see #rotate(ref Quaterniond) 6600 * 6601 * @param translation 6602 * the translation 6603 * @param quat 6604 * the quaternion representing a rotation 6605 * @return this 6606 */ 6607 ref public Matrix4d translationRotate(ref Vector3d translation, 6608 Quaterniond quat) return { 6609 return translationRotate(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w); 6610 } 6611 6612 /** 6613 * 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 6614 * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>. 6615 * <p> 6616 * This method is equivalent to calling: <code>translationRotate(...).invert()</code> 6617 * 6618 * @see #translationRotate(double, double, double, double, double, double, double) 6619 * @see #invert() 6620 * 6621 * @param tx 6622 * the number of units by which to translate the x-component 6623 * @param ty 6624 * the number of units by which to translate the y-component 6625 * @param tz 6626 * the number of units by which to translate the z-component 6627 * @param qx 6628 * the x-coordinate of the vector part of the quaternion 6629 * @param qy 6630 * the y-coordinate of the vector part of the quaternion 6631 * @param qz 6632 * the z-coordinate of the vector part of the quaternion 6633 * @param qw 6634 * the scalar part of the quaternion 6635 * @return this 6636 */ 6637 ref public Matrix4d translationRotateInvert(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return { 6638 double nqx = -qx, nqy = -qy, nqz = -qz; 6639 double dqx = nqx + nqx; 6640 double dqy = nqy + nqy; 6641 double dqz = nqz + nqz; 6642 double q00 = dqx * nqx; 6643 double q11 = dqy * nqy; 6644 double q22 = dqz * nqz; 6645 double q01 = dqx * nqy; 6646 double q02 = dqx * nqz; 6647 double q03 = dqx * qw; 6648 double q12 = dqy * nqz; 6649 double q13 = dqy * qw; 6650 double q23 = dqz * qw; 6651 return this 6652 ._m00(1.0 - q11 - q22) 6653 ._m01(q01 + q23) 6654 ._m02(q02 - q13) 6655 ._m03(0.0) 6656 ._m10(q01 - q23) 6657 ._m11(1.0 - q22 - q00) 6658 ._m12(q12 + q03) 6659 ._m13(0.0) 6660 ._m20(q02 + q13) 6661 ._m21(q12 - q03) 6662 ._m22(1.0 - q11 - q00) 6663 ._m23(0.0) 6664 ._m30(-m00 * tx - m10 * ty - m20 * tz) 6665 ._m31(-m01 * tx - m11 * ty - m21 * tz) 6666 ._m32(-m02 * tx - m12 * ty - m22 * tz) 6667 ._m33(1.0) 6668 ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 6669 } 6670 6671 6672 6673 /** 6674 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store 6675 * the result in <code>dest</code>. 6676 * <p> 6677 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6678 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6679 * When used with a left-handed coordinate system, the rotation is clockwise. 6680 * <p> 6681 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6682 * then the new matrix will be <code>M * Q</code>. So when transforming a 6683 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6684 * the quaternion rotation will be applied first! 6685 * <p> 6686 * In order to set the matrix to a rotation transformation without post-multiplying, 6687 * use {@link #rotation(ref Quaterniond)}. 6688 * <p> 6689 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6690 * 6691 * @see #rotation(ref Quaterniond) 6692 * 6693 * @param quat 6694 * the {@link Quaterniond} 6695 * @param dest 6696 * will hold the result 6697 * @return dest 6698 */ 6699 public Matrix4d rotate(ref Quaterniond quat, ref Matrix4d dest) { 6700 if ((properties & PROPERTY_IDENTITY) != 0) 6701 return dest.rotation(quat); 6702 else if ((properties & PROPERTY_TRANSLATION) != 0) 6703 return rotateTranslation(quat, dest); 6704 else if ((properties & PROPERTY_AFFINE) != 0) 6705 return rotateAffine(quat, dest); 6706 return rotateGeneric(quat, dest); 6707 } 6708 private Matrix4d rotateGeneric(ref Quaterniond quat, ref Matrix4d dest) { 6709 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6710 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6711 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6712 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6713 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6714 double rm00 = w2 + x2 - z2 - y2; 6715 double rm01 = dxy + dzw; 6716 double rm02 = dxz - dyw; 6717 double rm10 = -dzw + dxy; 6718 double rm11 = y2 - z2 + w2 - x2; 6719 double rm12 = dyz + dxw; 6720 double rm20 = dyw + dxz; 6721 double rm21 = dyz - dxw; 6722 double rm22 = z2 - y2 - x2 + w2; 6723 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 6724 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 6725 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 6726 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 6727 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 6728 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 6729 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 6730 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 6731 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 6732 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 6733 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 6734 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 6735 ._m00(nm00) 6736 ._m01(nm01) 6737 ._m02(nm02) 6738 ._m03(nm03) 6739 ._m10(nm10) 6740 ._m11(nm11) 6741 ._m12(nm12) 6742 ._m13(nm13) 6743 ._m30(m30) 6744 ._m31(m31) 6745 ._m32(m32) 6746 ._m33(m33) 6747 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6748 return dest; 6749 } 6750 6751 6752 /** 6753 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 6754 * <p> 6755 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6756 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6757 * When used with a left-handed coordinate system, the rotation is clockwise. 6758 * <p> 6759 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6760 * then the new matrix will be <code>M * Q</code>. So when transforming a 6761 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6762 * the quaternion rotation will be applied first! 6763 * <p> 6764 * In order to set the matrix to a rotation transformation without post-multiplying, 6765 * use {@link #rotation(ref Quaterniond)}. 6766 * <p> 6767 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6768 * 6769 * @see #rotation(ref Quaterniond) 6770 * 6771 * @param quat 6772 * the {@link Quaterniond} 6773 * @return this 6774 */ 6775 ref public Matrix4d rotate(ref Quaterniond quat) return { 6776 rotate(quat, this); 6777 return this; 6778 } 6779 6780 6781 /** 6782 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this {@link #isAffine() affine} matrix and store 6783 * the result in <code>dest</code>. 6784 * <p> 6785 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 6786 * <p> 6787 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6788 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6789 * When used with a left-handed coordinate system, the rotation is clockwise. 6790 * <p> 6791 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6792 * then the new matrix will be <code>M * Q</code>. So when transforming a 6793 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6794 * the quaternion rotation will be applied first! 6795 * <p> 6796 * In order to set the matrix to a rotation transformation without post-multiplying, 6797 * use {@link #rotation(ref Quaterniond)}. 6798 * <p> 6799 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6800 * 6801 * @see #rotation(ref Quaterniond) 6802 * 6803 * @param quat 6804 * the {@link Quaterniond} 6805 * @param dest 6806 * will hold the result 6807 * @return dest 6808 */ 6809 public Matrix4d rotateAffine(ref Quaterniond quat, ref Matrix4d dest) { 6810 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6811 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6812 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6813 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6814 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6815 double rm00 = w2 + x2 - z2 - y2; 6816 double rm01 = dxy + dzw; 6817 double rm02 = dxz - dyw; 6818 double rm10 = -dzw + dxy; 6819 double rm11 = y2 - z2 + w2 - x2; 6820 double rm12 = dyz + dxw; 6821 double rm20 = dyw + dxz; 6822 double rm21 = dyz - dxw; 6823 double rm22 = z2 - y2 - x2 + w2; 6824 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 6825 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 6826 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 6827 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 6828 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 6829 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 6830 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 6831 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 6832 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 6833 ._m23(0.0) 6834 ._m00(nm00) 6835 ._m01(nm01) 6836 ._m02(nm02) 6837 ._m03(0.0) 6838 ._m10(nm10) 6839 ._m11(nm11) 6840 ._m12(nm12) 6841 ._m13(0.0) 6842 ._m30(m30) 6843 ._m31(m31) 6844 ._m32(m32) 6845 ._m33(m33) 6846 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6847 return dest; 6848 } 6849 6850 /** 6851 * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 6852 * <p> 6853 * This method assumes <code>this</code> to be {@link #isAffine() affine}. 6854 * <p> 6855 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6856 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6857 * When used with a left-handed coordinate system, the rotation is clockwise. 6858 * <p> 6859 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6860 * then the new matrix will be <code>M * Q</code>. So when transforming a 6861 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6862 * the quaternion rotation will be applied first! 6863 * <p> 6864 * In order to set the matrix to a rotation transformation without post-multiplying, 6865 * use {@link #rotation(ref Quaterniond)}. 6866 * <p> 6867 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6868 * 6869 * @see #rotation(ref Quaterniond) 6870 * 6871 * @param quat 6872 * the {@link Quaterniond} 6873 * @return this 6874 */ 6875 ref public Matrix4d rotateAffine(ref Quaterniond quat) return { 6876 rotateAffine(quat, this); 6877 return this; 6878 } 6879 6880 /** 6881 * 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 6882 * the result in <code>dest</code>. 6883 * <p> 6884 * This method assumes <code>this</code> to only contain a translation. 6885 * <p> 6886 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6887 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6888 * When used with a left-handed coordinate system, the rotation is clockwise. 6889 * <p> 6890 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6891 * then the new matrix will be <code>M * Q</code>. So when transforming a 6892 * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>, 6893 * the quaternion rotation will be applied first! 6894 * <p> 6895 * In order to set the matrix to a rotation transformation without post-multiplying, 6896 * use {@link #rotation(ref Quaterniond)}. 6897 * <p> 6898 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6899 * 6900 * @see #rotation(ref Quaterniond) 6901 * 6902 * @param quat 6903 * the {@link Quaterniond} 6904 * @param dest 6905 * will hold the result 6906 * @return dest 6907 */ 6908 public Matrix4d rotateTranslation(ref Quaterniond quat, ref Matrix4d dest) { 6909 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6910 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6911 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6912 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6913 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6914 double rm00 = w2 + x2 - z2 - y2; 6915 double rm01 = dxy + dzw; 6916 double rm02 = dxz - dyw; 6917 double rm10 = -dzw + dxy; 6918 double rm11 = y2 - z2 + w2 - x2; 6919 double rm12 = dyz + dxw; 6920 double rm20 = dyw + dxz; 6921 double rm21 = dyz - dxw; 6922 double rm22 = z2 - y2 - x2 + w2; 6923 dest._m20(rm20) 6924 ._m21(rm21) 6925 ._m22(rm22) 6926 ._m23(0.0) 6927 ._m00(rm00) 6928 ._m01(rm01) 6929 ._m02(rm02) 6930 ._m03(0.0) 6931 ._m10(rm10) 6932 ._m11(rm11) 6933 ._m12(rm12) 6934 ._m13(0.0) 6935 ._m30(m30) 6936 ._m31(m31) 6937 ._m32(m32) 6938 ._m33(1.0) 6939 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 6940 return dest; 6941 } 6942 6943 6944 /** 6945 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store 6946 * the result in <code>dest</code>. 6947 * <p> 6948 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 6949 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 6950 * When used with a left-handed coordinate system, the rotation is clockwise. 6951 * <p> 6952 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 6953 * then the new matrix will be <code>Q * M</code>. So when transforming a 6954 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 6955 * the quaternion rotation will be applied last! 6956 * <p> 6957 * In order to set the matrix to a rotation transformation without pre-multiplying, 6958 * use {@link #rotation(ref Quaterniond)}. 6959 * <p> 6960 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 6961 * 6962 * @see #rotation(ref Quaterniond) 6963 * 6964 * @param quat 6965 * the {@link Quaterniond} 6966 * @param dest 6967 * will hold the result 6968 * @return dest 6969 */ 6970 public Matrix4d rotateLocal(ref Quaterniond quat, ref Matrix4d dest) { 6971 double w2 = quat.w * quat.w, x2 = quat.x * quat.x; 6972 double y2 = quat.y * quat.y, z2 = quat.z * quat.z; 6973 double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy; 6974 double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw; 6975 double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw; 6976 double lm00 = w2 + x2 - z2 - y2; 6977 double lm01 = dxy + dzw; 6978 double lm02 = dxz - dyw; 6979 double lm10 = -dzw + dxy; 6980 double lm11 = y2 - z2 + w2 - x2; 6981 double lm12 = dyz + dxw; 6982 double lm20 = dyw + dxz; 6983 double lm21 = dyz - dxw; 6984 double lm22 = z2 - y2 - x2 + w2; 6985 double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; 6986 double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; 6987 double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; 6988 double nm03 = m03; 6989 double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; 6990 double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; 6991 double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; 6992 double nm13 = m13; 6993 double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; 6994 double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; 6995 double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; 6996 double nm23 = m23; 6997 double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32; 6998 double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32; 6999 double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32; 7000 dest._m00(nm00) 7001 ._m01(nm01) 7002 ._m02(nm02) 7003 ._m03(nm03) 7004 ._m10(nm10) 7005 ._m11(nm11) 7006 ._m12(nm12) 7007 ._m13(nm13) 7008 ._m20(nm20) 7009 ._m21(nm21) 7010 ._m22(nm22) 7011 ._m23(nm23) 7012 ._m30(nm30) 7013 ._m31(nm31) 7014 ._m32(nm32) 7015 ._m33(m33) 7016 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7017 return dest; 7018 } 7019 7020 /** 7021 * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix. 7022 * <p> 7023 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7024 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7025 * When used with a left-handed coordinate system, the rotation is clockwise. 7026 * <p> 7027 * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion, 7028 * then the new matrix will be <code>Q * M</code>. So when transforming a 7029 * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>, 7030 * the quaternion rotation will be applied last! 7031 * <p> 7032 * In order to set the matrix to a rotation transformation without pre-multiplying, 7033 * use {@link #rotation(ref Quaterniond)}. 7034 * <p> 7035 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a> 7036 * 7037 * @see #rotation(ref Quaterniond) 7038 * 7039 * @param quat 7040 * the {@link Quaterniond} 7041 * @return this 7042 */ 7043 ref public Matrix4d rotateLocal(ref Quaterniond quat) return { 7044 rotateLocal(quat, this); 7045 return this; 7046 } 7047 7048 7049 /** 7050 * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix. 7051 * <p> 7052 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7053 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7054 * When used with a left-handed coordinate system, the rotation is clockwise. 7055 * <p> 7056 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d}, 7057 * then the new matrix will be <code>M * A</code>. So when transforming a 7058 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7059 * the {@link AxisAngle4d} rotation will be applied first! 7060 * <p> 7061 * In order to set the matrix to a rotation transformation without post-multiplying, 7062 * use {@link #rotation(ref AxisAngle4d)}. 7063 * <p> 7064 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7065 * 7066 * @see #rotate(double, double, double, double) 7067 * @see #rotation(ref AxisAngle4d) 7068 * 7069 * @param axisAngle 7070 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 7071 * @return this 7072 */ 7073 ref public Matrix4d rotate(ref AxisAngle4d axisAngle) return { 7074 return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z); 7075 } 7076 7077 /** 7078 * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in <code>dest</code>. 7079 * <p> 7080 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7081 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7082 * When used with a left-handed coordinate system, the rotation is clockwise. 7083 * <p> 7084 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d}, 7085 * then the new matrix will be <code>M * A</code>. So when transforming a 7086 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7087 * the {@link AxisAngle4d} rotation will be applied first! 7088 * <p> 7089 * In order to set the matrix to a rotation transformation without post-multiplying, 7090 * use {@link #rotation(ref AxisAngle4d)}. 7091 * <p> 7092 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7093 * 7094 * @see #rotate(double, double, double, double) 7095 * @see #rotation(ref AxisAngle4d) 7096 * 7097 * @param axisAngle 7098 * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized}) 7099 * @param dest 7100 * will hold the result 7101 * @return dest 7102 */ 7103 public Matrix4d rotate(ref AxisAngle4d axisAngle, ref Matrix4d dest) { 7104 return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest); 7105 } 7106 7107 /** 7108 * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix. 7109 * <p> 7110 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7111 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7112 * When used with a left-handed coordinate system, the rotation is clockwise. 7113 * <p> 7114 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis, 7115 * then the new matrix will be <code>M * A</code>. So when transforming a 7116 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7117 * the axis-angle rotation will be applied first! 7118 * <p> 7119 * In order to set the matrix to a rotation transformation without post-multiplying, 7120 * use {@link #rotation(double, Vector3d)}. 7121 * <p> 7122 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7123 * 7124 * @see #rotate(double, double, double, double) 7125 * @see #rotation(double, Vector3d) 7126 * 7127 * @param angle 7128 * the angle in radians 7129 * @param axis 7130 * the rotation axis (needs to be {@link Vector3d#normalize() normalized}) 7131 * @return this 7132 */ 7133 ref public Matrix4d rotate(double angle, Vector3d axis) return { 7134 return rotate(angle, axis.x, axis.y, axis.z); 7135 } 7136 7137 /** 7138 * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in <code>dest</code>. 7139 * <p> 7140 * When used with a right-handed coordinate system, the produced rotation will rotate a vector 7141 * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. 7142 * When used with a left-handed coordinate system, the rotation is clockwise. 7143 * <p> 7144 * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis, 7145 * then the new matrix will be <code>M * A</code>. So when transforming a 7146 * vector <code>v</code> with the new matrix by using <code>M * A * v</code>, 7147 * the axis-angle rotation will be applied first! 7148 * <p> 7149 * In order to set the matrix to a rotation transformation without post-multiplying, 7150 * use {@link #rotation(double, Vector3d)}. 7151 * <p> 7152 * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a> 7153 * 7154 * @see #rotate(double, double, double, double) 7155 * @see #rotation(double, Vector3d) 7156 * 7157 * @param angle 7158 * the angle in radians 7159 * @param axis 7160 * the rotation axis (needs to be {@link Vector3d#normalize() normalized}) 7161 * @param dest 7162 * will hold the result 7163 * @return dest 7164 */ 7165 public Matrix4d rotate(double angle, Vector3d axis, ref Matrix4d dest) { 7166 return rotate(angle, axis.x, axis.y, axis.z, dest); 7167 } 7168 7169 public Vector4d getRow(int row, ref Vector4d dest) { 7170 switch (row) { 7171 case 0: 7172 dest.x = m00; 7173 dest.y = m10; 7174 dest.z = m20; 7175 dest.w = m30; 7176 break; 7177 case 1: 7178 dest.x = m01; 7179 dest.y = m11; 7180 dest.z = m21; 7181 dest.w = m31; 7182 break; 7183 case 2: 7184 dest.x = m02; 7185 dest.y = m12; 7186 dest.z = m22; 7187 dest.w = m32; 7188 break; 7189 case 3: 7190 dest.x = m03; 7191 dest.y = m13; 7192 dest.z = m23; 7193 dest.w = m33; 7194 break; 7195 default: {} 7196 } 7197 return dest; 7198 } 7199 7200 public Vector3d getRow(int row, ref Vector3d dest){ 7201 switch (row) { 7202 case 0: 7203 dest.x = m00; 7204 dest.y = m10; 7205 dest.z = m20; 7206 break; 7207 case 1: 7208 dest.x = m01; 7209 dest.y = m11; 7210 dest.z = m21; 7211 break; 7212 case 2: 7213 dest.x = m02; 7214 dest.y = m12; 7215 dest.z = m22; 7216 break; 7217 case 3: 7218 dest.x = m03; 7219 dest.y = m13; 7220 dest.z = m23; 7221 break; 7222 default: {} 7223 } 7224 return dest; 7225 } 7226 7227 /** 7228 * Set the row at the given <code>row</code> index, starting with <code>0</code>. 7229 * 7230 * @param row 7231 * the row index in <code>[0..3]</code> 7232 * @param src 7233 * the row components to set 7234 * @return this 7235 * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..3]</code> 7236 */ 7237 ref public Matrix4d setRow(int row, Vector4d src) return { 7238 switch (row) { 7239 case 0: 7240 return _m00(src.x)._m10(src.y)._m20(src.z)._m30(src.w)._properties(0); 7241 case 1: 7242 return _m01(src.x)._m11(src.y)._m21(src.z)._m31(src.w)._properties(0); 7243 case 2: 7244 return _m02(src.x)._m12(src.y)._m22(src.z)._m32(src.w)._properties(0); 7245 case 3: 7246 return _m03(src.x)._m13(src.y)._m23(src.z)._m33(src.w)._properties(0); 7247 default: 7248 return this; 7249 } 7250 } 7251 7252 public Vector4d getColumn(int column, ref Vector4d dest) { 7253 switch (column) { 7254 case 0: 7255 dest.x = m00; 7256 dest.y = m01; 7257 dest.z = m02; 7258 dest.w = m03; 7259 break; 7260 case 1: 7261 dest.x = m10; 7262 dest.y = m11; 7263 dest.z = m12; 7264 dest.w = m13; 7265 break; 7266 case 2: 7267 dest.x = m20; 7268 dest.y = m21; 7269 dest.z = m22; 7270 dest.w = m23; 7271 break; 7272 case 3: 7273 dest.x = m30; 7274 dest.y = m31; 7275 dest.z = m32; 7276 dest.w = m33; 7277 break; 7278 default: {} 7279 } 7280 return dest; 7281 } 7282 7283 public Vector3d getColumn(int column, ref Vector3d dest) { 7284 switch (column) { 7285 case 0: 7286 dest.x = m00; 7287 dest.y = m01; 7288 dest.z = m02; 7289 break; 7290 case 1: 7291 dest.x = m10; 7292 dest.y = m11; 7293 dest.z = m12; 7294 break; 7295 case 2: 7296 dest.x = m20; 7297 dest.y = m21; 7298 dest.z = m22; 7299 break; 7300 case 3: 7301 dest.x = m30; 7302 dest.y = m31; 7303 dest.z = m32; 7304 break; 7305 default: {} 7306 } 7307 return dest; 7308 } 7309 7310 /** 7311 * Set the column at the given <code>column</code> index, starting with <code>0</code>. 7312 * 7313 * @param column 7314 * the column index in <code>[0..3]</code> 7315 * @param src 7316 * the column components to set 7317 * @return this 7318 * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..3]</code> 7319 */ 7320 ref public Matrix4d setColumn(int column, Vector4d src) return { 7321 switch (column) { 7322 case 0: 7323 return _m00(src.x)._m01(src.y)._m02(src.z)._m03(src.w)._properties(0); 7324 case 1: 7325 return _m10(src.x)._m11(src.y)._m12(src.z)._m13(src.w)._properties(0); 7326 case 2: 7327 return _m20(src.x)._m21(src.y)._m22(src.z)._m23(src.w)._properties(0); 7328 case 3: 7329 return _m30(src.x)._m31(src.y)._m32(src.z)._m33(src.w)._properties(0); 7330 default: 7331 return this; 7332 } 7333 } 7334 7335 public double get(int column, int row) { 7336 return MemUtil.get(this, column, row); 7337 } 7338 7339 /** 7340 * Set the matrix element at the given column and row to the specified value. 7341 * 7342 * @param column 7343 * the colum index in <code>[0..3]</code> 7344 * @param row 7345 * the row index in <code>[0..3]</code> 7346 * @param value 7347 * the value 7348 * @return this 7349 */ 7350 ref public Matrix4d set(int column, int row, double value) return { 7351 MemUtil.set(this, column, row, value); 7352 return this; 7353 } 7354 7355 public double getRowColumn(int row, int column) { 7356 return MemUtil.get(this, column, row); 7357 } 7358 7359 /** 7360 * Set the matrix element at the given row and column to the specified value. 7361 * 7362 * @param row 7363 * the row index in <code>[0..3]</code> 7364 * @param column 7365 * the colum index in <code>[0..3]</code> 7366 * @param value 7367 * the value 7368 * @return this 7369 */ 7370 ref public Matrix4d setRowColumn(int row, int column, double value) return { 7371 MemUtil.set(this, column, row, value); 7372 return this; 7373 } 7374 7375 /** 7376 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7377 * and store it into the upper left 3x3 submatrix of <code>this</code>. 7378 * All other values of <code>this</code> will be set to {@link #identity() identity}. 7379 * <p> 7380 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7381 * <p> 7382 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7383 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7384 * In that case, use {@link #set3x3(Matrix4d)} to set a given Matrix4f to only the upper left 3x3 submatrix 7385 * of this matrix. 7386 * 7387 * @see #set3x3(Matrix4d) 7388 * 7389 * @return this 7390 */ 7391 ref public Matrix4d normal() return { 7392 normal(this); 7393 return this; 7394 } 7395 7396 /** 7397 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7398 * and store it into the upper left 3x3 submatrix of <code>dest</code>. 7399 * All other values of <code>dest</code> will be set to {@link #identity() identity}. 7400 * <p> 7401 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7402 * <p> 7403 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7404 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7405 * In that case, use {@link #set3x3(Matrix4d)} to set a given Matrix4d to only the upper left 3x3 submatrix 7406 * of a given matrix. 7407 * 7408 * @see #set3x3(Matrix4d) 7409 * 7410 * @param dest 7411 * will hold the result 7412 * @return dest 7413 */ 7414 public Matrix4d normal(ref Matrix4d dest) { 7415 if ((properties & PROPERTY_IDENTITY) != 0) 7416 return dest.identity(); 7417 else if ((properties & PROPERTY_ORTHONORMAL) != 0) 7418 return normalOrthonormal(dest); 7419 return normalGeneric(dest); 7420 } 7421 private Matrix4d normalOrthonormal(ref Matrix4d dest) { 7422 if (dest != this) 7423 dest.set(this); 7424 return dest._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 7425 } 7426 private Matrix4d normalGeneric(ref Matrix4d dest) { 7427 double m00m11 = m00 * m11; 7428 double m01m10 = m01 * m10; 7429 double m02m10 = m02 * m10; 7430 double m00m12 = m00 * m12; 7431 double m01m12 = m01 * m12; 7432 double m02m11 = m02 * m11; 7433 double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; 7434 double s = 1.0 / det; 7435 /* Invert and transpose in one go */ 7436 double nm00 = (m11 * m22 - m21 * m12) * s; 7437 double nm01 = (m20 * m12 - m10 * m22) * s; 7438 double nm02 = (m10 * m21 - m20 * m11) * s; 7439 double nm10 = (m21 * m02 - m01 * m22) * s; 7440 double nm11 = (m00 * m22 - m20 * m02) * s; 7441 double nm12 = (m20 * m01 - m00 * m21) * s; 7442 double nm20 = (m01m12 - m02m11) * s; 7443 double nm21 = (m02m10 - m00m12) * s; 7444 double nm22 = (m00m11 - m01m10) * s; 7445 return dest 7446 ._m00(nm00) 7447 ._m01(nm01) 7448 ._m02(nm02) 7449 ._m03(0.0) 7450 ._m10(nm10) 7451 ._m11(nm11) 7452 ._m12(nm12) 7453 ._m13(0.0) 7454 ._m20(nm20) 7455 ._m21(nm21) 7456 ._m22(nm22) 7457 ._m23(0.0) 7458 ._m30(0.0) 7459 ._m31(0.0) 7460 ._m32(0.0) 7461 ._m33(1.0) 7462 ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE)); 7463 } 7464 7465 /** 7466 * Compute a normal matrix from the upper left 3x3 submatrix of <code>this</code> 7467 * and store it into <code>dest</code>. 7468 * <p> 7469 * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>. 7470 * <p> 7471 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 7472 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 7473 * In that case, use {@link Matrix3d#set(Matrix4d)} to set a given Matrix3d to only the upper left 3x3 submatrix 7474 * of this matrix. 7475 * 7476 * @see Matrix3d#set(Matrix4d) 7477 * @see #get3x3(Matrix3d) 7478 * 7479 * @param dest 7480 * will hold the result 7481 * @return dest 7482 */ 7483 public Matrix3d normal(ref Matrix3d dest) { 7484 if ((properties & PROPERTY_ORTHONORMAL) != 0) 7485 return normalOrthonormal(dest); 7486 return normalGeneric(dest); 7487 } 7488 private Matrix3d normalOrthonormal(ref Matrix3d dest) { 7489 dest.set(this); 7490 return dest; 7491 } 7492 private Matrix3d normalGeneric(ref Matrix3d dest) { 7493 double m00m11 = m00 * m11; 7494 double m01m10 = m01 * m10; 7495 double m02m10 = m02 * m10; 7496 double m00m12 = m00 * m12; 7497 double m01m12 = m01 * m12; 7498 double m02m11 = m02 * m11; 7499 double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; 7500 double s = 1.0 / det; 7501 /* Invert and transpose in one go */ 7502 return dest._m00((m11 * m22 - m21 * m12) * s) 7503 ._m01((m20 * m12 - m10 * m22) * s) 7504 ._m02((m10 * m21 - m20 * m11) * s) 7505 ._m10((m21 * m02 - m01 * m22) * s) 7506 ._m11((m00 * m22 - m20 * m02) * s) 7507 ._m12((m20 * m01 - m00 * m21) * s) 7508 ._m20((m01m12 - m02m11) * s) 7509 ._m21((m02m10 - m00m12) * s) 7510 ._m22((m00m11 - m01m10) * s); 7511 } 7512 7513 /** 7514 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code>. 7515 * <p> 7516 * The cofactor matrix can be used instead of {@link #normal()} to transform normals 7517 * when the orientation of the normals with respect to the surface should be preserved. 7518 * 7519 * @return this 7520 */ 7521 ref public Matrix4d cofactor3x3() return { 7522 cofactor3x3(this); 7523 return this; 7524 } 7525 7526 /** 7527 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code> 7528 * and store it into <code>dest</code>. 7529 * <p> 7530 * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals 7531 * when the orientation of the normals with respect to the surface should be preserved. 7532 * 7533 * @param dest 7534 * will hold the result 7535 * @return dest 7536 */ 7537 public Matrix3d cofactor3x3(ref Matrix3d dest) { 7538 return dest._m00(m11 * m22 - m21 * m12) 7539 ._m01(m20 * m12 - m10 * m22) 7540 ._m02(m10 * m21 - m20 * m11) 7541 ._m10(m21 * m02 - m01 * m22) 7542 ._m11(m00 * m22 - m20 * m02) 7543 ._m12(m20 * m01 - m00 * m21) 7544 ._m20(m01 * m12 - m02 * m11) 7545 ._m21(m02 * m10 - m00 * m12) 7546 ._m22(m00 * m11 - m01 * m10); 7547 } 7548 7549 /** 7550 * Compute the cofactor matrix of the upper left 3x3 submatrix of <code>this</code> 7551 * and store it into <code>dest</code>. 7552 * All other values of <code>dest</code> will be set to {@link #identity() identity}. 7553 * <p> 7554 * The cofactor matrix can be used instead of {@link #normal(Matrix4d)} to transform normals 7555 * when the orientation of the normals with respect to the surface should be preserved. 7556 * 7557 * @param dest 7558 * will hold the result 7559 * @return dest 7560 */ 7561 public Matrix4d cofactor3x3(ref Matrix4d dest) { 7562 double nm10 = m21 * m02 - m01 * m22; 7563 double nm11 = m00 * m22 - m20 * m02; 7564 double nm12 = m20 * m01 - m00 * m21; 7565 double nm20 = m01 * m12 - m11 * m02; 7566 double nm21 = m02 * m10 - m12 * m00; 7567 double nm22 = m00 * m11 - m10 * m01; 7568 return dest 7569 ._m00(m11 * m22 - m21 * m12) 7570 ._m01(m20 * m12 - m10 * m22) 7571 ._m02(m10 * m21 - m20 * m11) 7572 ._m03(0.0) 7573 ._m10(nm10) 7574 ._m11(nm11) 7575 ._m12(nm12) 7576 ._m13(0.0) 7577 ._m20(nm20) 7578 ._m21(nm21) 7579 ._m22(nm22) 7580 ._m23(0.0) 7581 ._m30(0.0) 7582 ._m31(0.0) 7583 ._m32(0.0) 7584 ._m33(1.0) 7585 ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE)); 7586 } 7587 7588 /** 7589 * Normalize the upper left 3x3 submatrix of this matrix. 7590 * <p> 7591 * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit 7592 * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself 7593 * (i.e. had <i>skewing</i>). 7594 * 7595 * @return this 7596 */ 7597 ref public Matrix4d normalize3x3() return { 7598 normalize3x3(this); 7599 return this; 7600 } 7601 7602 public Matrix4d normalize3x3(ref Matrix4d dest) { 7603 double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 7604 double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 7605 double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 7606 dest._m00(m00 * invXlen)._m01(m01 * invXlen)._m02(m02 * invXlen) 7607 ._m10(m10 * invYlen)._m11(m11 * invYlen)._m12(m12 * invYlen) 7608 ._m20(m20 * invZlen)._m21(m21 * invZlen)._m22(m22 * invZlen) 7609 ._m30(m30)._m31(m31)._m32(m32)._m33(m33) 7610 ._properties(properties); 7611 return dest; 7612 } 7613 7614 public Matrix3d normalize3x3(ref Matrix3d dest) { 7615 double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 7616 double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 7617 double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 7618 dest.m00 = (m00 * invXlen); 7619 dest.m01 = (m01 * invXlen); 7620 dest.m02 = (m02 * invXlen); 7621 7622 dest.m10 = (m10 * invYlen); 7623 dest.m11 = (m11 * invYlen); 7624 dest.m12 = (m12 * invYlen); 7625 7626 dest.m20 = (m20 * invZlen); 7627 dest.m21 = (m21 * invZlen); 7628 dest.m22 = (m22 * invZlen); 7629 return dest; 7630 } 7631 7632 public Vector4d unproject(double winX, double winY, double winZ, int[] viewport, ref Vector4d dest) { 7633 double a = m00 * m11 - m01 * m10; 7634 double b = m00 * m12 - m02 * m10; 7635 double c = m00 * m13 - m03 * m10; 7636 double d = m01 * m12 - m02 * m11; 7637 double e = m01 * m13 - m03 * m11; 7638 double f = m02 * m13 - m03 * m12; 7639 double g = m20 * m31 - m21 * m30; 7640 double h = m20 * m32 - m22 * m30; 7641 double i = m20 * m33 - m23 * m30; 7642 double j = m21 * m32 - m22 * m31; 7643 double k = m21 * m33 - m23 * m31; 7644 double l = m22 * m33 - m23 * m32; 7645 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7646 det = 1.0 / det; 7647 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7648 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7649 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7650 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7651 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7652 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7653 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7654 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7655 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7656 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7657 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7658 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7659 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7660 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7661 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7662 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7663 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7664 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7665 double ndcZ = winZ+winZ-1.0; 7666 double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); 7667 dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW; 7668 dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW; 7669 dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW; 7670 dest.w = 1.0; 7671 return dest; 7672 } 7673 7674 public Vector3d unproject(double winX, double winY, double winZ, int[] viewport, ref Vector3d dest) { 7675 double a = m00 * m11 - m01 * m10; 7676 double b = m00 * m12 - m02 * m10; 7677 double c = m00 * m13 - m03 * m10; 7678 double d = m01 * m12 - m02 * m11; 7679 double e = m01 * m13 - m03 * m11; 7680 double f = m02 * m13 - m03 * m12; 7681 double g = m20 * m31 - m21 * m30; 7682 double h = m20 * m32 - m22 * m30; 7683 double i = m20 * m33 - m23 * m30; 7684 double j = m21 * m32 - m22 * m31; 7685 double k = m21 * m33 - m23 * m31; 7686 double l = m22 * m33 - m23 * m32; 7687 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7688 det = 1.0 / det; 7689 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7690 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7691 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7692 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7693 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7694 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7695 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7696 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7697 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7698 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7699 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7700 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7701 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7702 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7703 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7704 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7705 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7706 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7707 double ndcZ = winZ+winZ-1.0; 7708 double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); 7709 dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW; 7710 dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW; 7711 dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW; 7712 return dest; 7713 } 7714 7715 public Vector4d unproject(ref Vector3d winCoords, int[] viewport, ref Vector4d dest) { 7716 return unproject(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7717 } 7718 7719 public Vector3d unproject(ref Vector3d winCoords, int[] viewport, ref Vector3d dest) { 7720 return unproject(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7721 } 7722 7723 ref public Matrix4d unprojectRay(double winX, double winY, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) return { 7724 double a = m00 * m11 - m01 * m10; 7725 double b = m00 * m12 - m02 * m10; 7726 double c = m00 * m13 - m03 * m10; 7727 double d = m01 * m12 - m02 * m11; 7728 double e = m01 * m13 - m03 * m11; 7729 double f = m02 * m13 - m03 * m12; 7730 double g = m20 * m31 - m21 * m30; 7731 double h = m20 * m32 - m22 * m30; 7732 double i = m20 * m33 - m23 * m30; 7733 double j = m21 * m32 - m22 * m31; 7734 double k = m21 * m33 - m23 * m31; 7735 double l = m22 * m33 - m23 * m32; 7736 double det = a * l - b * k + c * j + d * i - e * h + f * g; 7737 det = 1.0 / det; 7738 double im00 = ( m11 * l - m12 * k + m13 * j) * det; 7739 double im01 = (-m01 * l + m02 * k - m03 * j) * det; 7740 double im02 = ( m31 * f - m32 * e + m33 * d) * det; 7741 double im03 = (-m21 * f + m22 * e - m23 * d) * det; 7742 double im10 = (-m10 * l + m12 * i - m13 * h) * det; 7743 double im11 = ( m00 * l - m02 * i + m03 * h) * det; 7744 double im12 = (-m30 * f + m32 * c - m33 * b) * det; 7745 double im13 = ( m20 * f - m22 * c + m23 * b) * det; 7746 double im20 = ( m10 * k - m11 * i + m13 * g) * det; 7747 double im21 = (-m00 * k + m01 * i - m03 * g) * det; 7748 double im22 = ( m30 * e - m31 * c + m33 * a) * det; 7749 double im23 = (-m20 * e + m21 * c - m23 * a) * det; 7750 double im30 = (-m10 * j + m11 * h - m12 * g) * det; 7751 double im31 = ( m00 * j - m01 * h + m02 * g) * det; 7752 double im32 = (-m30 * d + m31 * b - m32 * a) * det; 7753 double im33 = ( m20 * d - m21 * b + m22 * a) * det; 7754 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7755 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7756 double px = im00 * ndcX + im10 * ndcY + im30; 7757 double py = im01 * ndcX + im11 * ndcY + im31; 7758 double pz = im02 * ndcX + im12 * ndcY + im32; 7759 double invNearW = 1.0 / (im03 * ndcX + im13 * ndcY - im23 + im33); 7760 double nearX = (px - im20) * invNearW; 7761 double nearY = (py - im21) * invNearW; 7762 double nearZ = (pz - im22) * invNearW; 7763 double invW0 = 1.0 / (im03 * ndcX + im13 * ndcY + im33); 7764 double x0 = px * invW0; 7765 double y0 = py * invW0; 7766 double z0 = pz * invW0; 7767 originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ; 7768 dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ; 7769 return this; 7770 } 7771 7772 public Matrix4d unprojectRay(ref Vector2d winCoords, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) { 7773 return unprojectRay(winCoords.x, winCoords.y, viewport, originDest, dirDest); 7774 } 7775 7776 public Vector4d unprojectInv(ref Vector3d winCoords, int[] viewport, ref Vector4d dest) { 7777 return unprojectInv(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7778 } 7779 7780 public Vector4d unprojectInv(double winX, double winY, double winZ, int[] viewport, ref Vector4d dest) { 7781 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7782 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7783 double ndcZ = winZ+winZ-1.0; 7784 double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33); 7785 dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW; 7786 dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW; 7787 dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW; 7788 dest.w = 1.0; 7789 return dest; 7790 } 7791 7792 public Vector3d unprojectInv(ref Vector3d winCoords, int[] viewport, ref Vector3d dest) { 7793 return unprojectInv(winCoords.x, winCoords.y, winCoords.z, viewport, dest); 7794 } 7795 7796 public Vector3d unprojectInv(double winX, double winY, double winZ, int[] viewport, ref Vector3d dest) { 7797 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7798 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7799 double ndcZ = winZ+winZ-1.0; 7800 double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33); 7801 dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW; 7802 dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW; 7803 dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW; 7804 return dest; 7805 } 7806 7807 public Matrix4d unprojectInvRay(ref Vector2d winCoords, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) { 7808 return unprojectInvRay(winCoords.x, winCoords.y, viewport, originDest, dirDest); 7809 } 7810 7811 ref public Matrix4d unprojectInvRay(double winX, double winY, int[] viewport, ref Vector3d originDest, ref Vector3d dirDest) return { 7812 double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0; 7813 double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0; 7814 double px = m00 * ndcX + m10 * ndcY + m30; 7815 double py = m01 * ndcX + m11 * ndcY + m31; 7816 double pz = m02 * ndcX + m12 * ndcY + m32; 7817 double invNearW = 1.0 / (m03 * ndcX + m13 * ndcY - m23 + m33); 7818 double nearX = (px - m20) * invNearW; 7819 double nearY = (py - m21) * invNearW; 7820 double nearZ = (pz - m22) * invNearW; 7821 double invW0 = 1.0 / (m03 * ndcX + m13 * ndcY + m33); 7822 double x0 = px * invW0; 7823 double y0 = py * invW0; 7824 double z0 = pz * invW0; 7825 originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ; 7826 dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ; 7827 return this; 7828 } 7829 7830 public Vector4d project(double x, double y, double z, int[] viewport, ref Vector4d winCoordsDest) { 7831 double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))); 7832 double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW; 7833 double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW; 7834 double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW; 7835 return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]), 7836 Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]), 7837 Math.fma(0.5, nz, 0.5), 7838 1.0); 7839 } 7840 7841 public Vector3d project(double x, double y, double z, int[] viewport, ref Vector3d winCoordsDest) { 7842 double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))); 7843 double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW; 7844 double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW; 7845 double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW; 7846 winCoordsDest.x = Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]); 7847 winCoordsDest.y = Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]); 7848 winCoordsDest.z = Math.fma(0.5, nz, 0.5); 7849 return winCoordsDest; 7850 } 7851 7852 public Vector4d project(ref Vector3d position, int[] viewport, ref Vector4d dest) { 7853 return project(position.x, position.y, position.z, viewport, dest); 7854 } 7855 7856 public Vector3d project(ref Vector3d position, int[] viewport, ref Vector3d dest) { 7857 return project(position.x, position.y, position.z, viewport, dest); 7858 } 7859 7860 public Matrix4d reflect(double a, double b, double c, double d, ref Matrix4d dest) { 7861 if ((properties & PROPERTY_IDENTITY) != 0) 7862 return dest.reflection(a, b, c, d); 7863 if ((properties & PROPERTY_IDENTITY) != 0) 7864 return dest.reflection(a, b, c, d); 7865 else if ((properties & PROPERTY_AFFINE) != 0) 7866 return reflectAffine(a, b, c, d, dest); 7867 return reflectGeneric(a, b, c, d, dest); 7868 } 7869 private Matrix4d reflectAffine(double a, double b, double c, double d, ref Matrix4d dest) { 7870 double da = a + a, db = b + b, dc = c + c, dd = d + d; 7871 double rm00 = 1.0 - da * a; 7872 double rm01 = -da * b; 7873 double rm02 = -da * c; 7874 double rm10 = -db * a; 7875 double rm11 = 1.0 - db * b; 7876 double rm12 = -db * c; 7877 double rm20 = -dc * a; 7878 double rm21 = -dc * b; 7879 double rm22 = 1.0 - dc * c; 7880 double rm30 = -dd * a; 7881 double rm31 = -dd * b; 7882 double rm32 = -dd * c; 7883 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 7884 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 7885 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 7886 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 7887 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 7888 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 7889 // matrix multiplication 7890 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 7891 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 7892 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 7893 ._m33(m33) 7894 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 7895 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 7896 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 7897 ._m23(0.0) 7898 ._m00(nm00) 7899 ._m01(nm01) 7900 ._m02(nm02) 7901 ._m03(0.0) 7902 ._m10(nm10) 7903 ._m11(nm11) 7904 ._m12(nm12) 7905 ._m13(0.0) 7906 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7907 return dest; 7908 } 7909 private Matrix4d reflectGeneric(double a, double b, double c, double d, ref Matrix4d dest) { 7910 double da = a + a, db = b + b, dc = c + c, dd = d + d; 7911 double rm00 = 1.0 - da * a; 7912 double rm01 = -da * b; 7913 double rm02 = -da * c; 7914 double rm10 = -db * a; 7915 double rm11 = 1.0 - db * b; 7916 double rm12 = -db * c; 7917 double rm20 = -dc * a; 7918 double rm21 = -dc * b; 7919 double rm22 = 1.0 - dc * c; 7920 double rm30 = -dd * a; 7921 double rm31 = -dd * b; 7922 double rm32 = -dd * c; 7923 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 7924 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 7925 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 7926 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 7927 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 7928 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 7929 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 7930 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 7931 // matrix multiplication 7932 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 7933 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 7934 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 7935 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 7936 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 7937 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 7938 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 7939 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 7940 ._m00(nm00) 7941 ._m01(nm01) 7942 ._m02(nm02) 7943 ._m03(nm03) 7944 ._m10(nm10) 7945 ._m11(nm11) 7946 ._m12(nm12) 7947 ._m13(nm13) 7948 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 7949 return dest; 7950 } 7951 7952 /** 7953 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 7954 * specified via the equation <code>x*a + y*b + z*c + d = 0</code>. 7955 * <p> 7956 * The vector <code>(a, b, c)</code> must be a unit vector. 7957 * <p> 7958 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 7959 * then the new matrix will be <code>M * R</code>. So when transforming a 7960 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 7961 * reflection will be applied first! 7962 * <p> 7963 * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a> 7964 * 7965 * @param a 7966 * the x factor in the plane equation 7967 * @param b 7968 * the y factor in the plane equation 7969 * @param c 7970 * the z factor in the plane equation 7971 * @param d 7972 * the constant in the plane equation 7973 * @return this 7974 */ 7975 ref public Matrix4d reflect(double a, double b, double c, double d) return { 7976 reflect(a, b, c, d, this); 7977 return this; 7978 } 7979 7980 /** 7981 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 7982 * specified via the plane normal and a point on the plane. 7983 * <p> 7984 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 7985 * then the new matrix will be <code>M * R</code>. So when transforming a 7986 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 7987 * reflection will be applied first! 7988 * 7989 * @param nx 7990 * the x-coordinate of the plane normal 7991 * @param ny 7992 * the y-coordinate of the plane normal 7993 * @param nz 7994 * the z-coordinate of the plane normal 7995 * @param px 7996 * the x-coordinate of a point on the plane 7997 * @param py 7998 * the y-coordinate of a point on the plane 7999 * @param pz 8000 * the z-coordinate of a point on the plane 8001 * @return this 8002 */ 8003 ref public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz) return { 8004 reflect(nx, ny, nz, px, py, pz, this); 8005 return this; 8006 } 8007 8008 public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz, ref Matrix4d dest) { 8009 double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz); 8010 double nnx = nx * invLength; 8011 double nny = ny * invLength; 8012 double nnz = nz * invLength; 8013 /* See: http://mathworld.wolfram.com/Plane.html */ 8014 return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest); 8015 } 8016 8017 /** 8018 * Apply a mirror/reflection transformation to this matrix that reflects about the given plane 8019 * specified via the plane normal and a point on the plane. 8020 * <p> 8021 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8022 * then the new matrix will be <code>M * R</code>. So when transforming a 8023 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8024 * reflection will be applied first! 8025 * 8026 * @param normal 8027 * the plane normal 8028 * @param point 8029 * a point on the plane 8030 * @return this 8031 */ 8032 ref public Matrix4d reflect(ref Vector3d normal, Vector3d point) return { 8033 return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z); 8034 } 8035 8036 /** 8037 * Apply a mirror/reflection transformation to this matrix that reflects about a plane 8038 * specified via the plane orientation and a point on the plane. 8039 * <p> 8040 * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. 8041 * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is 8042 * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>. 8043 * <p> 8044 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix, 8045 * then the new matrix will be <code>M * R</code>. So when transforming a 8046 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 8047 * reflection will be applied first! 8048 * 8049 * @param orientation 8050 * the plane orientation relative to an implied normal vector of <code>(0, 0, 1)</code> 8051 * @param point 8052 * a point on the plane 8053 * @return this 8054 */ 8055 ref public Matrix4d reflect(ref Quaterniond orientation, Vector3d point) return { 8056 reflect(orientation, point, this); 8057 return this; 8058 } 8059 8060 public Matrix4d reflect(ref Quaterniond orientation, Vector3d point, ref Matrix4d dest) { 8061 double num1 = orientation.x + orientation.x; 8062 double num2 = orientation.y + orientation.y; 8063 double num3 = orientation.z + orientation.z; 8064 double normalX = orientation.x * num3 + orientation.w * num2; 8065 double normalY = orientation.y * num3 - orientation.w * num1; 8066 double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2); 8067 return reflect(normalX, normalY, normalZ, point.x, point.y, point.z, dest); 8068 } 8069 8070 public Matrix4d reflect(ref Vector3d normal, Vector3d point, ref Matrix4d dest) { 8071 return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z, dest); 8072 } 8073 8074 /** 8075 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8076 * specified via the equation <code>x*a + y*b + z*c + d = 0</code>. 8077 * <p> 8078 * The vector <code>(a, b, c)</code> must be a unit vector. 8079 * <p> 8080 * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a> 8081 * 8082 * @param a 8083 * the x factor in the plane equation 8084 * @param b 8085 * the y factor in the plane equation 8086 * @param c 8087 * the z factor in the plane equation 8088 * @param d 8089 * the constant in the plane equation 8090 * @return this 8091 */ 8092 ref public Matrix4d reflection(double a, double b, double c, double d) return { 8093 double da = a + a, db = b + b, dc = c + c, dd = d + d; 8094 _m00(1.0 - da * a). 8095 _m01(-da * b). 8096 _m02(-da * c). 8097 _m03(0.0). 8098 _m10(-db * a). 8099 _m11(1.0 - db * b). 8100 _m12(-db * c). 8101 _m13(0.0). 8102 _m20(-dc * a). 8103 _m21(-dc * b). 8104 _m22(1.0 - dc * c). 8105 _m23(0.0). 8106 _m30(-dd * a). 8107 _m31(-dd * b). 8108 _m32(-dd * c). 8109 _m33(1.0). 8110 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 8111 return this; 8112 } 8113 8114 /** 8115 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8116 * specified via the plane normal and a point on the plane. 8117 * 8118 * @param nx 8119 * the x-coordinate of the plane normal 8120 * @param ny 8121 * the y-coordinate of the plane normal 8122 * @param nz 8123 * the z-coordinate of the plane normal 8124 * @param px 8125 * the x-coordinate of a point on the plane 8126 * @param py 8127 * the y-coordinate of a point on the plane 8128 * @param pz 8129 * the z-coordinate of a point on the plane 8130 * @return this 8131 */ 8132 ref public Matrix4d reflection(double nx, double ny, double nz, double px, double py, double pz) return { 8133 double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz); 8134 double nnx = nx * invLength; 8135 double nny = ny * invLength; 8136 double nnz = nz * invLength; 8137 /* See: http://mathworld.wolfram.com/Plane.html */ 8138 return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz); 8139 } 8140 8141 /** 8142 * Set this matrix to a mirror/reflection transformation that reflects about the given plane 8143 * specified via the plane normal and a point on the plane. 8144 * 8145 * @param normal 8146 * the plane normal 8147 * @param point 8148 * a point on the plane 8149 * @return this 8150 */ 8151 ref public Matrix4d reflection(ref Vector3d normal, Vector3d point) return { 8152 return reflection(normal.x, normal.y, normal.z, point.x, point.y, point.z); 8153 } 8154 8155 /** 8156 * Set this matrix to a mirror/reflection transformation that reflects about a plane 8157 * specified via the plane orientation and a point on the plane. 8158 * <p> 8159 * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. 8160 * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is 8161 * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>. 8162 * 8163 * @param orientation 8164 * the plane orientation 8165 * @param point 8166 * a point on the plane 8167 * @return this 8168 */ 8169 ref public Matrix4d reflection(ref Quaterniond orientation, Vector3d point) return { 8170 double num1 = orientation.x + orientation.x; 8171 double num2 = orientation.y + orientation.y; 8172 double num3 = orientation.z + orientation.z; 8173 double normalX = orientation.x * num3 + orientation.w * num2; 8174 double normalY = orientation.y * num3 - orientation.w * num1; 8175 double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2); 8176 return reflection(normalX, normalY, normalZ, point.x, point.y, point.z); 8177 } 8178 8179 /** 8180 * Apply an orthographic projection transformation for a right-handed coordinate system 8181 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8182 * <p> 8183 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8184 * then the new matrix will be <code>M * O</code>. So when transforming a 8185 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8186 * orthographic projection transformation will be applied first! 8187 * <p> 8188 * In order to set the matrix to an orthographic projection without post-multiplying it, 8189 * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}. 8190 * <p> 8191 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8192 * 8193 * @see #setOrtho(double, double, double, double, double, double, bool) 8194 * 8195 * @param left 8196 * the distance from the center to the left frustum edge 8197 * @param right 8198 * the distance from the center to the right frustum edge 8199 * @param bottom 8200 * the distance from the center to the bottom frustum edge 8201 * @param top 8202 * the distance from the center to the top frustum edge 8203 * @param zNear 8204 * near clipping plane distance 8205 * @param zFar 8206 * far clipping plane distance 8207 * @param zZeroToOne 8208 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8209 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8210 * @param dest 8211 * will hold the result 8212 * @return dest 8213 */ 8214 public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8215 if ((properties & PROPERTY_IDENTITY) != 0) 8216 return dest.setOrtho(left, right, bottom, top, zNear, zFar, zZeroToOne); 8217 return orthoGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 8218 } 8219 private Matrix4d orthoGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8220 // calculate right matrix elements 8221 double rm00 = 2.0 / (right - left); 8222 double rm11 = 2.0 / (top - bottom); 8223 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar); 8224 double rm30 = (left + right) / (left - right); 8225 double rm31 = (top + bottom) / (bottom - top); 8226 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8227 // perform optimized multiplication 8228 // compute the last column first, because other columns do not depend on it 8229 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 8230 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 8231 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 8232 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 8233 ._m00(m00 * rm00) 8234 ._m01(m01 * rm00) 8235 ._m02(m02 * rm00) 8236 ._m03(m03 * rm00) 8237 ._m10(m10 * rm11) 8238 ._m11(m11 * rm11) 8239 ._m12(m12 * rm11) 8240 ._m13(m13 * rm11) 8241 ._m20(m20 * rm22) 8242 ._m21(m21 * rm22) 8243 ._m22(m22 * rm22) 8244 ._m23(m23 * rm22) 8245 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8246 return dest; 8247 } 8248 8249 /** 8250 * Apply an orthographic projection transformation for a right-handed coordinate system 8251 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8252 * <p> 8253 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8254 * then the new matrix will be <code>M * O</code>. So when transforming a 8255 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8256 * orthographic projection transformation will be applied first! 8257 * <p> 8258 * In order to set the matrix to an orthographic projection without post-multiplying it, 8259 * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}. 8260 * <p> 8261 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8262 * 8263 * @see #setOrtho(double, double, double, double, double, double) 8264 * 8265 * @param left 8266 * the distance from the center to the left frustum edge 8267 * @param right 8268 * the distance from the center to the right frustum edge 8269 * @param bottom 8270 * the distance from the center to the bottom frustum edge 8271 * @param top 8272 * the distance from the center to the top frustum edge 8273 * @param zNear 8274 * near clipping plane distance 8275 * @param zFar 8276 * far clipping plane distance 8277 * @param dest 8278 * will hold the result 8279 * @return dest 8280 */ 8281 public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 8282 return ortho(left, right, bottom, top, zNear, zFar, false, dest); 8283 } 8284 8285 /** 8286 * Apply an orthographic projection transformation for a right-handed coordinate system 8287 * using the given NDC z range to this matrix. 8288 * <p> 8289 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8290 * then the new matrix will be <code>M * O</code>. So when transforming a 8291 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8292 * orthographic projection transformation will be applied first! 8293 * <p> 8294 * In order to set the matrix to an orthographic projection without post-multiplying it, 8295 * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}. 8296 * <p> 8297 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8298 * 8299 * @see #setOrtho(double, double, double, double, double, double, bool) 8300 * 8301 * @param left 8302 * the distance from the center to the left frustum edge 8303 * @param right 8304 * the distance from the center to the right frustum edge 8305 * @param bottom 8306 * the distance from the center to the bottom frustum edge 8307 * @param top 8308 * the distance from the center to the top frustum edge 8309 * @param zNear 8310 * near clipping plane distance 8311 * @param zFar 8312 * far clipping plane distance 8313 * @param zZeroToOne 8314 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8315 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8316 * @return this 8317 */ 8318 ref public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8319 ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 8320 return this; 8321 } 8322 8323 /** 8324 * Apply an orthographic projection transformation for a right-handed coordinate system 8325 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8326 * <p> 8327 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8328 * then the new matrix will be <code>M * O</code>. So when transforming a 8329 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8330 * orthographic projection transformation will be applied first! 8331 * <p> 8332 * In order to set the matrix to an orthographic projection without post-multiplying it, 8333 * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}. 8334 * <p> 8335 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8336 * 8337 * @see #setOrtho(double, double, double, double, double, double) 8338 * 8339 * @param left 8340 * the distance from the center to the left frustum edge 8341 * @param right 8342 * the distance from the center to the right frustum edge 8343 * @param bottom 8344 * the distance from the center to the bottom frustum edge 8345 * @param top 8346 * the distance from the center to the top frustum edge 8347 * @param zNear 8348 * near clipping plane distance 8349 * @param zFar 8350 * far clipping plane distance 8351 * @return this 8352 */ 8353 ref public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar) return { 8354 return ortho(left, right, bottom, top, zNear, zFar, false); 8355 } 8356 8357 /** 8358 * Apply an orthographic projection transformation for a left-handed coordiante system 8359 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8360 * <p> 8361 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8362 * then the new matrix will be <code>M * O</code>. So when transforming a 8363 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8364 * orthographic projection transformation will be applied first! 8365 * <p> 8366 * In order to set the matrix to an orthographic projection without post-multiplying it, 8367 * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}. 8368 * <p> 8369 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8370 * 8371 * @see #setOrthoLH(double, double, double, double, double, double, bool) 8372 * 8373 * @param left 8374 * the distance from the center to the left frustum edge 8375 * @param right 8376 * the distance from the center to the right frustum edge 8377 * @param bottom 8378 * the distance from the center to the bottom frustum edge 8379 * @param top 8380 * the distance from the center to the top frustum edge 8381 * @param zNear 8382 * near clipping plane distance 8383 * @param zFar 8384 * far clipping plane distance 8385 * @param zZeroToOne 8386 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8387 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8388 * @param dest 8389 * will hold the result 8390 * @return dest 8391 */ 8392 public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8393 if ((properties & PROPERTY_IDENTITY) != 0) 8394 return dest.setOrthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne); 8395 return orthoLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 8396 } 8397 private Matrix4d orthoLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8398 // calculate right matrix elements 8399 double rm00 = 2.0 / (right - left); 8400 double rm11 = 2.0 / (top - bottom); 8401 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear); 8402 double rm30 = (left + right) / (left - right); 8403 double rm31 = (top + bottom) / (bottom - top); 8404 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8405 // perform optimized multiplication 8406 // compute the last column first, because other columns do not depend on it 8407 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 8408 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 8409 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 8410 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 8411 ._m00(m00 * rm00) 8412 ._m01(m01 * rm00) 8413 ._m02(m02 * rm00) 8414 ._m03(m03 * rm00) 8415 ._m10(m10 * rm11) 8416 ._m11(m11 * rm11) 8417 ._m12(m12 * rm11) 8418 ._m13(m13 * rm11) 8419 ._m20(m20 * rm22) 8420 ._m21(m21 * rm22) 8421 ._m22(m22 * rm22) 8422 ._m23(m23 * rm22) 8423 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8424 return dest; 8425 } 8426 8427 /** 8428 * Apply an orthographic projection transformation for a left-handed coordiante system 8429 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8430 * <p> 8431 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8432 * then the new matrix will be <code>M * O</code>. So when transforming a 8433 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8434 * orthographic projection transformation will be applied first! 8435 * <p> 8436 * In order to set the matrix to an orthographic projection without post-multiplying it, 8437 * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}. 8438 * <p> 8439 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8440 * 8441 * @see #setOrthoLH(double, double, double, double, double, double) 8442 * 8443 * @param left 8444 * the distance from the center to the left frustum edge 8445 * @param right 8446 * the distance from the center to the right frustum edge 8447 * @param bottom 8448 * the distance from the center to the bottom frustum edge 8449 * @param top 8450 * the distance from the center to the top frustum edge 8451 * @param zNear 8452 * near clipping plane distance 8453 * @param zFar 8454 * far clipping plane distance 8455 * @param dest 8456 * will hold the result 8457 * @return dest 8458 */ 8459 public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 8460 return orthoLH(left, right, bottom, top, zNear, zFar, false, dest); 8461 } 8462 8463 /** 8464 * Apply an orthographic projection transformation for a left-handed coordiante system 8465 * using the given NDC z range to this matrix. 8466 * <p> 8467 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8468 * then the new matrix will be <code>M * O</code>. So when transforming a 8469 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8470 * orthographic projection transformation will be applied first! 8471 * <p> 8472 * In order to set the matrix to an orthographic projection without post-multiplying it, 8473 * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}. 8474 * <p> 8475 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8476 * 8477 * @see #setOrthoLH(double, double, double, double, double, double, bool) 8478 * 8479 * @param left 8480 * the distance from the center to the left frustum edge 8481 * @param right 8482 * the distance from the center to the right frustum edge 8483 * @param bottom 8484 * the distance from the center to the bottom frustum edge 8485 * @param top 8486 * the distance from the center to the top frustum edge 8487 * @param zNear 8488 * near clipping plane distance 8489 * @param zFar 8490 * far clipping plane distance 8491 * @param zZeroToOne 8492 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8493 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8494 * @return this 8495 */ 8496 ref public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8497 orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 8498 return this; 8499 } 8500 8501 /** 8502 * Apply an orthographic projection transformation for a left-handed coordiante system 8503 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8504 * <p> 8505 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8506 * then the new matrix will be <code>M * O</code>. So when transforming a 8507 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8508 * orthographic projection transformation will be applied first! 8509 * <p> 8510 * In order to set the matrix to an orthographic projection without post-multiplying it, 8511 * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}. 8512 * <p> 8513 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8514 * 8515 * @see #setOrthoLH(double, double, double, double, double, double) 8516 * 8517 * @param left 8518 * the distance from the center to the left frustum edge 8519 * @param right 8520 * the distance from the center to the right frustum edge 8521 * @param bottom 8522 * the distance from the center to the bottom frustum edge 8523 * @param top 8524 * the distance from the center to the top frustum edge 8525 * @param zNear 8526 * near clipping plane distance 8527 * @param zFar 8528 * far clipping plane distance 8529 * @return this 8530 */ 8531 ref public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 8532 return orthoLH(left, right, bottom, top, zNear, zFar, false); 8533 } 8534 8535 /** 8536 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system 8537 * using the given NDC z range. 8538 * <p> 8539 * In order to apply the orthographic projection to an already existing transformation, 8540 * use {@link #ortho(double, double, double, double, double, double, bool) ortho()}. 8541 * <p> 8542 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8543 * 8544 * @see #ortho(double, double, double, double, double, double, bool) 8545 * 8546 * @param left 8547 * the distance from the center to the left frustum edge 8548 * @param right 8549 * the distance from the center to the right frustum edge 8550 * @param bottom 8551 * the distance from the center to the bottom frustum edge 8552 * @param top 8553 * the distance from the center to the top frustum edge 8554 * @param zNear 8555 * near clipping plane distance 8556 * @param zFar 8557 * far clipping plane distance 8558 * @param zZeroToOne 8559 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8560 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8561 * @return this 8562 */ 8563 ref public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8564 if ((properties & PROPERTY_IDENTITY) == 0) 8565 _identity(); 8566 _m00(2.0 / (right - left)). 8567 _m11(2.0 / (top - bottom)). 8568 _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)). 8569 _m30((right + left) / (left - right)). 8570 _m31((top + bottom) / (bottom - top)). 8571 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 8572 properties = PROPERTY_AFFINE; 8573 return this; 8574 } 8575 8576 /** 8577 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system 8578 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 8579 * <p> 8580 * In order to apply the orthographic projection to an already existing transformation, 8581 * use {@link #ortho(double, double, double, double, double, double) ortho()}. 8582 * <p> 8583 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8584 * 8585 * @see #ortho(double, double, double, double, double, double) 8586 * 8587 * @param left 8588 * the distance from the center to the left frustum edge 8589 * @param right 8590 * the distance from the center to the right frustum edge 8591 * @param bottom 8592 * the distance from the center to the bottom frustum edge 8593 * @param top 8594 * the distance from the center to the top frustum edge 8595 * @param zNear 8596 * near clipping plane distance 8597 * @param zFar 8598 * far clipping plane distance 8599 * @return this 8600 */ 8601 ref public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) return { 8602 return setOrtho(left, right, bottom, top, zNear, zFar, false); 8603 } 8604 8605 /** 8606 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system 8607 * using the given NDC z range. 8608 * <p> 8609 * In order to apply the orthographic projection to an already existing transformation, 8610 * use {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()}. 8611 * <p> 8612 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8613 * 8614 * @see #orthoLH(double, double, double, double, double, double, bool) 8615 * 8616 * @param left 8617 * the distance from the center to the left frustum edge 8618 * @param right 8619 * the distance from the center to the right frustum edge 8620 * @param bottom 8621 * the distance from the center to the bottom frustum edge 8622 * @param top 8623 * the distance from the center to the top frustum edge 8624 * @param zNear 8625 * near clipping plane distance 8626 * @param zFar 8627 * far clipping plane distance 8628 * @param zZeroToOne 8629 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8630 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8631 * @return this 8632 */ 8633 ref public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 8634 if ((properties & PROPERTY_IDENTITY) == 0) 8635 _identity(); 8636 _m00(2.0 / (right - left)). 8637 _m11(2.0 / (top - bottom)). 8638 _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)). 8639 _m30((right + left) / (left - right)). 8640 _m31((top + bottom) / (bottom - top)). 8641 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 8642 properties = PROPERTY_AFFINE; 8643 return this; 8644 } 8645 8646 /** 8647 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system 8648 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 8649 * <p> 8650 * In order to apply the orthographic projection to an already existing transformation, 8651 * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}. 8652 * <p> 8653 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8654 * 8655 * @see #orthoLH(double, double, double, double, double, double) 8656 * 8657 * @param left 8658 * the distance from the center to the left frustum edge 8659 * @param right 8660 * the distance from the center to the right frustum edge 8661 * @param bottom 8662 * the distance from the center to the bottom frustum edge 8663 * @param top 8664 * the distance from the center to the top frustum edge 8665 * @param zNear 8666 * near clipping plane distance 8667 * @param zFar 8668 * far clipping plane distance 8669 * @return this 8670 */ 8671 ref public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 8672 return setOrthoLH(left, right, bottom, top, zNear, zFar, false); 8673 } 8674 8675 /** 8676 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8677 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8678 * <p> 8679 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool, Matrix4d) ortho()} with 8680 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8681 * <p> 8682 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8683 * then the new matrix will be <code>M * O</code>. So when transforming a 8684 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8685 * orthographic projection transformation will be applied first! 8686 * <p> 8687 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8688 * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}. 8689 * <p> 8690 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8691 * 8692 * @see #setOrthoSymmetric(double, double, double, double, bool) 8693 * 8694 * @param width 8695 * the distance between the right and left frustum edges 8696 * @param height 8697 * the distance between the top and bottom frustum edges 8698 * @param zNear 8699 * near clipping plane distance 8700 * @param zFar 8701 * far clipping plane distance 8702 * @param dest 8703 * will hold the result 8704 * @param zZeroToOne 8705 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8706 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8707 * @return dest 8708 */ 8709 public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8710 if ((properties & PROPERTY_IDENTITY) != 0) 8711 return dest.setOrthoSymmetric(width, height, zNear, zFar, zZeroToOne); 8712 return orthoSymmetricGeneric(width, height, zNear, zFar, zZeroToOne, dest); 8713 } 8714 private Matrix4d orthoSymmetricGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8715 // calculate right matrix elements 8716 double rm00 = 2.0 / width; 8717 double rm11 = 2.0 / height; 8718 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar); 8719 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8720 // perform optimized multiplication 8721 // compute the last column first, because other columns do not depend on it 8722 dest._m30(m20 * rm32 + m30) 8723 ._m31(m21 * rm32 + m31) 8724 ._m32(m22 * rm32 + m32) 8725 ._m33(m23 * rm32 + m33) 8726 ._m00(m00 * rm00) 8727 ._m01(m01 * rm00) 8728 ._m02(m02 * rm00) 8729 ._m03(m03 * rm00) 8730 ._m10(m10 * rm11) 8731 ._m11(m11 * rm11) 8732 ._m12(m12 * rm11) 8733 ._m13(m13 * rm11) 8734 ._m20(m20 * rm22) 8735 ._m21(m21 * rm22) 8736 ._m22(m22 * rm22) 8737 ._m23(m23 * rm22) 8738 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8739 return dest; 8740 } 8741 8742 /** 8743 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8744 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8745 * <p> 8746 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with 8747 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8748 * <p> 8749 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8750 * then the new matrix will be <code>M * O</code>. So when transforming a 8751 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8752 * orthographic projection transformation will be applied first! 8753 * <p> 8754 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8755 * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}. 8756 * <p> 8757 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8758 * 8759 * @see #setOrthoSymmetric(double, double, double, double) 8760 * 8761 * @param width 8762 * the distance between the right and left frustum edges 8763 * @param height 8764 * the distance between the top and bottom frustum edges 8765 * @param zNear 8766 * near clipping plane distance 8767 * @param zFar 8768 * far clipping plane distance 8769 * @param dest 8770 * will hold the result 8771 * @return dest 8772 */ 8773 public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 8774 return orthoSymmetric(width, height, zNear, zFar, false, dest); 8775 } 8776 8777 /** 8778 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8779 * using the given NDC z range to this matrix. 8780 * <p> 8781 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool) ortho()} with 8782 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8783 * <p> 8784 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8785 * then the new matrix will be <code>M * O</code>. So when transforming a 8786 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8787 * orthographic projection transformation will be applied first! 8788 * <p> 8789 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8790 * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}. 8791 * <p> 8792 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8793 * 8794 * @see #setOrthoSymmetric(double, double, double, double, bool) 8795 * 8796 * @param width 8797 * the distance between the right and left frustum edges 8798 * @param height 8799 * the distance between the top and bottom frustum edges 8800 * @param zNear 8801 * near clipping plane distance 8802 * @param zFar 8803 * far clipping plane distance 8804 * @param zZeroToOne 8805 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8806 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8807 * @return this 8808 */ 8809 ref public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 8810 orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this); 8811 return this; 8812 } 8813 8814 /** 8815 * Apply a symmetric orthographic projection transformation for a right-handed coordinate system 8816 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8817 * <p> 8818 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with 8819 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8820 * <p> 8821 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8822 * then the new matrix will be <code>M * O</code>. So when transforming a 8823 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8824 * orthographic projection transformation will be applied first! 8825 * <p> 8826 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8827 * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}. 8828 * <p> 8829 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8830 * 8831 * @see #setOrthoSymmetric(double, double, double, double) 8832 * 8833 * @param width 8834 * the distance between the right and left frustum edges 8835 * @param height 8836 * the distance between the top and bottom frustum edges 8837 * @param zNear 8838 * near clipping plane distance 8839 * @param zFar 8840 * far clipping plane distance 8841 * @return this 8842 */ 8843 ref public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar) return { 8844 orthoSymmetric(width, height, zNear, zFar, false, this); 8845 return this; 8846 } 8847 8848 /** 8849 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8850 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 8851 * <p> 8852 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool, Matrix4d) orthoLH()} with 8853 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8854 * <p> 8855 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8856 * then the new matrix will be <code>M * O</code>. So when transforming a 8857 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8858 * orthographic projection transformation will be applied first! 8859 * <p> 8860 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8861 * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}. 8862 * <p> 8863 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8864 * 8865 * @see #setOrthoSymmetricLH(double, double, double, double, bool) 8866 * 8867 * @param width 8868 * the distance between the right and left frustum edges 8869 * @param height 8870 * the distance between the top and bottom frustum edges 8871 * @param zNear 8872 * near clipping plane distance 8873 * @param zFar 8874 * far clipping plane distance 8875 * @param dest 8876 * will hold the result 8877 * @param zZeroToOne 8878 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8879 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8880 * @return dest 8881 */ 8882 public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8883 if ((properties & PROPERTY_IDENTITY) != 0) 8884 return dest.setOrthoSymmetricLH(width, height, zNear, zFar, zZeroToOne); 8885 return orthoSymmetricLHGeneric(width, height, zNear, zFar, zZeroToOne, dest); 8886 } 8887 private Matrix4d orthoSymmetricLHGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 8888 // calculate right matrix elements 8889 double rm00 = 2.0 / width; 8890 double rm11 = 2.0 / height; 8891 double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear); 8892 double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); 8893 // perform optimized multiplication 8894 // compute the last column first, because other columns do not depend on it 8895 dest._m30(m20 * rm32 + m30) 8896 ._m31(m21 * rm32 + m31) 8897 ._m32(m22 * rm32 + m32) 8898 ._m33(m23 * rm32 + m33) 8899 ._m00(m00 * rm00) 8900 ._m01(m01 * rm00) 8901 ._m02(m02 * rm00) 8902 ._m03(m03 * rm00) 8903 ._m10(m10 * rm11) 8904 ._m11(m11 * rm11) 8905 ._m12(m12 * rm11) 8906 ._m13(m13 * rm11) 8907 ._m20(m20 * rm22) 8908 ._m21(m21 * rm22) 8909 ._m22(m22 * rm22) 8910 ._m23(m23 * rm22) 8911 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 8912 return dest; 8913 } 8914 8915 /** 8916 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8917 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 8918 * <p> 8919 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with 8920 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8921 * <p> 8922 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8923 * then the new matrix will be <code>M * O</code>. So when transforming a 8924 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8925 * orthographic projection transformation will be applied first! 8926 * <p> 8927 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8928 * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}. 8929 * <p> 8930 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8931 * 8932 * @see #setOrthoSymmetricLH(double, double, double, double) 8933 * 8934 * @param width 8935 * the distance between the right and left frustum edges 8936 * @param height 8937 * the distance between the top and bottom frustum edges 8938 * @param zNear 8939 * near clipping plane distance 8940 * @param zFar 8941 * far clipping plane distance 8942 * @param dest 8943 * will hold the result 8944 * @return dest 8945 */ 8946 public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 8947 return orthoSymmetricLH(width, height, zNear, zFar, false, dest); 8948 } 8949 8950 /** 8951 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8952 * using the given NDC z range to this matrix. 8953 * <p> 8954 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()} with 8955 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8956 * <p> 8957 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8958 * then the new matrix will be <code>M * O</code>. So when transforming a 8959 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8960 * orthographic projection transformation will be applied first! 8961 * <p> 8962 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 8963 * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}. 8964 * <p> 8965 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 8966 * 8967 * @see #setOrthoSymmetricLH(double, double, double, double, bool) 8968 * 8969 * @param width 8970 * the distance between the right and left frustum edges 8971 * @param height 8972 * the distance between the top and bottom frustum edges 8973 * @param zNear 8974 * near clipping plane distance 8975 * @param zFar 8976 * far clipping plane distance 8977 * @param zZeroToOne 8978 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 8979 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 8980 * @return this 8981 */ 8982 ref public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 8983 orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this); 8984 return this; 8985 } 8986 8987 /** 8988 * Apply a symmetric orthographic projection transformation for a left-handed coordinate system 8989 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 8990 * <p> 8991 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with 8992 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 8993 * <p> 8994 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 8995 * then the new matrix will be <code>M * O</code>. So when transforming a 8996 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 8997 * orthographic projection transformation will be applied first! 8998 * <p> 8999 * In order to set the matrix to a symmetric orthographic projection without post-multiplying it, 9000 * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}. 9001 * <p> 9002 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9003 * 9004 * @see #setOrthoSymmetricLH(double, double, double, double) 9005 * 9006 * @param width 9007 * the distance between the right and left frustum edges 9008 * @param height 9009 * the distance between the top and bottom frustum edges 9010 * @param zNear 9011 * near clipping plane distance 9012 * @param zFar 9013 * far clipping plane distance 9014 * @return this 9015 */ 9016 ref public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar) return { 9017 orthoSymmetricLH(width, height, zNear, zFar, false, this); 9018 return this; 9019 } 9020 9021 /** 9022 * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system 9023 * using the given NDC z range. 9024 * <p> 9025 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with 9026 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9027 * <p> 9028 * In order to apply the symmetric orthographic projection to an already existing transformation, 9029 * use {@link #orthoSymmetric(double, double, double, double, bool) orthoSymmetric()}. 9030 * <p> 9031 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9032 * 9033 * @see #orthoSymmetric(double, double, double, double, bool) 9034 * 9035 * @param width 9036 * the distance between the right and left frustum edges 9037 * @param height 9038 * the distance between the top and bottom frustum edges 9039 * @param zNear 9040 * near clipping plane distance 9041 * @param zFar 9042 * far clipping plane distance 9043 * @param zZeroToOne 9044 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9045 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9046 * @return this 9047 */ 9048 ref public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9049 if ((properties & PROPERTY_IDENTITY) == 0) 9050 _identity(); 9051 _m00(2.0 / width). 9052 _m11(2.0 / height). 9053 _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)). 9054 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 9055 properties = PROPERTY_AFFINE; 9056 return this; 9057 } 9058 9059 /** 9060 * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system 9061 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 9062 * <p> 9063 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with 9064 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9065 * <p> 9066 * In order to apply the symmetric orthographic projection to an already existing transformation, 9067 * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}. 9068 * <p> 9069 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9070 * 9071 * @see #orthoSymmetric(double, double, double, double) 9072 * 9073 * @param width 9074 * the distance between the right and left frustum edges 9075 * @param height 9076 * the distance between the top and bottom frustum edges 9077 * @param zNear 9078 * near clipping plane distance 9079 * @param zFar 9080 * far clipping plane distance 9081 * @return this 9082 */ 9083 ref public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar) return { 9084 return setOrthoSymmetric(width, height, zNear, zFar, false); 9085 } 9086 9087 /** 9088 * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range. 9089 * <p> 9090 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with 9091 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9092 * <p> 9093 * In order to apply the symmetric orthographic projection to an already existing transformation, 9094 * use {@link #orthoSymmetricLH(double, double, double, double, bool) orthoSymmetricLH()}. 9095 * <p> 9096 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9097 * 9098 * @see #orthoSymmetricLH(double, double, double, double, bool) 9099 * 9100 * @param width 9101 * the distance between the right and left frustum edges 9102 * @param height 9103 * the distance between the top and bottom frustum edges 9104 * @param zNear 9105 * near clipping plane distance 9106 * @param zFar 9107 * far clipping plane distance 9108 * @param zZeroToOne 9109 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 9110 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 9111 * @return this 9112 */ 9113 ref public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 9114 if ((properties & PROPERTY_IDENTITY) == 0) 9115 _identity(); 9116 _m00(2.0 / width). 9117 _m11(2.0 / height). 9118 _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)). 9119 _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)). 9120 properties = PROPERTY_AFFINE; 9121 return this; 9122 } 9123 9124 /** 9125 * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system 9126 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 9127 * <p> 9128 * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with 9129 * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>. 9130 * <p> 9131 * In order to apply the symmetric orthographic projection to an already existing transformation, 9132 * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}. 9133 * <p> 9134 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9135 * 9136 * @see #orthoSymmetricLH(double, double, double, double) 9137 * 9138 * @param width 9139 * the distance between the right and left frustum edges 9140 * @param height 9141 * the distance between the top and bottom frustum edges 9142 * @param zNear 9143 * near clipping plane distance 9144 * @param zFar 9145 * far clipping plane distance 9146 * @return this 9147 */ 9148 ref public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) return { 9149 return setOrthoSymmetricLH(width, height, zNear, zFar, false); 9150 } 9151 9152 /** 9153 * Apply an orthographic projection transformation for a right-handed coordinate system 9154 * to this matrix and store the result in <code>dest</code>. 9155 * <p> 9156 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with 9157 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9158 * <p> 9159 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9160 * then the new matrix will be <code>M * O</code>. So when transforming a 9161 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9162 * orthographic projection transformation will be applied first! 9163 * <p> 9164 * In order to set the matrix to an orthographic projection without post-multiplying it, 9165 * use {@link #setOrtho2D(double, double, double, double) setOrtho()}. 9166 * <p> 9167 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9168 * 9169 * @see #ortho(double, double, double, double, double, double, Matrix4d) 9170 * @see #setOrtho2D(double, double, double, double) 9171 * 9172 * @param left 9173 * the distance from the center to the left frustum edge 9174 * @param right 9175 * the distance from the center to the right frustum edge 9176 * @param bottom 9177 * the distance from the center to the bottom frustum edge 9178 * @param top 9179 * the distance from the center to the top frustum edge 9180 * @param dest 9181 * will hold the result 9182 * @return dest 9183 */ 9184 public Matrix4d ortho2D(double left, double right, double bottom, double top, ref Matrix4d dest) { 9185 if ((properties & PROPERTY_IDENTITY) != 0) 9186 return dest.setOrtho2D(left, right, bottom, top); 9187 return ortho2DGeneric(left, right, bottom, top, dest); 9188 } 9189 private Matrix4d ortho2DGeneric(double left, double right, double bottom, double top, ref Matrix4d dest) { 9190 // calculate right matrix elements 9191 double rm00 = 2.0 / (right - left); 9192 double rm11 = 2.0 / (top - bottom); 9193 double rm30 = (right + left) / (left - right); 9194 double rm31 = (top + bottom) / (bottom - top); 9195 // perform optimized multiplication 9196 // compute the last column first, because other columns do not depend on it 9197 dest._m30(m00 * rm30 + m10 * rm31 + m30) 9198 ._m31(m01 * rm30 + m11 * rm31 + m31) 9199 ._m32(m02 * rm30 + m12 * rm31 + m32) 9200 ._m33(m03 * rm30 + m13 * rm31 + m33) 9201 ._m00(m00 * rm00) 9202 ._m01(m01 * rm00) 9203 ._m02(m02 * rm00) 9204 ._m03(m03 * rm00) 9205 ._m10(m10 * rm11) 9206 ._m11(m11 * rm11) 9207 ._m12(m12 * rm11) 9208 ._m13(m13 * rm11) 9209 ._m20(-m20) 9210 ._m21(-m21) 9211 ._m22(-m22) 9212 ._m23(-m23) 9213 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 9214 return dest; 9215 } 9216 9217 /** 9218 * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix. 9219 * <p> 9220 * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with 9221 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9222 * <p> 9223 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9224 * then the new matrix will be <code>M * O</code>. So when transforming a 9225 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9226 * orthographic projection transformation will be applied first! 9227 * <p> 9228 * In order to set the matrix to an orthographic projection without post-multiplying it, 9229 * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}. 9230 * <p> 9231 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9232 * 9233 * @see #ortho(double, double, double, double, double, double) 9234 * @see #setOrtho2D(double, double, double, double) 9235 * 9236 * @param left 9237 * the distance from the center to the left frustum edge 9238 * @param right 9239 * the distance from the center to the right frustum edge 9240 * @param bottom 9241 * the distance from the center to the bottom frustum edge 9242 * @param top 9243 * the distance from the center to the top frustum edge 9244 * @return this 9245 */ 9246 ref public Matrix4d ortho2D(double left, double right, double bottom, double top) return { 9247 ortho2D(left, right, bottom, top, this); 9248 return this; 9249 } 9250 9251 /** 9252 * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in <code>dest</code>. 9253 * <p> 9254 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with 9255 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9256 * <p> 9257 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9258 * then the new matrix will be <code>M * O</code>. So when transforming a 9259 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9260 * orthographic projection transformation will be applied first! 9261 * <p> 9262 * In order to set the matrix to an orthographic projection without post-multiplying it, 9263 * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}. 9264 * <p> 9265 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9266 * 9267 * @see #orthoLH(double, double, double, double, double, double, Matrix4d) 9268 * @see #setOrtho2DLH(double, double, double, double) 9269 * 9270 * @param left 9271 * the distance from the center to the left frustum edge 9272 * @param right 9273 * the distance from the center to the right frustum edge 9274 * @param bottom 9275 * the distance from the center to the bottom frustum edge 9276 * @param top 9277 * the distance from the center to the top frustum edge 9278 * @param dest 9279 * will hold the result 9280 * @return dest 9281 */ 9282 public Matrix4d ortho2DLH(double left, double right, double bottom, double top, ref Matrix4d dest) { 9283 if ((properties & PROPERTY_IDENTITY) != 0) 9284 return dest.setOrtho2DLH(left, right, bottom, top); 9285 return ortho2DLHGeneric(left, right, bottom, top, dest); 9286 } 9287 private Matrix4d ortho2DLHGeneric(double left, double right, double bottom, double top, ref Matrix4d dest) { 9288 // calculate right matrix elements 9289 double rm00 = 2.0 / (right - left); 9290 double rm11 = 2.0 / (top - bottom); 9291 double rm30 = (right + left) / (left - right); 9292 double rm31 = (top + bottom) / (bottom - top); 9293 // perform optimized multiplication 9294 // compute the last column first, because other columns do not depend on it 9295 dest._m30(m00 * rm30 + m10 * rm31 + m30) 9296 ._m31(m01 * rm30 + m11 * rm31 + m31) 9297 ._m32(m02 * rm30 + m12 * rm31 + m32) 9298 ._m33(m03 * rm30 + m13 * rm31 + m33) 9299 ._m00(m00 * rm00) 9300 ._m01(m01 * rm00) 9301 ._m02(m02 * rm00) 9302 ._m03(m03 * rm00) 9303 ._m10(m10 * rm11) 9304 ._m11(m11 * rm11) 9305 ._m12(m12 * rm11) 9306 ._m13(m13 * rm11) 9307 ._m20(m20) 9308 ._m21(m21) 9309 ._m22(m22) 9310 ._m23(m23) 9311 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 9312 return dest; 9313 } 9314 9315 /** 9316 * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix. 9317 * <p> 9318 * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with 9319 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9320 * <p> 9321 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix, 9322 * then the new matrix will be <code>M * O</code>. So when transforming a 9323 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 9324 * orthographic projection transformation will be applied first! 9325 * <p> 9326 * In order to set the matrix to an orthographic projection without post-multiplying it, 9327 * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}. 9328 * <p> 9329 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9330 * 9331 * @see #orthoLH(double, double, double, double, double, double) 9332 * @see #setOrtho2DLH(double, double, double, double) 9333 * 9334 * @param left 9335 * the distance from the center to the left frustum edge 9336 * @param right 9337 * the distance from the center to the right frustum edge 9338 * @param bottom 9339 * the distance from the center to the bottom frustum edge 9340 * @param top 9341 * the distance from the center to the top frustum edge 9342 * @return this 9343 */ 9344 ref public Matrix4d ortho2DLH(double left, double right, double bottom, double top) return { 9345 ortho2DLH(left, right, bottom, top, this); 9346 return this; 9347 } 9348 9349 /** 9350 * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system. 9351 * <p> 9352 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with 9353 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9354 * <p> 9355 * In order to apply the orthographic projection to an already existing transformation, 9356 * use {@link #ortho2D(double, double, double, double) ortho2D()}. 9357 * <p> 9358 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9359 * 9360 * @see #setOrtho(double, double, double, double, double, double) 9361 * @see #ortho2D(double, double, double, double) 9362 * 9363 * @param left 9364 * the distance from the center to the left frustum edge 9365 * @param right 9366 * the distance from the center to the right frustum edge 9367 * @param bottom 9368 * the distance from the center to the bottom frustum edge 9369 * @param top 9370 * the distance from the center to the top frustum edge 9371 * @return this 9372 */ 9373 ref public Matrix4d setOrtho2D(double left, double right, double bottom, double top) return { 9374 if ((properties & PROPERTY_IDENTITY) == 0) 9375 _identity(); 9376 _m00(2.0 / (right - left)). 9377 _m11(2.0 / (top - bottom)). 9378 _m22(-1.0). 9379 _m30((right + left) / (left - right)). 9380 _m31((top + bottom) / (bottom - top)). 9381 properties = PROPERTY_AFFINE; 9382 return this; 9383 } 9384 9385 /** 9386 * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system. 9387 * <p> 9388 * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with 9389 * <code>zNear=-1</code> and <code>zFar=+1</code>. 9390 * <p> 9391 * In order to apply the orthographic projection to an already existing transformation, 9392 * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}. 9393 * <p> 9394 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a> 9395 * 9396 * @see #setOrthoLH(double, double, double, double, double, double) 9397 * @see #ortho2DLH(double, double, double, double) 9398 * 9399 * @param left 9400 * the distance from the center to the left frustum edge 9401 * @param right 9402 * the distance from the center to the right frustum edge 9403 * @param bottom 9404 * the distance from the center to the bottom frustum edge 9405 * @param top 9406 * the distance from the center to the top frustum edge 9407 * @return this 9408 */ 9409 ref public Matrix4d setOrtho2DLH(double left, double right, double bottom, double top) return { 9410 if ((properties & PROPERTY_IDENTITY) == 0) 9411 _identity(); 9412 _m00(2.0 / (right - left)). 9413 _m11(2.0 / (top - bottom)). 9414 _m30((right + left) / (left - right)). 9415 _m31((top + bottom) / (bottom - top)). 9416 properties = PROPERTY_AFFINE; 9417 return this; 9418 } 9419 9420 /** 9421 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 9422 * <p> 9423 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9424 * then the new matrix will be <code>M * L</code>. So when transforming a 9425 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9426 * lookalong rotation transformation will be applied first! 9427 * <p> 9428 * This is equivalent to calling 9429 * {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt} 9430 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9431 * <p> 9432 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9433 * use {@link #setLookAlong(ref Vector3d, Vector3d) setLookAlong()}. 9434 * 9435 * @see #lookAlong(double, double, double, double, double, double) 9436 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9437 * @see #setLookAlong(ref Vector3d, Vector3d) 9438 * 9439 * @param dir 9440 * the direction in space to look along 9441 * @param up 9442 * the direction of 'up' 9443 * @return this 9444 */ 9445 ref public Matrix4d lookAlong(ref Vector3d dir, Vector3d up) return { 9446 lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this); 9447 return this; 9448 } 9449 9450 /** 9451 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code> 9452 * and store the result in <code>dest</code>. 9453 * <p> 9454 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9455 * then the new matrix will be <code>M * L</code>. So when transforming a 9456 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9457 * lookalong rotation transformation will be applied first! 9458 * <p> 9459 * This is equivalent to calling 9460 * {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt} 9461 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9462 * <p> 9463 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9464 * use {@link #setLookAlong(ref Vector3d, Vector3d) setLookAlong()}. 9465 * 9466 * @see #lookAlong(double, double, double, double, double, double) 9467 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9468 * @see #setLookAlong(ref Vector3d, Vector3d) 9469 * 9470 * @param dir 9471 * the direction in space to look along 9472 * @param up 9473 * the direction of 'up' 9474 * @param dest 9475 * will hold the result 9476 * @return dest 9477 */ 9478 public Matrix4d lookAlong(ref Vector3d dir, Vector3d up, ref Matrix4d dest) { 9479 return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest); 9480 } 9481 9482 /** 9483 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code> 9484 * and store the result in <code>dest</code>. 9485 * <p> 9486 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9487 * then the new matrix will be <code>M * L</code>. So when transforming a 9488 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9489 * lookalong rotation transformation will be applied first! 9490 * <p> 9491 * This is equivalent to calling 9492 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()} 9493 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9494 * <p> 9495 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9496 * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()} 9497 * 9498 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9499 * @see #setLookAlong(double, double, double, double, double, double) 9500 * 9501 * @param dirX 9502 * the x-coordinate of the direction to look along 9503 * @param dirY 9504 * the y-coordinate of the direction to look along 9505 * @param dirZ 9506 * the z-coordinate of the direction to look along 9507 * @param upX 9508 * the x-coordinate of the up vector 9509 * @param upY 9510 * the y-coordinate of the up vector 9511 * @param upZ 9512 * the z-coordinate of the up vector 9513 * @param dest 9514 * will hold the result 9515 * @return dest 9516 */ 9517 public Matrix4d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 9518 if ((properties & PROPERTY_IDENTITY) != 0) 9519 return dest.setLookAlong(dirX, dirY, dirZ, upX, upY, upZ); 9520 return lookAlongGeneric(dirX, dirY, dirZ, upX, upY, upZ, dest); 9521 } 9522 9523 private Matrix4d lookAlongGeneric(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 9524 // Normalize direction 9525 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9526 dirX *= -invDirLength; 9527 dirY *= -invDirLength; 9528 dirZ *= -invDirLength; 9529 // left = up x direction 9530 double leftX, leftY, leftZ; 9531 leftX = upY * dirZ - upZ * dirY; 9532 leftY = upZ * dirX - upX * dirZ; 9533 leftZ = upX * dirY - upY * dirX; 9534 // normalize left 9535 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9536 leftX *= invLeftLength; 9537 leftY *= invLeftLength; 9538 leftZ *= invLeftLength; 9539 // up = direction x left 9540 double upnX = dirY * leftZ - dirZ * leftY; 9541 double upnY = dirZ * leftX - dirX * leftZ; 9542 double upnZ = dirX * leftY - dirY * leftX; 9543 // calculate right matrix elements 9544 double rm00 = leftX; 9545 double rm01 = upnX; 9546 double rm02 = dirX; 9547 double rm10 = leftY; 9548 double rm11 = upnY; 9549 double rm12 = dirY; 9550 double rm20 = leftZ; 9551 double rm21 = upnZ; 9552 double rm22 = dirZ; 9553 // perform optimized matrix multiplication 9554 // introduce temporaries for dependent results 9555 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 9556 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 9557 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 9558 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 9559 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 9560 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 9561 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 9562 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 9563 dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 9564 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 9565 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 9566 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 9567 // set the rest of the matrix elements 9568 ._m00(nm00) 9569 ._m01(nm01) 9570 ._m02(nm02) 9571 ._m03(nm03) 9572 ._m10(nm10) 9573 ._m11(nm11) 9574 ._m12(nm12) 9575 ._m13(nm13) 9576 ._m30(m30) 9577 ._m31(m31) 9578 ._m32(m32) 9579 ._m33(m33) 9580 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 9581 return dest; 9582 } 9583 9584 /** 9585 * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 9586 * <p> 9587 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix, 9588 * then the new matrix will be <code>M * L</code>. So when transforming a 9589 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the 9590 * lookalong rotation transformation will be applied first! 9591 * <p> 9592 * This is equivalent to calling 9593 * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()} 9594 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9595 * <p> 9596 * In order to set the matrix to a lookalong transformation without post-multiplying it, 9597 * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()} 9598 * 9599 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9600 * @see #setLookAlong(double, double, double, double, double, double) 9601 * 9602 * @param dirX 9603 * the x-coordinate of the direction to look along 9604 * @param dirY 9605 * the y-coordinate of the direction to look along 9606 * @param dirZ 9607 * the z-coordinate of the direction to look along 9608 * @param upX 9609 * the x-coordinate of the up vector 9610 * @param upY 9611 * the y-coordinate of the up vector 9612 * @param upZ 9613 * the z-coordinate of the up vector 9614 * @return this 9615 */ 9616 ref public Matrix4d lookAlong(double dirX, double dirY, double dirZ, 9617 double upX, double upY, double upZ) return { 9618 lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this); 9619 return this; 9620 } 9621 9622 /** 9623 * Set this matrix to a rotation transformation to make <code>-z</code> 9624 * point along <code>dir</code>. 9625 * <p> 9626 * This is equivalent to calling 9627 * {@link #setLookAt(ref Vector3d, Vector3d, Vector3d) setLookAt()} 9628 * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9629 * <p> 9630 * In order to apply the lookalong transformation to any previous existing transformation, 9631 * use {@link #lookAlong(ref Vector3d, Vector3d)}. 9632 * 9633 * @see #setLookAlong(ref Vector3d, Vector3d) 9634 * @see #lookAlong(ref Vector3d, Vector3d) 9635 * 9636 * @param dir 9637 * the direction in space to look along 9638 * @param up 9639 * the direction of 'up' 9640 * @return this 9641 */ 9642 ref public Matrix4d setLookAlong(ref Vector3d dir, Vector3d up) return { 9643 return setLookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z); 9644 } 9645 9646 /** 9647 * Set this matrix to a rotation transformation to make <code>-z</code> 9648 * point along <code>dir</code>. 9649 * <p> 9650 * This is equivalent to calling 9651 * {@link #setLookAt(double, double, double, double, double, double, double, double, double) 9652 * setLookAt()} with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>. 9653 * <p> 9654 * In order to apply the lookalong transformation to any previous existing transformation, 9655 * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()} 9656 * 9657 * @see #setLookAlong(double, double, double, double, double, double) 9658 * @see #lookAlong(double, double, double, double, double, double) 9659 * 9660 * @param dirX 9661 * the x-coordinate of the direction to look along 9662 * @param dirY 9663 * the y-coordinate of the direction to look along 9664 * @param dirZ 9665 * the z-coordinate of the direction to look along 9666 * @param upX 9667 * the x-coordinate of the up vector 9668 * @param upY 9669 * the y-coordinate of the up vector 9670 * @param upZ 9671 * the z-coordinate of the up vector 9672 * @return this 9673 */ 9674 ref public Matrix4d setLookAlong(double dirX, double dirY, double dirZ, 9675 double upX, double upY, double upZ) return { 9676 // Normalize direction 9677 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9678 dirX *= -invDirLength; 9679 dirY *= -invDirLength; 9680 dirZ *= -invDirLength; 9681 // left = up x direction 9682 double leftX, leftY, leftZ; 9683 leftX = upY * dirZ - upZ * dirY; 9684 leftY = upZ * dirX - upX * dirZ; 9685 leftZ = upX * dirY - upY * dirX; 9686 // normalize left 9687 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9688 leftX *= invLeftLength; 9689 leftY *= invLeftLength; 9690 leftZ *= invLeftLength; 9691 // up = direction x left 9692 double upnX = dirY * leftZ - dirZ * leftY; 9693 double upnY = dirZ * leftX - dirX * leftZ; 9694 double upnZ = dirX * leftY - dirY * leftX; 9695 _m00(leftX). 9696 _m01(upnX). 9697 _m02(dirX). 9698 _m03(0.0). 9699 _m10(leftY). 9700 _m11(upnY). 9701 _m12(dirY). 9702 _m13(0.0). 9703 _m20(leftZ). 9704 _m21(upnZ). 9705 _m22(dirZ). 9706 _m23(0.0). 9707 _m30(0.0). 9708 _m31(0.0). 9709 _m32(0.0). 9710 _m33(1.0). 9711 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 9712 return this; 9713 } 9714 9715 /** 9716 * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns 9717 * <code>-z</code> with <code>center - eye</code>. 9718 * <p> 9719 * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives, 9720 * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()} 9721 * instead. 9722 * <p> 9723 * In order to apply the lookat transformation to a previous existing transformation, 9724 * use {@link #lookAt(ref Vector3d, Vector3d, Vector3d) lookAt()}. 9725 * 9726 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 9727 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9728 * 9729 * @param eye 9730 * the position of the camera 9731 * @param center 9732 * the point in space to look at 9733 * @param up 9734 * the direction of 'up' 9735 * @return this 9736 */ 9737 ref public Matrix4d setLookAt(ref Vector3d eye, Vector3d center, Vector3d up) return { 9738 return setLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z); 9739 } 9740 9741 /** 9742 * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, 9743 * that aligns <code>-z</code> with <code>center - eye</code>. 9744 * <p> 9745 * In order to apply the lookat transformation to a previous existing transformation, 9746 * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}. 9747 * 9748 * @see #setLookAt(ref Vector3d, Vector3d, Vector3d) 9749 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9750 * 9751 * @param eyeX 9752 * the x-coordinate of the eye/camera location 9753 * @param eyeY 9754 * the y-coordinate of the eye/camera location 9755 * @param eyeZ 9756 * the z-coordinate of the eye/camera location 9757 * @param centerX 9758 * the x-coordinate of the point to look at 9759 * @param centerY 9760 * the y-coordinate of the point to look at 9761 * @param centerZ 9762 * the z-coordinate of the point to look at 9763 * @param upX 9764 * the x-coordinate of the up vector 9765 * @param upY 9766 * the y-coordinate of the up vector 9767 * @param upZ 9768 * the z-coordinate of the up vector 9769 * @return this 9770 */ 9771 ref public Matrix4d setLookAt(double eyeX, double eyeY, double eyeZ, 9772 double centerX, double centerY, double centerZ, 9773 double upX, double upY, double upZ) return { 9774 // Compute direction from position to lookAt 9775 double dirX, dirY, dirZ; 9776 dirX = eyeX - centerX; 9777 dirY = eyeY - centerY; 9778 dirZ = eyeZ - centerZ; 9779 // Normalize direction 9780 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9781 dirX *= invDirLength; 9782 dirY *= invDirLength; 9783 dirZ *= invDirLength; 9784 // left = up x direction 9785 double leftX, leftY, leftZ; 9786 leftX = upY * dirZ - upZ * dirY; 9787 leftY = upZ * dirX - upX * dirZ; 9788 leftZ = upX * dirY - upY * dirX; 9789 // normalize left 9790 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9791 leftX *= invLeftLength; 9792 leftY *= invLeftLength; 9793 leftZ *= invLeftLength; 9794 // up = direction x left 9795 double upnX = dirY * leftZ - dirZ * leftY; 9796 double upnY = dirZ * leftX - dirX * leftZ; 9797 double upnZ = dirX * leftY - dirY * leftX; 9798 return this. 9799 _m00(leftX). 9800 _m01(upnX). 9801 _m02(dirX). 9802 _m03(0.0). 9803 _m10(leftY). 9804 _m11(upnY). 9805 _m12(dirY). 9806 _m13(0.0). 9807 _m20(leftZ). 9808 _m21(upnZ). 9809 _m22(dirZ). 9810 _m23(0.0). 9811 _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)). 9812 _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)). 9813 _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)). 9814 _m33(1.0). 9815 _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL); 9816 } 9817 9818 /** 9819 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9820 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 9821 * <p> 9822 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9823 * then the new matrix will be <code>M * L</code>. So when transforming a 9824 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9825 * the lookat transformation will be applied first! 9826 * <p> 9827 * In order to set the matrix to a lookat transformation without post-multiplying it, 9828 * use {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)}. 9829 * 9830 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9831 * @see #setLookAlong(ref Vector3d, Vector3d) 9832 * 9833 * @param eye 9834 * the position of the camera 9835 * @param center 9836 * the point in space to look at 9837 * @param up 9838 * the direction of 'up' 9839 * @param dest 9840 * will hold the result 9841 * @return dest 9842 */ 9843 public Matrix4d lookAt(ref Vector3d eye, Vector3d center, Vector3d up, ref Matrix4d dest) { 9844 return lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest); 9845 } 9846 9847 /** 9848 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9849 * that aligns <code>-z</code> with <code>center - eye</code>. 9850 * <p> 9851 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9852 * then the new matrix will be <code>M * L</code>. So when transforming a 9853 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9854 * the lookat transformation will be applied first! 9855 * <p> 9856 * In order to set the matrix to a lookat transformation without post-multiplying it, 9857 * use {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)}. 9858 * 9859 * @see #lookAt(double, double, double, double, double, double, double, double, double) 9860 * @see #setLookAlong(ref Vector3d, Vector3d) 9861 * 9862 * @param eye 9863 * the position of the camera 9864 * @param center 9865 * the point in space to look at 9866 * @param up 9867 * the direction of 'up' 9868 * @return this 9869 */ 9870 ref public Matrix4d lookAt(ref Vector3d eye, Vector3d center, Vector3d up) return { 9871 lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this); 9872 return this; 9873 } 9874 9875 /** 9876 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9877 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 9878 * <p> 9879 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9880 * then the new matrix will be <code>M * L</code>. So when transforming a 9881 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 9882 * the lookat transformation will be applied first! 9883 * <p> 9884 * In order to set the matrix to a lookat transformation without post-multiplying it, 9885 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 9886 * 9887 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 9888 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 9889 * 9890 * @param eyeX 9891 * the x-coordinate of the eye/camera location 9892 * @param eyeY 9893 * the y-coordinate of the eye/camera location 9894 * @param eyeZ 9895 * the z-coordinate of the eye/camera location 9896 * @param centerX 9897 * the x-coordinate of the point to look at 9898 * @param centerY 9899 * the y-coordinate of the point to look at 9900 * @param centerZ 9901 * the z-coordinate of the point to look at 9902 * @param upX 9903 * the x-coordinate of the up vector 9904 * @param upY 9905 * the y-coordinate of the up vector 9906 * @param upZ 9907 * the z-coordinate of the up vector 9908 * @param dest 9909 * will hold the result 9910 * @return dest 9911 */ 9912 public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, 9913 double centerX, double centerY, double centerZ, 9914 double upX, double upY, double upZ, ref Matrix4d dest) { 9915 if ((properties & PROPERTY_IDENTITY) != 0) 9916 return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 9917 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 9918 return lookAtPerspective(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 9919 return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 9920 } 9921 private Matrix4d lookAtGeneric(double eyeX, double eyeY, double eyeZ, 9922 double centerX, double centerY, double centerZ, 9923 double upX, double upY, double upZ, ref Matrix4d dest) { 9924 // Compute direction from position to lookAt 9925 double dirX, dirY, dirZ; 9926 dirX = eyeX - centerX; 9927 dirY = eyeY - centerY; 9928 dirZ = eyeZ - centerZ; 9929 // Normalize direction 9930 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 9931 dirX *= invDirLength; 9932 dirY *= invDirLength; 9933 dirZ *= invDirLength; 9934 // left = up x direction 9935 double leftX, leftY, leftZ; 9936 leftX = upY * dirZ - upZ * dirY; 9937 leftY = upZ * dirX - upX * dirZ; 9938 leftZ = upX * dirY - upY * dirX; 9939 // normalize left 9940 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 9941 leftX *= invLeftLength; 9942 leftY *= invLeftLength; 9943 leftZ *= invLeftLength; 9944 // up = direction x left 9945 double upnX = dirY * leftZ - dirZ * leftY; 9946 double upnY = dirZ * leftX - dirX * leftZ; 9947 double upnZ = dirX * leftY - dirY * leftX; 9948 // calculate right matrix elements 9949 double rm00 = leftX; 9950 double rm01 = upnX; 9951 double rm02 = dirX; 9952 double rm10 = leftY; 9953 double rm11 = upnY; 9954 double rm12 = dirY; 9955 double rm20 = leftZ; 9956 double rm21 = upnZ; 9957 double rm22 = dirZ; 9958 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 9959 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 9960 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 9961 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 9962 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 9963 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 9964 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 9965 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 9966 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 9967 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 9968 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 9969 // perform optimized matrix multiplication 9970 // compute last column first, because others do not depend on it 9971 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 9972 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 9973 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 9974 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 9975 // introduce temporaries for dependent results 9976 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 9977 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 9978 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 9979 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 9980 // set the rest of the matrix elements 9981 ._m00(nm00) 9982 ._m01(nm01) 9983 ._m02(nm02) 9984 ._m03(nm03) 9985 ._m10(nm10) 9986 ._m11(nm11) 9987 ._m12(nm12) 9988 ._m13(nm13) 9989 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 9990 return dest; 9991 } 9992 9993 /** 9994 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 9995 * that aligns <code>-z</code> with <code>center - eye</code>. 9996 * <p> 9997 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 9998 * then the new matrix will be <code>M * L</code>. So when transforming a 9999 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10000 * the lookat transformation will be applied first! 10001 * <p> 10002 * In order to set the matrix to a lookat transformation without post-multiplying it, 10003 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 10004 * 10005 * @see #lookAt(ref Vector3d, Vector3d, Vector3d) 10006 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 10007 * 10008 * @param eyeX 10009 * the x-coordinate of the eye/camera location 10010 * @param eyeY 10011 * the y-coordinate of the eye/camera location 10012 * @param eyeZ 10013 * the z-coordinate of the eye/camera location 10014 * @param centerX 10015 * the x-coordinate of the point to look at 10016 * @param centerY 10017 * the y-coordinate of the point to look at 10018 * @param centerZ 10019 * the z-coordinate of the point to look at 10020 * @param upX 10021 * the x-coordinate of the up vector 10022 * @param upY 10023 * the y-coordinate of the up vector 10024 * @param upZ 10025 * the z-coordinate of the up vector 10026 * @return this 10027 */ 10028 ref public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, 10029 double centerX, double centerY, double centerZ, 10030 double upX, double upY, double upZ) return { 10031 lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this); 10032 return this; 10033 } 10034 10035 /** 10036 * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 10037 * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10038 * <p> 10039 * This method assumes <code>this</code> to be a perspective transformation, obtained via 10040 * {@link #frustum(double, double, double, double, double, double) frustum()} or {@link #perspective(double, double, double, double) perspective()} or 10041 * one of their overloads. 10042 * <p> 10043 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10044 * then the new matrix will be <code>M * L</code>. So when transforming a 10045 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10046 * the lookat transformation will be applied first! 10047 * <p> 10048 * In order to set the matrix to a lookat transformation without post-multiplying it, 10049 * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}. 10050 * 10051 * @see #setLookAt(double, double, double, double, double, double, double, double, double) 10052 * 10053 * @param eyeX 10054 * the x-coordinate of the eye/camera location 10055 * @param eyeY 10056 * the y-coordinate of the eye/camera location 10057 * @param eyeZ 10058 * the z-coordinate of the eye/camera location 10059 * @param centerX 10060 * the x-coordinate of the point to look at 10061 * @param centerY 10062 * the y-coordinate of the point to look at 10063 * @param centerZ 10064 * the z-coordinate of the point to look at 10065 * @param upX 10066 * the x-coordinate of the up vector 10067 * @param upY 10068 * the y-coordinate of the up vector 10069 * @param upZ 10070 * the z-coordinate of the up vector 10071 * @param dest 10072 * will hold the result 10073 * @return dest 10074 */ 10075 public Matrix4d lookAtPerspective(double eyeX, double eyeY, double eyeZ, 10076 double centerX, double centerY, double centerZ, 10077 double upX, double upY, double upZ, ref Matrix4d dest) { 10078 // Compute direction from position to lookAt 10079 double dirX, dirY, dirZ; 10080 dirX = eyeX - centerX; 10081 dirY = eyeY - centerY; 10082 dirZ = eyeZ - centerZ; 10083 // Normalize direction 10084 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10085 dirX *= invDirLength; 10086 dirY *= invDirLength; 10087 dirZ *= invDirLength; 10088 // left = up x direction 10089 double leftX, leftY, leftZ; 10090 leftX = upY * dirZ - upZ * dirY; 10091 leftY = upZ * dirX - upX * dirZ; 10092 leftZ = upX * dirY - upY * dirX; 10093 // normalize left 10094 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10095 leftX *= invLeftLength; 10096 leftY *= invLeftLength; 10097 leftZ *= invLeftLength; 10098 // up = direction x left 10099 double upnX = dirY * leftZ - dirZ * leftY; 10100 double upnY = dirZ * leftX - dirX * leftZ; 10101 double upnZ = dirX * leftY - dirY * leftX; 10102 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10103 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10104 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10105 double nm10 = m00 * leftY; 10106 double nm20 = m00 * leftZ; 10107 double nm21 = m11 * upnZ; 10108 double nm30 = m00 * rm30; 10109 double nm31 = m11 * rm31; 10110 double nm32 = m22 * rm32 + m32; 10111 double nm33 = m23 * rm32; 10112 return dest 10113 ._m00(m00 * leftX) 10114 ._m01(m11 * upnX) 10115 ._m02(m22 * dirX) 10116 ._m03(m23 * dirX) 10117 ._m10(nm10) 10118 ._m11(m11 * upnY) 10119 ._m12(m22 * dirY) 10120 ._m13(m23 * dirY) 10121 ._m20(nm20) 10122 ._m21(nm21) 10123 ._m22(m22 * dirZ) 10124 ._m23(m23 * dirZ) 10125 ._m30(nm30) 10126 ._m31(nm31) 10127 ._m32(nm32) 10128 ._m33(nm33) 10129 ._properties(0); 10130 } 10131 10132 /** 10133 * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns 10134 * <code>+z</code> with <code>center - eye</code>. 10135 * <p> 10136 * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives, 10137 * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()} 10138 * instead. 10139 * <p> 10140 * In order to apply the lookat transformation to a previous existing transformation, 10141 * use {@link #lookAtLH(ref Vector3d, Vector3d, Vector3d) lookAt()}. 10142 * 10143 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10144 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10145 * 10146 * @param eye 10147 * the position of the camera 10148 * @param center 10149 * the point in space to look at 10150 * @param up 10151 * the direction of 'up' 10152 * @return this 10153 */ 10154 ref public Matrix4d setLookAtLH(ref Vector3d eye, Vector3d center, Vector3d up) return { 10155 return setLookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z); 10156 } 10157 10158 /** 10159 * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, 10160 * that aligns <code>+z</code> with <code>center - eye</code>. 10161 * <p> 10162 * In order to apply the lookat transformation to a previous existing transformation, 10163 * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}. 10164 * 10165 * @see #setLookAtLH(ref Vector3d, Vector3d, Vector3d) 10166 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10167 * 10168 * @param eyeX 10169 * the x-coordinate of the eye/camera location 10170 * @param eyeY 10171 * the y-coordinate of the eye/camera location 10172 * @param eyeZ 10173 * the z-coordinate of the eye/camera location 10174 * @param centerX 10175 * the x-coordinate of the point to look at 10176 * @param centerY 10177 * the y-coordinate of the point to look at 10178 * @param centerZ 10179 * the z-coordinate of the point to look at 10180 * @param upX 10181 * the x-coordinate of the up vector 10182 * @param upY 10183 * the y-coordinate of the up vector 10184 * @param upZ 10185 * the z-coordinate of the up vector 10186 * @return this 10187 */ 10188 ref public Matrix4d setLookAtLH(double eyeX, double eyeY, double eyeZ, 10189 double centerX, double centerY, double centerZ, 10190 double upX, double upY, double upZ) return { 10191 // Compute direction from position to lookAt 10192 double dirX, dirY, dirZ; 10193 dirX = centerX - eyeX; 10194 dirY = centerY - eyeY; 10195 dirZ = centerZ - eyeZ; 10196 // Normalize direction 10197 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10198 dirX *= invDirLength; 10199 dirY *= invDirLength; 10200 dirZ *= invDirLength; 10201 // left = up x direction 10202 double leftX, leftY, leftZ; 10203 leftX = upY * dirZ - upZ * dirY; 10204 leftY = upZ * dirX - upX * dirZ; 10205 leftZ = upX * dirY - upY * dirX; 10206 // normalize left 10207 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10208 leftX *= invLeftLength; 10209 leftY *= invLeftLength; 10210 leftZ *= invLeftLength; 10211 // up = direction x left 10212 double upnX = dirY * leftZ - dirZ * leftY; 10213 double upnY = dirZ * leftX - dirX * leftZ; 10214 double upnZ = dirX * leftY - dirY * leftX; 10215 _m00(leftX). 10216 _m01(upnX). 10217 _m02(dirX). 10218 _m03(0.0). 10219 _m10(leftY). 10220 _m11(upnY). 10221 _m12(dirY). 10222 _m13(0.0). 10223 _m20(leftZ). 10224 _m21(upnZ). 10225 _m22(dirZ). 10226 _m23(0.0). 10227 _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)). 10228 _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)). 10229 _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)). 10230 _m33(1.0). 10231 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 10232 return this; 10233 } 10234 10235 /** 10236 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10237 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10238 * <p> 10239 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10240 * then the new matrix will be <code>M * L</code>. So when transforming a 10241 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10242 * the lookat transformation will be applied first! 10243 * <p> 10244 * In order to set the matrix to a lookat transformation without post-multiplying it, 10245 * use {@link #setLookAtLH(ref Vector3d, Vector3d, Vector3d)}. 10246 * 10247 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10248 * @see #setLookAtLH(ref Vector3d, Vector3d, Vector3d) 10249 * 10250 * @param eye 10251 * the position of the camera 10252 * @param center 10253 * the point in space to look at 10254 * @param up 10255 * the direction of 'up' 10256 * @param dest 10257 * will hold the result 10258 * @return dest 10259 */ 10260 public Matrix4d lookAtLH(ref Vector3d eye, Vector3d center, Vector3d up, ref Matrix4d dest) { 10261 return lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest); 10262 } 10263 10264 /** 10265 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10266 * that aligns <code>+z</code> with <code>center - eye</code>. 10267 * <p> 10268 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10269 * then the new matrix will be <code>M * L</code>. So when transforming a 10270 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10271 * the lookat transformation will be applied first! 10272 * <p> 10273 * In order to set the matrix to a lookat transformation without post-multiplying it, 10274 * use {@link #setLookAtLH(ref Vector3d, Vector3d, Vector3d)}. 10275 * 10276 * @see #lookAtLH(double, double, double, double, double, double, double, double, double) 10277 * 10278 * @param eye 10279 * the position of the camera 10280 * @param center 10281 * the point in space to look at 10282 * @param up 10283 * the direction of 'up' 10284 * @return this 10285 */ 10286 ref public Matrix4d lookAtLH(ref Vector3d eye, Vector3d center, Vector3d up) return { 10287 lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this); 10288 return this; 10289 } 10290 10291 /** 10292 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10293 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10294 * <p> 10295 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10296 * then the new matrix will be <code>M * L</code>. So when transforming a 10297 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10298 * the lookat transformation will be applied first! 10299 * <p> 10300 * In order to set the matrix to a lookat transformation without post-multiplying it, 10301 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10302 * 10303 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10304 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10305 * 10306 * @param eyeX 10307 * the x-coordinate of the eye/camera location 10308 * @param eyeY 10309 * the y-coordinate of the eye/camera location 10310 * @param eyeZ 10311 * the z-coordinate of the eye/camera location 10312 * @param centerX 10313 * the x-coordinate of the point to look at 10314 * @param centerY 10315 * the y-coordinate of the point to look at 10316 * @param centerZ 10317 * the z-coordinate of the point to look at 10318 * @param upX 10319 * the x-coordinate of the up vector 10320 * @param upY 10321 * the y-coordinate of the up vector 10322 * @param upZ 10323 * the z-coordinate of the up vector 10324 * @param dest 10325 * will hold the result 10326 * @return dest 10327 */ 10328 public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, 10329 double centerX, double centerY, double centerZ, 10330 double upX, double upY, double upZ, ref Matrix4d dest) { 10331 if ((properties & PROPERTY_IDENTITY) != 0) 10332 return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 10333 else if ((properties & PROPERTY_PERSPECTIVE) != 0) 10334 return lookAtPerspectiveLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 10335 return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest); 10336 } 10337 private Matrix4d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ, 10338 double centerX, double centerY, double centerZ, 10339 double upX, double upY, double upZ, ref Matrix4d dest) { 10340 // Compute direction from position to lookAt 10341 double dirX, dirY, dirZ; 10342 dirX = centerX - eyeX; 10343 dirY = centerY - eyeY; 10344 dirZ = centerZ - eyeZ; 10345 // Normalize direction 10346 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10347 dirX *= invDirLength; 10348 dirY *= invDirLength; 10349 dirZ *= invDirLength; 10350 // left = up x direction 10351 double leftX, leftY, leftZ; 10352 leftX = upY * dirZ - upZ * dirY; 10353 leftY = upZ * dirX - upX * dirZ; 10354 leftZ = upX * dirY - upY * dirX; 10355 // normalize left 10356 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10357 leftX *= invLeftLength; 10358 leftY *= invLeftLength; 10359 leftZ *= invLeftLength; 10360 // up = direction x left 10361 double upnX = dirY * leftZ - dirZ * leftY; 10362 double upnY = dirZ * leftX - dirX * leftZ; 10363 double upnZ = dirX * leftY - dirY * leftX; 10364 // calculate right matrix elements 10365 double rm00 = leftX; 10366 double rm01 = upnX; 10367 double rm02 = dirX; 10368 double rm10 = leftY; 10369 double rm11 = upnY; 10370 double rm12 = dirY; 10371 double rm20 = leftZ; 10372 double rm21 = upnZ; 10373 double rm22 = dirZ; 10374 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10375 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10376 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10377 // introduce temporaries for dependent results 10378 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 10379 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 10380 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 10381 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 10382 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 10383 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 10384 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 10385 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 10386 // perform optimized matrix multiplication 10387 // compute last column first, because others do not depend on it 10388 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30) 10389 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31) 10390 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32) 10391 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33) 10392 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 10393 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 10394 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 10395 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 10396 // set the rest of the matrix elements 10397 ._m00(nm00) 10398 ._m01(nm01) 10399 ._m02(nm02) 10400 ._m03(nm03) 10401 ._m10(nm10) 10402 ._m11(nm11) 10403 ._m12(nm12) 10404 ._m13(nm13) 10405 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 10406 return dest; 10407 } 10408 10409 /** 10410 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10411 * that aligns <code>+z</code> with <code>center - eye</code>. 10412 * <p> 10413 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10414 * then the new matrix will be <code>M * L</code>. So when transforming a 10415 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10416 * the lookat transformation will be applied first! 10417 * <p> 10418 * In order to set the matrix to a lookat transformation without post-multiplying it, 10419 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10420 * 10421 * @see #lookAtLH(ref Vector3d, Vector3d, Vector3d) 10422 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10423 * 10424 * @param eyeX 10425 * the x-coordinate of the eye/camera location 10426 * @param eyeY 10427 * the y-coordinate of the eye/camera location 10428 * @param eyeZ 10429 * the z-coordinate of the eye/camera location 10430 * @param centerX 10431 * the x-coordinate of the point to look at 10432 * @param centerY 10433 * the y-coordinate of the point to look at 10434 * @param centerZ 10435 * the z-coordinate of the point to look at 10436 * @param upX 10437 * the x-coordinate of the up vector 10438 * @param upY 10439 * the y-coordinate of the up vector 10440 * @param upZ 10441 * the z-coordinate of the up vector 10442 * @return this 10443 */ 10444 ref public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, 10445 double centerX, double centerY, double centerZ, 10446 double upX, double upY, double upZ) return { 10447 lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this); 10448 return this; 10449 } 10450 10451 /** 10452 * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 10453 * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>. 10454 * <p> 10455 * This method assumes <code>this</code> to be a perspective transformation, obtained via 10456 * {@link #frustumLH(double, double, double, double, double, double) frustumLH()} or {@link #perspectiveLH(double, double, double, double) perspectiveLH()} or 10457 * one of their overloads. 10458 * <p> 10459 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 10460 * then the new matrix will be <code>M * L</code>. So when transforming a 10461 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 10462 * the lookat transformation will be applied first! 10463 * <p> 10464 * In order to set the matrix to a lookat transformation without post-multiplying it, 10465 * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}. 10466 * 10467 * @see #setLookAtLH(double, double, double, double, double, double, double, double, double) 10468 * 10469 * @param eyeX 10470 * the x-coordinate of the eye/camera location 10471 * @param eyeY 10472 * the y-coordinate of the eye/camera location 10473 * @param eyeZ 10474 * the z-coordinate of the eye/camera location 10475 * @param centerX 10476 * the x-coordinate of the point to look at 10477 * @param centerY 10478 * the y-coordinate of the point to look at 10479 * @param centerZ 10480 * the z-coordinate of the point to look at 10481 * @param upX 10482 * the x-coordinate of the up vector 10483 * @param upY 10484 * the y-coordinate of the up vector 10485 * @param upZ 10486 * the z-coordinate of the up vector 10487 * @param dest 10488 * will hold the result 10489 * @return dest 10490 */ 10491 public Matrix4d lookAtPerspectiveLH(double eyeX, double eyeY, double eyeZ, 10492 double centerX, double centerY, double centerZ, 10493 double upX, double upY, double upZ, ref Matrix4d dest) { 10494 // Compute direction from position to lookAt 10495 double dirX, dirY, dirZ; 10496 dirX = centerX - eyeX; 10497 dirY = centerY - eyeY; 10498 dirZ = centerZ - eyeZ; 10499 // Normalize direction 10500 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 10501 dirX *= invDirLength; 10502 dirY *= invDirLength; 10503 dirZ *= invDirLength; 10504 // left = up x direction 10505 double leftX, leftY, leftZ; 10506 leftX = upY * dirZ - upZ * dirY; 10507 leftY = upZ * dirX - upX * dirZ; 10508 leftZ = upX * dirY - upY * dirX; 10509 // normalize left 10510 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 10511 leftX *= invLeftLength; 10512 leftY *= invLeftLength; 10513 leftZ *= invLeftLength; 10514 // up = direction x left 10515 double upnX = dirY * leftZ - dirZ * leftY; 10516 double upnY = dirZ * leftX - dirX * leftZ; 10517 double upnZ = dirX * leftY - dirY * leftX; 10518 10519 // calculate right matrix elements 10520 double rm00 = leftX; 10521 double rm01 = upnX; 10522 double rm02 = dirX; 10523 double rm10 = leftY; 10524 double rm11 = upnY; 10525 double rm12 = dirY; 10526 double rm20 = leftZ; 10527 double rm21 = upnZ; 10528 double rm22 = dirZ; 10529 double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ); 10530 double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ); 10531 double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ); 10532 10533 double nm00 = m00 * rm00; 10534 double nm01 = m11 * rm01; 10535 double nm02 = m22 * rm02; 10536 double nm03 = m23 * rm02; 10537 double nm10 = m00 * rm10; 10538 double nm11 = m11 * rm11; 10539 double nm12 = m22 * rm12; 10540 double nm13 = m23 * rm12; 10541 double nm20 = m00 * rm20; 10542 double nm21 = m11 * rm21; 10543 double nm22 = m22 * rm22; 10544 double nm23 = m23 * rm22; 10545 double nm30 = m00 * rm30; 10546 double nm31 = m11 * rm31; 10547 double nm32 = m22 * rm32 + m32; 10548 double nm33 = m23 * rm32; 10549 dest._m00(nm00) 10550 ._m01(nm01) 10551 ._m02(nm02) 10552 ._m03(nm03) 10553 ._m10(nm10) 10554 ._m11(nm11) 10555 ._m12(nm12) 10556 ._m13(nm13) 10557 ._m20(nm20) 10558 ._m21(nm21) 10559 ._m22(nm22) 10560 ._m23(nm23) 10561 ._m30(nm30) 10562 ._m31(nm31) 10563 ._m32(nm32) 10564 ._m33(nm33) 10565 ._properties(0); 10566 10567 return dest; 10568 } 10569 10570 /** 10571 * This method is equivalent to calling: <code>translate(w-1-2*x, h-1-2*y, 0).scale(w, h, 1)</code> 10572 * <p> 10573 * If <code>M</code> is <code>this</code> matrix and <code>T</code> the created transformation matrix, 10574 * then the new matrix will be <code>M * T</code>. So when transforming a 10575 * vector <code>v</code> with the new matrix by using <code>M * T * v</code>, the 10576 * created transformation will be applied first! 10577 * 10578 * @param x 10579 * the tile's x coordinate/index (should be in <code>[0..w)</code>) 10580 * @param y 10581 * the tile's y coordinate/index (should be in <code>[0..h)</code>) 10582 * @param w 10583 * the number of tiles along the x axis 10584 * @param h 10585 * the number of tiles along the y axis 10586 * @return this 10587 */ 10588 ref public Matrix4d tile(int x, int y, int w, int h) return { 10589 tile(x, y, w, h, this); 10590 return this; 10591 } 10592 public Matrix4d tile(int x, int y, int w, int h, ref Matrix4d dest) { 10593 double tx = w - 1 - (x<<1), ty = h - 1 - (y<<1); 10594 return dest 10595 ._m30(Math.fma(m00, tx, Math.fma(m10, ty, m30))) 10596 ._m31(Math.fma(m01, tx, Math.fma(m11, ty, m31))) 10597 ._m32(Math.fma(m02, tx, Math.fma(m12, ty, m32))) 10598 ._m33(Math.fma(m03, tx, Math.fma(m13, ty, m33))) 10599 ._m00(m00 * w) 10600 ._m01(m01 * w) 10601 ._m02(m02 * w) 10602 ._m03(m03 * w) 10603 ._m10(m10 * h) 10604 ._m11(m11 * h) 10605 ._m12(m12 * h) 10606 ._m13(m13 * h) 10607 ._m20(m20) 10608 ._m21(m21) 10609 ._m22(m22) 10610 ._m23(m23) 10611 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10612 } 10613 10614 /** 10615 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10616 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10617 * <p> 10618 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10619 * then the new matrix will be <code>M * P</code>. So when transforming a 10620 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10621 * the perspective projection will be applied first! 10622 * <p> 10623 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10624 * use {@link #setPerspective(double, double, double, double, bool) setPerspective}. 10625 * 10626 * @see #setPerspective(double, double, double, double, bool) 10627 * 10628 * @param fovy 10629 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10630 * @param aspect 10631 * the aspect ratio (i.e. width / height; must be greater than zero) 10632 * @param zNear 10633 * near clipping plane distance. This value must be greater than zero. 10634 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10635 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10636 * @param zFar 10637 * far clipping plane distance. This value must be greater than zero. 10638 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10639 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10640 * @param dest 10641 * will hold the result 10642 * @param zZeroToOne 10643 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10644 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10645 * @return dest 10646 */ 10647 public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10648 if ((properties & PROPERTY_IDENTITY) != 0) 10649 return dest.setPerspective(fovy, aspect, zNear, zFar, zZeroToOne); 10650 return perspectiveGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest); 10651 } 10652 private Matrix4d perspectiveGeneric(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10653 double h = Math.tan(fovy * 0.5); 10654 // calculate right matrix elements 10655 double rm00 = 1.0 / (h * aspect); 10656 double rm11 = 1.0 / h; 10657 double rm22; 10658 double rm32; 10659 bool farInf = zFar > 0 && Math.isInfinite(zFar); 10660 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 10661 if (farInf) { 10662 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 10663 double e = 1E-6; 10664 rm22 = e - 1.0; 10665 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 10666 } else if (nearInf) { 10667 double e = 1E-6; 10668 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 10669 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 10670 } else { 10671 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 10672 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 10673 } 10674 // perform optimized matrix multiplication 10675 double nm20 = m20 * rm22 - m30; 10676 double nm21 = m21 * rm22 - m31; 10677 double nm22 = m22 * rm22 - m32; 10678 double nm23 = m23 * rm22 - m33; 10679 dest._m00(m00 * rm00) 10680 ._m01(m01 * rm00) 10681 ._m02(m02 * rm00) 10682 ._m03(m03 * rm00) 10683 ._m10(m10 * rm11) 10684 ._m11(m11 * rm11) 10685 ._m12(m12 * rm11) 10686 ._m13(m13 * rm11) 10687 ._m30(m20 * rm32) 10688 ._m31(m21 * rm32) 10689 ._m32(m22 * rm32) 10690 ._m33(m23 * rm32) 10691 ._m20(nm20) 10692 ._m21(nm21) 10693 ._m22(nm22) 10694 ._m23(nm23) 10695 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10696 return dest; 10697 } 10698 10699 /** 10700 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10701 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 10702 * <p> 10703 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10704 * then the new matrix will be <code>M * P</code>. So when transforming a 10705 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10706 * the perspective projection will be applied first! 10707 * <p> 10708 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10709 * use {@link #setPerspective(double, double, double, double) setPerspective}. 10710 * 10711 * @see #setPerspective(double, double, double, double) 10712 * 10713 * @param fovy 10714 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10715 * @param aspect 10716 * the aspect ratio (i.e. width / height; must be greater than zero) 10717 * @param zNear 10718 * near clipping plane distance. This value must be greater than zero. 10719 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10720 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10721 * @param zFar 10722 * far clipping plane distance. This value must be greater than zero. 10723 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10724 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10725 * @param dest 10726 * will hold the result 10727 * @return dest 10728 */ 10729 public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, ref Matrix4d dest) { 10730 return perspective(fovy, aspect, zNear, zFar, false, dest); 10731 } 10732 10733 /** 10734 * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system 10735 * using the given NDC z range to this matrix. 10736 * <p> 10737 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10738 * then the new matrix will be <code>M * P</code>. So when transforming a 10739 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10740 * the perspective projection will be applied first! 10741 * <p> 10742 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10743 * use {@link #setPerspective(double, double, double, double, bool) setPerspective}. 10744 * 10745 * @see #setPerspective(double, double, double, double, bool) 10746 * 10747 * @param fovy 10748 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10749 * @param aspect 10750 * the aspect ratio (i.e. width / height; must be greater than zero) 10751 * @param zNear 10752 * near clipping plane distance. This value must be greater than zero. 10753 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10754 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10755 * @param zFar 10756 * far clipping plane distance. This value must be greater than zero. 10757 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10758 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10759 * @param zZeroToOne 10760 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10761 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10762 * @return this 10763 */ 10764 ref public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 10765 perspective(fovy, aspect, zNear, zFar, zZeroToOne, this); 10766 return this; 10767 } 10768 10769 /** 10770 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10771 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 10772 * <p> 10773 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10774 * then the new matrix will be <code>M * P</code>. So when transforming a 10775 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10776 * the perspective projection will be applied first! 10777 * <p> 10778 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10779 * use {@link #setPerspective(double, double, double, double) setPerspective}. 10780 * 10781 * @see #setPerspective(double, double, double, double) 10782 * 10783 * @param fovy 10784 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 10785 * @param aspect 10786 * the aspect ratio (i.e. width / height; must be greater than zero) 10787 * @param zNear 10788 * near clipping plane distance. This value must be greater than zero. 10789 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10790 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10791 * @param zFar 10792 * far clipping plane distance. This value must be greater than zero. 10793 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10794 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10795 * @return this 10796 */ 10797 ref public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar) return { 10798 perspective(fovy, aspect, zNear, zFar, this); 10799 return this; 10800 } 10801 10802 /** 10803 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10804 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10805 * <p> 10806 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10807 * then the new matrix will be <code>M * P</code>. So when transforming a 10808 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10809 * the perspective projection will be applied first! 10810 * <p> 10811 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10812 * use {@link #setPerspectiveRect(double, double, double, double, bool) setPerspectiveRect}. 10813 * 10814 * @see #setPerspectiveRect(double, double, double, double, bool) 10815 * 10816 * @param width 10817 * the width of the near frustum plane 10818 * @param height 10819 * the height of the near frustum plane 10820 * @param zNear 10821 * near clipping plane distance. This value must be greater than zero. 10822 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10823 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10824 * @param zFar 10825 * far clipping plane distance. This value must be greater than zero. 10826 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10827 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10828 * @param dest 10829 * will hold the result 10830 * @param zZeroToOne 10831 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10832 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10833 * @return dest 10834 */ 10835 public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10836 if ((properties & PROPERTY_IDENTITY) != 0) 10837 return dest.setPerspectiveRect(width, height, zNear, zFar, zZeroToOne); 10838 return perspectiveRectGeneric(width, height, zNear, zFar, zZeroToOne, dest); 10839 } 10840 private Matrix4d perspectiveRectGeneric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 10841 double rm00 = (zNear + zNear) / width; 10842 double rm11 = (zNear + zNear) / height; 10843 double rm22, rm32; 10844 bool farInf = zFar > 0 && Math.isInfinite(zFar); 10845 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 10846 if (farInf) { 10847 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 10848 double e = 1E-6f; 10849 rm22 = e - 1.0; 10850 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 10851 } else if (nearInf) { 10852 double e = 1E-6f; 10853 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 10854 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 10855 } else { 10856 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 10857 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 10858 } 10859 // perform optimized matrix multiplication 10860 double nm20 = m20 * rm22 - m30; 10861 double nm21 = m21 * rm22 - m31; 10862 double nm22 = m22 * rm22 - m32; 10863 double nm23 = m23 * rm22 - m33; 10864 dest._m00(m00 * rm00) 10865 ._m01(m01 * rm00) 10866 ._m02(m02 * rm00) 10867 ._m03(m03 * rm00) 10868 ._m10(m10 * rm11) 10869 ._m11(m11 * rm11) 10870 ._m12(m12 * rm11) 10871 ._m13(m13 * rm11) 10872 ._m30(m20 * rm32) 10873 ._m31(m21 * rm32) 10874 ._m32(m22 * rm32) 10875 ._m33(m23 * rm32) 10876 ._m20(nm20) 10877 ._m21(nm21) 10878 ._m22(nm22) 10879 ._m23(nm23) 10880 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 10881 return dest; 10882 } 10883 10884 /** 10885 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10886 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 10887 * <p> 10888 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10889 * then the new matrix will be <code>M * P</code>. So when transforming a 10890 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10891 * the perspective projection will be applied first! 10892 * <p> 10893 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10894 * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}. 10895 * 10896 * @see #setPerspectiveRect(double, double, double, double) 10897 * 10898 * @param width 10899 * the width of the near frustum plane 10900 * @param height 10901 * the height of the near frustum plane 10902 * @param zNear 10903 * near clipping plane distance. This value must be greater than zero. 10904 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10905 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10906 * @param zFar 10907 * far clipping plane distance. This value must be greater than zero. 10908 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10909 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10910 * @param dest 10911 * will hold the result 10912 * @return dest 10913 */ 10914 public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, ref Matrix4d dest) { 10915 return perspectiveRect(width, height, zNear, zFar, false, dest); 10916 } 10917 10918 /** 10919 * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system 10920 * using the given NDC z range to this matrix. 10921 * <p> 10922 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10923 * then the new matrix will be <code>M * P</code>. So when transforming a 10924 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10925 * the perspective projection will be applied first! 10926 * <p> 10927 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10928 * use {@link #setPerspectiveRect(double, double, double, double, bool) setPerspectiveRect}. 10929 * 10930 * @see #setPerspectiveRect(double, double, double, double, bool) 10931 * 10932 * @param width 10933 * the width of the near frustum plane 10934 * @param height 10935 * the height of the near frustum plane 10936 * @param zNear 10937 * near clipping plane distance. This value must be greater than zero. 10938 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10939 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10940 * @param zFar 10941 * far clipping plane distance. This value must be greater than zero. 10942 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10943 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10944 * @param zZeroToOne 10945 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 10946 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 10947 * @return this 10948 */ 10949 ref public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 10950 perspectiveRect(width, height, zNear, zFar, zZeroToOne, this); 10951 return this; 10952 } 10953 10954 /** 10955 * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system 10956 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 10957 * <p> 10958 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10959 * then the new matrix will be <code>M * P</code>. So when transforming a 10960 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10961 * the perspective projection will be applied first! 10962 * <p> 10963 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 10964 * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}. 10965 * 10966 * @see #setPerspectiveRect(double, double, double, double) 10967 * 10968 * @param width 10969 * the width of the near frustum plane 10970 * @param height 10971 * the height of the near frustum plane 10972 * @param zNear 10973 * near clipping plane distance. This value must be greater than zero. 10974 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 10975 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 10976 * @param zFar 10977 * far clipping plane distance. This value must be greater than zero. 10978 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 10979 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 10980 * @return this 10981 */ 10982 ref public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar) return { 10983 perspectiveRect(width, height, zNear, zFar, this); 10984 return this; 10985 } 10986 10987 /** 10988 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 10989 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 10990 * <p> 10991 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 10992 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 10993 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 10994 * is parallel to the XZ-plane. 10995 * <p> 10996 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 10997 * then the new matrix will be <code>M * P</code>. So when transforming a 10998 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 10999 * the perspective projection will be applied first! 11000 * <p> 11001 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11002 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, bool) setPerspectiveOffCenter}. 11003 * 11004 * @see #setPerspectiveOffCenter(double, double, double, double, double, double, bool) 11005 * 11006 * @param fovy 11007 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11008 * @param offAngleX 11009 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11010 * @param offAngleY 11011 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11012 * @param aspect 11013 * the aspect ratio (i.e. width / height; must be greater than zero) 11014 * @param zNear 11015 * near clipping plane distance. This value must be greater than zero. 11016 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11017 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11018 * @param zFar 11019 * far clipping plane distance. This value must be greater than zero. 11020 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11021 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11022 * @param dest 11023 * will hold the result 11024 * @param zZeroToOne 11025 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11026 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11027 * @return dest 11028 */ 11029 public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11030 if ((properties & PROPERTY_IDENTITY) != 0) 11031 return dest.setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne); 11032 return perspectiveOffCenterGeneric(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, dest); 11033 } 11034 private Matrix4d perspectiveOffCenterGeneric(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11035 double h = Math.tan(fovy * 0.5); 11036 // calculate right matrix elements 11037 double xScale = 1.0 / (h * aspect); 11038 double yScale = 1.0 / h; 11039 double rm00 = xScale; 11040 double rm11 = yScale; 11041 double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY); 11042 double rm20 = offX * xScale; 11043 double rm21 = offY * yScale; 11044 double rm22; 11045 double rm32; 11046 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11047 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11048 if (farInf) { 11049 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11050 double e = 1E-6; 11051 rm22 = e - 1.0; 11052 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 11053 } else if (nearInf) { 11054 double e = 1E-6; 11055 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 11056 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 11057 } else { 11058 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 11059 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 11060 } 11061 // perform optimized matrix multiplication 11062 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30; 11063 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31; 11064 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32; 11065 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33; 11066 dest._m00(m00 * rm00) 11067 ._m01(m01 * rm00) 11068 ._m02(m02 * rm00) 11069 ._m03(m03 * rm00) 11070 ._m10(m10 * rm11) 11071 ._m11(m11 * rm11) 11072 ._m12(m12 * rm11) 11073 ._m13(m13 * rm11) 11074 ._m30(m20 * rm32) 11075 ._m31(m21 * rm32) 11076 ._m32(m22 * rm32) 11077 ._m33(m23 * rm32) 11078 ._m20(nm20) 11079 ._m21(nm21) 11080 ._m22(nm22) 11081 ._m23(nm23) 11082 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION 11083 | PROPERTY_ORTHONORMAL | (rm20 == 0.0 && rm21 == 0.0 ? 0 : PROPERTY_PERSPECTIVE))); 11084 return dest; 11085 } 11086 11087 /** 11088 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11089 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 11090 * <p> 11091 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11092 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11093 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11094 * is parallel to the XZ-plane. 11095 * <p> 11096 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11097 * then the new matrix will be <code>M * P</code>. So when transforming a 11098 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11099 * the perspective projection will be applied first! 11100 * <p> 11101 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11102 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}. 11103 * 11104 * @see #setPerspectiveOffCenter(double, double, double, double, double, double) 11105 * 11106 * @param fovy 11107 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11108 * @param offAngleX 11109 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11110 * @param offAngleY 11111 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11112 * @param aspect 11113 * the aspect ratio (i.e. width / height; must be greater than zero) 11114 * @param zNear 11115 * near clipping plane distance. This value must be greater than zero. 11116 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11117 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11118 * @param zFar 11119 * far clipping plane distance. This value must be greater than zero. 11120 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11121 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11122 * @param dest 11123 * will hold the result 11124 * @return dest 11125 */ 11126 public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, ref Matrix4d dest) { 11127 return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false, dest); 11128 } 11129 11130 /** 11131 * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system 11132 * using the given NDC z range to this matrix. 11133 * <p> 11134 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11135 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11136 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11137 * is parallel to the XZ-plane. 11138 * <p> 11139 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11140 * then the new matrix will be <code>M * P</code>. So when transforming a 11141 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11142 * the perspective projection will be applied first! 11143 * <p> 11144 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11145 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, bool) setPerspectiveOffCenter}. 11146 * 11147 * @see #setPerspectiveOffCenter(double, double, double, double, double, double, bool) 11148 * 11149 * @param fovy 11150 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11151 * @param offAngleX 11152 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11153 * @param offAngleY 11154 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11155 * @param aspect 11156 * the aspect ratio (i.e. width / height; must be greater than zero) 11157 * @param zNear 11158 * near clipping plane distance. This value must be greater than zero. 11159 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11160 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11161 * @param zFar 11162 * far clipping plane distance. This value must be greater than zero. 11163 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11164 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11165 * @param zZeroToOne 11166 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11167 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11168 * @return this 11169 */ 11170 ref public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11171 perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, this); 11172 return this; 11173 } 11174 11175 /** 11176 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11177 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11178 * <p> 11179 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11180 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11181 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11182 * is parallel to the XZ-plane. 11183 * <p> 11184 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11185 * then the new matrix will be <code>M * P</code>. So when transforming a 11186 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11187 * the perspective projection will be applied first! 11188 * <p> 11189 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11190 * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}. 11191 * 11192 * @see #setPerspectiveOffCenter(double, double, double, double, double, double) 11193 * 11194 * @param fovy 11195 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11196 * @param offAngleX 11197 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11198 * @param offAngleY 11199 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11200 * @param aspect 11201 * the aspect ratio (i.e. width / height; must be greater than zero) 11202 * @param zNear 11203 * near clipping plane distance. This value must be greater than zero. 11204 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11205 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11206 * @param zFar 11207 * far clipping plane distance. This value must be greater than zero. 11208 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11209 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11210 * @return this 11211 */ 11212 ref public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar) return { 11213 perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, this); 11214 return this; 11215 } 11216 11217 /** 11218 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11219 * using the given NDC z range to this matrix. 11220 * <p> 11221 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11222 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11223 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11224 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11225 * <p> 11226 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11227 * then the new matrix will be <code>M * P</code>. So when transforming a 11228 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11229 * the perspective projection will be applied first! 11230 * <p> 11231 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11232 * use {@link #setPerspectiveOffCenterFov(double, double, double, double, double, double, bool) setPerspectiveOffCenterFov}. 11233 * 11234 * @see #setPerspectiveOffCenterFov(double, double, double, double, double, double, bool) 11235 * 11236 * @param angleLeft 11237 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11238 * For a symmetric frustum, this value is negative. 11239 * @param angleRight 11240 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11241 * @param angleDown 11242 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11243 * For a symmetric frustum, this value is negative. 11244 * @param angleUp 11245 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11246 * @param zNear 11247 * near clipping plane distance. This value must be greater than zero. 11248 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11249 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11250 * @param zFar 11251 * far clipping plane distance. This value must be greater than zero. 11252 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11253 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11254 * @param zZeroToOne 11255 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11256 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11257 * @return this 11258 */ 11259 ref public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11260 perspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, zZeroToOne, this); 11261 return this; 11262 } 11263 public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11264 return frustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne, dest); 11265 } 11266 11267 /** 11268 * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11269 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11270 * <p> 11271 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11272 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11273 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11274 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11275 * <p> 11276 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11277 * then the new matrix will be <code>M * P</code>. So when transforming a 11278 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11279 * the perspective projection will be applied first! 11280 * <p> 11281 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11282 * use {@link #setPerspectiveOffCenterFov(double, double, double, double, double, double) setPerspectiveOffCenterFov}. 11283 * 11284 * @see #setPerspectiveOffCenterFov(double, double, double, double, double, double) 11285 * 11286 * @param angleLeft 11287 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11288 * For a symmetric frustum, this value is negative. 11289 * @param angleRight 11290 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11291 * @param angleDown 11292 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11293 * For a symmetric frustum, this value is negative. 11294 * @param angleUp 11295 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11296 * @param zNear 11297 * near clipping plane distance. This value must be greater than zero. 11298 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11299 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11300 * @param zFar 11301 * far clipping plane distance. This value must be greater than zero. 11302 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11303 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11304 * @return this 11305 */ 11306 ref public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11307 perspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, this); 11308 return this; 11309 } 11310 public Matrix4d perspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, ref Matrix4d dest) { 11311 return frustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, dest); 11312 } 11313 11314 /** 11315 * Apply an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11316 * using the given NDC z range to this matrix. 11317 * <p> 11318 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11319 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11320 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11321 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11322 * <p> 11323 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11324 * then the new matrix will be <code>M * P</code>. So when transforming a 11325 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11326 * the perspective projection will be applied first! 11327 * <p> 11328 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11329 * use {@link #setPerspectiveOffCenterFovLH(double, double, double, double, double, double, bool) setPerspectiveOffCenterFovLH}. 11330 * 11331 * @see #setPerspectiveOffCenterFovLH(double, double, double, double, double, double, bool) 11332 * 11333 * @param angleLeft 11334 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11335 * For a symmetric frustum, this value is negative. 11336 * @param angleRight 11337 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11338 * @param angleDown 11339 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11340 * For a symmetric frustum, this value is negative. 11341 * @param angleUp 11342 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11343 * @param zNear 11344 * near clipping plane distance. This value must be greater than zero. 11345 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11346 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11347 * @param zFar 11348 * far clipping plane distance. This value must be greater than zero. 11349 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11350 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11351 * @param zZeroToOne 11352 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11353 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11354 * @return this 11355 */ 11356 ref public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11357 perspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, zZeroToOne, this); 11358 return this; 11359 } 11360 public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11361 return frustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne, dest); 11362 } 11363 11364 /** 11365 * Apply an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11366 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11367 * <p> 11368 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11369 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11370 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11371 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11372 * <p> 11373 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11374 * then the new matrix will be <code>M * P</code>. So when transforming a 11375 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11376 * the perspective projection will be applied first! 11377 * <p> 11378 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11379 * use {@link #setPerspectiveOffCenterFovLH(double, double, double, double, double, double) setPerspectiveOffCenterFovLH}. 11380 * 11381 * @see #setPerspectiveOffCenterFovLH(double, double, double, double, double, double) 11382 * 11383 * @param angleLeft 11384 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11385 * For a symmetric frustum, this value is negative. 11386 * @param angleRight 11387 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11388 * @param angleDown 11389 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11390 * For a symmetric frustum, this value is negative. 11391 * @param angleUp 11392 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11393 * @param zNear 11394 * near clipping plane distance. This value must be greater than zero. 11395 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11396 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11397 * @param zFar 11398 * far clipping plane distance. This value must be greater than zero. 11399 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11400 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11401 * @return this 11402 */ 11403 ref public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11404 perspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, this); 11405 return this; 11406 } 11407 public Matrix4d perspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, ref Matrix4d dest) { 11408 return frustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, dest); 11409 } 11410 11411 /** 11412 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11413 * using the given NDC z range. 11414 * <p> 11415 * In order to apply the perspective projection transformation to an existing transformation, 11416 * use {@link #perspective(double, double, double, double, bool) perspective()}. 11417 * 11418 * @see #perspective(double, double, double, double, bool) 11419 * 11420 * @param fovy 11421 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11422 * @param aspect 11423 * the aspect ratio (i.e. width / height; must be greater than zero) 11424 * @param zNear 11425 * near clipping plane distance. This value must be greater than zero. 11426 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11427 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11428 * @param zFar 11429 * far clipping plane distance. This value must be greater than zero. 11430 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11431 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11432 * @param zZeroToOne 11433 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11434 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11435 * @return this 11436 */ 11437 ref public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11438 double h = Math.tan(fovy * 0.5); 11439 _m00(1.0 / (h * aspect)). 11440 _m01(0.0). 11441 _m02(0.0). 11442 _m03(0.0). 11443 _m10(0.0). 11444 _m11(1.0 / h). 11445 _m12(0.0). 11446 _m13(0.0). 11447 _m20(0.0). 11448 _m21(0.0); 11449 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11450 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11451 if (farInf) { 11452 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11453 double e = 1E-6; 11454 _m22(e - 1.0). 11455 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11456 } else if (nearInf) { 11457 double e = 1E-6; 11458 _m22((zZeroToOne ? 0.0 : 1.0) - e). 11459 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11460 } else { 11461 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 11462 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11463 } 11464 _m23(-1.0). 11465 _m30(0.0). 11466 _m31(0.0). 11467 _m33(0.0). 11468 properties = PROPERTY_PERSPECTIVE; 11469 return this; 11470 } 11471 11472 /** 11473 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11474 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 11475 * <p> 11476 * In order to apply the perspective projection transformation to an existing transformation, 11477 * use {@link #perspective(double, double, double, double) perspective()}. 11478 * 11479 * @see #perspective(double, double, double, double) 11480 * 11481 * @param fovy 11482 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11483 * @param aspect 11484 * the aspect ratio (i.e. width / height; must be greater than zero) 11485 * @param zNear 11486 * near clipping plane distance. This value must be greater than zero. 11487 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11488 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11489 * @param zFar 11490 * far clipping plane distance. This value must be greater than zero. 11491 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11492 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11493 * @return this 11494 */ 11495 ref public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar) return { 11496 return setPerspective(fovy, aspect, zNear, zFar, false); 11497 } 11498 11499 /** 11500 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11501 * using the given NDC z range. 11502 * <p> 11503 * In order to apply the perspective projection transformation to an existing transformation, 11504 * use {@link #perspectiveRect(double, double, double, double, bool) perspectiveRect()}. 11505 * 11506 * @see #perspectiveRect(double, double, double, double, bool) 11507 * 11508 * @param width 11509 * the width of the near frustum plane 11510 * @param height 11511 * the height of the near frustum plane 11512 * @param zNear 11513 * near clipping plane distance. This value must be greater than zero. 11514 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11515 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11516 * @param zFar 11517 * far clipping plane distance. This value must be greater than zero. 11518 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11519 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11520 * @param zZeroToOne 11521 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11522 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11523 * @return this 11524 */ 11525 ref public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar, bool zZeroToOne) return { 11526 this.zero(); 11527 this._m00((zNear + zNear) / width); 11528 this._m11((zNear + zNear) / height); 11529 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11530 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11531 if (farInf) { 11532 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11533 double e = 1E-6; 11534 this._m22(e - 1.0); 11535 this._m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11536 } else if (nearInf) { 11537 double e = 1E-6f; 11538 this._m22((zZeroToOne ? 0.0 : 1.0) - e); 11539 this._m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11540 } else { 11541 this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)); 11542 this._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11543 } 11544 this._m23(-1.0); 11545 properties = PROPERTY_PERSPECTIVE; 11546 return this; 11547 } 11548 11549 /** 11550 * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system 11551 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 11552 * <p> 11553 * In order to apply the perspective projection transformation to an existing transformation, 11554 * use {@link #perspectiveRect(double, double, double, double) perspectiveRect()}. 11555 * 11556 * @see #perspectiveRect(double, double, double, double) 11557 * 11558 * @param width 11559 * the width of the near frustum plane 11560 * @param height 11561 * the height of the near frustum plane 11562 * @param zNear 11563 * near clipping plane distance. This value must be greater than zero. 11564 * If the special value {@link double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11565 * In that case, <code>zFar</code> may not also be {@link double#POSITIVE_INFINITY}. 11566 * @param zFar 11567 * far clipping plane distance. This value must be greater than zero. 11568 * If the special value {@link double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11569 * In that case, <code>zNear</code> may not also be {@link double#POSITIVE_INFINITY}. 11570 * @return this 11571 */ 11572 ref public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar) return { 11573 return setPerspectiveRect(width, height, zNear, zFar, false); 11574 } 11575 11576 /** 11577 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed 11578 * coordinate system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11579 * <p> 11580 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11581 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11582 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11583 * is parallel to the XZ-plane. 11584 * <p> 11585 * In order to apply the perspective projection transformation to an existing transformation, 11586 * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}. 11587 * 11588 * @see #perspectiveOffCenter(double, double, double, double, double, double) 11589 * 11590 * @param fovy 11591 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11592 * @param offAngleX 11593 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11594 * @param offAngleY 11595 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11596 * @param aspect 11597 * the aspect ratio (i.e. width / height; must be greater than zero) 11598 * @param zNear 11599 * near clipping plane distance. This value must be greater than zero. 11600 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11601 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11602 * @param zFar 11603 * far clipping plane distance. This value must be greater than zero. 11604 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11605 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11606 * @return this 11607 */ 11608 ref public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY, 11609 double aspect, double zNear, double zFar) return { 11610 return setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false); 11611 } 11612 /** 11613 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed 11614 * coordinate system using the given NDC z range. 11615 * <p> 11616 * The given angles <code>offAngleX</code> and <code>offAngleY</code> are the horizontal and vertical angles between 11617 * the line of sight and the line given by the center of the near and far frustum planes. So, when <code>offAngleY</code> 11618 * is just <code>fovy/2</code> then the projection frustum is rotated towards +Y and the bottom frustum plane 11619 * is parallel to the XZ-plane. 11620 * <p> 11621 * In order to apply the perspective projection transformation to an existing transformation, 11622 * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}. 11623 * 11624 * @see #perspectiveOffCenter(double, double, double, double, double, double) 11625 * 11626 * @param fovy 11627 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11628 * @param offAngleX 11629 * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes 11630 * @param offAngleY 11631 * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes 11632 * @param aspect 11633 * the aspect ratio (i.e. width / height; must be greater than zero) 11634 * @param zNear 11635 * near clipping plane distance. This value must be greater than zero. 11636 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11637 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11638 * @param zFar 11639 * far clipping plane distance. This value must be greater than zero. 11640 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11641 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11642 * @param zZeroToOne 11643 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11644 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11645 * @return this 11646 */ 11647 ref public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY, 11648 double aspect, double zNear, double zFar, bool zZeroToOne) return { 11649 this.zero(); 11650 double h = Math.tan(fovy * 0.5); 11651 double xScale = 1.0 / (h * aspect), yScale = 1.0 / h; 11652 _m00(xScale). 11653 _m11(yScale); 11654 double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY); 11655 _m20(offX * xScale). 11656 _m21(offY * yScale); 11657 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11658 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11659 if (farInf) { 11660 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11661 double e = 1E-6; 11662 _m22(e - 1.0). 11663 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 11664 } else if (nearInf) { 11665 double e = 1E-6; 11666 _m22((zZeroToOne ? 0.0 : 1.0) - e). 11667 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 11668 } else { 11669 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 11670 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 11671 } 11672 _m23(-1.0). 11673 _m30(0.0). 11674 _m31(0.0). 11675 _m33(0.0). 11676 properties = offAngleX == 0.0 && offAngleY == 0.0 ? PROPERTY_PERSPECTIVE : 0; 11677 return this; 11678 } 11679 11680 /** 11681 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate 11682 * system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11683 * <p> 11684 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11685 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11686 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11687 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11688 * <p> 11689 * In order to apply the perspective projection transformation to an existing transformation, 11690 * use {@link #perspectiveOffCenterFov(double, double, double, double, double, double) perspectiveOffCenterFov()}. 11691 * 11692 * @see #perspectiveOffCenterFov(double, double, double, double, double, double) 11693 * 11694 * @param angleLeft 11695 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11696 * For a symmetric frustum, this value is negative. 11697 * @param angleRight 11698 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11699 * @param angleDown 11700 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11701 * For a symmetric frustum, this value is negative. 11702 * @param angleUp 11703 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11704 * @param zNear 11705 * near clipping plane distance. This value must be greater than zero. 11706 * If the special value {@link double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11707 * In that case, <code>zFar</code> may not also be {@link double#POSITIVE_INFINITY}. 11708 * @param zFar 11709 * far clipping plane distance. This value must be greater than zero. 11710 * If the special value {@link double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11711 * In that case, <code>zNear</code> may not also be {@link double#POSITIVE_INFINITY}. 11712 * @return this 11713 */ 11714 ref public Matrix4d setPerspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11715 return setPerspectiveOffCenterFov(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, false); 11716 } 11717 /** 11718 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system 11719 * using the given NDC z range. 11720 * <p> 11721 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11722 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11723 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11724 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11725 * <p> 11726 * In order to apply the perspective projection transformation to an existing transformation, 11727 * use {@link #perspectiveOffCenterFov(double, double, double, double, double, double, bool) perspectiveOffCenterFov()}. 11728 * 11729 * @see #perspectiveOffCenterFov(double, double, double, double, double, double, bool) 11730 * 11731 * @param angleLeft 11732 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11733 * For a symmetric frustum, this value is negative. 11734 * @param angleRight 11735 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11736 * @param angleDown 11737 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11738 * For a symmetric frustum, this value is negative. 11739 * @param angleUp 11740 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11741 * @param zNear 11742 * near clipping plane distance. This value must be greater than zero. 11743 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11744 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11745 * @param zFar 11746 * far clipping plane distance. This value must be greater than zero. 11747 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11748 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11749 * @param zZeroToOne 11750 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11751 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11752 * @return this 11753 */ 11754 ref public Matrix4d setPerspectiveOffCenterFov(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11755 return setFrustum(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne); 11756 } 11757 11758 /** 11759 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate 11760 * system using OpenGL's NDC z range of <code>[-1..+1]</code>. 11761 * <p> 11762 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11763 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11764 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11765 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11766 * <p> 11767 * In order to apply the perspective projection transformation to an existing transformation, 11768 * use {@link #perspectiveOffCenterFovLH(double, double, double, double, double, double) perspectiveOffCenterFovLH()}. 11769 * 11770 * @see #perspectiveOffCenterFovLH(double, double, double, double, double, double) 11771 * 11772 * @param angleLeft 11773 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11774 * For a symmetric frustum, this value is negative. 11775 * @param angleRight 11776 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11777 * @param angleDown 11778 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11779 * For a symmetric frustum, this value is negative. 11780 * @param angleUp 11781 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11782 * @param zNear 11783 * near clipping plane distance. This value must be greater than zero. 11784 * If the special value {@link double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11785 * In that case, <code>zFar</code> may not also be {@link double#POSITIVE_INFINITY}. 11786 * @param zFar 11787 * far clipping plane distance. This value must be greater than zero. 11788 * If the special value {@link double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11789 * In that case, <code>zNear</code> may not also be {@link double#POSITIVE_INFINITY}. 11790 * @return this 11791 */ 11792 ref public Matrix4d setPerspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar) return { 11793 return setPerspectiveOffCenterFovLH(angleLeft, angleRight, angleDown, angleUp, zNear, zFar, false); 11794 } 11795 /** 11796 * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a left-handed coordinate system 11797 * using the given NDC z range. 11798 * <p> 11799 * The given angles <code>angleLeft</code> and <code>angleRight</code> are the horizontal angles between 11800 * the left and right frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11801 * The angles <code>angleDown</code> and <code>angleUp</code> are the vertical angles between 11802 * the bottom and top frustum planes, respectively, and a line perpendicular to the near and far frustum planes. 11803 * <p> 11804 * In order to apply the perspective projection transformation to an existing transformation, 11805 * use {@link #perspectiveOffCenterFovLH(double, double, double, double, double, double, bool) perspectiveOffCenterFovLH()}. 11806 * 11807 * @see #perspectiveOffCenterFovLH(double, double, double, double, double, double, bool) 11808 * 11809 * @param angleLeft 11810 * the horizontal angle between left frustum plane and a line perpendicular to the near/far frustum planes. 11811 * For a symmetric frustum, this value is negative. 11812 * @param angleRight 11813 * the horizontal angle between right frustum plane and a line perpendicular to the near/far frustum planes 11814 * @param angleDown 11815 * the vertical angle between bottom frustum plane and a line perpendicular to the near/far frustum planes. 11816 * For a symmetric frustum, this value is negative. 11817 * @param angleUp 11818 * the vertical angle between top frustum plane and a line perpendicular to the near/far frustum planes 11819 * @param zNear 11820 * near clipping plane distance. This value must be greater than zero. 11821 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11822 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11823 * @param zFar 11824 * far clipping plane distance. This value must be greater than zero. 11825 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11826 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11827 * @param zZeroToOne 11828 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11829 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11830 * @return this 11831 */ 11832 ref public Matrix4d setPerspectiveOffCenterFovLH(double angleLeft, double angleRight, double angleDown, double angleUp, double zNear, double zFar, bool zZeroToOne) return { 11833 return setFrustumLH(Math.tan(angleLeft)*zNear, Math.tan(angleRight)*zNear, Math.tan(angleDown)*zNear, Math.tan(angleUp)*zNear, zNear, zFar, zZeroToOne); 11834 } 11835 11836 /** 11837 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11838 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 11839 * <p> 11840 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11841 * then the new matrix will be <code>M * P</code>. So when transforming a 11842 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11843 * the perspective projection will be applied first! 11844 * <p> 11845 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11846 * use {@link #setPerspectiveLH(double, double, double, double, bool) setPerspectiveLH}. 11847 * 11848 * @see #setPerspectiveLH(double, double, double, double, bool) 11849 * 11850 * @param fovy 11851 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11852 * @param aspect 11853 * the aspect ratio (i.e. width / height; must be greater than zero) 11854 * @param zNear 11855 * near clipping plane distance. This value must be greater than zero. 11856 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11857 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11858 * @param zFar 11859 * far clipping plane distance. This value must be greater than zero. 11860 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11861 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11862 * @param zZeroToOne 11863 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11864 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11865 * @param dest 11866 * will hold the result 11867 * @return dest 11868 */ 11869 public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11870 if ((properties & PROPERTY_IDENTITY) != 0) 11871 return dest.setPerspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne); 11872 return perspectiveLHGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest); 11873 } 11874 private Matrix4d perspectiveLHGeneric(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 11875 double h = Math.tan(fovy * 0.5); 11876 // calculate right matrix elements 11877 double rm00 = 1.0 / (h * aspect); 11878 double rm11 = 1.0 / h; 11879 double rm22; 11880 double rm32; 11881 bool farInf = zFar > 0 && Math.isInfinite(zFar); 11882 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 11883 if (farInf) { 11884 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 11885 double e = 1E-6; 11886 rm22 = 1.0 - e; 11887 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 11888 } else if (nearInf) { 11889 double e = 1E-6; 11890 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 11891 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 11892 } else { 11893 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear); 11894 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 11895 } 11896 // perform optimized matrix multiplication 11897 double nm20 = m20 * rm22 + m30; 11898 double nm21 = m21 * rm22 + m31; 11899 double nm22 = m22 * rm22 + m32; 11900 double nm23 = m23 * rm22 + m33; 11901 dest._m00(m00 * rm00) 11902 ._m01(m01 * rm00) 11903 ._m02(m02 * rm00) 11904 ._m03(m03 * rm00) 11905 ._m10(m10 * rm11) 11906 ._m11(m11 * rm11) 11907 ._m12(m12 * rm11) 11908 ._m13(m13 * rm11) 11909 ._m30(m20 * rm32) 11910 ._m31(m21 * rm32) 11911 ._m32(m22 * rm32) 11912 ._m33(m23 * rm32) 11913 ._m20(nm20) 11914 ._m21(nm21) 11915 ._m22(nm22) 11916 ._m23(nm23) 11917 ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 11918 return dest; 11919 } 11920 11921 /** 11922 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11923 * using the given NDC z range to this matrix. 11924 * <p> 11925 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11926 * then the new matrix will be <code>M * P</code>. So when transforming a 11927 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11928 * the perspective projection will be applied first! 11929 * <p> 11930 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11931 * use {@link #setPerspectiveLH(double, double, double, double, bool) setPerspectiveLH}. 11932 * 11933 * @see #setPerspectiveLH(double, double, double, double, bool) 11934 * 11935 * @param fovy 11936 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11937 * @param aspect 11938 * the aspect ratio (i.e. width / height; must be greater than zero) 11939 * @param zNear 11940 * near clipping plane distance. This value must be greater than zero. 11941 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11942 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11943 * @param zFar 11944 * far clipping plane distance. This value must be greater than zero. 11945 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11946 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11947 * @param zZeroToOne 11948 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 11949 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 11950 * @return this 11951 */ 11952 ref public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 11953 perspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne, this); 11954 return this; 11955 } 11956 11957 /** 11958 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11959 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 11960 * <p> 11961 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11962 * then the new matrix will be <code>M * P</code>. So when transforming a 11963 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11964 * the perspective projection will be applied first! 11965 * <p> 11966 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 11967 * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}. 11968 * 11969 * @see #setPerspectiveLH(double, double, double, double) 11970 * 11971 * @param fovy 11972 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 11973 * @param aspect 11974 * the aspect ratio (i.e. width / height; must be greater than zero) 11975 * @param zNear 11976 * near clipping plane distance. This value must be greater than zero. 11977 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 11978 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 11979 * @param zFar 11980 * far clipping plane distance. This value must be greater than zero. 11981 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 11982 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 11983 * @param dest 11984 * will hold the result 11985 * @return dest 11986 */ 11987 public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, ref Matrix4d dest) { 11988 return perspectiveLH(fovy, aspect, zNear, zFar, false, dest); 11989 } 11990 11991 /** 11992 * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system 11993 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 11994 * <p> 11995 * If <code>M</code> is <code>this</code> matrix and <code>P</code> the perspective projection matrix, 11996 * then the new matrix will be <code>M * P</code>. So when transforming a 11997 * vector <code>v</code> with the new matrix by using <code>M * P * v</code>, 11998 * the perspective projection will be applied first! 11999 * <p> 12000 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12001 * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}. 12002 * 12003 * @see #setPerspectiveLH(double, double, double, double) 12004 * 12005 * @param fovy 12006 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12007 * @param aspect 12008 * the aspect ratio (i.e. width / height; must be greater than zero) 12009 * @param zNear 12010 * near clipping plane distance. This value must be greater than zero. 12011 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12012 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12013 * @param zFar 12014 * far clipping plane distance. This value must be greater than zero. 12015 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12016 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12017 * @return this 12018 */ 12019 ref public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar) return { 12020 perspectiveLH(fovy, aspect, zNear, zFar, this); 12021 return this; 12022 } 12023 12024 /** 12025 * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system 12026 * using the given NDC z range of <code>[-1..+1]</code>. 12027 * <p> 12028 * In order to apply the perspective projection transformation to an existing transformation, 12029 * use {@link #perspectiveLH(double, double, double, double, bool) perspectiveLH()}. 12030 * 12031 * @see #perspectiveLH(double, double, double, double, bool) 12032 * 12033 * @param fovy 12034 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12035 * @param aspect 12036 * the aspect ratio (i.e. width / height; must be greater than zero) 12037 * @param zNear 12038 * near clipping plane distance. This value must be greater than zero. 12039 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12040 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12041 * @param zFar 12042 * far clipping plane distance. This value must be greater than zero. 12043 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12044 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12045 * @param zZeroToOne 12046 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12047 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12048 * @return this 12049 */ 12050 ref public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar, bool zZeroToOne) return { 12051 double h = Math.tan(fovy * 0.5); 12052 _m00(1.0 / (h * aspect)). 12053 _m01(0.0). 12054 _m02(0.0). 12055 _m03(0.0). 12056 _m10(0.0). 12057 _m11(1.0 / h). 12058 _m12(0.0). 12059 _m13(0.0). 12060 _m20(0.0). 12061 _m21(0.0); 12062 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12063 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12064 if (farInf) { 12065 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12066 double e = 1E-6; 12067 _m22(1.0 - e). 12068 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12069 } else if (nearInf) { 12070 double e = 1E-6; 12071 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12072 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12073 } else { 12074 _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)). 12075 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12076 } 12077 _m23(1.0). 12078 _m30(0.0). 12079 _m31(0.0). 12080 _m33(0.0). 12081 properties = PROPERTY_PERSPECTIVE; 12082 return this; 12083 } 12084 12085 /** 12086 * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system 12087 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12088 * <p> 12089 * In order to apply the perspective projection transformation to an existing transformation, 12090 * use {@link #perspectiveLH(double, double, double, double) perspectiveLH()}. 12091 * 12092 * @see #perspectiveLH(double, double, double, double) 12093 * 12094 * @param fovy 12095 * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI}) 12096 * @param aspect 12097 * the aspect ratio (i.e. width / height; must be greater than zero) 12098 * @param zNear 12099 * near clipping plane distance. This value must be greater than zero. 12100 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12101 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12102 * @param zFar 12103 * far clipping plane distance. This value must be greater than zero. 12104 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12105 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12106 * @return this 12107 */ 12108 ref public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar) return { 12109 return setPerspectiveLH(fovy, aspect, zNear, zFar, false); 12110 } 12111 12112 /** 12113 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12114 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 12115 * <p> 12116 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12117 * then the new matrix will be <code>M * F</code>. So when transforming a 12118 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12119 * the frustum transformation will be applied first! 12120 * <p> 12121 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12122 * use {@link #setFrustum(double, double, double, double, double, double, bool) setFrustum()}. 12123 * <p> 12124 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12125 * 12126 * @see #setFrustum(double, double, double, double, double, double, bool) 12127 * 12128 * @param left 12129 * the distance along the x-axis to the left frustum edge 12130 * @param right 12131 * the distance along the x-axis to the right frustum edge 12132 * @param bottom 12133 * the distance along the y-axis to the bottom frustum edge 12134 * @param top 12135 * the distance along the y-axis to the top frustum edge 12136 * @param zNear 12137 * near clipping plane distance. This value must be greater than zero. 12138 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12139 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12140 * @param zFar 12141 * far clipping plane distance. This value must be greater than zero. 12142 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12143 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12144 * @param zZeroToOne 12145 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12146 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12147 * @param dest 12148 * will hold the result 12149 * @return dest 12150 */ 12151 public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12152 if ((properties & PROPERTY_IDENTITY) != 0) 12153 return dest.setFrustum(left, right, bottom, top, zNear, zFar, zZeroToOne); 12154 return frustumGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 12155 } 12156 private Matrix4d frustumGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12157 // calculate right matrix elements 12158 double rm00 = (zNear + zNear) / (right - left); 12159 double rm11 = (zNear + zNear) / (top - bottom); 12160 double rm20 = (right + left) / (right - left); 12161 double rm21 = (top + bottom) / (top - bottom); 12162 double rm22; 12163 double rm32; 12164 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12165 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12166 if (farInf) { 12167 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12168 double e = 1E-6; 12169 rm22 = e - 1.0; 12170 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 12171 } else if (nearInf) { 12172 double e = 1E-6; 12173 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 12174 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 12175 } else { 12176 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar); 12177 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 12178 } 12179 // perform optimized matrix multiplication 12180 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30; 12181 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31; 12182 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32; 12183 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33; 12184 dest._m00(m00 * rm00) 12185 ._m01(m01 * rm00) 12186 ._m02(m02 * rm00) 12187 ._m03(m03 * rm00) 12188 ._m10(m10 * rm11) 12189 ._m11(m11 * rm11) 12190 ._m12(m12 * rm11) 12191 ._m13(m13 * rm11) 12192 ._m30(m20 * rm32) 12193 ._m31(m21 * rm32) 12194 ._m32(m22 * rm32) 12195 ._m33(m23 * rm32) 12196 ._m20(nm20) 12197 ._m21(nm21) 12198 ._m22(nm22) 12199 ._m23(nm23) 12200 ._properties(0); 12201 return dest; 12202 } 12203 12204 /** 12205 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12206 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12207 * <p> 12208 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12209 * then the new matrix will be <code>M * F</code>. So when transforming a 12210 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12211 * the frustum transformation will be applied first! 12212 * <p> 12213 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12214 * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}. 12215 * <p> 12216 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12217 * 12218 * @see #setFrustum(double, double, double, double, double, double) 12219 * 12220 * @param left 12221 * the distance along the x-axis to the left frustum edge 12222 * @param right 12223 * the distance along the x-axis to the right frustum edge 12224 * @param bottom 12225 * the distance along the y-axis to the bottom frustum edge 12226 * @param top 12227 * the distance along the y-axis to the top frustum edge 12228 * @param zNear 12229 * near clipping plane distance. This value must be greater than zero. 12230 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12231 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12232 * @param zFar 12233 * far clipping plane distance. This value must be greater than zero. 12234 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12235 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12236 * @param dest 12237 * will hold the result 12238 * @return dest 12239 */ 12240 public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 12241 return frustum(left, right, bottom, top, zNear, zFar, false, dest); 12242 } 12243 12244 /** 12245 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12246 * using the given NDC z range to this matrix. 12247 * <p> 12248 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12249 * then the new matrix will be <code>M * F</code>. So when transforming a 12250 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12251 * the frustum transformation will be applied first! 12252 * <p> 12253 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12254 * use {@link #setFrustum(double, double, double, double, double, double, bool) setFrustum()}. 12255 * <p> 12256 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12257 * 12258 * @see #setFrustum(double, double, double, double, double, double, bool) 12259 * 12260 * @param left 12261 * the distance along the x-axis to the left frustum edge 12262 * @param right 12263 * the distance along the x-axis to the right frustum edge 12264 * @param bottom 12265 * the distance along the y-axis to the bottom frustum edge 12266 * @param top 12267 * the distance along the y-axis to the top frustum edge 12268 * @param zNear 12269 * near clipping plane distance. This value must be greater than zero. 12270 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12271 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12272 * @param zFar 12273 * far clipping plane distance. This value must be greater than zero. 12274 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12275 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12276 * @param zZeroToOne 12277 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12278 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12279 * @return this 12280 */ 12281 ref public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12282 frustum(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 12283 return this; 12284 } 12285 12286 /** 12287 * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12288 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix. 12289 * <p> 12290 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12291 * then the new matrix will be <code>M * F</code>. So when transforming a 12292 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12293 * the frustum transformation will be applied first! 12294 * <p> 12295 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12296 * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}. 12297 * <p> 12298 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12299 * 12300 * @see #setFrustum(double, double, double, double, double, double) 12301 * 12302 * @param left 12303 * the distance along the x-axis to the left frustum edge 12304 * @param right 12305 * the distance along the x-axis to the right frustum edge 12306 * @param bottom 12307 * the distance along the y-axis to the bottom frustum edge 12308 * @param top 12309 * the distance along the y-axis to the top frustum edge 12310 * @param zNear 12311 * near clipping plane distance. This value must be greater than zero. 12312 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12313 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12314 * @param zFar 12315 * far clipping plane distance. This value must be greater than zero. 12316 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12317 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12318 * @return this 12319 */ 12320 ref public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar) return { 12321 frustum(left, right, bottom, top, zNear, zFar, this); 12322 return this; 12323 } 12324 12325 /** 12326 * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12327 * using the given NDC z range. 12328 * <p> 12329 * In order to apply the perspective frustum transformation to an existing transformation, 12330 * use {@link #frustum(double, double, double, double, double, double, bool) frustum()}. 12331 * <p> 12332 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12333 * 12334 * @see #frustum(double, double, double, double, double, double, bool) 12335 * 12336 * @param left 12337 * the distance along the x-axis to the left frustum edge 12338 * @param right 12339 * the distance along the x-axis to the right frustum edge 12340 * @param bottom 12341 * the distance along the y-axis to the bottom frustum edge 12342 * @param top 12343 * the distance along the y-axis to the top frustum edge 12344 * @param zNear 12345 * near clipping plane distance. This value must be greater than zero. 12346 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12347 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12348 * @param zFar 12349 * far clipping plane distance. This value must be greater than zero. 12350 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12351 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12352 * @param zZeroToOne 12353 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12354 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12355 * @return this 12356 */ 12357 ref public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12358 if ((properties & PROPERTY_IDENTITY) == 0) 12359 _identity(); 12360 _m00((zNear + zNear) / (right - left)). 12361 _m11((zNear + zNear) / (top - bottom)). 12362 _m20((right + left) / (right - left)). 12363 _m21((top + bottom) / (top - bottom)); 12364 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12365 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12366 if (farInf) { 12367 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12368 double e = 1E-6; 12369 _m22(e - 1.0). 12370 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12371 } else if (nearInf) { 12372 double e = 1E-6; 12373 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12374 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12375 } else { 12376 _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)). 12377 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12378 } 12379 _m23(-1.0). 12380 _m33(0.0). 12381 properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0; 12382 return this; 12383 } 12384 12385 /** 12386 * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system 12387 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12388 * <p> 12389 * In order to apply the perspective frustum transformation to an existing transformation, 12390 * use {@link #frustum(double, double, double, double, double, double) frustum()}. 12391 * <p> 12392 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12393 * 12394 * @see #frustum(double, double, double, double, double, double) 12395 * 12396 * @param left 12397 * the distance along the x-axis to the left frustum edge 12398 * @param right 12399 * the distance along the x-axis to the right frustum edge 12400 * @param bottom 12401 * the distance along the y-axis to the bottom frustum edge 12402 * @param top 12403 * the distance along the y-axis to the top frustum edge 12404 * @param zNear 12405 * near clipping plane distance. This value must be greater than zero. 12406 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12407 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12408 * @param zFar 12409 * far clipping plane distance. This value must be greater than zero. 12410 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12411 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12412 * @return this 12413 */ 12414 ref public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar) return { 12415 return setFrustum(left, right, bottom, top, zNear, zFar, false); 12416 } 12417 12418 /** 12419 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12420 * using the given NDC z range to this matrix and store the result in <code>dest</code>. 12421 * <p> 12422 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12423 * then the new matrix will be <code>M * F</code>. So when transforming a 12424 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12425 * the frustum transformation will be applied first! 12426 * <p> 12427 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12428 * use {@link #setFrustumLH(double, double, double, double, double, double, bool) setFrustumLH()}. 12429 * <p> 12430 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12431 * 12432 * @see #setFrustumLH(double, double, double, double, double, double, bool) 12433 * 12434 * @param left 12435 * the distance along the x-axis to the left frustum edge 12436 * @param right 12437 * the distance along the x-axis to the right frustum edge 12438 * @param bottom 12439 * the distance along the y-axis to the bottom frustum edge 12440 * @param top 12441 * the distance along the y-axis to the top frustum edge 12442 * @param zNear 12443 * near clipping plane distance. This value must be greater than zero. 12444 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12445 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12446 * @param zFar 12447 * far clipping plane distance. This value must be greater than zero. 12448 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12449 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12450 * @param zZeroToOne 12451 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12452 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12453 * @param dest 12454 * will hold the result 12455 * @return dest 12456 */ 12457 public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12458 if ((properties & PROPERTY_IDENTITY) != 0) 12459 return dest.setFrustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne); 12460 return frustumLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest); 12461 } 12462 private Matrix4d frustumLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4d dest) { 12463 // calculate right matrix elements 12464 double rm00 = (zNear + zNear) / (right - left); 12465 double rm11 = (zNear + zNear) / (top - bottom); 12466 double rm20 = (right + left) / (right - left); 12467 double rm21 = (top + bottom) / (top - bottom); 12468 double rm22; 12469 double rm32; 12470 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12471 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12472 if (farInf) { 12473 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12474 double e = 1E-6; 12475 rm22 = 1.0 - e; 12476 rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear; 12477 } else if (nearInf) { 12478 double e = 1E-6; 12479 rm22 = (zZeroToOne ? 0.0 : 1.0) - e; 12480 rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar; 12481 } else { 12482 rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear); 12483 rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar); 12484 } 12485 // perform optimized matrix multiplication 12486 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30; 12487 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31; 12488 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32; 12489 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33; 12490 dest._m00(m00 * rm00) 12491 ._m01(m01 * rm00) 12492 ._m02(m02 * rm00) 12493 ._m03(m03 * rm00) 12494 ._m10(m10 * rm11) 12495 ._m11(m11 * rm11) 12496 ._m12(m12 * rm11) 12497 ._m13(m13 * rm11) 12498 ._m30(m20 * rm32) 12499 ._m31(m21 * rm32) 12500 ._m32(m22 * rm32) 12501 ._m33(m23 * rm32) 12502 ._m20(nm20) 12503 ._m21(nm21) 12504 ._m22(nm22) 12505 ._m23(nm23) 12506 ._properties(0); 12507 return dest; 12508 } 12509 12510 /** 12511 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12512 * using the given NDC z range to this matrix. 12513 * <p> 12514 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12515 * then the new matrix will be <code>M * F</code>. So when transforming a 12516 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12517 * the frustum transformation will be applied first! 12518 * <p> 12519 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12520 * use {@link #setFrustumLH(double, double, double, double, double, double, bool) setFrustumLH()}. 12521 * <p> 12522 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12523 * 12524 * @see #setFrustumLH(double, double, double, double, double, double, bool) 12525 * 12526 * @param left 12527 * the distance along the x-axis to the left frustum edge 12528 * @param right 12529 * the distance along the x-axis to the right frustum edge 12530 * @param bottom 12531 * the distance along the y-axis to the bottom frustum edge 12532 * @param top 12533 * the distance along the y-axis to the top frustum edge 12534 * @param zNear 12535 * near clipping plane distance. This value must be greater than zero. 12536 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12537 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12538 * @param zFar 12539 * far clipping plane distance. This value must be greater than zero. 12540 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12541 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12542 * @param zZeroToOne 12543 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12544 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12545 * @return this 12546 */ 12547 ref public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12548 frustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this); 12549 return this; 12550 } 12551 12552 /** 12553 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12554 * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>. 12555 * <p> 12556 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12557 * then the new matrix will be <code>M * F</code>. So when transforming a 12558 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12559 * the frustum transformation will be applied first! 12560 * <p> 12561 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12562 * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}. 12563 * <p> 12564 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12565 * 12566 * @see #setFrustumLH(double, double, double, double, double, double) 12567 * 12568 * @param left 12569 * the distance along the x-axis to the left frustum edge 12570 * @param right 12571 * the distance along the x-axis to the right frustum edge 12572 * @param bottom 12573 * the distance along the y-axis to the bottom frustum edge 12574 * @param top 12575 * the distance along the y-axis to the top frustum edge 12576 * @param zNear 12577 * near clipping plane distance. This value must be greater than zero. 12578 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12579 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12580 * @param zFar 12581 * far clipping plane distance. This value must be greater than zero. 12582 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12583 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12584 * @param dest 12585 * will hold the result 12586 * @return dest 12587 */ 12588 public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4d dest) { 12589 return frustumLH(left, right, bottom, top, zNear, zFar, false, dest); 12590 } 12591 12592 /** 12593 * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12594 * using the given NDC z range to this matrix. 12595 * <p> 12596 * If <code>M</code> is <code>this</code> matrix and <code>F</code> the frustum matrix, 12597 * then the new matrix will be <code>M * F</code>. So when transforming a 12598 * vector <code>v</code> with the new matrix by using <code>M * F * v</code>, 12599 * the frustum transformation will be applied first! 12600 * <p> 12601 * In order to set the matrix to a perspective frustum transformation without post-multiplying, 12602 * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}. 12603 * <p> 12604 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12605 * 12606 * @see #setFrustumLH(double, double, double, double, double, double) 12607 * 12608 * @param left 12609 * the distance along the x-axis to the left frustum edge 12610 * @param right 12611 * the distance along the x-axis to the right frustum edge 12612 * @param bottom 12613 * the distance along the y-axis to the bottom frustum edge 12614 * @param top 12615 * the distance along the y-axis to the top frustum edge 12616 * @param zNear 12617 * near clipping plane distance. This value must be greater than zero. 12618 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12619 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12620 * @param zFar 12621 * far clipping plane distance. This value must be greater than zero. 12622 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12623 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12624 * @return this 12625 */ 12626 ref public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 12627 frustumLH(left, right, bottom, top, zNear, zFar, this); 12628 return this; 12629 } 12630 12631 /** 12632 * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12633 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12634 * <p> 12635 * In order to apply the perspective frustum transformation to an existing transformation, 12636 * use {@link #frustumLH(double, double, double, double, double, double, bool) frustumLH()}. 12637 * <p> 12638 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12639 * 12640 * @see #frustumLH(double, double, double, double, double, double, bool) 12641 * 12642 * @param left 12643 * the distance along the x-axis to the left frustum edge 12644 * @param right 12645 * the distance along the x-axis to the right frustum edge 12646 * @param bottom 12647 * the distance along the y-axis to the bottom frustum edge 12648 * @param top 12649 * the distance along the y-axis to the top frustum edge 12650 * @param zNear 12651 * near clipping plane distance. This value must be greater than zero. 12652 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12653 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12654 * @param zFar 12655 * far clipping plane distance. This value must be greater than zero. 12656 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12657 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12658 * @param zZeroToOne 12659 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 12660 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 12661 * @return this 12662 */ 12663 ref public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return { 12664 if ((properties & PROPERTY_IDENTITY) == 0) 12665 _identity(); 12666 _m00((zNear + zNear) / (right - left)). 12667 _m11((zNear + zNear) / (top - bottom)). 12668 _m20((right + left) / (right - left)). 12669 _m21((top + bottom) / (top - bottom)); 12670 bool farInf = zFar > 0 && Math.isInfinite(zFar); 12671 bool nearInf = zNear > 0 && Math.isInfinite(zNear); 12672 if (farInf) { 12673 // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf) 12674 double e = 1E-6; 12675 _m22(1.0 - e). 12676 _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear); 12677 } else if (nearInf) { 12678 double e = 1E-6; 12679 _m22((zZeroToOne ? 0.0 : 1.0) - e). 12680 _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar); 12681 } else { 12682 _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)). 12683 _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar)); 12684 } 12685 _m23(1.0). 12686 _m33(0.0). 12687 properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0; 12688 return this; 12689 } 12690 12691 /** 12692 * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system 12693 * using OpenGL's NDC z range of <code>[-1..+1]</code>. 12694 * <p> 12695 * In order to apply the perspective frustum transformation to an existing transformation, 12696 * use {@link #frustumLH(double, double, double, double, double, double) frustumLH()}. 12697 * <p> 12698 * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#perspective">http://www.songho.ca</a> 12699 * 12700 * @see #frustumLH(double, double, double, double, double, double) 12701 * 12702 * @param left 12703 * the distance along the x-axis to the left frustum edge 12704 * @param right 12705 * the distance along the x-axis to the right frustum edge 12706 * @param bottom 12707 * the distance along the y-axis to the bottom frustum edge 12708 * @param top 12709 * the distance along the y-axis to the top frustum edge 12710 * @param zNear 12711 * near clipping plane distance. This value must be greater than zero. 12712 * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity. 12713 * In that case, <code>zFar</code> may not also be {@link Double#POSITIVE_INFINITY}. 12714 * @param zFar 12715 * far clipping plane distance. This value must be greater than zero. 12716 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 12717 * In that case, <code>zNear</code> may not also be {@link Double#POSITIVE_INFINITY}. 12718 * @return this 12719 */ 12720 ref public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar) return { 12721 return setFrustumLH(left, right, bottom, top, zNear, zFar, false); 12722 } 12723 12724 /** 12725 * Set this matrix to represent a perspective projection equivalent to the given intrinsic camera calibration parameters. 12726 * The resulting matrix will be suited for a right-handed coordinate system using OpenGL's NDC z range of <code>[-1..+1]</code>. 12727 * <p> 12728 * See: <a href="https://en.wikipedia.org/wiki/Camera_resectioning#Intrinsic_parameters">https://en.wikipedia.org/</a> 12729 * <p> 12730 * Reference: <a href="http://ksimek.github.io/2013/06/03/calibrated_cameras_in_opengl/">http://ksimek.github.io/</a> 12731 * 12732 * @param alphaX 12733 * specifies the focal length and scale along the X axis 12734 * @param alphaY 12735 * specifies the focal length and scale along the Y axis 12736 * @param gamma 12737 * the skew coefficient between the X and Y axis (may be <code>0</code>) 12738 * @param u0 12739 * the X coordinate of the principal point in image/sensor units 12740 * @param v0 12741 * the Y coordinate of the principal point in image/sensor units 12742 * @param imgWidth 12743 * the width of the sensor/image image/sensor units 12744 * @param imgHeight 12745 * the height of the sensor/image image/sensor units 12746 * @param near 12747 * the distance to the near plane 12748 * @param far 12749 * the distance to the far plane 12750 * @return this 12751 */ 12752 ref public Matrix4d setFromIntrinsic(double alphaX, double alphaY, double gamma, double u0, double v0, int imgWidth, int imgHeight, double near, double far) return { 12753 double l00 = 2.0 / imgWidth; 12754 double l11 = 2.0 / imgHeight; 12755 double l22 = 2.0 / (near - far); 12756 setm00(l00 * alphaX); 12757 setm01(0.0); 12758 setm02(0.0); 12759 setm03(0.0); 12760 setm10(l00 * gamma); 12761 setm11(l11 * alphaY); 12762 setm12(0.0); 12763 setm13(0.0); 12764 setm20(l00 * u0 - 1.0); 12765 setm21(l11 * v0 - 1.0); 12766 setm22(l22 * -(near + far) + (far + near) / (near - far)); 12767 setm23(-1.0); 12768 setm30(0.0); 12769 setm31(0.0); 12770 setm32(l22 * -near * far); 12771 setm33(0.0); 12772 this.properties = PROPERTY_PERSPECTIVE; 12773 return this; 12774 } 12775 12776 public Vector4d frustumPlane(int plane, ref Vector4d dest) { 12777 switch (plane) { 12778 case PLANE_NX: 12779 dest.set(m03 + m00, m13 + m10, m23 + m20, m33 + m30).normalize3(); 12780 break; 12781 case PLANE_PX: 12782 dest.set(m03 - m00, m13 - m10, m23 - m20, m33 - m30).normalize3(); 12783 break; 12784 case PLANE_NY: 12785 dest.set(m03 + m01, m13 + m11, m23 + m21, m33 + m31).normalize3(); 12786 break; 12787 case PLANE_PY: 12788 dest.set(m03 - m01, m13 - m11, m23 - m21, m33 - m31).normalize3(); 12789 break; 12790 case PLANE_NZ: 12791 dest.set(m03 + m02, m13 + m12, m23 + m22, m33 + m32).normalize3(); 12792 break; 12793 case PLANE_PZ: 12794 dest.set(m03 - m02, m13 - m12, m23 - m22, m33 - m32).normalize3(); 12795 break; 12796 default: 12797 // do nothing 12798 } 12799 return dest; 12800 } 12801 12802 public Vector3d frustumCorner(int corner, ref Vector3d dest) { 12803 double d1, d2, d3; 12804 double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z; 12805 switch (corner) { 12806 case CORNER_NXNYNZ: // left, bottom, near 12807 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12808 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12809 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12810 break; 12811 case CORNER_PXNYNZ: // right, bottom, near 12812 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12813 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12814 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12815 break; 12816 case CORNER_PXPYNZ: // right, top, near 12817 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12818 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12819 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12820 break; 12821 case CORNER_NXPYNZ: // left, top, near 12822 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12823 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12824 n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near 12825 break; 12826 case CORNER_PXNYPZ: // right, bottom, far 12827 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12828 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12829 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12830 break; 12831 case CORNER_NXNYPZ: // left, bottom, far 12832 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12833 n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom 12834 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12835 break; 12836 case CORNER_NXPYPZ: // left, top, far 12837 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12838 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12839 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12840 break; 12841 case CORNER_PXPYPZ: // right, top, far 12842 n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right 12843 n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top 12844 n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far 12845 break; 12846 default: 12847 // do nothing 12848 } 12849 double c23x, c23y, c23z; 12850 c23x = n2y * n3z - n2z * n3y; 12851 c23y = n2z * n3x - n2x * n3z; 12852 c23z = n2x * n3y - n2y * n3x; 12853 double c31x, c31y, c31z; 12854 c31x = n3y * n1z - n3z * n1y; 12855 c31y = n3z * n1x - n3x * n1z; 12856 c31z = n3x * n1y - n3y * n1x; 12857 double c12x, c12y, c12z; 12858 c12x = n1y * n2z - n1z * n2y; 12859 c12y = n1z * n2x - n1x * n2z; 12860 c12z = n1x * n2y - n1y * n2x; 12861 double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z); 12862 dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot; 12863 dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot; 12864 dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot; 12865 return dest; 12866 } 12867 12868 public Vector3d perspectiveOrigin(ref Vector3d dest) { 12869 /* 12870 * Simply compute the intersection point of the left, right and top frustum plane. 12871 */ 12872 double d1, d2, d3; 12873 double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z; 12874 n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left 12875 n2x = m03 - m00; n2y = m13 - m10; n2z = m23 - m20; d2 = m33 - m30; // right 12876 n3x = m03 - m01; n3y = m13 - m11; n3z = m23 - m21; d3 = m33 - m31; // top 12877 double c23x, c23y, c23z; 12878 c23x = n2y * n3z - n2z * n3y; 12879 c23y = n2z * n3x - n2x * n3z; 12880 c23z = n2x * n3y - n2y * n3x; 12881 double c31x, c31y, c31z; 12882 c31x = n3y * n1z - n3z * n1y; 12883 c31y = n3z * n1x - n3x * n1z; 12884 c31z = n3x * n1y - n3y * n1x; 12885 double c12x, c12y, c12z; 12886 c12x = n1y * n2z - n1z * n2y; 12887 c12y = n1z * n2x - n1x * n2z; 12888 c12z = n1x * n2y - n1y * n2x; 12889 double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z); 12890 dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot; 12891 dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot; 12892 dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot; 12893 return dest; 12894 } 12895 12896 public Vector3d perspectiveInvOrigin(ref Vector3d dest) { 12897 double invW = 1.0 / m23; 12898 dest.x = m20 * invW; 12899 dest.y = m21 * invW; 12900 dest.z = m22 * invW; 12901 return dest; 12902 } 12903 12904 public double perspectiveFov() { 12905 /* 12906 * Compute the angle between the bottom and top frustum plane normals. 12907 */ 12908 double n1x, n1y, n1z, n2x, n2y, n2z; 12909 n1x = m03 + m01; n1y = m13 + m11; n1z = m23 + m21; // bottom 12910 n2x = m01 - m03; n2y = m11 - m13; n2z = m21 - m23; // top 12911 double n1len = Math.sqrt(n1x * n1x + n1y * n1y + n1z * n1z); 12912 double n2len = Math.sqrt(n2x * n2x + n2y * n2y + n2z * n2z); 12913 return Math.acos((n1x * n2x + n1y * n2y + n1z * n2z) / (n1len * n2len)); 12914 } 12915 12916 public double perspectiveNear() { 12917 return m32 / (m23 + m22); 12918 } 12919 12920 public double perspectiveFar() { 12921 return m32 / (m22 - m23); 12922 } 12923 12924 public Vector3d frustumRayDir(double x, double y, ref Vector3d dest) { 12925 /* 12926 * This method works by first obtaining the frustum plane normals, 12927 * then building the cross product to obtain the corner rays, 12928 * and finally bilinearly interpolating to obtain the desired direction. 12929 * The code below uses a condense form of doing all this making use 12930 * of some mathematical identities to simplify the overall expression. 12931 */ 12932 double a = m10 * m23, b = m13 * m21, c = m10 * m21, d = m11 * m23, e = m13 * m20, f = m11 * m20; 12933 double g = m03 * m20, h = m01 * m23, i = m01 * m20, j = m03 * m21, k = m00 * m23, l = m00 * m21; 12934 double m = m00 * m13, n = m03 * m11, o = m00 * m11, p = m01 * m13, q = m03 * m10, r = m01 * m10; 12935 double m1x, m1y, m1z; 12936 m1x = (d + e + f - a - b - c) * (1.0 - y) + (a - b - c + d - e + f) * y; 12937 m1y = (j + k + l - g - h - i) * (1.0 - y) + (g - h - i + j - k + l) * y; 12938 m1z = (p + q + r - m - n - o) * (1.0 - y) + (m - n - o + p - q + r) * y; 12939 double m2x, m2y, m2z; 12940 m2x = (b - c - d + e + f - a) * (1.0 - y) + (a + b - c - d - e + f) * y; 12941 m2y = (h - i - j + k + l - g) * (1.0 - y) + (g + h - i - j - k + l) * y; 12942 m2z = (n - o - p + q + r - m) * (1.0 - y) + (m + n - o - p - q + r) * y; 12943 dest.x = m1x * (1.0 - x) + m2x * x; 12944 dest.y = m1y * (1.0 - x) + m2y * x; 12945 dest.z = m1z * (1.0 - x) + m2z * x; 12946 return dest.normalize(dest); 12947 } 12948 12949 public Vector3d positiveZ(ref Vector3d dir) { 12950 if ((properties & PROPERTY_ORTHONORMAL) != 0) 12951 return normalizedPositiveZ(dir); 12952 return positiveZGeneric(dir); 12953 } 12954 private Vector3d positiveZGeneric(ref Vector3d dir) { 12955 return dir.set(m10 * m21 - m11 * m20, m20 * m01 - m21 * m00, m00 * m11 - m01 * m10).normalize(); 12956 } 12957 12958 public Vector3d normalizedPositiveZ(ref Vector3d dir) { 12959 return dir.set(m02, m12, m22); 12960 } 12961 12962 public Vector3d positiveX(ref Vector3d dir) { 12963 if ((properties & PROPERTY_ORTHONORMAL) != 0) 12964 return normalizedPositiveX(dir); 12965 return positiveXGeneric(dir); 12966 } 12967 private Vector3d positiveXGeneric(ref Vector3d dir) { 12968 return dir.set(m11 * m22 - m12 * m21, m02 * m21 - m01 * m22, m01 * m12 - m02 * m11).normalize(); 12969 } 12970 12971 public Vector3d normalizedPositiveX(ref Vector3d dir) { 12972 return dir.set(m00, m10, m20); 12973 } 12974 12975 public Vector3d positiveY(ref Vector3d dir) { 12976 if ((properties & PROPERTY_ORTHONORMAL) != 0) 12977 return normalizedPositiveY(dir); 12978 return positiveYGeneric(dir); 12979 } 12980 private Vector3d positiveYGeneric(ref Vector3d dir) { 12981 return dir.set(m12 * m20 - m10 * m22, m00 * m22 - m02 * m20, m02 * m10 - m00 * m12).normalize(); 12982 } 12983 12984 public Vector3d normalizedPositiveY(ref Vector3d dir) { 12985 return dir.set(m01, m11, m21); 12986 } 12987 12988 public Vector3d originAffine(ref Vector3d dest) { 12989 double a = m00 * m11 - m01 * m10; 12990 double b = m00 * m12 - m02 * m10; 12991 double d = m01 * m12 - m02 * m11; 12992 double g = m20 * m31 - m21 * m30; 12993 double h = m20 * m32 - m22 * m30; 12994 double j = m21 * m32 - m22 * m31; 12995 dest.x = -m10 * j + m11 * h - m12 * g; 12996 dest.y = m00 * j - m01 * h + m02 * g; 12997 dest.z = -m30 * d + m31 * b - m32 * a; 12998 return dest; 12999 } 13000 13001 public Vector3d origin(ref Vector3d dest) { 13002 if ((properties & PROPERTY_AFFINE) != 0) 13003 return originAffine(dest); 13004 return originGeneric(dest); 13005 } 13006 private Vector3d originGeneric(ref Vector3d dest) { 13007 double a = m00 * m11 - m01 * m10; 13008 double b = m00 * m12 - m02 * m10; 13009 double c = m00 * m13 - m03 * m10; 13010 double d = m01 * m12 - m02 * m11; 13011 double e = m01 * m13 - m03 * m11; 13012 double f = m02 * m13 - m03 * m12; 13013 double g = m20 * m31 - m21 * m30; 13014 double h = m20 * m32 - m22 * m30; 13015 double i = m20 * m33 - m23 * m30; 13016 double j = m21 * m32 - m22 * m31; 13017 double k = m21 * m33 - m23 * m31; 13018 double l = m22 * m33 - m23 * m32; 13019 double det = a * l - b * k + c * j + d * i - e * h + f * g; 13020 double invDet = 1.0 / det; 13021 double nm30 = (-m10 * j + m11 * h - m12 * g) * invDet; 13022 double nm31 = ( m00 * j - m01 * h + m02 * g) * invDet; 13023 double nm32 = (-m30 * d + m31 * b - m32 * a) * invDet; 13024 double nm33 = det / ( m20 * d - m21 * b + m22 * a); 13025 double x = nm30 * nm33; 13026 double y = nm31 * nm33; 13027 double z = nm32 * nm33; 13028 return dest.set(x, y, z); 13029 } 13030 13031 /** 13032 * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation 13033 * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>light</code>. 13034 * <p> 13035 * 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. 13036 * <p> 13037 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13038 * then the new matrix will be <code>M * S</code>. So when transforming a 13039 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13040 * shadow projection will be applied first! 13041 * <p> 13042 * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a> 13043 * 13044 * @param light 13045 * the light's vector 13046 * @param a 13047 * the x factor in the plane equation 13048 * @param b 13049 * the y factor in the plane equation 13050 * @param c 13051 * the z factor in the plane equation 13052 * @param d 13053 * the constant in the plane equation 13054 * @return this 13055 */ 13056 ref public Matrix4d shadow(ref Vector4d light, double a, double b, double c, double d) return { 13057 shadow(light.x, light.y, light.z, light.w, a, b, c, d, this); 13058 return this; 13059 } 13060 13061 public Matrix4d shadow(ref Vector4d light, double a, double b, double c, double d, ref Matrix4d dest) { 13062 return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest); 13063 } 13064 13065 /** 13066 * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation 13067 * <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>. 13068 * <p> 13069 * 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. 13070 * <p> 13071 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13072 * then the new matrix will be <code>M * S</code>. So when transforming a 13073 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13074 * shadow projection will be applied first! 13075 * <p> 13076 * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a> 13077 * 13078 * @param lightX 13079 * the x-component of the light's vector 13080 * @param lightY 13081 * the y-component of the light's vector 13082 * @param lightZ 13083 * the z-component of the light's vector 13084 * @param lightW 13085 * the w-component of the light's vector 13086 * @param a 13087 * the x factor in the plane equation 13088 * @param b 13089 * the y factor in the plane equation 13090 * @param c 13091 * the z factor in the plane equation 13092 * @param d 13093 * the constant in the plane equation 13094 * @return this 13095 */ 13096 ref public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) return { 13097 shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this); 13098 return this; 13099 } 13100 13101 public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, ref Matrix4d dest) { 13102 // normalize plane 13103 double invPlaneLen = Math.invsqrt(a*a + b*b + c*c); 13104 double an = a * invPlaneLen; 13105 double bn = b * invPlaneLen; 13106 double cn = c * invPlaneLen; 13107 double dn = d * invPlaneLen; 13108 13109 double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW; 13110 13111 // compute right matrix elements 13112 double rm00 = dot - an * lightX; 13113 double rm01 = -an * lightY; 13114 double rm02 = -an * lightZ; 13115 double rm03 = -an * lightW; 13116 double rm10 = -bn * lightX; 13117 double rm11 = dot - bn * lightY; 13118 double rm12 = -bn * lightZ; 13119 double rm13 = -bn * lightW; 13120 double rm20 = -cn * lightX; 13121 double rm21 = -cn * lightY; 13122 double rm22 = dot - cn * lightZ; 13123 double rm23 = -cn * lightW; 13124 double rm30 = -dn * lightX; 13125 double rm31 = -dn * lightY; 13126 double rm32 = -dn * lightZ; 13127 double rm33 = dot - dn * lightW; 13128 13129 // matrix multiplication 13130 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03; 13131 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03; 13132 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03; 13133 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02 + m33 * rm03; 13134 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13; 13135 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13; 13136 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13; 13137 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12 + m33 * rm13; 13138 double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23; 13139 double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23; 13140 double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23; 13141 double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33 * rm23; 13142 dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33) 13143 ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33) 13144 ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33) 13145 ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33 * rm33) 13146 ._m00(nm00) 13147 ._m01(nm01) 13148 ._m02(nm02) 13149 ._m03(nm03) 13150 ._m10(nm10) 13151 ._m11(nm11) 13152 ._m12(nm12) 13153 ._m13(nm13) 13154 ._m20(nm20) 13155 ._m21(nm21) 13156 ._m22(nm22) 13157 ._m23(nm23) 13158 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 13159 return dest; 13160 } 13161 13162 public Matrix4d shadow(ref Vector4d light, Matrix4d planeTransform, ref Matrix4d dest) { 13163 // compute plane equation by transforming (y = 0) 13164 double a = planeTransform.m10; 13165 double b = planeTransform.m11; 13166 double c = planeTransform.m12; 13167 double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32; 13168 return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest); 13169 } 13170 13171 /** 13172 * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation 13173 * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>light</code>. 13174 * <p> 13175 * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>. 13176 * <p> 13177 * 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. 13178 * <p> 13179 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13180 * then the new matrix will be <code>M * S</code>. So when transforming a 13181 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13182 * shadow projection will be applied first! 13183 * 13184 * @param light 13185 * the light's vector 13186 * @param planeTransform 13187 * the transformation to transform the implied plane <code>y = 0</code> before applying the projection 13188 * @return this 13189 */ 13190 ref public Matrix4d shadow(ref Vector4d light, Matrix4d planeTransform) return { 13191 shadow(light, planeTransform, this); 13192 return this; 13193 } 13194 13195 public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4d planeTransform, ref Matrix4d dest) { 13196 // compute plane equation by transforming (y = 0) 13197 double a = planeTransform.m10; 13198 double b = planeTransform.m11; 13199 double c = planeTransform.m12; 13200 double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32; 13201 return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest); 13202 } 13203 13204 /** 13205 * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation 13206 * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>. 13207 * <p> 13208 * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>. 13209 * <p> 13210 * 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. 13211 * <p> 13212 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix, 13213 * then the new matrix will be <code>M * S</code>. So when transforming a 13214 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 13215 * shadow projection will be applied first! 13216 * 13217 * @param lightX 13218 * the x-component of the light vector 13219 * @param lightY 13220 * the y-component of the light vector 13221 * @param lightZ 13222 * the z-component of the light vector 13223 * @param lightW 13224 * the w-component of the light vector 13225 * @param planeTransform 13226 * the transformation to transform the implied plane <code>y = 0</code> before applying the projection 13227 * @return this 13228 */ 13229 ref public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4d planeTransform) return { 13230 shadow(lightX, lightY, lightZ, lightW, planeTransform, this); 13231 return this; 13232 } 13233 13234 /** 13235 * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13236 * a target position at <code>targetPos</code> while constraining a cylindrical rotation around the given <code>up</code> vector. 13237 * <p> 13238 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13239 * its position <code>objPos</code>. 13240 * 13241 * @param objPos 13242 * the position of the object to rotate towards <code>targetPos</code> 13243 * @param targetPos 13244 * the position of the target (for example the camera) towards which to rotate the object 13245 * @param up 13246 * the rotation axis (must be {@link Vector3d#normalize() normalized}) 13247 * @return this 13248 */ 13249 ref public Matrix4d billboardCylindrical(ref Vector3d objPos, Vector3d targetPos, Vector3d up) return { 13250 double dirX = targetPos.x - objPos.x; 13251 double dirY = targetPos.y - objPos.y; 13252 double dirZ = targetPos.z - objPos.z; 13253 // left = up x dir 13254 double leftX = up.y * dirZ - up.z * dirY; 13255 double leftY = up.z * dirX - up.x * dirZ; 13256 double leftZ = up.x * dirY - up.y * dirX; 13257 // normalize left 13258 double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 13259 leftX *= invLeftLen; 13260 leftY *= invLeftLen; 13261 leftZ *= invLeftLen; 13262 // recompute dir by constraining rotation around 'up' 13263 // dir = left x up 13264 dirX = leftY * up.z - leftZ * up.y; 13265 dirY = leftZ * up.x - leftX * up.z; 13266 dirZ = leftX * up.y - leftY * up.x; 13267 // normalize dir 13268 double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 13269 dirX *= invDirLen; 13270 dirY *= invDirLen; 13271 dirZ *= invDirLen; 13272 // set matrix elements 13273 _m00(leftX). 13274 _m01(leftY). 13275 _m02(leftZ). 13276 _m03(0.0). 13277 _m10(up.x). 13278 _m11(up.y). 13279 _m12(up.z). 13280 _m13(0.0). 13281 _m20(dirX). 13282 _m21(dirY). 13283 _m22(dirZ). 13284 _m23(0.0). 13285 _m30(objPos.x). 13286 _m31(objPos.y). 13287 _m32(objPos.z). 13288 _m33(1.0). 13289 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13290 return this; 13291 } 13292 13293 /** 13294 * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13295 * a target position at <code>targetPos</code>. 13296 * <p> 13297 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13298 * its position <code>objPos</code>. 13299 * <p> 13300 * If preserving an <i>up</i> vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained 13301 * using {@link #billboardSpherical(ref Vector3d, Vector3d)}. 13302 * 13303 * @see #billboardSpherical(ref Vector3d, Vector3d) 13304 * 13305 * @param objPos 13306 * the position of the object to rotate towards <code>targetPos</code> 13307 * @param targetPos 13308 * the position of the target (for example the camera) towards which to rotate the object 13309 * @param up 13310 * the up axis used to orient the object 13311 * @return this 13312 */ 13313 ref public Matrix4d billboardSpherical(ref Vector3d objPos, Vector3d targetPos, Vector3d up) return { 13314 double dirX = targetPos.x - objPos.x; 13315 double dirY = targetPos.y - objPos.y; 13316 double dirZ = targetPos.z - objPos.z; 13317 // normalize dir 13318 double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 13319 dirX *= invDirLen; 13320 dirY *= invDirLen; 13321 dirZ *= invDirLen; 13322 // left = up x dir 13323 double leftX = up.y * dirZ - up.z * dirY; 13324 double leftY = up.z * dirX - up.x * dirZ; 13325 double leftZ = up.x * dirY - up.y * dirX; 13326 // normalize left 13327 double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 13328 leftX *= invLeftLen; 13329 leftY *= invLeftLen; 13330 leftZ *= invLeftLen; 13331 // up = dir x left 13332 double upX = dirY * leftZ - dirZ * leftY; 13333 double upY = dirZ * leftX - dirX * leftZ; 13334 double upZ = dirX * leftY - dirY * leftX; 13335 // set matrix elements 13336 _m00(leftX). 13337 _m01(leftY). 13338 _m02(leftZ). 13339 _m03(0.0). 13340 _m10(upX). 13341 _m11(upY). 13342 _m12(upZ). 13343 _m13(0.0). 13344 _m20(dirX). 13345 _m21(dirY). 13346 _m22(dirZ). 13347 _m23(0.0). 13348 _m30(objPos.x). 13349 _m31(objPos.y). 13350 _m32(objPos.z). 13351 _m33(1.0). 13352 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13353 return this; 13354 } 13355 13356 /** 13357 * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards 13358 * a target position at <code>targetPos</code> using a shortest arc rotation by not preserving any <i>up</i> vector of the object. 13359 * <p> 13360 * This method can be used to create the complete model transformation for a given object, including the translation of the object to 13361 * its position <code>objPos</code>. 13362 * <p> 13363 * In order to specify an <i>up</i> vector which needs to be maintained when rotating the +Z axis of the object, 13364 * use {@link #billboardSpherical(ref Vector3d, Vector3d, Vector3d)}. 13365 * 13366 * @see #billboardSpherical(ref Vector3d, Vector3d, Vector3d) 13367 * 13368 * @param objPos 13369 * the position of the object to rotate towards <code>targetPos</code> 13370 * @param targetPos 13371 * the position of the target (for example the camera) towards which to rotate the object 13372 * @return this 13373 */ 13374 ref public Matrix4d billboardSpherical(ref Vector3d objPos, Vector3d targetPos) return { 13375 double toDirX = targetPos.x - objPos.x; 13376 double toDirY = targetPos.y - objPos.y; 13377 double toDirZ = targetPos.z - objPos.z; 13378 double x = -toDirY; 13379 double y = toDirX; 13380 double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ; 13381 double invNorm = Math.invsqrt(x * x + y * y + w * w); 13382 x *= invNorm; 13383 y *= invNorm; 13384 w *= invNorm; 13385 double q00 = (x + x) * x; 13386 double q11 = (y + y) * y; 13387 double q01 = (x + x) * y; 13388 double q03 = (x + x) * w; 13389 double q13 = (y + y) * w; 13390 _m00(1.0 - q11). 13391 _m01(q01). 13392 _m02(-q13). 13393 _m03(0.0). 13394 _m10(q01). 13395 _m11(1.0 - q00). 13396 _m12(q03). 13397 _m13(0.0). 13398 _m20(q13). 13399 _m21(-q03). 13400 _m22(1.0 - q11 - q00). 13401 _m23(0.0). 13402 _m30(objPos.x). 13403 _m31(objPos.y). 13404 _m32(objPos.z). 13405 _m33(1.0). 13406 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 13407 return this; 13408 } 13409 13410 public int hashCode() { 13411 immutable int prime = 31; 13412 int result = 1; 13413 long temp; 13414 temp = Math.doubleToLongBits(m00); 13415 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13416 temp = Math.doubleToLongBits(m01); 13417 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13418 temp = Math.doubleToLongBits(m02); 13419 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13420 temp = Math.doubleToLongBits(m03); 13421 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13422 temp = Math.doubleToLongBits(m10); 13423 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13424 temp = Math.doubleToLongBits(m11); 13425 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13426 temp = Math.doubleToLongBits(m12); 13427 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13428 temp = Math.doubleToLongBits(m13); 13429 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13430 temp = Math.doubleToLongBits(m20); 13431 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13432 temp = Math.doubleToLongBits(m21); 13433 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13434 temp = Math.doubleToLongBits(m22); 13435 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13436 temp = Math.doubleToLongBits(m23); 13437 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13438 temp = Math.doubleToLongBits(m30); 13439 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13440 temp = Math.doubleToLongBits(m31); 13441 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13442 temp = Math.doubleToLongBits(m32); 13443 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13444 temp = Math.doubleToLongBits(m33); 13445 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 13446 return result; 13447 } 13448 13449 public bool equals(Matrix4d m, double delta) { 13450 if (this == m) 13451 return true; 13452 if (!Math.equals(m00, m.m00, delta)) 13453 return false; 13454 if (!Math.equals(m01, m.m01, delta)) 13455 return false; 13456 if (!Math.equals(m02, m.m02, delta)) 13457 return false; 13458 if (!Math.equals(m03, m.m03, delta)) 13459 return false; 13460 if (!Math.equals(m10, m.m10, delta)) 13461 return false; 13462 if (!Math.equals(m11, m.m11, delta)) 13463 return false; 13464 if (!Math.equals(m12, m.m12, delta)) 13465 return false; 13466 if (!Math.equals(m13, m.m13, delta)) 13467 return false; 13468 if (!Math.equals(m20, m.m20, delta)) 13469 return false; 13470 if (!Math.equals(m21, m.m21, delta)) 13471 return false; 13472 if (!Math.equals(m22, m.m22, delta)) 13473 return false; 13474 if (!Math.equals(m23, m.m23, delta)) 13475 return false; 13476 if (!Math.equals(m30, m.m30, delta)) 13477 return false; 13478 if (!Math.equals(m31, m.m31, delta)) 13479 return false; 13480 if (!Math.equals(m32, m.m32, delta)) 13481 return false; 13482 if (!Math.equals(m33, m.m33, delta)) 13483 return false; 13484 return true; 13485 } 13486 13487 public Matrix4d pick(double x, double y, double width, double height, int[] viewport, ref Matrix4d dest) { 13488 double sx = viewport[2] / width; 13489 double sy = viewport[3] / height; 13490 double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width; 13491 double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height; 13492 dest._m30(m00 * tx + m10 * ty + m30) 13493 ._m31(m01 * tx + m11 * ty + m31) 13494 ._m32(m02 * tx + m12 * ty + m32) 13495 ._m33(m03 * tx + m13 * ty + m33) 13496 ._m00(m00 * sx) 13497 ._m01(m01 * sx) 13498 ._m02(m02 * sx) 13499 ._m03(m03 * sx) 13500 ._m10(m10 * sy) 13501 ._m11(m11 * sy) 13502 ._m12(m12 * sy) 13503 ._m13(m13 * sy) 13504 ._properties(0); 13505 return dest; 13506 } 13507 13508 /** 13509 * Apply a picking transformation to this matrix using the given window coordinates <code>(x, y)</code> as the pick center 13510 * and the given <code>(width, height)</code> as the size of the picking region in window coordinates. 13511 * 13512 * @param x 13513 * the x coordinate of the picking region center in window coordinates 13514 * @param y 13515 * the y coordinate of the picking region center in window coordinates 13516 * @param width 13517 * the width of the picking region in window coordinates 13518 * @param height 13519 * the height of the picking region in window coordinates 13520 * @param viewport 13521 * the viewport described by <code>[x, y, width, height]</code> 13522 * @return this 13523 */ 13524 ref public Matrix4d pick(double x, double y, double width, double height, int[] viewport) return { 13525 pick(x, y, width, height, viewport, this); 13526 return this; 13527 } 13528 13529 public bool isAffine() { 13530 return m03 == 0.0 && m13 == 0.0 && m23 == 0.0 && m33 == 1.0; 13531 } 13532 13533 /** 13534 * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix. 13535 * 13536 * @param other 13537 * the other matrix to exchange the values with 13538 * @return this 13539 */ 13540 ref public Matrix4d swap(ref Matrix4d other) return { 13541 double tmp; 13542 tmp = m00; m00 = other.m00; other.m00 = tmp; 13543 tmp = m01; m01 = other.m01; other.m01 = tmp; 13544 tmp = m02; m02 = other.m02; other.m02 = tmp; 13545 tmp = m03; m03 = other.m03; other.m03 = tmp; 13546 tmp = m10; m10 = other.m10; other.m10 = tmp; 13547 tmp = m11; m11 = other.m11; other.m11 = tmp; 13548 tmp = m12; m12 = other.m12; other.m12 = tmp; 13549 tmp = m13; m13 = other.m13; other.m13 = tmp; 13550 tmp = m20; m20 = other.m20; other.m20 = tmp; 13551 tmp = m21; m21 = other.m21; other.m21 = tmp; 13552 tmp = m22; m22 = other.m22; other.m22 = tmp; 13553 tmp = m23; m23 = other.m23; other.m23 = tmp; 13554 tmp = m30; m30 = other.m30; other.m30 = tmp; 13555 tmp = m31; m31 = other.m31; other.m31 = tmp; 13556 tmp = m32; m32 = other.m32; other.m32 = tmp; 13557 tmp = m33; m33 = other.m33; other.m33 = tmp; 13558 int props = properties; 13559 this.properties = other.properties; 13560 other.properties = props; 13561 return this; 13562 } 13563 13564 public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, ref Matrix4d dest) { 13565 double m30 = m20 * -radius + this.m30; 13566 double m31 = m21 * -radius + this.m31; 13567 double m32 = m22 * -radius + this.m32; 13568 double m33 = m23 * -radius + this.m33; 13569 double sin = Math.sin(angleX); 13570 double cos = Math.cosFromSin(sin, angleX); 13571 double nm10 = m10 * cos + m20 * sin; 13572 double nm11 = m11 * cos + m21 * sin; 13573 double nm12 = m12 * cos + m22 * sin; 13574 double nm13 = m13 * cos + m23 * sin; 13575 double m20 = this.m20 * cos - m10 * sin; 13576 double m21 = this.m21 * cos - m11 * sin; 13577 double m22 = this.m22 * cos - m12 * sin; 13578 double m23 = this.m23 * cos - m13 * sin; 13579 sin = Math.sin(angleY); 13580 cos = Math.cosFromSin(sin, angleY); 13581 double nm00 = m00 * cos - m20 * sin; 13582 double nm01 = m01 * cos - m21 * sin; 13583 double nm02 = m02 * cos - m22 * sin; 13584 double nm03 = m03 * cos - m23 * sin; 13585 double nm20 = m00 * sin + m20 * cos; 13586 double nm21 = m01 * sin + m21 * cos; 13587 double nm22 = m02 * sin + m22 * cos; 13588 double nm23 = m03 * sin + m23 * cos; 13589 dest._m30(-nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30) 13590 ._m31(-nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31) 13591 ._m32(-nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32) 13592 ._m33(-nm03 * centerX - nm13 * centerY - nm23 * centerZ + m33) 13593 ._m20(nm20) 13594 ._m21(nm21) 13595 ._m22(nm22) 13596 ._m23(nm23) 13597 ._m10(nm10) 13598 ._m11(nm11) 13599 ._m12(nm12) 13600 ._m13(nm13) 13601 ._m00(nm00) 13602 ._m01(nm01) 13603 ._m02(nm02) 13604 ._m03(nm03) 13605 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 13606 return dest; 13607 } 13608 13609 public Matrix4d arcball(double radius, Vector3d center, double angleX, double angleY, ref Matrix4d dest) { 13610 return arcball(radius, center.x, center.y, center.z, angleX, angleY, dest); 13611 } 13612 13613 /** 13614 * Apply an arcball view transformation to this matrix with the given <code>radius</code> and center <code>(centerX, centerY, centerZ)</code> 13615 * position of the arcball and the specified X and Y rotation angles. 13616 * <p> 13617 * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)</code> 13618 * 13619 * @param radius 13620 * the arcball radius 13621 * @param centerX 13622 * the x coordinate of the center position of the arcball 13623 * @param centerY 13624 * the y coordinate of the center position of the arcball 13625 * @param centerZ 13626 * the z coordinate of the center position of the arcball 13627 * @param angleX 13628 * the rotation angle around the X axis in radians 13629 * @param angleY 13630 * the rotation angle around the Y axis in radians 13631 * @return this 13632 */ 13633 ref public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) return { 13634 arcball(radius, centerX, centerY, centerZ, angleX, angleY, this); 13635 return this; 13636 } 13637 13638 /** 13639 * Apply an arcball view transformation to this matrix with the given <code>radius</code> and <code>center</code> 13640 * position of the arcball and the specified X and Y rotation angles. 13641 * <p> 13642 * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)</code> 13643 * 13644 * @param radius 13645 * the arcball radius 13646 * @param center 13647 * the center position of the arcball 13648 * @param angleX 13649 * the rotation angle around the X axis in radians 13650 * @param angleY 13651 * the rotation angle around the Y axis in radians 13652 * @return this 13653 */ 13654 ref public Matrix4d arcball(double radius, Vector3d center, double angleX, double angleY) return { 13655 arcball(radius, center.x, center.y, center.z, angleX, angleY, this); 13656 return this; 13657 } 13658 13659 /** 13660 * Compute the axis-aligned bounding box of the frustum described by <code>this</code> matrix and store the minimum corner 13661 * coordinates in the given <code>min</code> and the maximum corner coordinates in the given <code>max</code> vector. 13662 * <p> 13663 * The matrix <code>this</code> is assumed to be the {@link #invert() inverse} of the origial view-projection matrix 13664 * for which to compute the axis-aligned bounding box in world-space. 13665 * <p> 13666 * The axis-aligned bounding box of the unit frustum is <code>(-1, -1, -1)</code>, <code>(1, 1, 1)</code>. 13667 * 13668 * @param min 13669 * will hold the minimum corner coordinates of the axis-aligned bounding box 13670 * @param max 13671 * will hold the maximum corner coordinates of the axis-aligned bounding box 13672 * @return this 13673 */ 13674 ref public Matrix4d frustumAabb(ref Vector3d min, Vector3d max) return { 13675 double minX = double.infinity; 13676 double minY = double.infinity; 13677 double minZ = double.infinity; 13678 double maxX = -double.infinity; 13679 double maxY = -double.infinity; 13680 double maxZ = -double.infinity; 13681 for (int t = 0; t < 8; t++) { 13682 double x = ((t & 1) << 1) - 1.0; 13683 double y = (((t >>> 1) & 1) << 1) - 1.0; 13684 double z = (((t >>> 2) & 1) << 1) - 1.0; 13685 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 13686 double nx = (m00 * x + m10 * y + m20 * z + m30) * invW; 13687 double ny = (m01 * x + m11 * y + m21 * z + m31) * invW; 13688 double nz = (m02 * x + m12 * y + m22 * z + m32) * invW; 13689 minX = minX < nx ? minX : nx; 13690 minY = minY < ny ? minY : ny; 13691 minZ = minZ < nz ? minZ : nz; 13692 maxX = maxX > nx ? maxX : nx; 13693 maxY = maxY > ny ? maxY : ny; 13694 maxZ = maxZ > nz ? maxZ : nz; 13695 } 13696 min.x = minX; 13697 min.y = minY; 13698 min.z = minZ; 13699 max.x = maxX; 13700 max.y = maxY; 13701 max.z = maxZ; 13702 return this; 13703 } 13704 13705 public Matrix4d projectedGridRange(Matrix4d projector, double sLower, double sUpper, ref Matrix4d dest) { 13706 // Compute intersection with frustum edges and plane 13707 double minX = double.infinity, minY = double.infinity; 13708 double maxX = -double.infinity, maxY = -double.infinity; 13709 bool intersection = false; 13710 for (int t = 0; t < 3 * 4; t++) { 13711 double c0X, c0Y, c0Z; 13712 double c1X, c1Y, c1Z; 13713 if (t < 4) { 13714 // all x edges 13715 c0X = -1; c1X = +1; 13716 c0Y = c1Y = ((t & 1) << 1) - 1.0; 13717 c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0; 13718 } else if (t < 8) { 13719 // all y edges 13720 c0Y = -1; c1Y = +1; 13721 c0X = c1X = ((t & 1) << 1) - 1.0; 13722 c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0; 13723 } else { 13724 // all z edges 13725 c0Z = -1; c1Z = +1; 13726 c0X = c1X = ((t & 1) << 1) - 1.0; 13727 c0Y = c1Y = (((t >>> 1) & 1) << 1) - 1.0; 13728 } 13729 // unproject corners 13730 double invW = 1.0 / (m03 * c0X + m13 * c0Y + m23 * c0Z + m33); 13731 double p0x = (m00 * c0X + m10 * c0Y + m20 * c0Z + m30) * invW; 13732 double p0y = (m01 * c0X + m11 * c0Y + m21 * c0Z + m31) * invW; 13733 double p0z = (m02 * c0X + m12 * c0Y + m22 * c0Z + m32) * invW; 13734 invW = 1.0 / (m03 * c1X + m13 * c1Y + m23 * c1Z + m33); 13735 double p1x = (m00 * c1X + m10 * c1Y + m20 * c1Z + m30) * invW; 13736 double p1y = (m01 * c1X + m11 * c1Y + m21 * c1Z + m31) * invW; 13737 double p1z = (m02 * c1X + m12 * c1Y + m22 * c1Z + m32) * invW; 13738 double dirX = p1x - p0x; 13739 double dirY = p1y - p0y; 13740 double dirZ = p1z - p0z; 13741 double invDenom = 1.0 / dirY; 13742 // test for intersection 13743 for (int s = 0; s < 2; s++) { 13744 double isectT = -(p0y + (s == 0 ? sLower : sUpper)) * invDenom; 13745 if (isectT >= 0.0 && isectT <= 1.0) { 13746 intersection = true; 13747 // project with projector matrix 13748 double ix = p0x + isectT * dirX; 13749 double iz = p0z + isectT * dirZ; 13750 invW = 1.0 / (projector.m03 * ix + projector.m23 * iz + projector.m33); 13751 double px = (projector.m00 * ix + projector.m20 * iz + projector.m30) * invW; 13752 double py = (projector.m01 * ix + projector.m21 * iz + projector.m31) * invW; 13753 minX = minX < px ? minX : px; 13754 minY = minY < py ? minY : py; 13755 maxX = maxX > px ? maxX : px; 13756 maxY = maxY > py ? maxY : py; 13757 } 13758 } 13759 } 13760 if (!intersection) 13761 return dest; // <- projected grid is not visible 13762 dest.set(maxX - minX, 0, 0, 0, 0, maxY - minY, 0, 0, 0, 0, 1, 0, minX, minY, 0, 1) 13763 ._properties(PROPERTY_AFFINE); 13764 return dest; 13765 } 13766 13767 public Matrix4d perspectiveFrustumSlice(double near, double far, ref Matrix4d dest) { 13768 double invOldNear = (m23 + m22) / m32; 13769 double invNearFar = 1.0 / (near - far); 13770 dest._m00(m00 * invOldNear * near) 13771 ._m01(m01) 13772 ._m02(m02) 13773 ._m03(m03) 13774 ._m10(m10) 13775 ._m11(m11 * invOldNear * near) 13776 ._m12(m12) 13777 ._m13(m13) 13778 ._m20(m20) 13779 ._m21(m21) 13780 ._m22((far + near) * invNearFar) 13781 ._m23(m23) 13782 ._m30(m30) 13783 ._m31(m31) 13784 ._m32((far + far) * near * invNearFar) 13785 ._m33(m33) 13786 ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL)); 13787 return dest; 13788 } 13789 13790 public Matrix4d orthoCrop(Matrix4d view, ref Matrix4d dest) { 13791 // determine min/max world z and min/max orthographically view-projected x/y 13792 double minX = double.infinity, maxX = -double.infinity; 13793 double minY = double.infinity, maxY = -double.infinity; 13794 double minZ = double.infinity, maxZ = -double.infinity; 13795 for (int t = 0; t < 8; t++) { 13796 double x = ((t & 1) << 1) - 1.0; 13797 double y = (((t >>> 1) & 1) << 1) - 1.0; 13798 double z = (((t >>> 2) & 1) << 1) - 1.0; 13799 double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33); 13800 double wx = (m00 * x + m10 * y + m20 * z + m30) * invW; 13801 double wy = (m01 * x + m11 * y + m21 * z + m31) * invW; 13802 double wz = (m02 * x + m12 * y + m22 * z + m32) * invW; 13803 invW = 1.0 / (view.m03 * wx + view.m13 * wy + view.m23 * wz + view.m33); 13804 double vx = view.m00 * wx + view.m10 * wy + view.m20 * wz + view.m30; 13805 double vy = view.m01 * wx + view.m11 * wy + view.m21 * wz + view.m31; 13806 double vz = (view.m02 * wx + view.m12 * wy + view.m22 * wz + view.m32) * invW; 13807 minX = minX < vx ? minX : vx; 13808 maxX = maxX > vx ? maxX : vx; 13809 minY = minY < vy ? minY : vy; 13810 maxY = maxY > vy ? maxY : vy; 13811 minZ = minZ < vz ? minZ : vz; 13812 maxZ = maxZ > vz ? maxZ : vz; 13813 } 13814 // build crop projection matrix to fit 'this' frustum into view 13815 return dest.setOrtho(minX, maxX, minY, maxY, -maxZ, -minZ); 13816 } 13817 13818 /** 13819 * Set <code>this</code> matrix to a perspective transformation that maps the trapezoid spanned by the four corner coordinates 13820 * <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>. 13821 * <p> 13822 * The corner coordinates are given in counter-clockwise order starting from the <i>left</i> corner on the smaller parallel side of the trapezoid 13823 * seen when looking at the trapezoid oriented with its shorter parallel edge at the bottom and its longer parallel edge at the top. 13824 * <p> 13825 * Reference: <a href="http://www.comp.nus.edu.sg/~tants/tsm/TSM_recipe.html">Trapezoidal Shadow Maps (TSM) - Recipe</a> 13826 * 13827 * @param p0x 13828 * the x coordinate of the left corner at the shorter edge of the trapezoid 13829 * @param p0y 13830 * the y coordinate of the left corner at the shorter edge of the trapezoid 13831 * @param p1x 13832 * the x coordinate of the right corner at the shorter edge of the trapezoid 13833 * @param p1y 13834 * the y coordinate of the right corner at the shorter edge of the trapezoid 13835 * @param p2x 13836 * the x coordinate of the right corner at the longer edge of the trapezoid 13837 * @param p2y 13838 * the y coordinate of the right corner at the longer edge of the trapezoid 13839 * @param p3x 13840 * the x coordinate of the left corner at the longer edge of the trapezoid 13841 * @param p3y 13842 * the y coordinate of the left corner at the longer edge of the trapezoid 13843 * @return this 13844 */ 13845 ref public Matrix4d trapezoidCrop(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y, double p3x, double p3y) return { 13846 double aX = p1y - p0y, aY = p0x - p1x; 13847 double nm00 = aY; 13848 double nm10 = -aX; 13849 double nm30 = aX * p0y - aY * p0x; 13850 double nm01 = aX; 13851 double nm11 = aY; 13852 double nm31 = -(aX * p0x + aY * p0y); 13853 double c3x = nm00 * p3x + nm10 * p3y + nm30; 13854 double c3y = nm01 * p3x + nm11 * p3y + nm31; 13855 double s = -c3x / c3y; 13856 nm00 += s * nm01; 13857 nm10 += s * nm11; 13858 nm30 += s * nm31; 13859 double d1x = nm00 * p1x + nm10 * p1y + nm30; 13860 double d2x = nm00 * p2x + nm10 * p2y + nm30; 13861 double d = d1x * c3y / (d2x - d1x); 13862 nm31 += d; 13863 double sx = 2.0 / d2x; 13864 double sy = 1.0 / (c3y + d); 13865 double u = (sy + sy) * d / (1.0 - sy * d); 13866 double m03 = nm01 * sy; 13867 double m13 = nm11 * sy; 13868 double m33 = nm31 * sy; 13869 nm01 = (u + 1.0) * m03; 13870 nm11 = (u + 1.0) * m13; 13871 nm31 = (u + 1.0) * m33 - u; 13872 nm00 = sx * nm00 - m03; 13873 nm10 = sx * nm10 - m13; 13874 nm30 = sx * nm30 - m33; 13875 set(nm00, nm01, 0, m03, 13876 nm10, nm11, 0, m13, 13877 0, 0, 1, 0, 13878 nm30, nm31, 0, m33); 13879 properties = 0; 13880 return this; 13881 } 13882 13883 ref public Matrix4d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, ref Vector3d outMin, ref Vector3d outMax) return { 13884 double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX; 13885 double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX; 13886 double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY; 13887 double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY; 13888 double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ; 13889 double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ; 13890 double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz; 13891 double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz; 13892 if (xax < xbx) { 13893 xminx = xax; 13894 xmaxx = xbx; 13895 } else { 13896 xminx = xbx; 13897 xmaxx = xax; 13898 } 13899 if (xay < xby) { 13900 xminy = xay; 13901 xmaxy = xby; 13902 } else { 13903 xminy = xby; 13904 xmaxy = xay; 13905 } 13906 if (xaz < xbz) { 13907 xminz = xaz; 13908 xmaxz = xbz; 13909 } else { 13910 xminz = xbz; 13911 xmaxz = xaz; 13912 } 13913 if (yax < ybx) { 13914 yminx = yax; 13915 ymaxx = ybx; 13916 } else { 13917 yminx = ybx; 13918 ymaxx = yax; 13919 } 13920 if (yay < yby) { 13921 yminy = yay; 13922 ymaxy = yby; 13923 } else { 13924 yminy = yby; 13925 ymaxy = yay; 13926 } 13927 if (yaz < ybz) { 13928 yminz = yaz; 13929 ymaxz = ybz; 13930 } else { 13931 yminz = ybz; 13932 ymaxz = yaz; 13933 } 13934 if (zax < zbx) { 13935 zminx = zax; 13936 zmaxx = zbx; 13937 } else { 13938 zminx = zbx; 13939 zmaxx = zax; 13940 } 13941 if (zay < zby) { 13942 zminy = zay; 13943 zmaxy = zby; 13944 } else { 13945 zminy = zby; 13946 zmaxy = zay; 13947 } 13948 if (zaz < zbz) { 13949 zminz = zaz; 13950 zmaxz = zbz; 13951 } else { 13952 zminz = zbz; 13953 zmaxz = zaz; 13954 } 13955 outMin.x = xminx + yminx + zminx + m30; 13956 outMin.y = xminy + yminy + zminy + m31; 13957 outMin.z = xminz + yminz + zminz + m32; 13958 outMax.x = xmaxx + ymaxx + zmaxx + m30; 13959 outMax.y = xmaxy + ymaxy + zmaxy + m31; 13960 outMax.z = xmaxz + ymaxz + zmaxz + m32; 13961 return this; 13962 } 13963 13964 ref public Matrix4d transformAab(ref Vector3d min, ref Vector3d max, ref Vector3d outMin, ref Vector3d outMax) return { 13965 return transformAab(min.x, min.y, min.z, max.x, max.y, max.z, outMin, outMax); 13966 } 13967 13968 /** 13969 * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code> 13970 * and store the result in <code>this</code>. 13971 * <p> 13972 * 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> 13973 * then the result is <code>other</code>. 13974 * 13975 * @param other 13976 * the other matrix 13977 * @param t 13978 * the interpolation factor between 0.0 and 1.0 13979 * @return this 13980 */ 13981 ref public Matrix4d lerp(Matrix4d other, double t) return { 13982 lerp(other, t, this); 13983 return this; 13984 } 13985 13986 public Matrix4d lerp(Matrix4d other, double t, ref Matrix4d dest) { 13987 dest._m00(Math.fma(other.m00 - m00, t, m00)) 13988 ._m01(Math.fma(other.m01 - m01, t, m01)) 13989 ._m02(Math.fma(other.m02 - m02, t, m02)) 13990 ._m03(Math.fma(other.m03 - m03, t, m03)) 13991 ._m10(Math.fma(other.m10 - m10, t, m10)) 13992 ._m11(Math.fma(other.m11 - m11, t, m11)) 13993 ._m12(Math.fma(other.m12 - m12, t, m12)) 13994 ._m13(Math.fma(other.m13 - m13, t, m13)) 13995 ._m20(Math.fma(other.m20 - m20, t, m20)) 13996 ._m21(Math.fma(other.m21 - m21, t, m21)) 13997 ._m22(Math.fma(other.m22 - m22, t, m22)) 13998 ._m23(Math.fma(other.m23 - m23, t, m23)) 13999 ._m30(Math.fma(other.m30 - m30, t, m30)) 14000 ._m31(Math.fma(other.m31 - m31, t, m31)) 14001 ._m32(Math.fma(other.m32 - m32, t, m32)) 14002 ._m33(Math.fma(other.m33 - m33, t, m33)) 14003 ._properties(properties & other.properties); 14004 return dest; 14005 } 14006 14007 /** 14008 * Apply a model transformation to this matrix for a right-handed coordinate system, 14009 * that aligns the local <code>+Z</code> axis with <code>direction</code> 14010 * and store the result in <code>dest</code>. 14011 * <p> 14012 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14013 * then the new matrix will be <code>M * L</code>. So when transforming a 14014 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14015 * the lookat transformation will be applied first! 14016 * <p> 14017 * In order to set the matrix to a rotation transformation without post-multiplying it, 14018 * use {@link #rotationTowards(ref Vector3d, Vector3d) rotationTowards()}. 14019 * <p> 14020 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine(), dest)</code> 14021 * 14022 * @see #rotateTowards(double, double, double, double, double, double, Matrix4d) 14023 * @see #rotationTowards(ref Vector3d, Vector3d) 14024 * 14025 * @param direction 14026 * the direction to rotate towards 14027 * @param up 14028 * the up vector 14029 * @param dest 14030 * will hold the result 14031 * @return dest 14032 */ 14033 public Matrix4d rotateTowards(ref Vector3d direction, Vector3d up, ref Matrix4d dest) { 14034 return rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, dest); 14035 } 14036 14037 /** 14038 * Apply a model transformation to this matrix for a right-handed coordinate system, 14039 * that aligns the local <code>+Z</code> axis with <code>direction</code>. 14040 * <p> 14041 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14042 * then the new matrix will be <code>M * L</code>. So when transforming a 14043 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14044 * the lookat transformation will be applied first! 14045 * <p> 14046 * In order to set the matrix to a rotation transformation without post-multiplying it, 14047 * use {@link #rotationTowards(ref Vector3d, Vector3d) rotationTowards()}. 14048 * <p> 14049 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine())</code> 14050 * 14051 * @see #rotateTowards(double, double, double, double, double, double) 14052 * @see #rotationTowards(ref Vector3d, Vector3d) 14053 * 14054 * @param direction 14055 * the direction to orient towards 14056 * @param up 14057 * the up vector 14058 * @return this 14059 */ 14060 ref public Matrix4d rotateTowards(ref Vector3d direction, Vector3d up) return { 14061 rotateTowards(direction.x, direction.y, direction.z, up.x, up.y, up.z, this); 14062 return this; 14063 } 14064 14065 /** 14066 * Apply a model transformation to this matrix for a right-handed coordinate system, 14067 * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>. 14068 * <p> 14069 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14070 * then the new matrix will be <code>M * L</code>. So when transforming a 14071 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14072 * the lookat transformation will be applied first! 14073 * <p> 14074 * In order to set the matrix to a rotation transformation without post-multiplying it, 14075 * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}. 14076 * <p> 14077 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine())</code> 14078 * 14079 * @see #rotateTowards(ref Vector3d, Vector3d) 14080 * @see #rotationTowards(double, double, double, double, double, double) 14081 * 14082 * @param dirX 14083 * the x-coordinate of the direction to rotate towards 14084 * @param dirY 14085 * the y-coordinate of the direction to rotate towards 14086 * @param dirZ 14087 * the z-coordinate of the direction to rotate towards 14088 * @param upX 14089 * the x-coordinate of the up vector 14090 * @param upY 14091 * the y-coordinate of the up vector 14092 * @param upZ 14093 * the z-coordinate of the up vector 14094 * @return this 14095 */ 14096 ref public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14097 rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this); 14098 return this; 14099 } 14100 14101 /** 14102 * Apply a model transformation to this matrix for a right-handed coordinate system, 14103 * that aligns the local <code>+Z</code> axis with <code>dir</code> 14104 * and store the result in <code>dest</code>. 14105 * <p> 14106 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix, 14107 * then the new matrix will be <code>M * L</code>. So when transforming a 14108 * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, 14109 * the lookat transformation will be applied first! 14110 * <p> 14111 * In order to set the matrix to a rotation transformation without post-multiplying it, 14112 * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}. 14113 * <p> 14114 * This method is equivalent to calling: <code>mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)</code> 14115 * 14116 * @see #rotateTowards(ref Vector3d, Vector3d) 14117 * @see #rotationTowards(double, double, double, double, double, double) 14118 * 14119 * @param dirX 14120 * the x-coordinate of the direction to rotate towards 14121 * @param dirY 14122 * the y-coordinate of the direction to rotate towards 14123 * @param dirZ 14124 * the z-coordinate of the direction to rotate towards 14125 * @param upX 14126 * the x-coordinate of the up vector 14127 * @param upY 14128 * the y-coordinate of the up vector 14129 * @param upZ 14130 * the z-coordinate of the up vector 14131 * @param dest 14132 * will hold the result 14133 * @return dest 14134 */ 14135 public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4d dest) { 14136 // Normalize direction 14137 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14138 double ndirX = dirX * invDirLength; 14139 double ndirY = dirY * invDirLength; 14140 double ndirZ = dirZ * invDirLength; 14141 // left = up x direction 14142 double leftX, leftY, leftZ; 14143 leftX = upY * ndirZ - upZ * ndirY; 14144 leftY = upZ * ndirX - upX * ndirZ; 14145 leftZ = upX * ndirY - upY * ndirX; 14146 // normalize left 14147 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14148 leftX *= invLeftLength; 14149 leftY *= invLeftLength; 14150 leftZ *= invLeftLength; 14151 // up = direction x left 14152 double upnX = ndirY * leftZ - ndirZ * leftY; 14153 double upnY = ndirZ * leftX - ndirX * leftZ; 14154 double upnZ = ndirX * leftY - ndirY * leftX; 14155 double rm00 = leftX; 14156 double rm01 = leftY; 14157 double rm02 = leftZ; 14158 double rm10 = upnX; 14159 double rm11 = upnY; 14160 double rm12 = upnZ; 14161 double rm20 = ndirX; 14162 double rm21 = ndirY; 14163 double rm22 = ndirZ; 14164 double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; 14165 double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; 14166 double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; 14167 double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02; 14168 double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; 14169 double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; 14170 double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; 14171 double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12; 14172 dest._m30(m30) 14173 ._m31(m31) 14174 ._m32(m32) 14175 ._m33(m33) 14176 ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) 14177 ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) 14178 ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) 14179 ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22) 14180 ._m00(nm00) 14181 ._m01(nm01) 14182 ._m02(nm02) 14183 ._m03(nm03) 14184 ._m10(nm10) 14185 ._m11(nm11) 14186 ._m12(nm12) 14187 ._m13(nm13) 14188 ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 14189 return dest; 14190 } 14191 14192 /** 14193 * Set this matrix to a model transformation for a right-handed coordinate system, 14194 * that aligns the local <code>-z</code> axis with <code>dir</code>. 14195 * <p> 14196 * In order to apply the rotation transformation to a previous existing transformation, 14197 * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}. 14198 * <p> 14199 * This method is equivalent to calling: <code>setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine()</code> 14200 * 14201 * @see #rotationTowards(ref Vector3d, Vector3d) 14202 * @see #rotateTowards(double, double, double, double, double, double) 14203 * 14204 * @param dir 14205 * the direction to orient the local -z axis towards 14206 * @param up 14207 * the up vector 14208 * @return this 14209 */ 14210 ref public Matrix4d rotationTowards(ref Vector3d dir, Vector3d up) return { 14211 return rotationTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z); 14212 } 14213 14214 /** 14215 * Set this matrix to a model transformation for a right-handed coordinate system, 14216 * that aligns the local <code>-z</code> axis with <code>dir</code>. 14217 * <p> 14218 * In order to apply the rotation transformation to a previous existing transformation, 14219 * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}. 14220 * <p> 14221 * This method is equivalent to calling: <code>setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine()</code> 14222 * 14223 * @see #rotateTowards(ref Vector3d, Vector3d) 14224 * @see #rotationTowards(double, double, double, double, double, double) 14225 * 14226 * @param dirX 14227 * the x-coordinate of the direction to rotate towards 14228 * @param dirY 14229 * the y-coordinate of the direction to rotate towards 14230 * @param dirZ 14231 * the z-coordinate of the direction to rotate towards 14232 * @param upX 14233 * the x-coordinate of the up vector 14234 * @param upY 14235 * the y-coordinate of the up vector 14236 * @param upZ 14237 * the z-coordinate of the up vector 14238 * @return this 14239 */ 14240 ref public Matrix4d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14241 // Normalize direction 14242 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14243 double ndirX = dirX * invDirLength; 14244 double ndirY = dirY * invDirLength; 14245 double ndirZ = dirZ * invDirLength; 14246 // left = up x direction 14247 double leftX, leftY, leftZ; 14248 leftX = upY * ndirZ - upZ * ndirY; 14249 leftY = upZ * ndirX - upX * ndirZ; 14250 leftZ = upX * ndirY - upY * ndirX; 14251 // normalize left 14252 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14253 leftX *= invLeftLength; 14254 leftY *= invLeftLength; 14255 leftZ *= invLeftLength; 14256 // up = direction x left 14257 double upnX = ndirY * leftZ - ndirZ * leftY; 14258 double upnY = ndirZ * leftX - ndirX * leftZ; 14259 double upnZ = ndirX * leftY - ndirY * leftX; 14260 if ((properties & PROPERTY_IDENTITY) == 0) 14261 this._identity(); 14262 setm00(leftX); 14263 setm01(leftY); 14264 setm02(leftZ); 14265 setm10(upnX); 14266 setm11(upnY); 14267 setm12(upnZ); 14268 setm20(ndirX); 14269 setm21(ndirY); 14270 setm22(ndirZ); 14271 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 14272 return this; 14273 } 14274 14275 /** 14276 * Set this matrix to a model transformation for a right-handed coordinate system, 14277 * that translates to the given <code>pos</code> and aligns the local <code>-z</code> 14278 * axis with <code>dir</code>. 14279 * <p> 14280 * This method is equivalent to calling: <code>translation(pos).rotateTowards(dir, up)</code> 14281 * 14282 * @see #translation(ref Vector3d) 14283 * @see #rotateTowards(ref Vector3d, Vector3d) 14284 * 14285 * @param pos 14286 * the position to translate to 14287 * @param dir 14288 * the direction to rotate towards 14289 * @param up 14290 * the up vector 14291 * @return this 14292 */ 14293 ref public Matrix4d translationRotateTowards(ref Vector3d pos, Vector3d dir, Vector3d up) return { 14294 return translationRotateTowards(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); 14295 } 14296 14297 /** 14298 * Set this matrix to a model transformation for a right-handed coordinate system, 14299 * that translates to the given <code>(posX, posY, posZ)</code> and aligns the local <code>-z</code> 14300 * axis with <code>(dirX, dirY, dirZ)</code>. 14301 * <p> 14302 * This method is equivalent to calling: <code>translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)</code> 14303 * 14304 * @see #translation(double, double, double) 14305 * @see #rotateTowards(double, double, double, double, double, double) 14306 * 14307 * @param posX 14308 * the x-coordinate of the position to translate to 14309 * @param posY 14310 * the y-coordinate of the position to translate to 14311 * @param posZ 14312 * the z-coordinate of the position to translate to 14313 * @param dirX 14314 * the x-coordinate of the direction to rotate towards 14315 * @param dirY 14316 * the y-coordinate of the direction to rotate towards 14317 * @param dirZ 14318 * the z-coordinate of the direction to rotate towards 14319 * @param upX 14320 * the x-coordinate of the up vector 14321 * @param upY 14322 * the y-coordinate of the up vector 14323 * @param upZ 14324 * the z-coordinate of the up vector 14325 * @return this 14326 */ 14327 ref public Matrix4d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 14328 // Normalize direction 14329 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 14330 double ndirX = dirX * invDirLength; 14331 double ndirY = dirY * invDirLength; 14332 double ndirZ = dirZ * invDirLength; 14333 // left = up x direction 14334 double leftX, leftY, leftZ; 14335 leftX = upY * ndirZ - upZ * ndirY; 14336 leftY = upZ * ndirX - upX * ndirZ; 14337 leftZ = upX * ndirY - upY * ndirX; 14338 // normalize left 14339 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 14340 leftX *= invLeftLength; 14341 leftY *= invLeftLength; 14342 leftZ *= invLeftLength; 14343 // up = direction x left 14344 double upnX = ndirY * leftZ - ndirZ * leftY; 14345 double upnY = ndirZ * leftX - ndirX * leftZ; 14346 double upnZ = ndirX * leftY - ndirY * leftX; 14347 setm00(leftX); 14348 setm01(leftY); 14349 setm02(leftZ); 14350 setm03(0.0); 14351 setm10(upnX); 14352 setm11(upnY); 14353 setm12(upnZ); 14354 setm13(0.0); 14355 setm20(ndirX); 14356 setm21(ndirY); 14357 setm22(ndirZ); 14358 setm23(0.0); 14359 setm30(posX); 14360 setm31(posY); 14361 setm32(posZ); 14362 setm33(1.0); 14363 properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL; 14364 return this; 14365 } 14366 14367 public Vector3d getEulerAnglesZYX(ref Vector3d dest) { 14368 dest.x = Math.atan2(m12, m22); 14369 dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02)); 14370 dest.z = Math.atan2(m01, m00); 14371 return dest; 14372 } 14373 14374 public Vector3d getEulerAnglesXYZ(ref Vector3d dest) { 14375 dest.x = Math.atan2(-m21, m22); 14376 dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20)); 14377 dest.z = Math.atan2(-m10, m00); 14378 return dest; 14379 } 14380 14381 /** 14382 * Compute the extents of the coordinate system before this {@link #isAffine() affine} transformation was applied 14383 * and store the resulting corner coordinates in <code>corner</code> and the span vectors in 14384 * <code>xDir</code>, <code>yDir</code> and <code>zDir</code>. 14385 * <p> 14386 * That means, given the maximum extents of the coordinate system between <code>[-1..+1]</code> in all dimensions, 14387 * this method returns one corner and the length and direction of the three base axis vectors in the coordinate 14388 * system before this transformation is applied, which transforms into the corner coordinates <code>[-1, +1]</code>. 14389 * <p> 14390 * This method is equivalent to computing at least three adjacent corners using {@link #frustumCorner(int, Vector3d)} 14391 * and subtracting them to obtain the length and direction of the span vectors. 14392 * 14393 * @param corner 14394 * will hold one corner of the span (usually the corner {@link Matrix4d#CORNER_NXNYNZ}) 14395 * @param xDir 14396 * will hold the direction and length of the span along the positive X axis 14397 * @param yDir 14398 * will hold the direction and length of the span along the positive Y axis 14399 * @param zDir 14400 * will hold the direction and length of the span along the positive z axis 14401 * @return this 14402 */ 14403 ref public Matrix4d affineSpan(ref Vector3d corner, ref Vector3d xDir, ref Vector3d yDir, ref Vector3d zDir) return { 14404 double a = m10 * m22, b = m10 * m21, c = m10 * m02, d = m10 * m01; 14405 double e = m11 * m22, f = m11 * m20, g = m11 * m02, h = m11 * m00; 14406 double i = m12 * m21, j = m12 * m20, k = m12 * m01, l = m12 * m00; 14407 double m = m20 * m02, n = m20 * m01, o = m21 * m02, p = m21 * m00; 14408 double q = m22 * m01, r = m22 * m00; 14409 double s = 1.0 / (m00 * m11 - m01 * m10) * m22 + (m02 * m10 - m00 * m12) * m21 + (m01 * m12 - m02 * m11) * m20; 14410 double nm00 = (e - i) * s, nm01 = (o - q) * s, nm02 = (k - g) * s; 14411 double nm10 = (j - a) * s, nm11 = (r - m) * s, nm12 = (c - l) * s; 14412 double nm20 = (b - f) * s, nm21 = (n - p) * s, nm22 = (h - d) * s; 14413 corner.x = -nm00 - nm10 - nm20 + (a * m31 - b * m32 + f * m32 - e * m30 + i * m30 - j * m31) * s; 14414 corner.y = -nm01 - nm11 - nm21 + (m * m31 - n * m32 + p * m32 - o * m30 + q * m30 - r * m31) * s; 14415 corner.z = -nm02 - nm12 - nm22 + (g * m30 - k * m30 + l * m31 - c * m31 + d * m32 - h * m32) * s; 14416 xDir.x = 2.0 * nm00; xDir.y = 2.0 * nm01; xDir.z = 2.0 * nm02; 14417 yDir.x = 2.0 * nm10; yDir.y = 2.0 * nm11; yDir.z = 2.0 * nm12; 14418 zDir.x = 2.0 * nm20; zDir.y = 2.0 * nm21; zDir.z = 2.0 * nm22; 14419 return this; 14420 } 14421 14422 public bool testPoint(double x, double y, double z) { 14423 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14424 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14425 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14426 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14427 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14428 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14429 return nxX * x + nxY * y + nxZ * z + nxW >= 0 && pxX * x + pxY * y + pxZ * z + pxW >= 0 && 14430 nyX * x + nyY * y + nyZ * z + nyW >= 0 && pyX * x + pyY * y + pyZ * z + pyW >= 0 && 14431 nzX * x + nzY * y + nzZ * z + nzW >= 0 && pzX * x + pzY * y + pzZ * z + pzW >= 0; 14432 } 14433 14434 public bool testSphere(double x, double y, double z, double r) { 14435 double invl; 14436 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14437 invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ); 14438 nxX *= invl; nxY *= invl; nxZ *= invl; nxW *= invl; 14439 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14440 invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ); 14441 pxX *= invl; pxY *= invl; pxZ *= invl; pxW *= invl; 14442 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14443 invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ); 14444 nyX *= invl; nyY *= invl; nyZ *= invl; nyW *= invl; 14445 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14446 invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ); 14447 pyX *= invl; pyY *= invl; pyZ *= invl; pyW *= invl; 14448 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14449 invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ); 14450 nzX *= invl; nzY *= invl; nzZ *= invl; nzW *= invl; 14451 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14452 invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ); 14453 pzX *= invl; pzY *= invl; pzZ *= invl; pzW *= invl; 14454 return nxX * x + nxY * y + nxZ * z + nxW >= -r && pxX * x + pxY * y + pxZ * z + pxW >= -r && 14455 nyX * x + nyY * y + nyZ * z + nyW >= -r && pyX * x + pyY * y + pyZ * z + pyW >= -r && 14456 nzX * x + nzY * y + nzZ * z + nzW >= -r && pzX * x + pzY * y + pzZ * z + pzW >= -r; 14457 } 14458 14459 public bool testAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { 14460 double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30; 14461 double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30; 14462 double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31; 14463 double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31; 14464 double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32; 14465 double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32; 14466 /* 14467 * This is an implementation of the "2.4 Basic intersection test" of the mentioned site. 14468 * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted. 14469 */ 14470 return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW && 14471 pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW && 14472 nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW && 14473 pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW && 14474 nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW && 14475 pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW; 14476 } 14477 14478 /** 14479 * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and 14480 * <code>b</code>. 14481 * <p> 14482 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix, 14483 * then the new matrix will be <code>M * O</code>. So when transforming a 14484 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 14485 * oblique transformation will be applied first! 14486 * <p> 14487 * The oblique transformation is defined as: 14488 * <pre> 14489 * x' = x + a*z 14490 * y' = y + a*z 14491 * z' = z 14492 * </pre> 14493 * or in matrix form: 14494 * <pre> 14495 * 1 0 a 0 14496 * 0 1 b 0 14497 * 0 0 1 0 14498 * 0 0 0 1 14499 * </pre> 14500 * 14501 * @param a 14502 * the value for the z factor that applies to x 14503 * @param b 14504 * the value for the z factor that applies to y 14505 * @return this 14506 */ 14507 ref public Matrix4d obliqueZ(double a, double b) return { 14508 setm20(m00 * a + m10 * b + m20); 14509 setm21(m01 * a + m11 * b + m21); 14510 setm22(m02 * a + m12 * b + m22); 14511 this.properties &= PROPERTY_AFFINE; 14512 return this; 14513 } 14514 14515 /** 14516 * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and 14517 * <code>b</code> and store the result in <code>dest</code>. 14518 * <p> 14519 * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix, 14520 * then the new matrix will be <code>M * O</code>. So when transforming a 14521 * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the 14522 * oblique transformation will be applied first! 14523 * <p> 14524 * The oblique transformation is defined as: 14525 * <pre> 14526 * x' = x + a*z 14527 * y' = y + a*z 14528 * z' = z 14529 * </pre> 14530 * or in matrix form: 14531 * <pre> 14532 * 1 0 a 0 14533 * 0 1 b 0 14534 * 0 0 1 0 14535 * 0 0 0 1 14536 * </pre> 14537 * 14538 * @param a 14539 * the value for the z factor that applies to x 14540 * @param b 14541 * the value for the z factor that applies to y 14542 * @param dest 14543 * will hold the result 14544 * @return dest 14545 */ 14546 public Matrix4d obliqueZ(double a, double b, ref Matrix4d dest) { 14547 dest._m00(m00) 14548 ._m01(m01) 14549 ._m02(m02) 14550 ._m03(m03) 14551 ._m10(m10) 14552 ._m11(m11) 14553 ._m12(m12) 14554 ._m13(m13) 14555 ._m20(m00 * a + m10 * b + m20) 14556 ._m21(m01 * a + m11 * b + m21) 14557 ._m22(m02 * a + m12 * b + m22) 14558 ._m23(m23) 14559 ._m30(m30) 14560 ._m31(m31) 14561 ._m32(m32) 14562 ._m33(m33) 14563 ._properties(properties & PROPERTY_AFFINE); 14564 return dest; 14565 } 14566 14567 /** 14568 * 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 14569 * and the extents of the near plane rectangle along its local <code>x</code> and <code>y</code> axes, and store the resulting matrices 14570 * in <code>projDest</code> and <code>viewDest</code>. 14571 * <p> 14572 * This method creates a view and perspective projection matrix assuming that there is a pinhole camera at position <code>eye</code> 14573 * projecting the scene onto the near plane defined by the rectangle. 14574 * <p> 14575 * All positions and lengths are in the same (world) unit. 14576 * 14577 * @param eye 14578 * the position of the camera 14579 * @param p 14580 * the bottom left corner of the near plane rectangle (will map to the bottom left corner in window coordinates) 14581 * @param x 14582 * the direction and length of the local "bottom/top" X axis/side of the near plane rectangle 14583 * @param y 14584 * the direction and length of the local "left/right" Y axis/side of the near plane rectangle 14585 * @param nearFarDist 14586 * the distance between the far and near plane (the near plane will be calculated by this method). 14587 * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity. 14588 * If the special value {@link Double#NEGATIVE_INFINITY} is used, the near and far planes will be swapped and 14589 * the near clipping plane will be at positive infinity. 14590 * If a negative value is used (except for {@link Double#NEGATIVE_INFINITY}) the near and far planes will be swapped 14591 * @param zeroToOne 14592 * whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code> 14593 * or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code> 14594 * @param projDest 14595 * will hold the resulting projection matrix 14596 * @param viewDest 14597 * will hold the resulting view matrix 14598 */ 14599 public static void projViewFromRectangle( 14600 Vector3d eye, Vector3d p, Vector3d x, Vector3d y, double nearFarDist, bool zeroToOne, 14601 ref Matrix4d projDest, ref Matrix4d viewDest) { 14602 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; 14603 double zd = zx * (p.x - eye.x) + zy * (p.y - eye.y) + zz * (p.z - eye.z); 14604 double zs = zd >= 0 ? 1 : -1; zx *= zs; zy *= zs; zz *= zs; zd *= zs; 14605 viewDest.setLookAt(eye.x, eye.y, eye.z, eye.x + zx, eye.y + zy, eye.z + zz, y.x, y.y, y.z); 14606 double px = viewDest.m00 * p.x + viewDest.m10 * p.y + viewDest.m20 * p.z + viewDest.m30; 14607 double py = viewDest.m01 * p.x + viewDest.m11 * p.y + viewDest.m21 * p.z + viewDest.m31; 14608 double tx = viewDest.m00 * x.x + viewDest.m10 * x.y + viewDest.m20 * x.z; 14609 double ty = viewDest.m01 * y.x + viewDest.m11 * y.y + viewDest.m21 * y.z; 14610 double len = Math.sqrt(zx * zx + zy * zy + zz * zz); 14611 double near = zd / len, far; 14612 if (Math.isInfinite(nearFarDist) && nearFarDist < 0.0) { 14613 far = near; 14614 near = double.infinity; 14615 } else if (Math.isInfinite(nearFarDist) && nearFarDist > 0.0) { 14616 far = double.infinity; 14617 } else if (nearFarDist < 0.0) { 14618 far = near; 14619 near = near + nearFarDist; 14620 } else { 14621 far = near + nearFarDist; 14622 } 14623 projDest.setFrustum(px, px + tx, py, py + ty, near, far, zeroToOne); 14624 } 14625 14626 /** 14627 * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(ref Vector3d)}) 14628 * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(ref Vector3d)}) and the 14629 * given vector <code>up</code>. 14630 * <p> 14631 * This effectively ensures that the resulting matrix will be equal to the one obtained from 14632 * {@link #setLookAt(ref Vector3d, Vector3d, Vector3d)} called with the current 14633 * local origin of this matrix (as obtained by {@link #originAffine(ref Vector3d)}), the sum of this position and the 14634 * negated local Z axis as well as the given vector <code>up</code>. 14635 * <p> 14636 * This method must only be called on {@link #isAffine()} matrices. 14637 * 14638 * @param up 14639 * the up vector 14640 * @return this 14641 */ 14642 ref public Matrix4d withLookAtUp(ref Vector3d up) return { 14643 withLookAtUp(up.x, up.y, up.z, this); 14644 return this; 14645 } 14646 14647 public Matrix4d withLookAtUp(ref Vector3d up, ref Matrix4d dest) { 14648 return dest.withLookAtUp(up.x, up.y, up.z); 14649 } 14650 14651 /** 14652 * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(ref Vector3d)}) 14653 * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(ref Vector3d)}) and the 14654 * given vector <code>(upX, upY, upZ)</code>. 14655 * <p> 14656 * This effectively ensures that the resulting matrix will be equal to the one obtained from 14657 * {@link #setLookAt(double, double, double, double, double, double, double, double, double)} called with the current 14658 * local origin of this matrix (as obtained by {@link #originAffine(ref Vector3d)}), the sum of this position and the 14659 * negated local Z axis as well as the given vector <code>(upX, upY, upZ)</code>. 14660 * <p> 14661 * This method must only be called on {@link #isAffine()} matrices. 14662 * 14663 * @param upX 14664 * the x coordinate of the up vector 14665 * @param upY 14666 * the y coordinate of the up vector 14667 * @param upZ 14668 * the z coordinate of the up vector 14669 * @return this 14670 */ 14671 ref public Matrix4d withLookAtUp(double upX, double upY, double upZ) return { 14672 withLookAtUp(upX, upY, upZ, this); 14673 return this; 14674 } 14675 14676 public Matrix4d withLookAtUp(double upX, double upY, double upZ, ref Matrix4d dest) { 14677 double y = (upY * m21 - upZ * m11) * m02 + 14678 (upZ * m01 - upX * m21) * m12 + 14679 (upX * m11 - upY * m01) * m22; 14680 double x = upX * m01 + upY * m11 + upZ * m21; 14681 if ((properties & PROPERTY_ORTHONORMAL) == 0) 14682 x *= Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21); 14683 double invsqrt = Math.invsqrt(y * y + x * x); 14684 double c = x * invsqrt, s = y * invsqrt; 14685 double nm00 = c * m00 - s * m01, nm10 = c * m10 - s * m11, nm20 = c * m20 - s * m21, nm31 = s * m30 + c * m31; 14686 double nm01 = s * m00 + c * m01, nm11 = s * m10 + c * m11, nm21 = s * m20 + c * m21, nm30 = c * m30 - s * m31; 14687 dest._m00(nm00)._m10(nm10)._m20(nm20)._m30(nm30) 14688 ._m01(nm01)._m11(nm11)._m21(nm21)._m31(nm31); 14689 if (dest != this) { 14690 dest 14691 ._m02(m02)._m12(m12)._m22(m22)._m32(m32) 14692 ._m03(m03)._m13(m13)._m23(m23)._m33(m33); 14693 } 14694 dest._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION)); 14695 return dest; 14696 } 14697 14698 /** 14699 * Multiply <code>this</code> by the matrix 14700 * <pre> 14701 * 1 0 0 0 14702 * 0 0 1 0 14703 * 0 1 0 0 14704 * 0 0 0 1 14705 * </pre> 14706 * 14707 * @return this 14708 */ 14709 ref public Matrix4d mapXZY() return { 14710 mapXZY(this); 14711 return this; 14712 } 14713 public Matrix4d mapXZY(ref Matrix4d dest) { 14714 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14715 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)); 14716 } 14717 /** 14718 * Multiply <code>this</code> by the matrix 14719 * <pre> 14720 * 1 0 0 0 14721 * 0 0 -1 0 14722 * 0 1 0 0 14723 * 0 0 0 1 14724 * </pre> 14725 * 14726 * @return this 14727 */ 14728 ref public Matrix4d mapXZnY() return { 14729 mapXZnY(this); 14730 return this; 14731 } 14732 public Matrix4d mapXZnY(ref Matrix4d dest) { 14733 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14734 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)); 14735 } 14736 /** 14737 * Multiply <code>this</code> by the matrix 14738 * <pre> 14739 * 1 0 0 0 14740 * 0 -1 0 0 14741 * 0 0 -1 0 14742 * 0 0 0 1 14743 * </pre> 14744 * 14745 * @return this 14746 */ 14747 ref public Matrix4d mapXnYnZ() return { 14748 mapXnYnZ(this); 14749 return this; 14750 } 14751 public Matrix4d mapXnYnZ(ref Matrix4d dest) { 14752 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)); 14753 } 14754 /** 14755 * Multiply <code>this</code> by the matrix 14756 * <pre> 14757 * 1 0 0 0 14758 * 0 0 1 0 14759 * 0 -1 0 0 14760 * 0 0 0 1 14761 * </pre> 14762 * 14763 * @return this 14764 */ 14765 ref public Matrix4d mapXnZY() return { 14766 mapXnZY(this); 14767 return this; 14768 } 14769 public Matrix4d mapXnZY(ref Matrix4d dest) { 14770 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14771 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)); 14772 } 14773 /** 14774 * Multiply <code>this</code> by the matrix 14775 * <pre> 14776 * 1 0 0 0 14777 * 0 0 -1 0 14778 * 0 -1 0 0 14779 * 0 0 0 1 14780 * </pre> 14781 * 14782 * @return this 14783 */ 14784 ref public Matrix4d mapXnZnY() return { 14785 mapXnZnY(this); 14786 return this; 14787 } 14788 public Matrix4d mapXnZnY(ref Matrix4d dest) { 14789 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14790 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)); 14791 } 14792 /** 14793 * Multiply <code>this</code> by the matrix 14794 * <pre> 14795 * 0 1 0 0 14796 * 1 0 0 0 14797 * 0 0 1 0 14798 * 0 0 0 1 14799 * </pre> 14800 * 14801 * @return this 14802 */ 14803 ref public Matrix4d mapYXZ() return { 14804 mapYXZ(this); 14805 return this; 14806 } 14807 public Matrix4d mapYXZ(ref Matrix4d dest) { 14808 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14809 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)); 14810 } 14811 /** 14812 * Multiply <code>this</code> by the matrix 14813 * <pre> 14814 * 0 1 0 0 14815 * 1 0 0 0 14816 * 0 0 -1 0 14817 * 0 0 0 1 14818 * </pre> 14819 * 14820 * @return this 14821 */ 14822 ref public Matrix4d mapYXnZ() return { 14823 mapYXnZ(this); 14824 return this; 14825 } 14826 public Matrix4d mapYXnZ(ref Matrix4d dest) { 14827 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14828 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)); 14829 } 14830 /** 14831 * Multiply <code>this</code> by the matrix 14832 * <pre> 14833 * 0 0 1 0 14834 * 1 0 0 0 14835 * 0 1 0 0 14836 * 0 0 0 1 14837 * </pre> 14838 * 14839 * @return this 14840 */ 14841 ref public Matrix4d mapYZX() return { 14842 mapYZX(this); 14843 return this; 14844 } 14845 public Matrix4d mapYZX(ref Matrix4d dest) { 14846 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14847 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)); 14848 } 14849 /** 14850 * Multiply <code>this</code> by the matrix 14851 * <pre> 14852 * 0 0 -1 0 14853 * 1 0 0 0 14854 * 0 1 0 0 14855 * 0 0 0 1 14856 * </pre> 14857 * 14858 * @return this 14859 */ 14860 ref public Matrix4d mapYZnX() return { 14861 mapYZnX(this); 14862 return this; 14863 } 14864 public Matrix4d mapYZnX(ref Matrix4d dest) { 14865 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14866 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)); 14867 } 14868 /** 14869 * Multiply <code>this</code> by the matrix 14870 * <pre> 14871 * 0 -1 0 0 14872 * 1 0 0 0 14873 * 0 0 1 0 14874 * 0 0 0 1 14875 * </pre> 14876 * 14877 * @return this 14878 */ 14879 ref public Matrix4d mapYnXZ() return { 14880 mapYnXZ(this); 14881 return this; 14882 } 14883 public Matrix4d mapYnXZ(ref Matrix4d dest) { 14884 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14885 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)); 14886 } 14887 /** 14888 * Multiply <code>this</code> by the matrix 14889 * <pre> 14890 * 0 -1 0 0 14891 * 1 0 0 0 14892 * 0 0 -1 0 14893 * 0 0 0 1 14894 * </pre> 14895 * 14896 * @return this 14897 */ 14898 ref public Matrix4d mapYnXnZ() return { 14899 mapYnXnZ(this); 14900 return this; 14901 } 14902 public Matrix4d mapYnXnZ(ref Matrix4d dest) { 14903 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14904 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)); 14905 } 14906 /** 14907 * Multiply <code>this</code> by the matrix 14908 * <pre> 14909 * 0 0 1 0 14910 * 1 0 0 0 14911 * 0 -1 0 0 14912 * 0 0 0 1 14913 * </pre> 14914 * 14915 * @return this 14916 */ 14917 ref public Matrix4d mapYnZX() return { 14918 mapYnZX(this); 14919 return this; 14920 } 14921 public Matrix4d mapYnZX(ref Matrix4d dest) { 14922 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14923 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)); 14924 } 14925 /** 14926 * Multiply <code>this</code> by the matrix 14927 * <pre> 14928 * 0 0 -1 0 14929 * 1 0 0 0 14930 * 0 -1 0 0 14931 * 0 0 0 1 14932 * </pre> 14933 * 14934 * @return this 14935 */ 14936 ref public Matrix4d mapYnZnX() return { 14937 mapYnZnX(this); 14938 return this; 14939 } 14940 public Matrix4d mapYnZnX(ref Matrix4d dest) { 14941 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14942 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)); 14943 } 14944 /** 14945 * Multiply <code>this</code> by the matrix 14946 * <pre> 14947 * 0 1 0 0 14948 * 0 0 1 0 14949 * 1 0 0 0 14950 * 0 0 0 1 14951 * </pre> 14952 * 14953 * @return this 14954 */ 14955 ref public Matrix4d mapZXY() return { 14956 mapZXY(this); 14957 return this; 14958 } 14959 public Matrix4d mapZXY(ref Matrix4d dest) { 14960 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14961 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14962 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)); 14963 } 14964 /** 14965 * Multiply <code>this</code> by the matrix 14966 * <pre> 14967 * 0 1 0 0 14968 * 0 0 -1 0 14969 * 1 0 0 0 14970 * 0 0 0 1 14971 * </pre> 14972 * 14973 * @return this 14974 */ 14975 ref public Matrix4d mapZXnY() return { 14976 mapZXnY(this); 14977 return this; 14978 } 14979 public Matrix4d mapZXnY(ref Matrix4d dest) { 14980 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 14981 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 14982 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)); 14983 } 14984 /** 14985 * Multiply <code>this</code> by the matrix 14986 * <pre> 14987 * 0 0 1 0 14988 * 0 1 0 0 14989 * 1 0 0 0 14990 * 0 0 0 1 14991 * </pre> 14992 * 14993 * @return this 14994 */ 14995 ref public Matrix4d mapZYX() return { 14996 mapZYX(this); 14997 return this; 14998 } 14999 public Matrix4d mapZYX(ref Matrix4d dest) { 15000 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15001 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)); 15002 } 15003 /** 15004 * Multiply <code>this</code> by the matrix 15005 * <pre> 15006 * 0 0 -1 0 15007 * 0 1 0 0 15008 * 1 0 0 0 15009 * 0 0 0 1 15010 * </pre> 15011 * 15012 * @return this 15013 */ 15014 ref public Matrix4d mapZYnX() return { 15015 mapZYnX(this); 15016 return this; 15017 } 15018 public Matrix4d mapZYnX(ref Matrix4d dest) { 15019 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15020 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)); 15021 } 15022 /** 15023 * Multiply <code>this</code> by the matrix 15024 * <pre> 15025 * 0 -1 0 0 15026 * 0 0 1 0 15027 * 1 0 0 0 15028 * 0 0 0 1 15029 * </pre> 15030 * 15031 * @return this 15032 */ 15033 ref public Matrix4d mapZnXY() return { 15034 mapZnXY(this); 15035 return this; 15036 } 15037 public Matrix4d mapZnXY(ref Matrix4d dest) { 15038 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15039 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15040 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)); 15041 } 15042 /** 15043 * Multiply <code>this</code> by the matrix 15044 * <pre> 15045 * 0 -1 0 0 15046 * 0 0 -1 0 15047 * 1 0 0 0 15048 * 0 0 0 1 15049 * </pre> 15050 * 15051 * @return this 15052 */ 15053 ref public Matrix4d mapZnXnY() return { 15054 mapZnXnY(this); 15055 return this; 15056 } 15057 public Matrix4d mapZnXnY(ref Matrix4d dest) { 15058 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15059 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15060 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)); 15061 } 15062 /** 15063 * Multiply <code>this</code> by the matrix 15064 * <pre> 15065 * 0 0 1 0 15066 * 0 -1 0 0 15067 * 1 0 0 0 15068 * 0 0 0 1 15069 * </pre> 15070 * 15071 * @return this 15072 */ 15073 ref public Matrix4d mapZnYX() return { 15074 mapZnYX(this); 15075 return this; 15076 } 15077 public Matrix4d mapZnYX(ref Matrix4d dest) { 15078 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15079 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)); 15080 } 15081 /** 15082 * Multiply <code>this</code> by the matrix 15083 * <pre> 15084 * 0 0 -1 0 15085 * 0 -1 0 0 15086 * 1 0 0 0 15087 * 0 0 0 1 15088 * </pre> 15089 * 15090 * @return this 15091 */ 15092 ref public Matrix4d mapZnYnX() return { 15093 mapZnYnX(this); 15094 return this; 15095 } 15096 public Matrix4d mapZnYnX(ref Matrix4d dest) { 15097 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15098 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)); 15099 } 15100 /** 15101 * Multiply <code>this</code> by the matrix 15102 * <pre> 15103 * -1 0 0 0 15104 * 0 1 0 0 15105 * 0 0 -1 0 15106 * 0 0 0 1 15107 * </pre> 15108 * 15109 * @return this 15110 */ 15111 ref public Matrix4d mapnXYnZ() return { 15112 mapnXYnZ(this); 15113 return this; 15114 } 15115 public Matrix4d mapnXYnZ(ref Matrix4d dest) { 15116 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)); 15117 } 15118 /** 15119 * Multiply <code>this</code> by the matrix 15120 * <pre> 15121 * -1 0 0 0 15122 * 0 0 1 0 15123 * 0 1 0 0 15124 * 0 0 0 1 15125 * </pre> 15126 * 15127 * @return this 15128 */ 15129 ref public Matrix4d mapnXZY() return { 15130 mapnXZY(this); 15131 return this; 15132 } 15133 public Matrix4d mapnXZY(ref Matrix4d dest) { 15134 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15135 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)); 15136 } 15137 /** 15138 * Multiply <code>this</code> by the matrix 15139 * <pre> 15140 * -1 0 0 0 15141 * 0 0 -1 0 15142 * 0 1 0 0 15143 * 0 0 0 1 15144 * </pre> 15145 * 15146 * @return this 15147 */ 15148 ref public Matrix4d mapnXZnY() return { 15149 mapnXZnY(this); 15150 return this; 15151 } 15152 public Matrix4d mapnXZnY(ref Matrix4d dest) { 15153 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15154 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)); 15155 } 15156 /** 15157 * Multiply <code>this</code> by the matrix 15158 * <pre> 15159 * -1 0 0 0 15160 * 0 -1 0 0 15161 * 0 0 1 0 15162 * 0 0 0 1 15163 * </pre> 15164 * 15165 * @return this 15166 */ 15167 ref public Matrix4d mapnXnYZ() return { 15168 mapnXnYZ(this); 15169 return this; 15170 } 15171 public Matrix4d mapnXnYZ(ref Matrix4d dest) { 15172 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)); 15173 } 15174 /** 15175 * Multiply <code>this</code> by the matrix 15176 * <pre> 15177 * -1 0 0 0 15178 * 0 -1 0 0 15179 * 0 0 -1 0 15180 * 0 0 0 1 15181 * </pre> 15182 * 15183 * @return this 15184 */ 15185 ref public Matrix4d mapnXnYnZ() return { 15186 mapnXnYnZ(this); 15187 return this; 15188 } 15189 public Matrix4d mapnXnYnZ(ref Matrix4d dest) { 15190 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)); 15191 } 15192 /** 15193 * Multiply <code>this</code> by the matrix 15194 * <pre> 15195 * -1 0 0 0 15196 * 0 0 1 0 15197 * 0 -1 0 0 15198 * 0 0 0 1 15199 * </pre> 15200 * 15201 * @return this 15202 */ 15203 ref public Matrix4d mapnXnZY() return { 15204 mapnXnZY(this); 15205 return this; 15206 } 15207 public Matrix4d mapnXnZY(ref Matrix4d dest) { 15208 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15209 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)); 15210 } 15211 /** 15212 * Multiply <code>this</code> by the matrix 15213 * <pre> 15214 * -1 0 0 0 15215 * 0 0 -1 0 15216 * 0 -1 0 0 15217 * 0 0 0 1 15218 * </pre> 15219 * 15220 * @return this 15221 */ 15222 ref public Matrix4d mapnXnZnY() return { 15223 mapnXnZnY(this); 15224 return this; 15225 } 15226 public Matrix4d mapnXnZnY(ref Matrix4d dest) { 15227 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15228 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)); 15229 } 15230 /** 15231 * Multiply <code>this</code> by the matrix 15232 * <pre> 15233 * 0 1 0 0 15234 * -1 0 0 0 15235 * 0 0 1 0 15236 * 0 0 0 1 15237 * </pre> 15238 * 15239 * @return this 15240 */ 15241 ref public Matrix4d mapnYXZ() return { 15242 mapnYXZ(this); 15243 return this; 15244 } 15245 public Matrix4d mapnYXZ(ref Matrix4d dest) { 15246 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15247 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)); 15248 } 15249 /** 15250 * Multiply <code>this</code> by the matrix 15251 * <pre> 15252 * 0 1 0 0 15253 * -1 0 0 0 15254 * 0 0 -1 0 15255 * 0 0 0 1 15256 * </pre> 15257 * 15258 * @return this 15259 */ 15260 ref public Matrix4d mapnYXnZ() return { 15261 mapnYXnZ(this); 15262 return this; 15263 } 15264 public Matrix4d mapnYXnZ(ref Matrix4d dest) { 15265 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15266 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)); 15267 } 15268 /** 15269 * Multiply <code>this</code> by the matrix 15270 * <pre> 15271 * 0 0 1 0 15272 * -1 0 0 0 15273 * 0 1 0 0 15274 * 0 0 0 1 15275 * </pre> 15276 * 15277 * @return this 15278 */ 15279 ref public Matrix4d mapnYZX() return { 15280 mapnYZX(this); 15281 return this; 15282 } 15283 public Matrix4d mapnYZX(ref Matrix4d dest) { 15284 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15285 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)); 15286 } 15287 /** 15288 * Multiply <code>this</code> by the matrix 15289 * <pre> 15290 * 0 0 -1 0 15291 * -1 0 0 0 15292 * 0 1 0 0 15293 * 0 0 0 1 15294 * </pre> 15295 * 15296 * @return this 15297 */ 15298 ref public Matrix4d mapnYZnX() return { 15299 mapnYZnX(this); 15300 return this; 15301 } 15302 public Matrix4d mapnYZnX(ref Matrix4d dest) { 15303 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15304 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)); 15305 } 15306 /** 15307 * Multiply <code>this</code> by the matrix 15308 * <pre> 15309 * 0 -1 0 0 15310 * -1 0 0 0 15311 * 0 0 1 0 15312 * 0 0 0 1 15313 * </pre> 15314 * 15315 * @return this 15316 */ 15317 ref public Matrix4d mapnYnXZ() return { 15318 mapnYnXZ(this); 15319 return this; 15320 } 15321 public Matrix4d mapnYnXZ(ref Matrix4d dest) { 15322 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15323 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)); 15324 } 15325 /** 15326 * Multiply <code>this</code> by the matrix 15327 * <pre> 15328 * 0 -1 0 0 15329 * -1 0 0 0 15330 * 0 0 -1 0 15331 * 0 0 0 1 15332 * </pre> 15333 * 15334 * @return this 15335 */ 15336 ref public Matrix4d mapnYnXnZ() return { 15337 mapnYnXnZ(this); 15338 return this; 15339 } 15340 public Matrix4d mapnYnXnZ(ref Matrix4d dest) { 15341 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15342 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)); 15343 } 15344 /** 15345 * Multiply <code>this</code> by the matrix 15346 * <pre> 15347 * 0 0 1 0 15348 * -1 0 0 0 15349 * 0 -1 0 0 15350 * 0 0 0 1 15351 * </pre> 15352 * 15353 * @return this 15354 */ 15355 ref public Matrix4d mapnYnZX() return { 15356 mapnYnZX(this); 15357 return this; 15358 } 15359 public Matrix4d mapnYnZX(ref Matrix4d dest) { 15360 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15361 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)); 15362 } 15363 /** 15364 * Multiply <code>this</code> by the matrix 15365 * <pre> 15366 * 0 0 -1 0 15367 * -1 0 0 0 15368 * 0 -1 0 0 15369 * 0 0 0 1 15370 * </pre> 15371 * 15372 * @return this 15373 */ 15374 ref public Matrix4d mapnYnZnX() return { 15375 mapnYnZnX(this); 15376 return this; 15377 } 15378 public Matrix4d mapnYnZnX(ref Matrix4d dest) { 15379 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15380 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)); 15381 } 15382 /** 15383 * Multiply <code>this</code> by the matrix 15384 * <pre> 15385 * 0 1 0 0 15386 * 0 0 1 0 15387 * -1 0 0 0 15388 * 0 0 0 1 15389 * </pre> 15390 * 15391 * @return this 15392 */ 15393 ref public Matrix4d mapnZXY() return { 15394 mapnZXY(this); 15395 return this; 15396 } 15397 public Matrix4d mapnZXY(ref Matrix4d dest) { 15398 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15399 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15400 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)); 15401 } 15402 /** 15403 * Multiply <code>this</code> by the matrix 15404 * <pre> 15405 * 0 1 0 0 15406 * 0 0 -1 0 15407 * -1 0 0 0 15408 * 0 0 0 1 15409 * </pre> 15410 * 15411 * @return this 15412 */ 15413 ref public Matrix4d mapnZXnY() return { 15414 mapnZXnY(this); 15415 return this; 15416 } 15417 public Matrix4d mapnZXnY(ref Matrix4d dest) { 15418 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15419 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15420 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)); 15421 } 15422 /** 15423 * Multiply <code>this</code> by the matrix 15424 * <pre> 15425 * 0 0 1 0 15426 * 0 1 0 0 15427 * -1 0 0 0 15428 * 0 0 0 1 15429 * </pre> 15430 * 15431 * @return this 15432 */ 15433 ref public Matrix4d mapnZYX() return { 15434 mapnZYX(this); 15435 return this; 15436 } 15437 public Matrix4d mapnZYX(ref Matrix4d dest) { 15438 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15439 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)); 15440 } 15441 /** 15442 * Multiply <code>this</code> by the matrix 15443 * <pre> 15444 * 0 0 -1 0 15445 * 0 1 0 0 15446 * -1 0 0 0 15447 * 0 0 0 1 15448 * </pre> 15449 * 15450 * @return this 15451 */ 15452 ref public Matrix4d mapnZYnX() return { 15453 mapnZYnX(this); 15454 return this; 15455 } 15456 public Matrix4d mapnZYnX(ref Matrix4d dest) { 15457 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15458 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)); 15459 } 15460 /** 15461 * Multiply <code>this</code> by the matrix 15462 * <pre> 15463 * 0 -1 0 0 15464 * 0 0 1 0 15465 * -1 0 0 0 15466 * 0 0 0 1 15467 * </pre> 15468 * 15469 * @return this 15470 */ 15471 ref public Matrix4d mapnZnXY() return { 15472 mapnZnXY(this); 15473 return this; 15474 } 15475 public Matrix4d mapnZnXY(ref Matrix4d dest) { 15476 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15477 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15478 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)); 15479 } 15480 /** 15481 * Multiply <code>this</code> by the matrix 15482 * <pre> 15483 * 0 -1 0 0 15484 * 0 0 -1 0 15485 * -1 0 0 0 15486 * 0 0 0 1 15487 * </pre> 15488 * 15489 * @return this 15490 */ 15491 ref public Matrix4d mapnZnXnY() return { 15492 mapnZnXnY(this); 15493 return this; 15494 } 15495 public Matrix4d mapnZnXnY(ref Matrix4d dest) { 15496 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15497 double m10 = this.m10, m11 = this.m11, m12 = this.m12; 15498 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)); 15499 } 15500 /** 15501 * Multiply <code>this</code> by the matrix 15502 * <pre> 15503 * 0 0 1 0 15504 * 0 -1 0 0 15505 * -1 0 0 0 15506 * 0 0 0 1 15507 * </pre> 15508 * 15509 * @return this 15510 */ 15511 ref public Matrix4d mapnZnYX() return { 15512 mapnZnYX(this); 15513 return this; 15514 } 15515 public Matrix4d mapnZnYX(ref Matrix4d dest) { 15516 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15517 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)); 15518 } 15519 /** 15520 * Multiply <code>this</code> by the matrix 15521 * <pre> 15522 * 0 0 -1 0 15523 * 0 -1 0 0 15524 * -1 0 0 0 15525 * 0 0 0 1 15526 * </pre> 15527 * 15528 * @return this 15529 */ 15530 ref public Matrix4d mapnZnYnX() return { 15531 mapnZnYnX(this); 15532 return this; 15533 } 15534 public Matrix4d mapnZnYnX(ref Matrix4d dest) { 15535 double m00 = this.m00, m01 = this.m01, m02 = this.m02; 15536 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)); 15537 } 15538 15539 /** 15540 * Multiply <code>this</code> by the matrix 15541 * <pre> 15542 * -1 0 0 0 15543 * 0 1 0 0 15544 * 0 0 1 0 15545 * 0 0 0 1 15546 * </pre> 15547 * 15548 * @return this 15549 */ 15550 ref public Matrix4d negateX() return { 15551 return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15552 } 15553 public Matrix4d negateX(ref Matrix4d dest) { 15554 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)); 15555 } 15556 15557 /** 15558 * Multiply <code>this</code> by the matrix 15559 * <pre> 15560 * 1 0 0 0 15561 * 0 -1 0 0 15562 * 0 0 1 0 15563 * 0 0 0 1 15564 * </pre> 15565 * 15566 * @return this 15567 */ 15568 ref public Matrix4d negateY() return { 15569 return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15570 } 15571 public Matrix4d negateY(ref Matrix4d dest) { 15572 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)); 15573 } 15574 15575 /** 15576 * Multiply <code>this</code> by the matrix 15577 * <pre> 15578 * 1 0 0 0 15579 * 0 1 0 0 15580 * 0 0 -1 0 15581 * 0 0 0 1 15582 * </pre> 15583 * 15584 * @return this 15585 */ 15586 ref public Matrix4d negateZ() return { 15587 return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL)); 15588 } 15589 public Matrix4d negateZ(ref Matrix4d dest) { 15590 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)); 15591 } 15592 15593 public bool isFinite() { 15594 return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) && Math.isFinite(m03) && 15595 Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) && Math.isFinite(m13) && 15596 Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) && Math.isFinite(m23) && 15597 Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32) && Math.isFinite(m33); 15598 } 15599 15600 }