diff --git a/src/Magnum/Math/Matrix4.h b/src/Magnum/Math/Matrix4.h index 73e0c936b..c7dc88f91 100644 --- a/src/Magnum/Math/Matrix4.h +++ b/src/Magnum/Math/Matrix4.h @@ -281,7 +281,7 @@ template class Matrix4: public Matrix4x4 { * @param near Distance to near clipping plane, positive is ahead * @param far Distance to far clipping plane, positive is ahead * - * @f[ + * If @p far is finite, the result is: @f[ * \boldsymbol{A} = \begin{pmatrix} * \frac{2n}{s_x} & 0 & 0 & 0 \\ * 0 & \frac{2n}{s_y} & 0 & 0 \\ @@ -289,7 +289,17 @@ template class Matrix4: public Matrix4x4 { * 0 & 0 & -1 & 0 * \end{pmatrix} * @f] - * @see @ref orthographicProjection(), @ref Matrix3::projection() + * + * For infinite @p far, the result is: @f[ + * \boldsymbol{A} = \begin{pmatrix} + * \frac{2n}{s_x} & 0 & 0 & 0 \\ + * 0 & \frac{2n}{s_y} & 0 & 0 \\ + * 0 & 0 & -1 & -2n \\ + * 0 & 0 & -1 & 0 + * \end{pmatrix} + * @f] + * @see @ref orthographicProjection(), @ref Matrix3::projection(), + * @ref Constants::inf() */ static Matrix4 perspectiveProjection(const Vector2& size, T near, T far); @@ -300,7 +310,7 @@ template class Matrix4: public Matrix4x4 { * @param near Near clipping plane * @param far Far clipping plane * - * @f[ + * If @p far is finite, the result is: @f[ * \boldsymbol{A} = \begin{pmatrix} * \frac{1}{\tan{\frac{\theta}{2}}} & 0 & 0 & 0 \\ * 0 & \frac{a}{\tan{\frac{\theta}{2}}} & 0 & 0 \\ @@ -308,7 +318,17 @@ template class Matrix4: public Matrix4x4 { * 0 & 0 & -1 & 0 * \end{pmatrix} * @f] - * @see @ref orthographicProjection(), @ref Matrix3::projection() + * + * For infinite @p far, the result is: @f[ + * \boldsymbol{A} = \begin{pmatrix} + * \frac{1}{\tan{\frac{\theta}{2}}} & 0 & 0 & 0 \\ + * 0 & \frac{a}{\tan{\frac{\theta}{2}}} & 0 & 0 \\ + * 0 & 0 & -1 & -2n \\ + * 0 & 0 & -1 & 0 + * \end{pmatrix} + * @f] + * @see @ref orthographicProjection(), @ref Matrix3::projection(), + * @ref Constants::inf() */ static Matrix4 perspectiveProjection(Rad fov, T aspectRatio, T near, T far) { const T xyScale = 2*std::tan(T(fov)/2)*near; @@ -640,13 +660,20 @@ template Matrix4 Matrix4::orthographicProjection(const Vector2 } template Matrix4 Matrix4::perspectiveProjection(const Vector2& size, const T near, const T far) { - Vector2 xyScale = 2*near/size; - T zScale = T(1.0)/(near-far); - - return {{xyScale.x(), T(0), T(0), T(0)}, - { T(0), xyScale.y(), T(0), T(0)}, - { T(0), T(0), (far+near)*zScale, T(-1)}, - { T(0), T(0), T(2)*far*near*zScale, T(0)}}; + const Vector2 xyScale = 2*near/size; + + if(far == Constants::inf()) { + return {{xyScale.x(), T(0), T(0), T(0)}, + { T(0), xyScale.y(), T(0), T(0)}, + { T(0), T(0), T(-1), T(-1)}, + { T(0), T(0), T(-2)*near, T(0)}}; + } else { + const T zScale = T(1.0)/(near-far); + return {{xyScale.x(), T(0), T(0), T(0)}, + { T(0), xyScale.y(), T(0), T(0)}, + { T(0), T(0), (far+near)*zScale, T(-1)}, + { T(0), T(0), T(2)*far*near*zScale, T(0)}}; + } } template Matrix4 Matrix4::lookAt(const Vector3& eye, const Vector3& target, const Vector3& up) { diff --git a/src/Magnum/Math/Test/Matrix4Test.cpp b/src/Magnum/Math/Test/Matrix4Test.cpp index 49e20cade..7cce470c9 100644 --- a/src/Magnum/Math/Test/Matrix4Test.cpp +++ b/src/Magnum/Math/Test/Matrix4Test.cpp @@ -84,7 +84,9 @@ struct Matrix4Test: Corrade::TestSuite::Tester { void shearingYZ(); void orthographicProjection(); void perspectiveProjection(); + void perspectiveProjectionInfiniteFar(); void perspectiveProjectionFov(); + void perspectiveProjectionFovInfiniteFar(); void lookAt(); void fromParts(); @@ -134,7 +136,9 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::shearingYZ, &Matrix4Test::orthographicProjection, &Matrix4Test::perspectiveProjection, + &Matrix4Test::perspectiveProjectionInfiniteFar, &Matrix4Test::perspectiveProjectionFov, + &Matrix4Test::perspectiveProjectionFovInfiniteFar, &Matrix4Test::lookAt, &Matrix4Test::fromParts, @@ -420,12 +424,34 @@ void Matrix4Test::perspectiveProjection() { CORRADE_COMPARE(actual.transformPoint({0.0f, 0.0f, -100.0f}), Vector3(0.0f, 0.0f, +1.0f)); } +void Matrix4Test::perspectiveProjectionInfiniteFar() { + Matrix4 expected({4.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 7.111111f, 0.0f, 0.0f}, + {0.0f, 0.0f, -1.0f, -1.0f}, + {0.0f, 0.0f, -64.0f, 0.0f}); + Matrix4 actual = Matrix4::perspectiveProjection({16.0f, 9.0f}, 32.0f, Constants::inf()); + CORRADE_COMPARE(actual, expected); + + /* NDC is left-handed, so point on near plane should be -1 and a *vector* + in direction of far plane +1 */ + CORRADE_COMPARE(actual.transformPoint({0.0f, 0.0f, -32.0f}), Vector3(0.0f, 0.0f, -1.0f)); + CORRADE_COMPARE(actual.transformVector({0.0f, 0.0f, -1.0f}), Vector3(0.0f, 0.0f, +1.0f)); +} + void Matrix4Test::perspectiveProjectionFov() { Matrix4 expected({4.1652994f, 0.0f, 0.0f, 0.0f}, { 0.0f, 9.788454f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.9411764f, -1.0f}, { 0.0f, 0.0f, -94.1176452f, 0.0f}); - CORRADE_COMPARE(Matrix4::perspectiveProjection(Deg(27.0f), 2.35f, 32.0f, 100), expected); + CORRADE_COMPARE(Matrix4::perspectiveProjection(Deg(27.0f), 2.35f, 32.0f, 100.0f), expected); +} + +void Matrix4Test::perspectiveProjectionFovInfiniteFar() { + Matrix4 expected({4.1652994f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 9.788454f, 0.0f, 0.0f}, + { 0.0f, 0.0f, -1.0f, -1.0f}, + { 0.0f, 0.0f, -64.0f, 0.0f}); + CORRADE_COMPARE(Matrix4::perspectiveProjection(Deg(27.0f), 2.35f, 32.0f, Constants::inf()), expected); } void Matrix4Test::fromParts() {