diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2018-12-08 09:17:57 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2018-12-11 20:40:51 +0300 |
commit | 48a3f97b23501fd33f6e400b7682ea4cb2988a8a (patch) | |
tree | 10b571a29b3ba81d60f072ea648c24f2c59b684a /source/blender/blenkernel | |
parent | 4de5478409ea3b7749de46ff28bedceb79b6b481 (diff) |
RNA: provide access to bone parent transform math from Python.
Applying the effect of bone parent is much more complicated than
simple matrix multiplication because of the various flags like
Inherit Scale. Thus it is reasonable to provide access to this
math from Python for complicated rest pose related manipulations.
The simple case of this is handled by Object.convert_space, so
the new method is only needed for complex tasks.
Differential Revision: https://developer.blender.org/D4053
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 21 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 126 |
2 files changed, 98 insertions, 49 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); |