author Bastien Montagne Fri, 9 Oct 2015 18:57:37 +0000 (20:57 +0200) committer Bastien Montagne Fri, 9 Oct 2015 19:26:33 +0000 (21:26 +0200)
mat3_polar_decompose gives the right polar decomposition of given matrix,
as a pair (U, P) of matrices.

interp_m3_m3m3 uses that polar decomposition to perform a correct matrix interpolation,
even with non-uniformly scaled ones (where blend_m3_m3m3 would fail).

interp_m4_m4m4 just adds translation interpolation to the _m3 variant.

index d7a309e08350732521a7a13433632b7cf038d558..80a399ac6d7bc2cc35529e976d880b0ce13ba2ce 100644 (file)
@@ -215,6 +215,8 @@ void mat4_to_loc_rot_size(float loc, float rot, float size, float wm
void mat4_to_loc_quat(float loc, float quat, float wmat);
void mat4_decompose(float loc, float quat, float size, float wmat);

+void mat3_polar_decompose(float mat3, float r_U, float r_P);
+
void loc_eul_size_to_mat4(float R,
const float loc, const float eul, const float size);
void loc_eulO_size_to_mat4(float R,
@@ -227,6 +229,9 @@ void loc_axisangle_size_to_mat4(float R,
void blend_m3_m3m3(float R, float A, float B, const float t);
void blend_m4_m4m4(float R, float A, float B, const float t);

+void interp_m3_m3m3(float R, float A, float B, const float t);
+void interp_m4_m4m4(float R, float A, float B, const float t);
+
bool is_negative_m3(float mat);
bool is_negative_m4(float mat);

index 33d0fb87acac6d0c4168b6cdabeb3f84d8c32b1b..8e41a86b52fcb1c7942b405f6315d1c41e23b574 100644 (file)
@@ -1521,6 +1521,34 @@ void mat4_decompose(float loc, float quat, float size, float wmat
mat3_to_quat(quat, rot);
}

+/**
+ * Right polar decomposition:
+ *     M = UP
+ *
+ * U is the 'rotation'-like component, the closest orthogonal matrix to M.
+ * P is the 'scaling'-like component, defined in U space.
+ *
+ * See https://en.wikipedia.org/wiki/Polar_decomposition for more.
+ */
+void mat3_polar_decompose(float mat3, float r_U, float r_P)
+{
+       /* From svd decomposition (M = WSV*), we have:
+        *     U = WV*
+        *     P = VSV*
+        */
+       float W, S, V, Vt;
+       float sval;
+
+       BLI_svd_m3(mat3, W, sval, V);
+
+       size_to_mat3(S, sval);
+
+       transpose_m3_m3(Vt, V);
+       mul_m3_m3m3(r_U, W, Vt);
+       mul_m3_series(r_P, V, S, Vt);
+}
+
+
void scale_m3_fl(float m, float scale)
{
m = m = m = scale;
@@ -1660,6 +1688,75 @@ void blend_m4_m4m4(float out, float dst, float src, const floa
loc_quat_size_to_mat4(out, floc, fquat, fsize);
}

+/**
+ * A polar-decomposition-based interpolation between matrix A and matrix B.
+ *
+ * \note This code is about five times slower as the 'naive' interpolation done by \a blend_m3_m3m3
+ *       (it typically remains below 2 usec on an average i74700, while \a blend_m3_m3m3 remains below 0.4 usec).
+ *       However, it gives expected results even with non-uniformaly scaled matrices, see T46418 for an example.
+ *
+ * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
+ *
+ * @return R the interpolated matrix.
+ * @param A the intput matrix which is totally effective with \a t = 0.0.
+ * @param B the intput matrix which is totally effective with \a t = 1.0.
+ * @param t the interpolation factor.
+ */
+void interp_m3_m3m3(float R, float A, float B, const float t)
+{
+       /* 'Rotation' component ('U' part of polar decomposition, the closest orthogonal matrix to M3 rot/scale
+        * transformation matrix), spherically interpolated. */
+       float U_A, U_B, U;
+       float quat_A, quat_B, quat;
+       /* 'Scaling' component ('P' part of polar decomposition, i.e. scaling in U-defined space), linearly interpolated. */
+       float P_A, P_B, P;
+
+       int i;
+
+       mat3_polar_decompose(A, U_A, P_A);
+       mat3_polar_decompose(B, U_B, P_B);
+
+       mat3_to_quat(quat_A, U_A);
+       mat3_to_quat(quat_B, U_B);
+       interp_qt_qtqt(quat, quat_A, quat_B, t);
+       quat_to_mat3(U, quat);
+
+       for (i = 0; i < 3; i++) {
+               interp_v3_v3v3(P[i], P_A[i], P_B[i], t);
+       }
+
+       /* And we reconstruct rot/scale matrix from interpolated polar components */
+       mul_m3_m3m3(R, U, P);
+}
+
+/**
+ * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from interp_m3_m3m3.
+ *
+ * @return R the interpolated matrix.
+ * @param A the intput matrix which is totally effective with \a t = 0.0.
+ * @param B the intput matrix which is totally effective with \a t = 1.0.
+ * @param t the interpolation factor.
+ */
+void interp_m4_m4m4(float R, float A, float B, const float t)
+{
+       float A3, B3, R3;
+
+       /* Location component, linearly interpolated. */
+       float loc_A, loc_B, loc;
+
+       copy_v3_v3(loc_A, A);
+       copy_v3_v3(loc_B, B);
+       interp_v3_v3v3(loc, loc_A, loc_B, t);
+
+       copy_m3_m4(A3, A);
+       copy_m3_m4(B3, B);
+
+       interp_m3_m3m3(R3, A3, B3, t);
+
+       copy_m4_m3(R, R3);
+       copy_v3_v3(R, loc);
+}
+
bool is_negative_m3(float mat)
{
float vec;
index acd9f944e4cffaf554ea170dd25332b1166a2d73..e10d6b13b5983df02f759be68fe032a50246ecdc 100644 (file)
@@ -37,11 +37,11 @@ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "\${CMAKE_EXE_LINKER_FLAGS_DEBUG} \${PLATFORM_LIN

BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
-BLENDER_TEST(BLI_math_geom "bf_blenlib")
+BLENDER_TEST(BLI_math_geom "bf_blenlib;extern_eigen3")
BLENDER_TEST(BLI_math_base "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")
BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;\${ZLIB_LIBRARIES}")
-BLENDER_TEST(BLI_polyfill2d "bf_blenlib")
+BLENDER_TEST(BLI_polyfill2d "bf_blenlib;extern_eigen3")
BLENDER_TEST(BLI_listbase "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")