diff options
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 21 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 126 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 12 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_armature_api.c | 55 |
4 files changed, 159 insertions, 55 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index e0e1103fe21..3a29dd0c3cb 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -128,9 +128,26 @@ void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, float mat[4][4], bool use_ void BKE_pchan_to_mat4(struct bPoseChannel *pchan, float chan_mat[4][4]); void BKE_pchan_calc_mat(struct bPoseChannel *pchan); -/* Get the "pchan to pose" transform matrix. These matrices apply the effects of +/* Simple helper, computes the offset bone matrix. */ +void BKE_get_offset_bone_mat(struct Bone *bone, float offs_bone[4][4]); + +/* Transformation inherited from the parent bone. These matrices apply the effects of * HINGE/NO_SCALE/NO_LOCAL_LOCATION options over the pchan loc/rot/scale transformations. */ -void BKE_pchan_to_pose_mat(struct bPoseChannel *pchan, float rotscale_mat[4][4], float loc_mat[4][4]); +typedef struct BoneParentTransform { + float rotscale_mat[4][4]; /* parent effect on rotation & scale pose channels */ + float loc_mat[4][4]; /* parent effect on location pose channel */ +} BoneParentTransform; + +/* Matrix-like algebra operations on the transform */ +void BKE_clear_bone_parent_transform(struct BoneParentTransform *bpt); +void BKE_invert_bone_parent_transform(struct BoneParentTransform *bpt); +void BKE_combine_bone_parent_transform(const struct BoneParentTransform *in1, const struct BoneParentTransform *in2, struct BoneParentTransform *result); + +void BKE_apply_bone_parent_transform(const struct BoneParentTransform *bpt, const float inmat[4][4], float outmat[4][4]); + +/* Get the current parent transformation for the given pose bone. */ +void BKE_pchan_to_parent_transform(struct bPoseChannel *pchan, struct BoneParentTransform *r_bpt); +void BKE_calc_bone_parent_transform(int bone_flag, const float offs_bone[4][4], const float parent_arm_mat[4][4], const float parent_pose_mat[4][4], struct BoneParentTransform *r_bpt); /* Rotation Mode Conversions - Used for PoseChannels + Objects... */ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index de4f89fe146..0c63d66bb29 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1459,9 +1459,8 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl } /* Simple helper, computes the offset bone matrix. - * offs_bone = yoffs(b-1) + root(b) + bonemat(b). - * Not exported, as it is only used in this file currently... */ -static void get_offset_bone_mat(Bone *bone, float offs_bone[4][4]) + * offs_bone = yoffs(b-1) + root(b) + bonemat(b). */ +void BKE_get_offset_bone_mat(Bone *bone, float offs_bone[4][4]) { BLI_assert(bone->parent != NULL); @@ -1492,7 +1491,7 @@ static void get_offset_bone_mat(Bone *bone, float offs_bone[4][4]) * pose-channel into its local space (i.e. 'visual'-keyframing). * (note: I don't understand that, so I keep it :p --mont29). */ -void BKE_pchan_to_pose_mat(bPoseChannel *pchan, float rotscale_mat[4][4], float loc_mat[4][4]) +void BKE_pchan_to_parent_transform(bPoseChannel *pchan, BoneParentTransform *r_bpt) { Bone *bone, *parbone; bPoseChannel *parchan; @@ -1505,109 +1504,142 @@ void BKE_pchan_to_pose_mat(bPoseChannel *pchan, float rotscale_mat[4][4], float if (parchan) { float offs_bone[4][4]; /* yoffs(b-1) + root(b) + bonemat(b). */ - get_offset_bone_mat(bone, offs_bone); + BKE_get_offset_bone_mat(bone, offs_bone); + BKE_calc_bone_parent_transform(bone->flag, offs_bone, parbone->arm_mat, parchan->pose_mat, r_bpt); + } + else { + BKE_calc_bone_parent_transform(bone->flag, bone->arm_mat, NULL, NULL, r_bpt); + } +} + +/* Compute the parent transform using data decoupled from specific data structures. + * + * bone_flag: Bone->flag containing settings + * offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent) + * parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL + * r_bpt: OUTPUT parent transform */ +void BKE_calc_bone_parent_transform(int bone_flag, const float offs_bone[4][4], const float parent_arm_mat[4][4], const float parent_pose_mat[4][4], BoneParentTransform *r_bpt) +{ + if (parent_pose_mat) { /* Compose the rotscale matrix for this bone. */ - if ((bone->flag & BONE_HINGE) && (bone->flag & BONE_NO_SCALE)) { + if ((bone_flag & BONE_HINGE) && (bone_flag & BONE_NO_SCALE)) { /* Parent rest rotation and scale. */ - mul_m4_m4m4(rotscale_mat, parbone->arm_mat, offs_bone); + mul_m4_m4m4(r_bpt->rotscale_mat, parent_arm_mat, offs_bone); } - else if (bone->flag & BONE_HINGE) { + else if (bone_flag & BONE_HINGE) { /* Parent rest rotation and pose scale. */ float tmat[4][4], tscale[3]; /* Extract the scale of the parent pose matrix. */ - mat4_to_size(tscale, parchan->pose_mat); + mat4_to_size(tscale, parent_pose_mat); size_to_mat4(tmat, tscale); /* Applies the parent pose scale to the rest matrix. */ - mul_m4_m4m4(tmat, tmat, parbone->arm_mat); + mul_m4_m4m4(tmat, tmat, parent_arm_mat); - mul_m4_m4m4(rotscale_mat, tmat, offs_bone); + mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone); } - else if (bone->flag & BONE_NO_SCALE) { + else if (bone_flag & BONE_NO_SCALE) { /* Parent pose rotation and rest scale (i.e. no scaling). */ float tmat[4][4]; - copy_m4_m4(tmat, parchan->pose_mat); + copy_m4_m4(tmat, parent_pose_mat); normalize_m4(tmat); - mul_m4_m4m4(rotscale_mat, tmat, offs_bone); + mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone); } else - mul_m4_m4m4(rotscale_mat, parchan->pose_mat, offs_bone); + mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone); /* Compose the loc matrix for this bone. */ /* NOTE: That version does not modify bone's loc when HINGE/NO_SCALE options are set. */ /* In this case, use the object's space *orientation*. */ - if (bone->flag & BONE_NO_LOCAL_LOCATION) { + if (bone_flag & BONE_NO_LOCAL_LOCATION) { /* XXX I'm sure that code can be simplified! */ float bone_loc[4][4], bone_rotscale[3][3], tmat4[4][4], tmat3[3][3]; unit_m4(bone_loc); - unit_m4(loc_mat); + unit_m4(r_bpt->loc_mat); unit_m4(tmat4); - mul_v3_m4v3(bone_loc[3], parchan->pose_mat, offs_bone[3]); + mul_v3_m4v3(bone_loc[3], parent_pose_mat, offs_bone[3]); unit_m3(bone_rotscale); - copy_m3_m4(tmat3, parchan->pose_mat); + copy_m3_m4(tmat3, parent_pose_mat); mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale); copy_m4_m3(tmat4, bone_rotscale); - mul_m4_m4m4(loc_mat, bone_loc, tmat4); + mul_m4_m4m4(r_bpt->loc_mat, bone_loc, tmat4); } /* Those flags do not affect position, use plain parent transform space! */ - else if (bone->flag & (BONE_HINGE | BONE_NO_SCALE)) { - mul_m4_m4m4(loc_mat, parchan->pose_mat, offs_bone); + else if (bone_flag & (BONE_HINGE | BONE_NO_SCALE)) { + mul_m4_m4m4(r_bpt->loc_mat, parent_pose_mat, offs_bone); } /* Else (i.e. default, usual case), just use the same matrix for rotation/scaling, and location. */ else - copy_m4_m4(loc_mat, rotscale_mat); + copy_m4_m4(r_bpt->loc_mat, r_bpt->rotscale_mat); } /* Root bones. */ else { /* Rotation/scaling. */ - copy_m4_m4(rotscale_mat, pchan->bone->arm_mat); + copy_m4_m4(r_bpt->rotscale_mat, offs_bone); /* Translation. */ - if (pchan->bone->flag & BONE_NO_LOCAL_LOCATION) { + if (bone_flag & BONE_NO_LOCAL_LOCATION) { /* Translation of arm_mat, without the rotation. */ - unit_m4(loc_mat); - copy_v3_v3(loc_mat[3], pchan->bone->arm_mat[3]); + unit_m4(r_bpt->loc_mat); + copy_v3_v3(r_bpt->loc_mat[3], offs_bone[3]); } else - copy_m4_m4(loc_mat, rotscale_mat); + copy_m4_m4(r_bpt->loc_mat, r_bpt->rotscale_mat); } } +void BKE_clear_bone_parent_transform(struct BoneParentTransform *bpt) +{ + unit_m4(bpt->rotscale_mat); + unit_m4(bpt->loc_mat); +} + +void BKE_invert_bone_parent_transform(struct BoneParentTransform *bpt) +{ + invert_m4(bpt->rotscale_mat); + invert_m4(bpt->loc_mat); +} + +void BKE_combine_bone_parent_transform(const struct BoneParentTransform *in1, const struct BoneParentTransform *in2, struct BoneParentTransform *result) +{ + mul_m4_m4m4(result->rotscale_mat, in1->rotscale_mat, in2->rotscale_mat); + mul_m4_m4m4(result->loc_mat, in1->loc_mat, in2->loc_mat); +} + +void BKE_apply_bone_parent_transform(const struct BoneParentTransform *bpt, const float inmat[4][4], float outmat[4][4]) +{ + /* in case inmat == outmat */ + float tmploc[3]; + copy_v3_v3(tmploc, inmat[3]); + + mul_m4_m4m4(outmat, bpt->rotscale_mat, inmat); + mul_v3_m4v3(outmat[3], bpt->loc_mat, tmploc); +} + /* Convert Pose-Space Matrix to Bone-Space Matrix. * NOTE: this cannot be used to convert to pose-space transforms of the supplied * pose-channel into its local space (i.e. 'visual'-keyframing) */ void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) { - float rotscale_mat[4][4], loc_mat[4][4], inmat_[4][4]; - - /* Security, this allows to call with inmat == outmat! */ - copy_m4_m4(inmat_, inmat); + BoneParentTransform bpt; - BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat); - invert_m4(rotscale_mat); - invert_m4(loc_mat); - - mul_m4_m4m4(outmat, rotscale_mat, inmat_); - mul_v3_m4v3(outmat[3], loc_mat, inmat_[3]); + BKE_pchan_to_parent_transform(pchan, &bpt); + BKE_invert_bone_parent_transform(&bpt); + BKE_apply_bone_parent_transform(&bpt, inmat, outmat); } /* Convert Bone-Space Matrix to Pose-Space Matrix. */ void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) { - float rotscale_mat[4][4], loc_mat[4][4], inmat_[4][4]; - - /* Security, this allows to call with inmat == outmat! */ - copy_m4_m4(inmat_, inmat); - - BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat); + BoneParentTransform bpt; - mul_m4_m4m4(outmat, rotscale_mat, inmat_); - mul_v3_m4v3(outmat[3], loc_mat, inmat_[3]); + BKE_pchan_to_parent_transform(pchan, &bpt); + BKE_apply_bone_parent_transform(&bpt, inmat, outmat); } /* Convert Pose-Space Location to Bone-Space Location @@ -1917,7 +1949,7 @@ void BKE_armature_where_is_bone(Bone *bone, Bone *prevbone, const bool use_recur if (prevbone) { float offs_bone[4][4]; /* yoffs(b-1) + root(b) + bonemat(b) */ - get_offset_bone_mat(bone, offs_bone); + BKE_get_offset_bone_mat(bone, offs_bone); /* Compose the matrix for this bone */ mul_m4_m4m4(bone->arm_mat, prevbone->arm_mat, offs_bone); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 599bff810da..110f51d8fc1 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -677,22 +677,22 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr /* proper way to get parent transform + own transform + constraints transform */ copy_m3_m4(omat, ob->obmat); - /* New code, using "generic" BKE_pchan_to_pose_mat(). */ + /* New code, using "generic" BKE_pchan_to_parent_transform(). */ { - float rotscale_mat[4][4], loc_mat[4][4]; + BoneParentTransform bpt; float rpmat[3][3]; - BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat); + BKE_pchan_to_parent_transform(pchan, &bpt); if (t->mode == TFM_TRANSLATION) - copy_m3_m4(pmat, loc_mat); + copy_m3_m4(pmat, bpt.loc_mat); else - copy_m3_m4(pmat, rotscale_mat); + copy_m3_m4(pmat, bpt.rotscale_mat); /* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal, * and want align snapping, we just need both loc_mat and rotscale_mat. * So simply always store rotscale mat in td->ext, and always use it to apply rotations... * Ugly to need such hacks! :/ */ - copy_m3_m4(rpmat, rotscale_mat); + copy_m3_m4(rpmat, bpt.rotscale_mat); if (constraints_list_needinv(t, &pchan->constraints)) { copy_m3_m4(tmat, pchan->constinv); diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c index 55caac973d8..cc311fbe1d2 100644 --- a/source/blender/makesrna/intern/rna_armature_api.c +++ b/source/blender/makesrna/intern/rna_armature_api.c @@ -42,6 +42,8 @@ #include <stddef.h> +#include "DNA_armature_types.h" + #include "BLI_math_vector.h" #include "BKE_armature.h" @@ -57,6 +59,32 @@ static float rna_Bone_do_envelope(Bone *bone, float *vec) bone->rad_tail * scale, bone->dist * scale); } +static void rna_Bone_convert_local_to_pose(Bone *bone, float *r_matrix, float *matrix, float *matrix_local, float *parent_matrix, float *parent_matrix_local, bool invert) +{ + BoneParentTransform bpt; + float offs_bone[4][4]; + float (*bone_arm_mat)[4] = (float (*)[4])matrix_local; + float (*parent_pose_mat)[4] = (float (*)[4])parent_matrix; + float (*parent_arm_mat)[4] = (float (*)[4])parent_matrix_local; + + if (is_zero_m4(parent_pose_mat) || is_zero_m4(parent_arm_mat)) { + /* No parent case. */ + BKE_calc_bone_parent_transform(bone->flag, bone_arm_mat, NULL, NULL, &bpt); + } + else { + invert_m4_m4(offs_bone, parent_arm_mat); + mul_m4_m4m4(offs_bone, offs_bone, bone_arm_mat); + + BKE_calc_bone_parent_transform(bone->flag, offs_bone, parent_arm_mat, parent_pose_mat, &bpt); + } + + if (invert) { + BKE_invert_bone_parent_transform(&bpt); + } + + BKE_apply_bone_parent_transform(&bpt, (float (*)[4])matrix, (float (*)[4])r_matrix); +} + static void rna_Bone_MatrixFromAxisRoll(float *axis, float roll, float *r_matrix) { vec_roll_to_mat3(axis, roll, (float (*)[3])r_matrix); @@ -103,6 +131,33 @@ void RNA_api_bone(StructRNA *srna) parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "convert_local_to_pose", "rna_Bone_convert_local_to_pose"); + RNA_def_function_ui_description(func, + "Transform a matrix from Local to Pose space (or back), taking " + "into account options like Inherit Scale and Local Location. " + "Unlike Object.convert_space, this uses custom rest and pose " + "matrices provided by the caller. If the parent matrices are " + "omitted, the bone is assumed to have no parent."); + parm = RNA_def_property(func, "matrix_return", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The transformed matrix"); + RNA_def_function_output(func, parm); + parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The matrix to transform"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_property(func, "matrix_local", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The custom rest matrix of this bone (Bone.matrix_local)"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_property(func, "parent_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The custom pose matrix of the parent bone (PoseBone.matrix)"); + parm = RNA_def_property(func, "parent_matrix_local", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The custom rest matrix of the parent bone (Bone.matrix_local)"); + parm = RNA_def_boolean(func, "invert", false, "", "Convert from Pose to Local space"); + /* Conversions between Matrix and Axis + Roll representations. */ func = RNA_def_function(srna, "MatrixFromAxisRoll", "rna_Bone_MatrixFromAxisRoll"); RNA_def_function_ui_description(func, "Convert the axis + roll representation to a matrix"); |