From 3b7aadc2e35c972d4bf95cf7f032ac34e9c559e9 Mon Sep 17 00:00:00 2001 From: Christophe Riccio Date: Sun, 31 Aug 2014 18:12:38 -0400 Subject: [PATCH] Added initial commit for GLM_GTX_matrix_decompose #227 --- glm/gtc/matrix_transform.hpp | 2 +- glm/gtx/closest_point.inl | 5 - glm/gtx/matrix_decompose.hpp | 66 +++++++++ glm/gtx/matrix_decompose.inl | 227 ++++++++++++++++++++++++++++++ test/gtx/CMakeLists.txt | 1 + test/gtx/gtx_component_wise.cpp | 1 - test/gtx/gtx_matrix_decompose.cpp | 17 +++ 7 files changed, 312 insertions(+), 7 deletions(-) create mode 100644 glm/gtx/matrix_decompose.hpp create mode 100644 glm/gtx/matrix_decompose.inl create mode 100644 test/gtx/gtx_matrix_decompose.cpp diff --git a/glm/gtc/matrix_transform.hpp b/glm/gtc/matrix_transform.hpp index 2eb24cbf..2b4dade2 100644 --- a/glm/gtc/matrix_transform.hpp +++ b/glm/gtc/matrix_transform.hpp @@ -46,7 +46,7 @@ #ifndef GLM_GTC_matrix_transform #define GLM_GTC_matrix_transform -// Dependency: +// Dependencies #include "../mat4x4.hpp" #include "../vec2.hpp" #include "../vec3.hpp" diff --git a/glm/gtx/closest_point.inl b/glm/gtx/closest_point.inl index 76a60c6b..b13370b2 100644 --- a/glm/gtx/closest_point.inl +++ b/glm/gtx/closest_point.inl @@ -7,9 +7,6 @@ // File : glm/gtx/closest_point.inl /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef glm_gtx_closest_point -#define glm_gtx_closest_point - namespace glm { template @@ -32,5 +29,3 @@ namespace glm return a + LineDirection * Distance; } }//namespace glm - -#endif//glm_gtx_closest_point diff --git a/glm/gtx/matrix_decompose.hpp b/glm/gtx/matrix_decompose.hpp new file mode 100644 index 00000000..55492a81 --- /dev/null +++ b/glm/gtx/matrix_decompose.hpp @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @ref gtx_decomposition +/// @file glm/gtx/decomposition.hpp +/// @date 2014-08-29 / 2014-08-29 +/// @author Christophe Riccio +/// +/// @see core (dependence) +/// +/// @defgroup gtx_decomposition GLM_GTX_decomposition +/// @ingroup gtx +/// +/// @brief Decomposes a model matrix to translations, rotation and scale components +/// +/// need to be included to use these functionalities. +/////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtc/matrix_transform.hpp" + +#if(defined(GLM_MESSAGES) && !defined(GLM_EXT_INCLUDED)) +# pragma message("GLM: GLM_GTX_decomposition extension included") +#endif + +namespace glm +{ + /// @addtogroup gtx_decomposition + /// @{ + + /// Decomposes a model matrix to translations, rotation and scale components + /// @see gtx_decomposition + template + GLM_FUNC_DECL bool decompose( + detail::tmat4x4 const & modelMatrix, + detail::tvec3 & scale, detail::tquat & orientation, detail::tvec3 & translation, detail::tvec3 & skew, detail::tvec4 & perspective); + + /// @} +}//namespace glm + +#include "matrix_decompose.inl" diff --git a/glm/gtx/matrix_decompose.inl b/glm/gtx/matrix_decompose.inl new file mode 100644 index 00000000..0be67e65 --- /dev/null +++ b/glm/gtx/matrix_decompose.inl @@ -0,0 +1,227 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @ref gtx_decomposition +/// @file glm/gtx/decomposition.inl +/// @date 2014-08-29 / 2014-08-29 +/// @author Christophe Riccio +/////////////////////////////////////////////////////////////////////////////////// + +namespace glm +{ + /// Make a linear combination of two vectors and return the result. + // result = (a * ascl) + (b * bscl) + template + GLM_FUNC_QUALIFIER detail::tvec3 combine( + detail::tvec3 const & a, + detail::tvec3 const & b, + T ascl, T bscl) + { + return (a * ascl) + (b * bscl); + } + + template + GLM_FUNC_QUALIFIER void v3Scale(detail::tvec3 & v, T desiredLength) + { + T len = glm::length(v); + if(len != 0) + { + T l = desiredLength / len; + v[0] *= l; + v[1] *= l; + v[2] *= l; + } + } + + /** + * Matrix decompose + * http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp + * Decomposes the mode matrix to translations,rotation scale components + * + */ + + template + GLM_FUNC_QUALIFIER bool decompose(detail::tmat4x4 const & ModelMatrix, detail::tvec3 & Scale, detail::tquat & Orientation, detail::tvec3 & Translation, detail::tvec3 & Skew, detail::tvec4 & Perspective) + { + detail::tmat4x4 LocalMatrix(ModelMatrix); + + // Normalize the matrix. + if(LocalMatrix[3][3] == static_cast(0)) + return false; + + for(length_t i = 0; i < 4; i++) + for(length_t j = 0; j < 4; j++) + LocalMatrix[i][j] /= LocalMatrix[3][3]; + + // perspectiveMatrix is used to solve for perspective, but it also provides + // an easy way to test for singularity of the upper 3x3 component. + detail::tmat4x4 PerspectiveMatrix(LocalMatrix); + + for(length_t i = 0; i < 3; i++) + PerspectiveMatrix[i][3] = 0; + PerspectiveMatrix[3][3] = 1; + + /// TODO: Fixme! + if(determinant(PerspectiveMatrix) == static_cast(0)) + return false; + + // First, isolate perspective. This is the messiest. + if(LocalMatrix[0][3] != 0 || LocalMatrix[1][3] != 0 || LocalMatrix[2][3] != 0) + { + // rightHandSide is the right hand side of the equation. + detail::tvec4 RightHandSide; + RightHandSide[0] = LocalMatrix[0][3]; + RightHandSide[1] = LocalMatrix[1][3]; + RightHandSide[2] = LocalMatrix[2][3]; + RightHandSide[3] = LocalMatrix[3][3]; + + // Solve the equation by inverting PerspectiveMatrix and multiplying + // rightHandSide by the inverse. (This is the easiest way, not + // necessarily the best.) + detail::tmat4x4 InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);// inverse(PerspectiveMatrix, inversePerspectiveMatrix); + detail::tmat4x4 TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);// transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); + + Perspective = TransposedInversePerspectiveMatrix * RightHandSide; + // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); + + // Clear the perspective partition + LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = 0; + LocalMatrix[3][3] = 1; + } + else + { + // No perspective. + Perspective = detail::tvec4(0, 0, 0, 1); + } + + // Next take care of translation (easy). + Translation = detail::tvec3(LocalMatrix[3]); + LocalMatrix[3] = detail::tvec4(0, 0, 0, LocalMatrix[3].w); + + detail::tvec3 Row[3], Pdum3; + + // Now get scale and shear. + for(length_t i = 0; i < 3; ++i) + Row[i] = LocalMatrix[i]; + + // Compute X scale factor and normalize first row. + Scale.x = length(Row[0]);// v3Length(Row[0]); + + v3Scale(Row[0], 1.0); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + Skew.z = dot(Row[0], Row[1]); + Row[1] = combine(Row[1], Row[0], 1.0, -Skew.z); + + // Now, compute Y scale and normalize 2nd row. + Scale.y = length(Row[1]); + v3Scale(Row[1], 1.0); + Skew.z /= Scale.y; + + // Compute XZ and YZ shears, orthogonalize 3rd row. + Skew.y = glm::dot(Row[0], Row[2]); + Row[2] = combine(Row[2], Row[0], 1.0, -Skew.y); + Skew.x = glm::dot(Row[1], Row[2]); + Row[2] = combine(Row[2], Row[1], 1.0, -Skew.x); + + // Next, get Z scale and normalize 3rd row. + Scale.z = length(Row[2]); + v3Scale(Row[2], 1.0); + Skew.y /= Scale.z; + Skew.x /= Scale.z; + + // At this point, the matrix (in rows[]) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3); + if(dot(Row[0], Pdum3) < 0) + { + for(length_t i = 0; i < 3; i++) + { + Scale.x *= static_cast(-1); + Row[i] *= static_cast(-1); + } + } + + // Now, get the rotations out, as described in the gem. + + // FIXME - Add the ability to return either quaternions (which are + // easier to recompose with) or Euler angles (rx, ry, rz), which + // are easier for authors to deal with. The latter will only be useful + // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I + // will leave the Euler angle code here for now. + + // ret.rotateY = asin(-Row[0][2]); + // if (cos(ret.rotateY) != 0) { + // ret.rotateX = atan2(Row[1][2], Row[2][2]); + // ret.rotateZ = atan2(Row[0][1], Row[0][0]); + // } else { + // ret.rotateX = atan2(-Row[2][0], Row[1][1]); + // ret.rotateZ = 0; + // } + + T s, t, x, y, z, w; + + t = Row[0][0] + Row[1][1] + Row[2][2] + 1.0; + + if(t > 1e-4) + { + s = 0.5 / sqrt(t); + w = 0.25 / s; + x = (Row[2][1] - Row[1][2]) * s; + y = (Row[0][2] - Row[2][0]) * s; + z = (Row[1][0] - Row[0][1]) * s; + } + else if(Row[0][0] > Row[1][1] && Row[0][0] > Row[2][2]) + { + s = sqrt (1.0 + Row[0][0] - Row[1][1] - Row[2][2]) * 2.0; // S=4*qx + x = 0.25 * s; + y = (Row[0][1] + Row[1][0]) / s; + z = (Row[0][2] + Row[2][0]) / s; + w = (Row[2][1] - Row[1][2]) / s; + } + else if(Row[1][1] > Row[2][2]) + { + s = sqrt (1.0 + Row[1][1] - Row[0][0] - Row[2][2]) * 2.0; // S=4*qy + x = (Row[0][1] + Row[1][0]) / s; + y = 0.25 * s; + z = (Row[1][2] + Row[2][1]) / s; + w = (Row[0][2] - Row[2][0]) / s; + } + else + { + s = sqrt(1.0 + Row[2][2] - Row[0][0] - Row[1][1]) * 2.0; // S=4*qz + x = (Row[0][2] + Row[2][0]) / s; + y = (Row[1][2] + Row[2][1]) / s; + z = 0.25 * s; + w = (Row[1][0] - Row[0][1]) / s; + } + + Orientation.x = x; + Orientation.y = y; + Orientation.z = z; + Orientation.w = w; + + return true; + + } +}//namespace glm diff --git a/test/gtx/CMakeLists.txt b/test/gtx/CMakeLists.txt index c0dda185..9b8674bd 100644 --- a/test/gtx/CMakeLists.txt +++ b/test/gtx/CMakeLists.txt @@ -19,6 +19,7 @@ glmCreateTestGTC(gtx_intersect) glmCreateTestGTC(gtx_io) glmCreateTestGTC(gtx_log_base) glmCreateTestGTC(gtx_matrix_cross_product) +glmCreateTestGTC(gtx_matrix_decompose) glmCreateTestGTC(gtx_matrix_interpolation) glmCreateTestGTC(gtx_matrix_major_storage) glmCreateTestGTC(gtx_matrix_operation) diff --git a/test/gtx/gtx_component_wise.cpp b/test/gtx/gtx_component_wise.cpp index 35bcc452..9e5ffff3 100644 --- a/test/gtx/gtx_component_wise.cpp +++ b/test/gtx/gtx_component_wise.cpp @@ -7,7 +7,6 @@ // File : test/gtx/component_wise.cpp /////////////////////////////////////////////////////////////////////////////////////////////////// -#define GLM_FORCE_RADIANS #include #include diff --git a/test/gtx/gtx_matrix_decompose.cpp b/test/gtx/gtx_matrix_decompose.cpp new file mode 100644 index 00000000..6a9241ae --- /dev/null +++ b/test/gtx/gtx_matrix_decompose.cpp @@ -0,0 +1,17 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenGL Mathematics Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Created : 2014-08-31 +// Updated : 2014-08-31 +// Licence : This source is under MIT licence +// File : test/gtx/decomposition.cpp +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +int main() +{ + int Error(0); + + return Error; +}