Browse Source

Math: support infinite far plane in Matrix::perspectiveProjection().

pull/179/head
Vladimír Vondruš 10 years ago
parent
commit
87074202c8
  1. 49
      src/Magnum/Math/Matrix4.h
  2. 28
      src/Magnum/Math/Test/Matrix4Test.cpp

49
src/Magnum/Math/Matrix4.h

@ -281,7 +281,7 @@ template<class T> class Matrix4: public Matrix4x4<T> {
* @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 T> class Matrix4: public Matrix4x4<T> {
* 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<T> perspectiveProjection(const Vector2<T>& size, T near, T far);
@ -300,7 +310,7 @@ template<class T> class Matrix4: public Matrix4x4<T> {
* @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 T> class Matrix4: public Matrix4x4<T> {
* 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<T> perspectiveProjection(Rad<T> fov, T aspectRatio, T near, T far) {
const T xyScale = 2*std::tan(T(fov)/2)*near;
@ -640,13 +660,20 @@ template<class T> Matrix4<T> Matrix4<T>::orthographicProjection(const Vector2<T>
}
template<class T> Matrix4<T> Matrix4<T>::perspectiveProjection(const Vector2<T>& size, const T near, const T far) {
Vector2<T> 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<T> xyScale = 2*near/size;
if(far == Constants<T>::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<class T> Matrix4<T> Matrix4<T>::lookAt(const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& up) {

28
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() {

Loading…
Cancel
Save