master
ブランチ master
VulkanExample / dep / include / glm / gtx / matrix_decompose.inl
7.7 KB、234行 生 Blame 履歴
1/// @ref gtx_matrix_decompose
2
3#include "../gtc/constants.hpp"
4#include "../gtc/epsilon.hpp"
5#include "../gtx/transform.hpp"
6
7namespace glm{
8namespace detail
9{
10 /// Make a linear combination of two vectors and return the result.
11 // result = (a * ascl) + (b * bscl)
12 template<typename T, qualifier Q>
13 GLM_FUNC_QUALIFIER vec<3, T, Q> combine(
14 vec<3, T, Q> const& a,
15 vec<3, T, Q> const& b,
16 T ascl, T bscl)
17 {
18 return (a * ascl) + (b * bscl);
19 }
20
21 template<typename T, qualifier Q>
22 GLM_FUNC_QUALIFIER vec<3, T, Q> scale(vec<3, T, Q> const& v, T desiredLength)
23 {
24 return v * desiredLength / length(v);
25 }
26}//namespace detail
27
28 // Matrix decompose
29 // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
30 // Decomposes the mode matrix to translations,rotation scale components
31
32 template<typename T, qualifier Q>
33 GLM_FUNC_QUALIFIER bool decompose(mat<4, 4, T, Q> const& ModelMatrix, vec<3, T, Q> & Scale, qua<T, Q> & Orientation, vec<3, T, Q> & Translation, vec<3, T, Q> & Skew, vec<4, T, Q> & Perspective)
34 {
35 mat<4, 4, T, Q> LocalMatrix(ModelMatrix);
36
37 // Normalize the matrix.
38 if(epsilonEqual(LocalMatrix[3][3], static_cast<T>(0), epsilon<T>()))
39 return false;
40
41 for(length_t i = 0; i < 4; ++i)
42 for(length_t j = 0; j < 4; ++j)
43 LocalMatrix[i][j] /= LocalMatrix[3][3];
44
45 // perspectiveMatrix is used to solve for perspective, but it also provides
46 // an easy way to test for singularity of the upper 3x3 component.
47 mat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix);
48
49 for(length_t i = 0; i < 3; i++)
50 PerspectiveMatrix[i][3] = static_cast<T>(0);
51 PerspectiveMatrix[3][3] = static_cast<T>(1);
52
53 /// TODO: Fixme!
54 if(epsilonEqual(determinant(PerspectiveMatrix), static_cast<T>(0), epsilon<T>()))
55 return false;
56
57 // First, isolate perspective. This is the messiest.
58 if(
59 epsilonNotEqual(LocalMatrix[0][3], static_cast<T>(0), epsilon<T>()) ||
60 epsilonNotEqual(LocalMatrix[1][3], static_cast<T>(0), epsilon<T>()) ||
61 epsilonNotEqual(LocalMatrix[2][3], static_cast<T>(0), epsilon<T>()))
62 {
63 // rightHandSide is the right hand side of the equation.
64 vec<4, T, Q> RightHandSide;
65 RightHandSide[0] = LocalMatrix[0][3];
66 RightHandSide[1] = LocalMatrix[1][3];
67 RightHandSide[2] = LocalMatrix[2][3];
68 RightHandSide[3] = LocalMatrix[3][3];
69
70 // Solve the equation by inverting PerspectiveMatrix and multiplying
71 // rightHandSide by the inverse. (This is the easiest way, not
72 // necessarily the best.)
73 mat<4, 4, T, Q> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);// inverse(PerspectiveMatrix, inversePerspectiveMatrix);
74 mat<4, 4, T, Q> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);// transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
75
76 Perspective = TransposedInversePerspectiveMatrix * RightHandSide;
77 // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
78
79 // Clear the perspective partition
80 LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast<T>(0);
81 LocalMatrix[3][3] = static_cast<T>(1);
82 }
83 else
84 {
85 // No perspective.
86 Perspective = vec<4, T, Q>(0, 0, 0, 1);
87 }
88
89 // Next take care of translation (easy).
90 Translation = vec<3, T, Q>(LocalMatrix[3]);
91 LocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w);
92
93 vec<3, T, Q> Row[3], Pdum3;
94
95 // Now get scale and shear.
96 for(length_t i = 0; i < 3; ++i)
97 for(length_t j = 0; j < 3; ++j)
98 Row[i][j] = LocalMatrix[i][j];
99
100 // Compute X scale factor and normalize first row.
101 Scale.x = length(Row[0]);// v3Length(Row[0]);
102
103 Row[0] = detail::scale(Row[0], static_cast<T>(1));
104
105 // Compute XY shear factor and make 2nd row orthogonal to 1st.
106 Skew.z = dot(Row[0], Row[1]);
107 Row[1] = detail::combine(Row[1], Row[0], static_cast<T>(1), -Skew.z);
108
109 // Now, compute Y scale and normalize 2nd row.
110 Scale.y = length(Row[1]);
111 Row[1] = detail::scale(Row[1], static_cast<T>(1));
112 Skew.z /= Scale.y;
113
114 // Compute XZ and YZ shears, orthogonalize 3rd row.
115 Skew.y = glm::dot(Row[0], Row[2]);
116 Row[2] = detail::combine(Row[2], Row[0], static_cast<T>(1), -Skew.y);
117 Skew.x = glm::dot(Row[1], Row[2]);
118 Row[2] = detail::combine(Row[2], Row[1], static_cast<T>(1), -Skew.x);
119
120 // Next, get Z scale and normalize 3rd row.
121 Scale.z = length(Row[2]);
122 Row[2] = detail::scale(Row[2], static_cast<T>(1));
123 Skew.y /= Scale.z;
124 Skew.x /= Scale.z;
125
126 // At this point, the matrix (in rows[]) is orthonormal.
127 // Check for a coordinate system flip. If the determinant
128 // is -1, then negate the matrix and the scaling factors.
129 Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3);
130 if(dot(Row[0], Pdum3) < 0)
131 {
132 for(length_t i = 0; i < 3; i++)
133 {
134 Scale[i] *= static_cast<T>(-1);
135 Row[i] *= static_cast<T>(-1);
136 }
137 }
138
139 // Now, get the rotations out, as described in the gem.
140
141 // FIXME - Add the ability to return either quaternions (which are
142 // easier to recompose with) or Euler angles (rx, ry, rz), which
143 // are easier for authors to deal with. The latter will only be useful
144 // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
145 // will leave the Euler angle code here for now.
146
147 // ret.rotateY = asin(-Row[0][2]);
148 // if (cos(ret.rotateY) != 0) {
149 // ret.rotateX = atan2(Row[1][2], Row[2][2]);
150 // ret.rotateZ = atan2(Row[0][1], Row[0][0]);
151 // } else {
152 // ret.rotateX = atan2(-Row[2][0], Row[1][1]);
153 // ret.rotateZ = 0;
154 // }
155
156 int i, j, k = 0;
157 T root, trace = Row[0].x + Row[1].y + Row[2].z;
158 if(trace > static_cast<T>(0))
159 {
160 root = sqrt(trace + static_cast<T>(1.0));
161 Orientation.w = static_cast<T>(0.5) * root;
162 root = static_cast<T>(0.5) / root;
163 Orientation.x = root * (Row[1].z - Row[2].y);
164 Orientation.y = root * (Row[2].x - Row[0].z);
165 Orientation.z = root * (Row[0].y - Row[1].x);
166 } // End if > 0
167 else
168 {
169 static int Next[3] = {1, 2, 0};
170 i = 0;
171 if(Row[1].y > Row[0].x) i = 1;
172 if(Row[2].z > Row[i][i]) i = 2;
173 j = Next[i];
174 k = Next[j];
175
176# ifdef GLM_FORCE_QUAT_DATA_WXYZ
177 int off = 1;
178# else
179 int off = 0;
180# endif
181
182 root = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast<T>(1.0));
183
184 Orientation[i + off] = static_cast<T>(0.5) * root;
185 root = static_cast<T>(0.5) / root;
186 Orientation[j + off] = root * (Row[i][j] + Row[j][i]);
187 Orientation[k + off] = root * (Row[i][k] + Row[k][i]);
188 Orientation.w = root * (Row[j][k] - Row[k][j]);
189 } // End if <= 0
190
191 return true;
192 }
193
194 // Recomposes a model matrix from a previously-decomposed matrix
195 // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
196 // https://stackoverflow.com/a/75573092/1047040
197 template <typename T, qualifier Q>
198 GLM_FUNC_DECL mat<4, 4, T, Q> recompose(
199 vec<3, T, Q> const& scale, qua<T, Q> const& orientation, vec<3, T, Q> const& translation,
200 vec<3, T, Q> const& skew, vec<4, T, Q> const& perspective)
201 {
202 glm::mat4 m = glm::mat4(1.f);
203
204 m[0][3] = perspective.x;
205 m[1][3] = perspective.y;
206 m[2][3] = perspective.z;
207 m[3][3] = perspective.w;
208
209 m *= glm::translate(translation);
210 m *= glm::mat4_cast(orientation);
211
212 if (abs(skew.x) > static_cast<T>(0)) {
213 glm::mat4 tmp(1.f);
214 tmp[2][1] = skew.x;
215 m *= tmp;
216 }
217
218 if (abs(skew.y) > static_cast<T>(0)) {
219 glm::mat4 tmp(1.f);
220 tmp[2][0] = skew.y;
221 m *= tmp;
222 }
223
224 if (abs(skew.z) > static_cast<T>(0)) {
225 glm::mat4 tmp(1.f);
226 tmp[1][0] = skew.z;
227 m *= tmp;
228 }
229
230 m *= glm::scale(scale);
231
232 return m;
233 }
234}//namespace glm