Revision: 43450 http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=43450 Author: mont29 Date: 2012-01-17 13:30:20 +0000 (Tue, 17 Jan 2012) Log Message: ----------- New pchan to pose matrices computes. Fixes [#27898] Bone snap to cursor fails and [#29461] Selection-to-Cursor works strange with bones with TrackTo constraint. Also fixes some inconsistant behavior of no Inherit Rotation/Scale options.
WARNING: This commits modifies how translated unconnected child bones with *no Inherit Rotation option* are positionned. This means that if you open a posed/animated armature using such (corner-case) setup, you'll have to adjust manually the locations of such bones: now, disabling Inherit Rotation/Scale will no more move the bone, only affecting its rotation/scale. Many thanks to Bassam Kurdali (slikdigit) for his advices and tests of the patch! ----- Dev notes?\194?\160: the pchan_to_pose_mat() func was added to BKE_armature.h, which computes two matrices to get the pose transformations (pchan) of the bone directly in pose (i.e. armature object) space. The first matrix is the rotation/scaling parts, the second one is for location. That new function is used by (hence deduplicating and simplifying their code): * The pose evaluation code (where_is_pose_bone()). * The interactive transformation code (add_pose_transdata(), in transform_conversion.c). * The snap to cursor/grid code (through armature_loc_pose_to_bone()/armature_mat_pose_to_bone()). Modified Paths: -------------- trunk/blender/source/blender/blenkernel/BKE_armature.h trunk/blender/source/blender/blenkernel/intern/armature.c trunk/blender/source/blender/editors/space_view3d/view3d_snap.c trunk/blender/source/blender/editors/transform/transform_conversions.c Modified: trunk/blender/source/blender/blenkernel/BKE_armature.h =================================================================== --- trunk/blender/source/blender/blenkernel/BKE_armature.h 2012-01-17 13:26:59 UTC (rev 43449) +++ trunk/blender/source/blender/blenkernel/BKE_armature.h 2012-01-17 13:30:20 UTC (rev 43450) @@ -114,6 +114,10 @@ void pchan_to_mat4(struct bPoseChannel *pchan, float chan_mat[4][4]); void pchan_calc_mat(struct bPoseChannel *pchan); +/* Get the "pchan to pose" transform matrix. These matrices apply the effects of + * HINGE/NO_SCALE/NO_LOCAL_LOCATION options over the pchan loc/rot/scale transformations. */ +void pchan_to_pose_mat(struct bPoseChannel *pchan, float rotscale_mat[][4], float loc_mat[][4]); + /* 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); Modified: trunk/blender/source/blender/blenkernel/intern/armature.c =================================================================== --- trunk/blender/source/blender/blenkernel/intern/armature.c 2012-01-17 13:26:59 UTC (rev 43449) +++ trunk/blender/source/blender/blenkernel/intern/armature.c 2012-01-17 13:30:20 UTC (rev 43450) @@ -590,7 +590,7 @@ /* ************ Armature Deform ******************* */ typedef struct bPoseChanDeform { - Mat4 *b_bone_mats; + Mat4 *b_bone_mats; DualQuat *dual_quat; DualQuat *b_bone_dual_quats; } bPoseChanDeform; @@ -1123,66 +1123,183 @@ copy_v3_v3(outloc, nLocMat[3]); } -/* 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) +/* Construct the matrices (rot/scale and loc) to apply the PoseChannels into the armature (object) space. + * I.e. (roughly) the "pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)" in the + * pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) + * ...function. + * + * This allows to get the transformations of a bone in its object space, *before* constraints (and IK) + * get applied (used by pose evaluation code). + * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale + * in object space (used by interactive transform, and snapping code). + * + * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix + * will differ from the rotation/scale 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). + * (note: I don't understand that, so I keep it :p --mont29). */ -void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outmat[][4]) +void pchan_to_pose_mat(bPoseChannel *pchan, float rotscale_mat[][4], float loc_mat[][4]) { - float pc_trans[4][4], inv_trans[4][4]; - float pc_posemat[4][4], inv_posemat[4][4]; - float pose_mat[4][4]; + Bone *bone, *parbone; + bPoseChannel *parchan; - /* paranoia: prevent crashes with no pose-channel supplied */ - if (pchan==NULL) return; + /* set up variables for quicker access below */ + bone= pchan->bone; + parbone= bone->parent; + parchan= pchan->parent; - /* default flag */ - if((pchan->bone->flag & BONE_NO_LOCAL_LOCATION)==0) { - /* get the inverse matrix of the pchan's transforms */ - switch(pchan->rotmode) { - case ROT_MODE_QUAT: - loc_quat_size_to_mat4(pc_trans, pchan->loc, pchan->quat, pchan->size); - break; - case ROT_MODE_AXISANGLE: - loc_axisangle_size_to_mat4(pc_trans, pchan->loc, pchan->rotAxis, pchan->rotAngle, pchan->size); - break; - default: /* euler */ - loc_eul_size_to_mat4(pc_trans, pchan->loc, pchan->eul, pchan->size); + if(parchan) { + float offs_bone[4][4]; /* yoffs(b-1) + root(b) + bonemat(b). */ + + /* Bone transform itself. */ + copy_m4_m3(offs_bone, bone->bone_mat); + + /* The bone's root offset (is in the parent's coordinate system). */ + copy_v3_v3(offs_bone[3], bone->head); + + /* Get the length translation of parent (length along y axis). */ + offs_bone[3][1]+= parbone->length; + + /* Compose the rotscale matrix for this bone. */ + if((bone->flag & BONE_HINGE) && (bone->flag & BONE_NO_SCALE)) { + /* Parent rest rotation and scale. */ + mult_m4_m4m4(rotscale_mat, parbone->arm_mat, offs_bone); } + else if(bone->flag & BONE_HINGE) { + /* Parent rest rotation and pose scale. */ + float tmat[4][4], tscale[3]; - copy_m4_m4(pose_mat, pchan->pose_mat); + /* Extract the scale of the parent pose matrix. */ + mat4_to_size(tscale, parchan->pose_mat); + size_to_mat4(tmat, tscale); + + /* Applies the parent pose scale to the rest matrix. */ + mult_m4_m4m4(tmat, tmat, parbone->arm_mat); + + mult_m4_m4m4(rotscale_mat, tmat, offs_bone); + } + 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); + normalize_m4(tmat); + mult_m4_m4m4(rotscale_mat, tmat, offs_bone); + } + else + mult_m4_m4m4(rotscale_mat, parchan->pose_mat, offs_bone); + +# if 1 + /* Compose the loc matrix for this bone. */ + /* NOTE: That version deos 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) { + /* 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(tmat4); + + mul_v3_m4v3(bone_loc[3], parchan->pose_mat, offs_bone[3]); + + unit_m3(bone_rotscale); + copy_m3_m4(tmat3, parchan->pose_mat); + mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale); + + copy_m4_m3(tmat4, bone_rotscale); + mult_m4_m4m4(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)) { + mult_m4_m4m4(loc_mat, parchan->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); +# endif +# if 0 + /* Compose the loc matrix for this bone. */ + /* NOTE: That version modifies bone's loc when HINGE/NO_SCALE options are set. */ + + /* In these cases we need to compute location separately */ + if(bone->flag & (BONE_HINGE|BONE_NO_SCALE|BONE_NO_LOCAL_LOCATION)) { + 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(tmat4); + + mul_v3_m4v3(bone_loc[3], parchan->pose_mat, offs_bone[3]); + + /* "No local location" is not transformed by bone matrix. */ + /* This only affects orientations (rotations), as scale is always 1.0 here. */ + if(bone->flag & BONE_NO_LOCAL_LOCATION) + unit_m3(bone_rotscale); + else + /* We could also use bone->bone_mat directly, here... */ + copy_m3_m4(bone_rotscale, offs_bone); + + if(bone->flag & BONE_HINGE) { + copy_m3_m4(tmat3, parbone->arm_mat); + /* for hinge-only, we use armature *rotation*, but pose mat *scale*! */ + if(!(bone->flag & BONE_NO_SCALE)) { + float size[3], tsmat[3][3]; + mat4_to_size(size, parchan->pose_mat); + size_to_mat3(tsmat, size); + mul_m3_m3m3(tmat3, tsmat, tmat3); + } + mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale); + } + else if(bone->flag & BONE_NO_SCALE) { + /* For no-scale only, normalized parent pose mat is enough! */ + copy_m3_m4(tmat3, parchan->pose_mat); + normalize_m3(tmat3); + mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale); + } + /* NO_LOCAL_LOCATION only. */ + else { + copy_m3_m4(tmat3, parchan->pose_mat); + mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale); + } + + copy_m4_m3(tmat4, bone_rotscale); + mult_m4_m4m4(loc_mat, bone_loc, tmat4); + } + /* Else, just use the same matrix for rotation/scaling, and location. */ + else + copy_m4_m4(loc_mat, rotscale_mat); +# endif } + /* Root bones. */ else { - /* local location, this is not default, different calculation - * note: only tested for location with pose bone snapping. - * If this is not useful in other cases the BONE_NO_LOCAL_LOCATION - * case may have to be split into its own function. */ - unit_m4(pc_trans); - copy_v3_v3(pc_trans[3], pchan->loc); + /* Rotation/scaling. */ + copy_m4_m4(rotscale_mat, pchan->bone->arm_mat); + /* Translation. */ + if(pchan->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]); + } + else + copy_m4_m4(loc_mat, rotscale_mat); + } +} - /* use parents rotation/scale space + own absolute position */ - if(pchan->parent) copy_m4_m4(pose_mat, pchan->parent->pose_mat); - else unit_m4(pose_mat); +/* 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 armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outmat[][4]) +{ + float rotscale_mat[4][4], loc_mat[4][4]; - copy_v3_v3(pose_mat[3], pchan->pose_mat[3]); - } + pchan_to_pose_mat(pchan, rotscale_mat, loc_mat); + invert_m4(rotscale_mat); + invert_m4(loc_mat); - - invert_m4_m4(inv_trans, pc_trans); - - /* Remove the pchan's transforms from it's pose_mat. - * This should leave behind the effects of restpose + - * parenting + constraints - */ - mult_m4_m4m4(pc_posemat, pose_mat, inv_trans); - - /* get the inverse of the leftovers so that we can remove - * that component from the supplied matrix - */ - invert_m4_m4(inv_posemat, pc_posemat); - - /* get the new matrix */ - mult_m4_m4m4(outmat, inv_posemat, inmat); + mult_m4_m4m4(outmat, rotscale_mat, inmat); + mul_v3_m4v3(outmat[3], loc_mat, inmat[3]); } /* Convert Pose-Space Location to Bone-Space Location @@ -2263,98 +2380,30 @@ */ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, int do_extra) { - Bone *bone, *parbone; - bPoseChannel *parchan; - float vec[3]; - - /* set up variables for quicker access below */ - bone= pchan->bone; - parbone= bone->parent; - parchan= pchan->parent; - - /* this gives a chan_mat with actions (ipos) results */ @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs