| 445 | } |
| 446 | |
| 447 | bool Mat4::decompose(Vec3* scale, Quaternion* rotation, Vec3* translation) const |
| 448 | { |
| 449 | if (translation) |
| 450 | { |
| 451 | // Extract the translation. |
| 452 | translation->x = m[12]; |
| 453 | translation->y = m[13]; |
| 454 | translation->z = m[14]; |
| 455 | } |
| 456 | |
| 457 | // Nothing left to do. |
| 458 | if (scale == nullptr && rotation == nullptr) |
| 459 | return true; |
| 460 | |
| 461 | // Extract the scale. |
| 462 | // This is simply the length of each axis (row/column) in the matrix. |
| 463 | Vec3 xaxis(m[0], m[1], m[2]); |
| 464 | float scaleX = xaxis.length(); |
| 465 | |
| 466 | Vec3 yaxis(m[4], m[5], m[6]); |
| 467 | float scaleY = yaxis.length(); |
| 468 | |
| 469 | Vec3 zaxis(m[8], m[9], m[10]); |
| 470 | float scaleZ = zaxis.length(); |
| 471 | |
| 472 | // Determine if we have a negative scale (true if determinant is less than zero). |
| 473 | // In this case, we simply negate a single axis of the scale. |
| 474 | float det = determinant(); |
| 475 | if (det < 0) |
| 476 | scaleZ = -scaleZ; |
| 477 | |
| 478 | if (scale) |
| 479 | { |
| 480 | scale->x = scaleX; |
| 481 | scale->y = scaleY; |
| 482 | scale->z = scaleZ; |
| 483 | } |
| 484 | |
| 485 | // Nothing left to do. |
| 486 | if (rotation == nullptr) |
| 487 | return true; |
| 488 | |
| 489 | // Scale too close to zero, can't decompose rotation. |
| 490 | if (scaleX < MATH_TOLERANCE || scaleY < MATH_TOLERANCE || std::abs(scaleZ) < MATH_TOLERANCE) |
| 491 | return false; |
| 492 | |
| 493 | float rn; |
| 494 | |
| 495 | // Factor the scale out of the matrix axes. |
| 496 | rn = 1.0f / scaleX; |
| 497 | xaxis.x *= rn; |
| 498 | xaxis.y *= rn; |
| 499 | xaxis.z *= rn; |
| 500 | |
| 501 | rn = 1.0f / scaleY; |
| 502 | yaxis.x *= rn; |
| 503 | yaxis.y *= rn; |
| 504 | yaxis.z *= rn; |
no test coverage detected