diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_constraint.py | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_fcurve.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 37 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/fcurve.c | 68 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_constraint_types.h | 24 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_enum_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_constraint.c | 29 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_fcurve.c | 26 |
8 files changed, 154 insertions, 42 deletions
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index d8eb0db62fc..0ba9fd0630c 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -370,6 +370,8 @@ class ConstraintButtonsPanel: def COPY_ROTATION(self, _context, layout, con): self.target_template(layout, con) + layout.prop(con, "euler_order", text="Order") + split = layout.split() col = split.column() @@ -685,6 +687,9 @@ class ConstraintButtonsPanel: col.row().label(text="Source:") col.row().prop(con, "map_from", expand=True) + if con.map_from == 'ROTATION': + layout.prop(con, "from_rotation_mode", text="Mode") + split = layout.split() ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale" @@ -727,6 +732,9 @@ class ConstraintButtonsPanel: col.label(text="Destination:") col.row().prop(con, "map_to", expand=True) + if con.map_to == 'ROTATION': + layout.prop(con, "to_euler_order", text="Order") + split = layout.split() ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale" diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 4c1a115eb23..5be9a35b168 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -89,6 +89,9 @@ struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver); void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list); +void BKE_driver_target_matrix_to_rot_channels( + float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]); + void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar); void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 1a3c562941e..ccacb85651c 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -62,6 +62,7 @@ #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_editmesh.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" @@ -1808,18 +1809,25 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar copy_v3_v3(loc, cob->matrix[3]); mat4_to_size(size, cob->matrix); + /* Select the Euler rotation order, defaulting to the owner. */ + short rot_order = cob->rotOrder; + + if (data->euler_order != CONSTRAINT_EULER_AUTO) { + rot_order = data->euler_order; + } + /* To allow compatible rotations, must get both rotations in the order of the owner... */ - mat4_to_eulO(obeul, cob->rotOrder, cob->matrix); + mat4_to_eulO(obeul, rot_order, cob->matrix); /* We must get compatible eulers from the beginning because * some of them can be modified below (see bug T21875). */ - mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix); + mat4_to_compatible_eulO(eul, obeul, rot_order, ct->matrix); if ((data->flag & ROTLIKE_X) == 0) { eul[0] = obeul[0]; } else { if (data->flag & ROTLIKE_OFFSET) { - rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]); + rotate_eulO(eul, rot_order, 'X', obeul[0]); } if (data->flag & ROTLIKE_X_INVERT) { @@ -1832,7 +1840,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } else { if (data->flag & ROTLIKE_OFFSET) { - rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]); + rotate_eulO(eul, rot_order, 'Y', obeul[1]); } if (data->flag & ROTLIKE_Y_INVERT) { @@ -1845,7 +1853,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } else { if (data->flag & ROTLIKE_OFFSET) { - rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]); + rotate_eulO(eul, rot_order, 'Z', obeul[2]); } if (data->flag & ROTLIKE_Z_INVERT) { @@ -1856,7 +1864,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* Good to make eulers compatible again, * since we don't know how much they were changed above. */ compatible_eul(eul, obeul); - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); + loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order); } } @@ -3719,7 +3727,8 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t if (VALID_CONS_TARGET(ct)) { float *from_min, *from_max, *to_min, *to_max; float loc[3], eul[3], size[3]; - float dvec[3], sval[3]; + float dbuf[4], sval[3]; + float *const dvec = dbuf + 1; int i; /* obtain target effect */ @@ -3738,7 +3747,8 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t from_max = data->from_max_scale; break; case TRANS_ROTATION: - mat4_to_eulO(dvec, cob->rotOrder, ct->matrix); + BKE_driver_target_matrix_to_rot_channels( + ct->matrix, cob->rotOrder, data->from_rotation_mode, -1, true, dbuf); from_min = data->from_min_rot; from_max = data->from_max_rot; break; @@ -3750,9 +3760,16 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t break; } + /* Select the output Euler rotation order, defaulting to the owner. */ + short rot_order = cob->rotOrder; + + if (data->to == TRANS_ROTATION && data->to_euler_order != CONSTRAINT_EULER_AUTO) { + rot_order = data->to_euler_order; + } + /* extract components of owner's matrix */ copy_v3_v3(loc, cob->matrix[3]); - mat4_to_eulO(eul, cob->rotOrder, cob->matrix); + mat4_to_eulO(eul, rot_order, cob->matrix); mat4_to_size(size, cob->matrix); /* determine where in range current transforms lie */ @@ -3811,7 +3828,7 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t } /* apply to matrix */ - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); + loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order); } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index ef53c926daa..c4da2d2efc9 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1732,35 +1732,21 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) * - only an option for "transform space", if quality is really bad with a) */ float quat[4]; - float *const eul = quat + 1; int channel; if (dtar->transChan == DTAR_TRANSCHAN_ROTW) { channel = 0; - quat[0] = 0.0f; } else { channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX; BLI_assert(channel < 4); } - if (dtar->rotation_mode == DTAR_ROTMODE_AUTO) { - mat4_to_eulO(eul, rot_order, mat); + BKE_driver_target_matrix_to_rot_channels( + mat, rot_order, dtar->rotation_mode, channel, false, quat); - if (use_eulers) { - compatible_eul(eul, oldEul); - } - } - else if (dtar->rotation_mode >= DTAR_ROTMODE_EULER_MIN && - dtar->rotation_mode <= DTAR_ROTMODE_EULER_MAX) { - mat4_to_eulO(eul, dtar->rotation_mode, mat); - } - else if (dtar->rotation_mode == DTAR_ROTMODE_QUATERNION) { - mat4_to_quat(quat, mat); - } - else { - BLI_assert(false); - zero_v3(eul); + if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) { + compatible_eul(quat + 1, oldEul); } return quat[channel]; @@ -1771,6 +1757,52 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) } } +/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */ +static void quaternion_to_angles(float quat[4], int channel) +{ + if (channel < 0) { + quat[0] = 2.0f * saacosf(quat[0]); + + for (int i = 1; i < 4; i++) { + quat[i] = 2.0f * saasinf(quat[i]); + } + } + else if (channel == 0) { + quat[0] = 2.0f * saacosf(quat[0]); + } + else { + quat[channel] = 2.0f * saasinf(quat[channel]); + } +} + +/* Compute channel values for a rotational Transform Channel driver variable. */ +void BKE_driver_target_matrix_to_rot_channels( + float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]) +{ + float *const quat = r_buf; + float *const eul = r_buf + 1; + + zero_v4(r_buf); + + if (rotation_mode == DTAR_ROTMODE_AUTO) { + mat4_to_eulO(eul, auto_order, mat); + } + else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) { + mat4_to_eulO(eul, rotation_mode, mat); + } + else if (rotation_mode == DTAR_ROTMODE_QUATERNION) { + mat4_to_quat(quat, mat); + + /* For Transformation constraint convenience, convert to pseudo-angles. */ + if (angles) { + quaternion_to_angles(quat, channel); + } + } + else { + BLI_assert(false); + } +} + /* ......... */ /* Table of Driver Variable Type Info Data */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 17ce279f1b7..42d58cb34d0 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -271,7 +271,8 @@ typedef struct bTrackToConstraint { typedef struct bRotateLikeConstraint { struct Object *tar; int flag; - int reserved1; + char euler_order; + char _pad[3]; /** MAX_ID_NAME-2. */ char subtarget[64]; } bRotateLikeConstraint; @@ -441,6 +442,13 @@ typedef struct bTransformConstraint { /** Extrapolate motion? if 0, confine to ranges. */ char expo; + /** Input rotation type - uses the same values as driver targets. */ + char from_rotation_mode; + /** Output euler order override. */ + char to_euler_order; + + char _pad[6]; + /** From_min/max defines range of target transform. */ float from_min[3]; /** To map on to to_min/max range. */ @@ -715,6 +723,20 @@ typedef enum eConstraintChannel_Flags { CONSTRAINT_CHANNEL_PROTECTED = (1 << 1), } eConstraintChannel_Flags; +/* Common enum for constraints that support override. */ +typedef enum eConstraint_EulerOrder { + /** Automatic euler mode. */ + CONSTRAINT_EULER_AUTO = 0, + + /** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */ + CONSTRAINT_EULER_XYZ = 1, + CONSTRAINT_EULER_XZY, + CONSTRAINT_EULER_YXZ, + CONSTRAINT_EULER_YZX, + CONSTRAINT_EULER_ZXY, + CONSTRAINT_EULER_ZYX, +} eConstraint_EulerOrder; + /* -------------------------------------- */ /* bRotateLikeConstraint.flag */ diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 02aaef44a1f..b3e1f22f413 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -91,6 +91,7 @@ extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[]; extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]; extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]; extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[]; +extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[]; extern const EnumPropertyItem rna_enum_keyblock_type_items[]; diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 539e2a66296..05154dcc20e 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -256,6 +256,17 @@ static const EnumPropertyItem track_axis_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem euler_order_items[] = { + {CONSTRAINT_EULER_AUTO, "AUTO", 0, "Default", "Euler using the default rotation order"}, + {CONSTRAINT_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"}, + {CONSTRAINT_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"}, + {CONSTRAINT_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"}, + {CONSTRAINT_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"}, + {CONSTRAINT_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"}, + {CONSTRAINT_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME static const EnumPropertyItem space_object_items[] = { @@ -1324,6 +1335,12 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert Z", "Invert the Z rotation"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "euler_order", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "euler_order"); + RNA_def_property_enum_items(prop, euler_order_items); + RNA_def_property_ui_text(prop, "Euler Order", "Explicitly specify the euler rotation order"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ROTLIKE_OFFSET); RNA_def_property_ui_text(prop, "Offset", "Add original rotation into copied rotation"); @@ -1885,6 +1902,18 @@ static void rna_def_constraint_transform(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Extrapolate Motion", "Extrapolate ranges"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "from_rotation_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "from_rotation_mode"); + RNA_def_property_enum_items(prop, rna_enum_driver_target_rotation_mode_items); + RNA_def_property_ui_text(prop, "From Mode", "Specify the type of rotation channels to use"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "to_euler_order", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "to_euler_order"); + RNA_def_property_enum_items(prop, euler_order_items); + RNA_def_property_ui_text(prop, "To Order", "Explicitly specify the output euler rotation order"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* Loc */ prop = RNA_def_property(srna, "from_min_x", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "from_min[0]"); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 684c786b1b9..b6b759882b3 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -132,6 +132,18 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[] = { + {DTAR_ROTMODE_AUTO, "AUTO", 0, "Auto Euler", "Euler using the rotation order of the target"}, + {DTAR_ROTMODE_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"}, + {DTAR_ROTMODE_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"}, + {DTAR_ROTMODE_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"}, + {DTAR_ROTMODE_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"}, + {DTAR_ROTMODE_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"}, + {DTAR_ROTMODE_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"}, + {DTAR_ROTMODE_QUATERNION, "QUATERNION", 0, "Quaternion", "Quaternion rotation"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "WM_api.h" @@ -1702,18 +1714,6 @@ static void rna_def_drivertarget(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - static const EnumPropertyItem prop_rotation_mode_items[] = { - {DTAR_ROTMODE_AUTO, "AUTO", 0, "Auto Euler", "Euler using the rotation order of the target"}, - {DTAR_ROTMODE_EULER_XYZ, "XYZ", 0, "XYZ Euler", "Euler using the XYZ rotation order"}, - {DTAR_ROTMODE_EULER_XZY, "XZY", 0, "XZY Euler", "Euler using the XZY rotation order"}, - {DTAR_ROTMODE_EULER_YXZ, "YXZ", 0, "YXZ Euler", "Euler using the YXZ rotation order"}, - {DTAR_ROTMODE_EULER_YZX, "YZX", 0, "YZX Euler", "Euler using the YZX rotation order"}, - {DTAR_ROTMODE_EULER_ZXY, "ZXY", 0, "ZXY Euler", "Euler using the ZXY rotation order"}, - {DTAR_ROTMODE_EULER_ZYX, "ZYX", 0, "ZYX Euler", "Euler using the ZYX rotation order"}, - {DTAR_ROTMODE_QUATERNION, "QUATERNION", 0, "Quaternion", "Quaternion rotation"}, - {0, NULL, 0, NULL, NULL}, - }; - srna = RNA_def_struct(brna, "DriverTarget", NULL); RNA_def_struct_ui_text(srna, "Driver Target", "Source of input values for driver variables"); @@ -1764,7 +1764,7 @@ static void rna_def_drivertarget(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "rotation_mode"); - RNA_def_property_enum_items(prop, prop_rotation_mode_items); + RNA_def_property_enum_items(prop, rna_enum_driver_target_rotation_mode_items); RNA_def_property_ui_text(prop, "Rotation Mode", "Mode for calculating rotation channel values"); RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data"); |