From 74609bfd510c98161b8e251cb10f6e299e44e544 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 19 Mar 2021 15:22:45 +1100 Subject: Cleanup: minor changes to pose-mode apply visual transform - Remove use of evaluated poses, instead calculate transformations into an array which is applied afterwards. - Only update ID's for poses that have been changed. --- source/blender/editors/armature/pose_transform.c | 73 ++++++++++++++++-------- source/blender/makesdna/DNA_action_types.h | 5 +- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index bb7ec82490a..8d1c196e9c2 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -512,37 +512,60 @@ static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op)) { ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + + /* Needed to ensure #bPoseChannel.pose_mat are up to date. */ + CTX_data_ensure_evaluated_depsgraph(C); FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) { - /* Loop over all selected pchan's. - * - * TODO, loop over children before parents if multiple bones - * at once are to be predictable*/ - FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) { - const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); - float delta_mat[4][4]; - - /* chan_mat already contains the delta transform from rest pose to pose-mode pose - * as that is baked into there so that B-Bones will work. Once we've set this as the - * new raw-transform components, don't recalc the poses yet, otherwise IK result will - * change, thus changing the result we may be trying to record. - */ - /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset - * (see T38251). - * Using pchan->pose_mat and bringing it back in bone space seems to work as expected! - */ - BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, delta_mat); + const bArmature *arm = ob->data; + + int chanbase_len = BLI_listbase_count(&ob->pose->chanbase); + /* Storage for the calculated matrices to prevent reading from modified values. + * NOTE: this could be avoided if children were always calculated before parents + * however ensuring this is involved and doesn't give any significant advantage. */ + struct { + float matrix[4][4]; + bool is_set; + } *pchan_xform_array = MEM_mallocN(sizeof(*pchan_xform_array) * chanbase_len, __func__); + bool changed = false; - BKE_pchan_apply_mat4(pchan, delta_mat, true); + int i; + LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, i) { + if (!((pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone))) { + pchan_xform_array[i].is_set = false; + continue; + } + + /* `chan_mat` already contains the delta transform from rest pose to pose-mode pose + * as that is baked into there so that B-Bones will work. Once we've set this as the + * new raw-transform components, don't recalculate the poses yet, otherwise IK result will + * change, thus changing the result we may be trying to record. */ + + /* NOTE: For some reason `pchan->chan_mat` can't be used here as it gives odd + * rotation/offset, see T38251. + * Using `pchan->pose_mat` and bringing it back in bone space seems to work as expected! + * This matches how visual key-framing works. */ + BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, pchan_xform_array[i].matrix); + pchan_xform_array[i].is_set = true; + changed = true; } - FOREACH_PCHAN_SELECTED_IN_OBJECT_END; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + if (changed) { + /* Perform separately to prevent feedback loop. */ + LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, i) { + if (!pchan_xform_array[i].is_set) { + continue; + } + BKE_pchan_apply_mat4(pchan, pchan_xform_array[i].matrix, true); + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + } - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + MEM_freeN(pchan_xform_array); } FOREACH_OBJECT_IN_MODE_END; diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 27374c451e9..5cc525a6cff 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -287,7 +287,10 @@ typedef struct bPoseChannel { short rotmode; char _pad[2]; - /** Matrix result of loc/quat/size, and where we put deform in, see next line */ + /** + * Matrix result of location/rotation/scale components & constraints. + * This is the dynamic component of `pose_mat` (without #Bone.arm_mat). + */ float chan_mat[4][4]; /** * Constraints accumulate here. in the end, `pose_mat = bone->arm_mat * chan_mat` -- cgit v1.2.3