From 0f318f63afdc250efa0ecb13b4eb8785bb237bfb Mon Sep 17 00:00:00 2001 From: arikanli Date: Thu, 20 Jan 2022 21:27:30 +0800 Subject: [PATCH] feat: add shearing matrix operation on matrix_transfom --- glm/ext/matrix_transform.hpp | 29 +++++++++++- glm/ext/matrix_transform.inl | 54 ++++++++++++++++++++++ test/core/core_func_matrix.cpp | 82 +++++++++++++++++++++++++++++++++- 3 files changed, 163 insertions(+), 2 deletions(-) diff --git a/glm/ext/matrix_transform.hpp b/glm/ext/matrix_transform.hpp index cbd187ef..3e688b91 100644 --- a/glm/ext/matrix_transform.hpp +++ b/glm/ext/matrix_transform.hpp @@ -95,7 +95,34 @@ namespace glm GLM_FUNC_DECL mat<4, 4, T, Q> scale( mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); - /// Build a right handed look at view matrix. + /// Builds a scale 4 * 4 matrix created from point referent 3 shearers. + /// + /// @param m Input matrix multiplied by this shear matrix. + /// @param p Point of shearing as reference. + /// @param l_x Ratio of matrix.x projection in YZ plane relative to the y-axis/z-axis. + /// @param l_y Ratio of matrix.y projection in XZ plane relative to the x-axis/z-axis. + /// @param l_z Ratio of matrix.z projection in XY plane relative to the x-axis/y-axis. + /// + /// as example: + /// [1 , l_xy, l_xz, -(l_xy+l_xz) * p_x] [x] T + /// [x`, y`, z`, w`] = [x`, y`, z`, w`] * [l_yx, 1 , l_yz, -(l_yx+l_yz) * p_y] [y] + /// [l_zx, l_zy, 1 , -(l_zx+l_zy) * p_z] [z] + /// [0 , 0 , 0 , 1 ] [w] + /// + /// @tparam T A floating-point shear type + /// @tparam Q A value from qualifier enum + /// + /// @see - shear(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - shear(vec<3, T, Q> const& p) + /// @see - shear(vec<2, T, Q> const& l_x) + /// @see - shear(vec<2, T, Q> const& l_y) + /// @see - shear(vec<2, T, Q> const& l_z) + /// @see no resource... + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear( + mat<4, 4, T, Q> const &m, vec<3, T, Q> const& p, vec<2, T, Q> const &l_x, vec<2, T, Q> const &l_y, vec<2, T, Q> const &l_z); + + /// Build a right handed look at view matrix. /// /// @param eye Position of the camera /// @param center Position where the camera is looking at diff --git a/glm/ext/matrix_transform.inl b/glm/ext/matrix_transform.inl index 01cefab6..ef2e9f34 100644 --- a/glm/ext/matrix_transform.inl +++ b/glm/ext/matrix_transform.inl @@ -95,6 +95,60 @@ namespace glm return m * Result; } + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(mat<4, 4, T, Q> const &m, vec<3, T, Q> const& p, vec<2, T, Q> const &l_x, vec<2, T, Q> const &l_y, vec<2, T, Q> const &l_z) + { + T const lambda_xy = l_x[0]; + T const lambda_xz = l_x[1]; + T const lambda_yx = l_y[0]; + T const lambda_yz = l_y[1]; + T const lambda_zx = l_z[0]; + T const lambda_zy = l_z[1]; + + vec<3, T, Q> point_lambda = vec<3, T, Q>( + (lambda_xy + lambda_xz), (lambda_yx + lambda_yz), (lambda_zx + lambda_zy) + ); + + mat<4, 4, T, Q> Shear = mat<4, 4, T, Q>( + 1 , lambda_yx , lambda_zx , 0, + lambda_xy , 1 , lambda_zy , 0, + lambda_xz , lambda_yz , 1 , 0, + -point_lambda[0] * p[0], -point_lambda[1] * p[1], -point_lambda[2] * p[2], 1 + ); + + mat<4, 4, T, Q> Result; + Result[0] = Shear[0] * m[0][0] + Shear[1] * m[0][1] + Shear[2] * m[0][2] + Shear[3] * m[0][3]; + Result[1] = Shear[0] * m[1][0] + Shear[1] * m[1][1] + Shear[2] * m[1][2] + Shear[3] * m[1][3]; + Result[2] = Shear[0] * m[2][0] + Shear[1] * m[2][1] + Shear[2] * m[2][2] + Shear[3] * m[2][3]; + Result[3] = Shear[0] * m[3][0] + Shear[1] * m[3][1] + Shear[2] * m[3][2] + Shear[3] * m[3][3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear_slow(mat<4, 4, T, Q> const &m, vec<3, T, Q> const& p, vec<2, T, Q> const &l_x, vec<2, T, Q> const &l_y, vec<2, T, Q> const &l_z) + { + T const lambda_xy = static_cast(l_x[0]); + T const lambda_xz = static_cast(l_x[1]); + T const lambda_yx = static_cast(l_y[0]); + T const lambda_yz = static_cast(l_y[1]); + T const lambda_zx = static_cast(l_z[0]); + T const lambda_zy = static_cast(l_z[1]); + + vec<3, T, Q> point_lambda = vec<3, T, Q>( + static_cast(lambda_xy + lambda_xz), + static_cast(lambda_yx + lambda_yz), + static_cast(lambda_zx + lambda_zy) + ); + + mat<4, 4, T, Q> Shear = mat<4, 4, T, Q>( + 1 , lambda_yx , lambda_zx , 0, + lambda_xy , 1 , lambda_zy , 0, + lambda_xz , lambda_yz , 1 , 0, + -point_lambda[0] * p[0], -point_lambda[1] * p[1], -point_lambda[2] * p[2], 1 + ); + return m * Shear; + } + template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) { diff --git a/test/core/core_func_matrix.cpp b/test/core/core_func_matrix.cpp index c5b20072..b66ee7d6 100644 --- a/test/core/core_func_matrix.cpp +++ b/test/core/core_func_matrix.cpp @@ -240,6 +240,85 @@ int test_inverse_simd() return Error; } +int test_shearing() +{ + int Error = 0; + + { + glm::vec3 const center(0, 0, 0); + glm::vec2 const l_x(2, 0); + glm::vec2 const l_y(0, 0); + glm::vec2 const l_z(0, 0); + glm::mat4x4 const A4x4( + glm::vec4(0, 0, 1, 1), + glm::vec4(0, 1, 1, 0), + glm::vec4(1, 1, 1, 0), + glm::vec4(1, 1, 0, 1)); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(0, 0, 1, 1), + glm::vec4(2, 1, 1, 0), + glm::vec4(3, 1, 1, 0), + glm::vec4(3, 1, 0, 1)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + { + glm::vec3 const center(0, 0, 0); + glm::vec2 const l_x(1, 0); + glm::vec2 const l_y(0, 1); + glm::vec2 const l_z(1, 0); + glm::mat4x4 const A4x4( + glm::vec4(0, 0, 1, 0), + glm::vec4(0, 1, 1, 0), + glm::vec4(1, 1, 1, 0), + glm::vec4(1, 0, 0, 0)); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(0, 1, 1, 0), + glm::vec4(1, 2, 1, 0), + glm::vec4(2, 2, 2, 0), + glm::vec4(1, 0, 1, 0)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + { + glm::vec3 const center(3, 2, 1); + glm::vec2 const l_x(1, 2); + glm::vec2 const l_y(3, 1); + glm::vec2 const l_z(4, 5); + glm::mat4x4 const A4x4(1); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(1, 3, 4, 0), + glm::vec4(1, 1, 5, 0), + glm::vec4(2, 1, 1, 0), + glm::vec4(-9, -8, -9, 1)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + { + glm::vec3 const center(3, 2, 1); + glm::vec2 const l_x(1, 2); + glm::vec2 const l_y(3, 1); + glm::vec2 const l_z(4, 5); + glm::mat4x4 const A4x4( + glm::vec4(-3, 2, 1, 0), + glm::vec4(3, 2, 1, 0), + glm::vec4(4, -8, 0, 0), + glm::vec4(7, 1, -2, 0)); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(1, -6, -1, 0), + glm::vec4(7, 12, 23, 0), + glm::vec4(-4, 4, -24, 0), + glm::vec4(4, 20, 31, 0)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + return Error; +} + template int test_inverse_perf(std::size_t Count, std::size_t Instance, char const * Message) { @@ -293,7 +372,8 @@ int main() Error += test_transpose(); Error += test_determinant(); Error += test_inverse(); - Error += test_inverse_simd(); + Error += test_inverse_simd(); + Error += test_shearing(); # ifdef NDEBUG std::size_t const Samples = 1000;