From 1854cccad7c31a6b8235faf980ffdd6a80163e02 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 5 May 2019 13:25:43 +0300 Subject: Drivers: add an Average Scale option to the Transform Channel driver vars. Unlike location and rotation, there is a meaningful definition of overall/average scaling via the total change in the volume. This adds an option to retrieve that via a single driver variable, instead of having to use three and an expression. Using the determinant to compute the volume scaling also allows detecting flipping due to negative scale - this is impossible to do via the three variable approach. The volume_scale functions are added purely for code readability: 'volume scale factor' is easier to understand than determinant. Differential Revision: https://developer.blender.org/D4803 --- source/blender/blenkernel/intern/fcurve.c | 5 +++++ source/blender/blenlib/BLI_math_matrix.h | 4 ++++ source/blender/blenlib/intern/math_matrix.c | 20 ++++++++++++++++++++ source/blender/makesdna/DNA_anim_types.h | 1 + source/blender/makesrna/intern/rna_fcurve.c | 1 + 5 files changed, 31 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 8c95e4c7ff3..e2d0a479792 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1707,6 +1707,11 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) /* not valid channel */ return 0.0f; } + else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) { + /* Cubic root of the change in volume, equal to the geometric mean + * of scale over all three axes unless the matrix includes shear. */ + return cbrtf(mat4_to_volume_scale(mat)); + } else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) { /* Extract scale, and choose the right axis, * inline 'mat4_to_size'. */ diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 652f096f32d..cc3159556bf 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -260,6 +260,7 @@ float determinant_m2(float a, float b, float c, float d); float determinant_m3( float a, float b, float c, float d, float e, float f, float g, float h, float i); float determinant_m3_array(const float m[3][3]); +float determinant_m4_mat3_array(const float m[4][4]); float determinant_m4(const float A[4][4]); #define PSEUDOINVERSE_EPSILON 1e-8f @@ -277,6 +278,9 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]); void scale_m3_fl(float R[3][3], float scale); void scale_m4_fl(float R[4][4], float scale); +float mat3_to_volume_scale(const float M[3][3]); +float mat4_to_volume_scale(const float M[4][4]); + float mat3_to_scale(const float M[3][3]); float mat4_to_scale(const float M[4][4]); float mat4_to_xy_scale(const float M[4][4]); diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index e09fae7d140..0fd947b6b1a 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -931,6 +931,13 @@ float determinant_m3_array(const float m[3][3]) m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); } +float determinant_m4_mat3_array(const float m[4][4]) +{ + return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - + m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + + m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); +} + bool invert_m3_ex(float m[3][3], const float epsilon) { float tmp[3][3]; @@ -1641,6 +1648,19 @@ void mat4_to_size(float size[3], const float mat[4][4]) size[2] = len_v3(mat[2]); } +/* This computes the overall volume scale factor of a transformation matrix. + * For an orthogonal matrix, it is the product of all three scale values. + * Returns a negative value if the transform is flipped by negative scale. */ +float mat3_to_volume_scale(const float mat[3][3]) +{ + return determinant_m3_array(mat); +} + +float mat4_to_volume_scale(const float mat[4][4]) +{ + return determinant_m4_mat3_array(mat); +} + /* this gets the average scale of a matrix, only use when your scaling * data that has no idea of scale axis, examples are bone-envelope-radius * and curve radius */ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index c76d4895b25..fbb720ad0b1 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -357,6 +357,7 @@ typedef enum eDriverTarget_TransformChannels { DTAR_TRANSCHAN_SCALEX, DTAR_TRANSCHAN_SCALEY, DTAR_TRANSCHAN_SCALEZ, + DTAR_TRANSCHAN_SCALE_AVG, MAX_DTAR_TRANSCHAN_TYPES, } eDriverTarget_TransformChannels; diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index c8df01a7dc7..d9917b670d9 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1645,6 +1645,7 @@ static void rna_def_drivertarget(BlenderRNA *brna) {DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""}, {DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""}, {DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""}, + {DTAR_TRANSCHAN_SCALE_AVG, "SCALE_AVG", 0, "Average Scale", ""}, {0, NULL, 0, NULL, NULL}, }; -- cgit v1.2.3