diff --git a/glm/ext/matrix_clip_space.inl b/glm/ext/matrix_clip_space.inl index 2a7f6123..bb3a05d7 100644 --- a/glm/ext/matrix_clip_space.inl +++ b/glm/ext/matrix_clip_space.inl @@ -501,7 +501,7 @@ namespace glm } template - GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear) + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH_NO(T fovy, T aspect, T zNear) { T const range = tan(fovy / static_cast(2)) * zNear; T const left = -range * aspect; @@ -518,11 +518,31 @@ namespace glm return Result; } + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH_ZO(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(T(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = static_cast(1); + Result[2][3] = static_cast(1); + Result[3][2] = - zNear; + return Result; + } + template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear) { -# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT - return infinitePerspectiveLH(fovy, aspect, zNear); +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return infinitePerspectiveLH_ZO(fovy, aspect, zNear); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return infinitePerspectiveLH_NO(fovy, aspect, zNear); # else return infinitePerspectiveRH(fovy, aspect, zNear); # endif diff --git a/test/gtc/gtc_matrix_transform.cpp b/test/gtc/gtc_matrix_transform.cpp index b50666e7..88db9d91 100644 --- a/test/gtc/gtc_matrix_transform.cpp +++ b/test/gtc/gtc_matrix_transform.cpp @@ -1,12 +1,70 @@ #include #include #include +#include int test_perspective() { int Error = 0; - glm::mat4 Projection = glm::perspective(glm::pi() * 0.25f, 4.0f / 3.0f, 0.1f, 100.0f); + const float Near = 0.1f; + const float Far = 100.0f; + const float Eps = glm::epsilon(); + + glm::mat4 Projection = glm::perspective(glm::pi() * 0.25f, 4.0f / 3.0f, Near, Far); + + Projection = glm::perspectiveLH_ZO(glm::pi() * 0.25f, 4.0f / 3.0f, Near, Far); + { + glm::vec4 N = Projection * glm::vec4{0.f, 0.f, Near, 1.f}; + glm::vec4 F = Projection * glm::vec4{0.f, 0.f, Far, 1.f}; + N /= N.w; + F /= F.w; + Error += glm::notEqual(N.z, 0.f, Eps); + Error += glm::notEqual(F.z, 1.f, Eps); + } + + Projection = glm::perspectiveLH_NO(glm::pi() * 0.25f, 4.0f / 3.0f, Near, Far); + { + glm::vec4 N = Projection * glm::vec4{0.f, 0.f, Near, 1.f}; + glm::vec4 F = Projection * glm::vec4{0.f, 0.f, Far, 1.f}; + N /= N.w; + F /= F.w; + Error += glm::notEqual(N.z, -1.f, Eps); + Error += glm::notEqual(F.z, 1.f, Eps); + } + + return Error; +} + +int test_infinitePerspective() +{ + int Error = 0; + + const float Near = 0.1f; + const float Inf = 1.0e+10f; + const float Eps = glm::epsilon(); + + glm::mat4 Projection = glm::infinitePerspective(glm::pi() * 0.25f, 4.0f / 3.0f, Near); + + Projection = glm::infinitePerspectiveLH_ZO(glm::pi() * 0.25f, 4.0f / 3.0f, Near); + { + glm::vec4 N = Projection * glm::vec4{0.f, 0.f, Near, 1.f}; + glm::vec4 F = Projection * glm::vec4{0.f, 0.f, Inf, 1.f}; + N /= N.w; + F /= F.w; + Error += glm::notEqual(N.z, 0.f, Eps); + Error += glm::notEqual(F.z, 1.f, Eps); + } + + Projection = glm::infinitePerspectiveLH_NO(glm::pi() * 0.25f, 4.0f / 3.0f, Near); + { + glm::vec4 N = Projection * glm::vec4{0.f, 0.f, Near, 1.f}; + glm::vec4 F = Projection * glm::vec4{0.f, 0.f, Inf, 1.f}; + N /= N.w; + F /= F.w; + Error += glm::notEqual(N.z, -1.f, Eps); + Error += glm::notEqual(F.z, 1.f, Eps); + } return Error; } @@ -50,6 +108,7 @@ int main() Error += test_tweakedInfinitePerspective(); Error += test_pick(); Error += test_perspective(); + Error += test_infinitePerspective(); return Error; }