Unravel Engine C++ Reference
Loading...
Searching...
No Matches
matrix_recompose.hpp
Go to the documentation of this file.
1#pragma once
2
4
5namespace math
6{
7using namespace glm;
8
9namespace detail
10{
11namespace
12{
13template<typename genType>
14GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType lowest_scale()
15{
16 GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_CONFIG_UNRESTRICTED_FLOAT,
17 "'pi' only accepts floating-point inputs");
18 return static_cast<genType>(0.0001);
19}
20
21} // namespace
22
23template<length_t L, typename T, qualifier Q>
24GLM_FUNC_QUALIFIER T length_impl(vec<L, T, Q> const& v)
25{
26 return std::max(lowest_scale<T>(), length(v));
27}
28
30// result = (a * ascl) + (b * bscl)
31template<typename T, qualifier Q>
32GLM_FUNC_QUALIFIER vec<3, T, Q> combine_impl(vec<3, T, Q> const& a, vec<3, T, Q> const& b, T ascl, T bscl)
33{
34 return (a * ascl) + (b * bscl);
35}
36
37template<typename T, qualifier Q>
38GLM_FUNC_QUALIFIER vec<3, T, Q> scale_impl(vec<3, T, Q> const& v, T desiredLength)
39{
40 return v * desiredLength / length_impl(v);
41}
42
43template<typename T>
44GLM_FUNC_QUALIFIER T scale_fix(T& in)
45{
46 T el = in;
47 if(math::epsilonEqual<T>(el, T(0), lowest_scale<T>()))
48 {
49 el = lowest_scale<T>() * (std::signbit(el) ? T(1.0) : T(1.0));
50 }
51
52 return el;
53}
54
55template<typename T, qualifier Q>
56GLM_FUNC_QUALIFIER vec<3, T, Q> scale_fix(vec<3, T, Q> const& scale)
57{
58 auto result = scale;
59 for(math::length_t i = 0; i < result.length(); ++i)
60 {
61 auto& el = result[i];
62 el = scale_fix(el);
63 }
64
65 return result;
66}
67
68} // namespace detail
69// Recomposes a model matrix from a previously-decomposed matrix
70// http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
71// https://stackoverflow.com/a/75573092/1047040
72template<typename T, qualifier Q>
73GLM_FUNC_QUALIFIER mat<4, 4, T, Q> recompose_impl(vec<3, T, Q> const& scale,
74 qua<T, Q> const& orientation,
75 vec<3, T, Q> const& translation,
76 vec<3, T, Q> const& skew,
77 vec<4, T, Q> const& perspective)
78{
79 mat<4, 4, T, Q> m(1);
80
81 m[0][3] = perspective.x;
82 m[1][3] = perspective.y;
83 m[2][3] = perspective.z;
84 m[3][3] = perspective.w;
85
86 m *= glm::translate(translation);
87 m *= glm::mat4_cast(orientation);
88
89 if(abs(skew.x) > static_cast<T>(0))
90 {
91 mat<4, 4, T, Q> tmp(static_cast<T>(1));
92 tmp[2][1] = skew.x;
93 m *= tmp;
94 }
95
96 if(abs(skew.y) > static_cast<T>(0))
97 {
98 mat<4, 4, T, Q> tmp(static_cast<T>(1));
99 tmp[2][0] = skew.y;
100 m *= tmp;
101 }
102
103 if(abs(skew.z) > static_cast<T>(0))
104 {
105 mat<4, 4, T, Q> tmp(static_cast<T>(1));
106 tmp[1][0] = skew.z;
107 m *= tmp;
108 }
109
110 m *= glm::scale(scale);
111
112 return m;
113}
114
115template<typename T, qualifier Q>
116GLM_FUNC_QUALIFIER void glm_recompose(mat<4, 4, T, Q>& model_matrix,
117 vec<3, T, Q> const& in_scale,
118 qua<T, Q> const& in_orientation,
119 vec<3, T, Q> const& in_translation,
120 vec<3, T, Q> const& in_skew,
121 vec<4, T, Q> const& in_perspective)
122{
123 model_matrix = recompose_impl(detail::scale_fix(in_scale), in_orientation, in_translation, in_skew, in_perspective);
124}
125
126// Matrix decompose
127// http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
128// Decomposes the mode matrix to translations,rotation scale components
129template<typename T, qualifier Q>
130GLM_FUNC_QUALIFIER bool glm_decompose(mat<4, 4, T, Q> const& ModelMatrix,
131 vec<3, T, Q>& Scale,
132 qua<T, Q>& Orientation,
133 vec<3, T, Q>& Translation,
134 vec<3, T, Q>& Skew,
135 vec<4, T, Q>& Perspective)
136{
137 mat<4, 4, T, Q> LocalMatrix(ModelMatrix);
138
139 // Normalize the matrix.
140 if(epsilonEqual(LocalMatrix[3][3], static_cast<T>(0), epsilon<T>()))
141 {
142 LocalMatrix[3][3] = T(1);
143
144 // DO not return here, but tread perspective as 1
145 //return false;
146 }
147
148 for(length_t i = 0; i < 4; ++i)
149 for(length_t j = 0; j < 4; ++j)
150 LocalMatrix[i][j] /= LocalMatrix[3][3];
151
152 // perspectiveMatrix is used to solve for perspective, but it also provides
153 // an easy way to test for singularity of the upper 3x3 component.
154 mat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix);
155
156 for(length_t i = 0; i < 3; i++)
157 PerspectiveMatrix[i][3] = static_cast<T>(0);
158 PerspectiveMatrix[3][3] = static_cast<T>(1);
159
163 // if(epsilonEqual(determinant(PerspectiveMatrix), static_cast<T>(0), epsilon<T>()))
164 // {
165 // return false;
166 // }
167 // return false;
168
169 // First, isolate perspective. This is the messiest.
170 if(epsilonNotEqual(LocalMatrix[0][3], static_cast<T>(0), epsilon<T>()) ||
171 epsilonNotEqual(LocalMatrix[1][3], static_cast<T>(0), epsilon<T>()) ||
172 epsilonNotEqual(LocalMatrix[2][3], static_cast<T>(0), epsilon<T>()))
173 {
174 // rightHandSide is the right hand side of the equation.
175 vec<4, T, Q> RightHandSide;
176 RightHandSide[0] = LocalMatrix[0][3];
177 RightHandSide[1] = LocalMatrix[1][3];
178 RightHandSide[2] = LocalMatrix[2][3];
179 RightHandSide[3] = LocalMatrix[3][3];
180
181 // Solve the equation by inverting PerspectiveMatrix and multiplying
182 // rightHandSide by the inverse. (This is the easiest way, not
183 // necessarily the best.)
184 mat<4, 4, T, Q> InversePerspectiveMatrix =
185 glm::inverse(PerspectiveMatrix); // inverse(PerspectiveMatrix, inversePerspectiveMatrix);
186 mat<4, 4, T, Q> TransposedInversePerspectiveMatrix =
187 glm::transpose(InversePerspectiveMatrix); // transposeMatrix4(inversePerspectiveMatrix,
188 // transposedInversePerspectiveMatrix);
189
190 Perspective = TransposedInversePerspectiveMatrix * RightHandSide;
191 // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
192
193 // Clear the perspective partition
194 LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast<T>(0);
195 LocalMatrix[3][3] = static_cast<T>(1);
196 }
197 else
198 {
199 // No perspective.
200 Perspective = vec<4, T, Q>(0, 0, 0, 1);
201 }
202
203 // Next take care of translation (easy).
204 Translation = vec<3, T, Q>(LocalMatrix[3]);
205 LocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w);
206
207 vec<3, T, Q> Row[3], Pdum3;
208
209 // Now get scale and shear.
210 for(length_t i = 0; i < 3; ++i)
211 for(length_t j = 0; j < 3; ++j)
212 Row[i][j] = LocalMatrix[i][j];
213
214 // Compute X scale factor and normalize first row.
215 Scale.x = detail::length_impl(Row[0]); // v3Length(Row[0]);
216
217 Row[0] = detail::scale_impl(Row[0], static_cast<T>(1));
218
219 // Compute XY shear factor and make 2nd row orthogonal to 1st.
220 Skew.z = dot(Row[0], Row[1]);
221 Row[1] = detail::combine_impl(Row[1], Row[0], static_cast<T>(1), -Skew.z);
222
223 // Now, compute Y scale and normalize 2nd row.
224 Scale.y = detail::length_impl(Row[1]);
225 Row[1] = detail::scale_impl(Row[1], static_cast<T>(1));
226 Skew.z /= Scale.y;
227
228 // Compute XZ and YZ shears, orthogonalize 3rd row.
229 Skew.y = glm::dot(Row[0], Row[2]);
230 Row[2] = detail::combine_impl(Row[2], Row[0], static_cast<T>(1), -Skew.y);
231 Skew.x = glm::dot(Row[1], Row[2]);
232 Row[2] = detail::combine_impl(Row[2], Row[1], static_cast<T>(1), -Skew.x);
233
234 // Next, get Z scale and normalize 3rd row.
235 Scale.z = detail::length_impl(Row[2]);
236 Row[2] = detail::scale_impl(Row[2], static_cast<T>(1));
237 Skew.y /= Scale.z;
238 Skew.x /= Scale.z;
239
240 // At this point, the matrix (in rows[]) is orthonormal.
241 // Check for a coordinate system flip. If the determinant
242 // is -1, then negate the matrix and the scaling factors.
243 Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3);
244 if(dot(Row[0], Pdum3) < 0)
245 {
246 for(length_t i = 0; i < 3; i++)
247 {
248 Scale[i] *= static_cast<T>(-1);
249 Row[i] *= static_cast<T>(-1);
250 }
251 }
252
253 // Now, get the rotations out, as described in the gem.
254
255 // FIXME - Add the ability to return either quaternions (which are
256 // easier to recompose with) or Euler angles (rx, ry, rz), which
257 // are easier for authors to deal with. The latter will only be useful
258 // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
259 // will leave the Euler angle code here for now.
260
261 // ret.rotateY = asin(-Row[0][2]);
262 // if (cos(ret.rotateY) != 0) {
263 // ret.rotateX = atan2(Row[1][2], Row[2][2]);
264 // ret.rotateZ = atan2(Row[0][1], Row[0][0]);
265 // } else {
266 // ret.rotateX = atan2(-Row[2][0], Row[1][1]);
267 // ret.rotateZ = 0;
268 // }
269
270 int i, j, k = 0;
271 T root, trace = Row[0].x + Row[1].y + Row[2].z;
272 if(trace > static_cast<T>(0))
273 {
274 root = sqrt(trace + static_cast<T>(1.0));
275 Orientation.w = static_cast<T>(0.5) * root;
276 root = static_cast<T>(0.5) / root;
277 Orientation.x = root * (Row[1].z - Row[2].y);
278 Orientation.y = root * (Row[2].x - Row[0].z);
279 Orientation.z = root * (Row[0].y - Row[1].x);
280 } // End if > 0
281 else
282 {
283 static int Next[3] = {1, 2, 0};
284 i = 0;
285 if(Row[1].y > Row[0].x)
286 i = 1;
287 if(Row[2].z > Row[i][i])
288 i = 2;
289 j = Next[i];
290 k = Next[j];
291
292#ifdef GLM_FORCE_QUAT_DATA_WXYZ
293 int off = 1;
294#else
295 int off = 0;
296#endif
297
298 root = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast<T>(1.0));
299
300 Orientation[i + off] = static_cast<T>(0.5) * root;
301 root = static_cast<T>(0.5) / root;
302 Orientation[j + off] = root * (Row[i][j] + Row[j][i]);
303 Orientation[k + off] = root * (Row[i][k] + Row[k][i]);
304 Orientation.w = root * (Row[j][k] - Row[k][j]);
305 } // End if <= 0
306
307 return true;
308}
309} // namespace math
entt::handle b
entt::handle a
float scale
Definition hub.cpp:25
GLM_FUNC_QUALIFIER vec< 3, T, Q > combine_impl(vec< 3, T, Q > const &a, vec< 3, T, Q > const &b, T ascl, T bscl)
Make a linear combination of two vectors and return the result.
GLM_FUNC_QUALIFIER T scale_fix(T &in)
GLM_FUNC_QUALIFIER vec< 3, T, Q > scale_impl(vec< 3, T, Q > const &v, T desiredLength)
GLM_FUNC_QUALIFIER T length_impl(vec< L, T, Q > const &v)
Definition bbox.cpp:5
GLM_FUNC_QUALIFIER void glm_recompose(mat< 4, 4, T, Q > &model_matrix, vec< 3, T, Q > const &in_scale, qua< T, Q > const &in_orientation, vec< 3, T, Q > const &in_translation, vec< 3, T, Q > const &in_skew, vec< 4, T, Q > const &in_perspective)
GLM_FUNC_QUALIFIER mat< 4, 4, T, Q > recompose_impl(vec< 3, T, Q > const &scale, qua< T, Q > const &orientation, vec< 3, T, Q > const &translation, vec< 3, T, Q > const &skew, vec< 4, T, Q > const &perspective)
GLM_FUNC_QUALIFIER bool glm_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)
float y
float x
float z