diff options
-rw-r--r-- | source/blender/blenkernel/BKE_action.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_armature.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/action.c | 18 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 90 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature_update.c | 17 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 32 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 1 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc | 11 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/builder/deg_builder_relations.cc | 48 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc | 56 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_type_defines.cc | 1 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_types.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_armature.c | 7 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_action_types.h | 19 |
14 files changed, 226 insertions, 86 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 79e0860cb98..7f4feb6c2d5 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -137,6 +137,8 @@ void action_groups_clear_tempflags(struct bAction *act); void BKE_pose_channel_free(struct bPoseChannel *pchan); void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user); +void BKE_pose_channel_free_bbone_cache(struct bPoseChannel *pchan); + void BKE_pose_channels_free(struct bPose *pose); void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index be8bd9557e5..1831e93cccb 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -170,6 +170,9 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, const bool rest, Mat4 resul int BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]); +void BKE_pchan_cache_bbone_segments(struct bPoseChannel *pchan); +void BKE_pchan_copy_bbone_segments_cache(struct bPoseChannel *pchan, struct bPoseChannel *pchan_from); + /* like EBONE_VISIBLE */ #define PBONE_VISIBLE(arm, bone) ( \ CHECK_TYPE_INLINE(arm, bArmature *), \ @@ -241,6 +244,11 @@ void BKE_pose_bone_done( struct Object *ob, int pchan_index); +void BKE_pose_eval_bbone_segments( + struct Depsgraph *depsgraph, + struct Object *ob, + int pchan_index); + void BKE_pose_iktree_evaluate( struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 87f821130c7..79230ad9e94 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -594,6 +594,9 @@ void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const } pchan->draw_data = NULL; /* Drawing cache, no need to copy. */ + + /* Runtime data, no need to copy. */ + memset(&pchan->runtime, 0, sizeof(pchan->runtime)); } /* for now, duplicate Bone Groups too when doing this */ @@ -790,6 +793,21 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) /* Cached data, for new draw manager rendering code. */ MEM_SAFE_FREE(pchan->draw_data); + + /* Cached B-Bone shape data. */ + BKE_pose_channel_free_bbone_cache(pchan); +} + +/** Deallocates runtime cache of a pose channel's B-Bone shape. */ +void BKE_pose_channel_free_bbone_cache(bPoseChannel *pchan) +{ + bPoseChannelRuntime *runtime = &pchan->runtime; + + runtime->bbone_segments = 0; + MEM_SAFE_FREE(runtime->bbone_rest_mats); + MEM_SAFE_FREE(runtime->bbone_pose_mats); + MEM_SAFE_FREE(runtime->bbone_deform_mats); + MEM_SAFE_FREE(runtime->bbone_dual_quats); } void BKE_pose_channel_free(bPoseChannel *pchan) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 967e2ac921c..2004b66c1ef 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -822,26 +822,46 @@ typedef struct ObjectBBoneDeform { int num_pchan; } ObjectBBoneDeform; -static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info, const bool use_quaternion) +static void allocate_bbone_cache(bPoseChannel *pchan, int segments) { + bPoseChannelRuntime *runtime = &pchan->runtime; + + if (runtime->bbone_segments != segments) { + if (runtime->bbone_segments != 0) { + BKE_pose_channel_free_bbone_cache(pchan); + } + + runtime->bbone_segments = segments; + runtime->bbone_rest_mats = MEM_malloc_arrayN(sizeof(Mat4), (uint)segments, "bPoseChannelRuntime::bbone_rest_mats"); + runtime->bbone_pose_mats = MEM_malloc_arrayN(sizeof(Mat4), (uint)segments, "bPoseChannelRuntime::bbone_pose_mats"); + runtime->bbone_deform_mats = MEM_malloc_arrayN(sizeof(Mat4), 1 + (uint)segments, "bPoseChannelRuntime::bbone_deform_mats"); + runtime->bbone_dual_quats = MEM_malloc_arrayN(sizeof(DualQuat), (uint)segments, "bPoseChannelRuntime::bbone_dual_quats"); + } +} + +/** Compute and cache the B-Bone shape in the channel runtime struct. */ +void BKE_pchan_cache_bbone_segments(bPoseChannel *pchan) +{ + bPoseChannelRuntime *runtime = &pchan->runtime; Bone *bone = pchan->bone; - Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV]; - Mat4 *b_bone_mats; - DualQuat *b_bone_dual_quats = NULL; + int segments = bone->segments; + + BLI_assert(segments > 1); + + /* Allocate the cache if needed. */ + allocate_bbone_cache(pchan, segments); + + /* Compute the shape. */ + Mat4 *b_bone = runtime->bbone_pose_mats; + Mat4 *b_bone_rest = runtime->bbone_rest_mats; + Mat4 *b_bone_mats = runtime->bbone_deform_mats; + DualQuat *b_bone_dual_quats = runtime->bbone_dual_quats; int a; b_bone_spline_setup(pchan, false, b_bone); b_bone_spline_setup(pchan, true, b_bone_rest); - /* allocate b_bone matrices and dual quats */ - b_bone_mats = MEM_mallocN((1 + bone->segments) * sizeof(Mat4), "BBone defmats"); - pdef_info->b_bone_mats = b_bone_mats; - - if (use_quaternion) { - b_bone_dual_quats = MEM_mallocN((bone->segments) * sizeof(DualQuat), "BBone dqs"); - pdef_info->b_bone_dual_quats = b_bone_dual_quats; - } - + /* Compute deform matrices. */ /* first matrix is the inverse arm_mat, to bring points in local bone space * for finding out which segment it belongs to */ invert_m4_m4(b_bone_mats[0].mat, bone->arm_mat); @@ -858,8 +878,27 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info invert_m4_m4(tmat, b_bone_rest[a].mat); mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat); - if (use_quaternion) - mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat); + mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat); + } +} + +/** Copy cached B-Bone segments from one channel to another */ +void BKE_pchan_copy_bbone_segments_cache(bPoseChannel *pchan, bPoseChannel *pchan_from) +{ + bPoseChannelRuntime *runtime = &pchan->runtime; + bPoseChannelRuntime *runtime_from = &pchan_from->runtime; + int segments = runtime_from->bbone_segments; + + if (segments <= 1) { + BKE_pose_channel_free_bbone_cache(pchan); + } + else { + allocate_bbone_cache(pchan, segments); + + memcpy(runtime->bbone_rest_mats, runtime_from->bbone_rest_mats, sizeof(Mat4) * segments); + memcpy(runtime->bbone_pose_mats, runtime_from->bbone_pose_mats, sizeof(Mat4) * segments); + memcpy(runtime->bbone_deform_mats, runtime_from->bbone_deform_mats, sizeof(Mat4) * (1 + segments)); + memcpy(runtime->bbone_dual_quats, runtime_from->bbone_dual_quats, sizeof(DualQuat) * segments); } } @@ -978,7 +1017,7 @@ static float dist_bone_deform(bPoseChannel *pchan, const bPoseChanDeform *pdef_i contrib = fac; if (contrib > 0.0f) { if (vec) { - if (bone->segments > 1) + if (bone->segments > 1 && pdef_info->b_bone_mats != NULL) /* applies on cop and bbonemat */ b_bone_deform(pdef_info, bone, cop, NULL, (mat) ? bbonemat : NULL); else @@ -992,7 +1031,7 @@ static float dist_bone_deform(bPoseChannel *pchan, const bPoseChanDeform *pdef_i pchan_deform_mat_add(pchan, fac, bbonemat, mat); } else { - if (bone->segments > 1) { + if (bone->segments > 1 && pdef_info->b_bone_mats != NULL) { b_bone_deform(pdef_info, bone, cop, &bbonedq, NULL); add_weighted_dq_dq(dq, &bbonedq, fac); } @@ -1059,7 +1098,10 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index) const bool use_quaternion = data->use_quaternion; if (pchan->bone->segments > 1) { - pchan_b_bone_defmats(pchan, pdef_info, use_quaternion); + BLI_assert(pchan->runtime.bbone_segments == pchan->bone->segments); + + pdef_info->b_bone_mats = pchan->runtime.bbone_deform_mats; + pdef_info->b_bone_dual_quats = pchan->runtime.bbone_dual_quats; } if (use_quaternion) { @@ -2498,16 +2540,6 @@ void BKE_armature_cached_bbone_deformation_free_data(Object *object) if (bbone_deform == NULL) { return; } - /* free B_bone matrices */ - for (int i = 0; i < bbone_deform->num_pchan; i++) { - bPoseChanDeform *pdef_info = &bbone_deform->pdef_info_array[i]; - if (pdef_info->b_bone_mats != NULL) { - MEM_freeN(pdef_info->b_bone_mats); - } - if (pdef_info->b_bone_dual_quats != NULL) { - MEM_freeN(pdef_info->b_bone_dual_quats); - } - } /* Free arrays. */ MEM_SAFE_FREE(bbone_deform->pdef_info_array); MEM_SAFE_FREE(bbone_deform->dualquats); @@ -2560,7 +2592,7 @@ void BKE_armature_cached_bbone_deformation_update(Object *object) BLI_task_parallel_listbase(&pose->chanbase, &data, armature_bbone_defmats_cb, - totchan > 512); + totchan > 1024); /* Store pointers. */ bbone_deform->dualquats = dualquats; atomic_cas_ptr((void **)&bbone_deform->pdef_info_array, diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 0fba7677479..b917aae08de 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -605,6 +605,11 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, /* clear flags */ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); + + /* Free B-Bone shape data cache if it's not a B-Bone. */ + if (pchan->bone == NULL || pchan->bone->segments <= 1) { + BKE_pose_channel_free_bbone_cache(pchan); + } } pose_pchan_index_create(pose); @@ -713,6 +718,17 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, } } +void BKE_pose_eval_bbone_segments(struct Depsgraph *depsgraph, + struct Object *ob, + int pchan_index) +{ + bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); + DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan); + if (pchan->bone != NULL && pchan->bone->segments > 1) { + BKE_pchan_cache_bbone_segments(pchan); + } +} + void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -834,4 +850,5 @@ void BKE_pose_eval_proxy_copy_bone( BLI_assert(pchan != NULL); BLI_assert(pchan_from != NULL); BKE_pose_copyesult_pchan_result(pchan, pchan_from); + BKE_pchan_copy_bbone_segments_cache(pchan, pchan_from); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 96df4f402c5..d8956ce28b7 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -590,15 +590,12 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m /* skip length interpolation if set to head */ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); } - else if (is_bbone) { + else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) { /* use point along bbone */ - Mat4 bbone[MAX_BBONE_SUBDIV]; + Mat4 *bbone = pchan->runtime.bbone_pose_mats; float tempmat[4][4]; float loc[3], fac; - /* get bbone segments */ - b_bone_spline_setup(pchan, false, bbone); - /* figure out which segment(s) the headtail value falls in */ fac = (float)pchan->bone->segments * headtail; @@ -2164,7 +2161,7 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph), /* Compute and accumulate transformation for a single target bone. */ static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, const float wco[3], bool force_envelope, float *r_totweight, float r_sum_mat[4][4], DualQuat *r_sum_dq) { - float mat[4][4], iobmat[4][4], iamat[4][4], basemat[4][4], co[3]; + float mat[4][4], iobmat[4][4], basemat[4][4], co[3]; Bone *bone = pchan->bone; float weight = ct->weight; @@ -2172,9 +2169,6 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, c invert_m4_m4(iobmat, ct->tar->obmat); mul_v3_m4v3(co, iobmat, wco); - /* Inverted rest pose matrix: bone->chan_mat may not be final yet. */ - invert_m4_m4(iamat, bone->arm_mat); - /* Multiply by the envelope weight when appropriate. */ if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) { weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail, @@ -2182,7 +2176,10 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, c } /* Find the correct bone transform matrix in world space. */ - if (bone->segments > 1) { + if (bone->segments > 1 && bone->segments == pchan->runtime.bbone_segments) { + Mat4 *b_bone_mats = pchan->runtime.bbone_deform_mats; + float (*iamat)[4] = b_bone_mats[0].mat; + /* The target is a B-Bone: * FIRST: find the segment (see b_bone_deform in armature.c) * Need to transform co back to bonespace, only need y. */ @@ -2193,19 +2190,12 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, c CLAMP(a, 0, bone->segments - 1); - /* SECOND: compute the matrix (see pchan_b_bone_defmats in armature.c) */ - Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV]; - float irmat[4][4]; - - b_bone_spline_setup(pchan, false, b_bone); - b_bone_spline_setup(pchan, true, b_bone_rest); - - invert_m4_m4(irmat, b_bone_rest[a].mat); - mul_m4_series(mat, ct->matrix, b_bone[a].mat, irmat, iamat, iobmat); + /* Convert the selected matrix into object space. */ + mul_m4_series(mat, ct->tar->obmat, b_bone_mats[a + 1].mat, iobmat); } else { - /* Simple bone. */ - mul_m4_series(mat, ct->matrix, iamat, iobmat); + /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */ + mul_m4_series(mat, ct->tar->obmat, pchan->chan_mat, iobmat); } /* Accumulate the transformation. */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f07f9363167..d44eda49151 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5095,6 +5095,7 @@ static void direct_link_pose(FileData *fd, bPose *pose) CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX); pchan->draw_data = NULL; + memset(&pchan->runtime, 0, sizeof(pchan->runtime)); } pose->ikdata = NULL; if (pose->ikparam != NULL) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index eb2ed0e637d..8c349b7067f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -261,7 +261,18 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) object_cow, pchan_index), DEG_OPCODE_BONE_DONE); + + /* B-Bone shape computation - the real last step if present. */ + if (pchan->bone != NULL && pchan->bone->segments > 1) { + op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, + function_bind(BKE_pose_eval_bbone_segments, _1, + object_cow, + pchan_index), + DEG_OPCODE_BONE_SEGMENTS); + } + op_node->set_as_exit(); + /* Custom properties. */ if (pchan->prop != NULL) { add_operation_node(&object->id, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 8f579216518..5e1ebee337c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -206,6 +206,17 @@ static eDepsOperation_Code bone_target_opcode(ID *target, return DEG_OPCODE_BONE_DONE; } +static bool bone_has_segments(Object *object, const char *bone_name) +{ + /* Proxies don't have BONE_SEGMENTS */ + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + return false; + } + /* Only B-Bones have segments. */ + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + return pchan && pchan->bone && pchan->bone->segments > 1; +} + /* **** General purpose functions **** */ DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, @@ -1017,39 +1028,20 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, /* relation to bone */ opcode = bone_target_opcode(&ct->tar->id, ct->subtarget, id, component_subdata, root_map); + /* Armature constraint always wants the final position and chan_mat. */ + if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { + opcode = DEG_OPCODE_BONE_DONE; + } + /* if needs bbone shape, reference the segment computation */ + if (BKE_constraint_target_uses_bbone(con, ct) && + bone_has_segments(ct->tar, ct->subtarget)) { + opcode = DEG_OPCODE_BONE_SEGMENTS; + } OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_BONE, ct->subtarget, opcode); add_relation(target_key, constraint_op_key, cti->name); - /* if needs bbone shape, also reference handles */ - if (BKE_constraint_target_uses_bbone(con, ct)) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); - /* actually a bbone */ - if (pchan && pchan->bone && pchan->bone->segments > 1) { - bPoseChannel *prev, *next; - BKE_pchan_get_bbone_handles(pchan, &prev, &next); - /* add handle links */ - if (prev) { - opcode = bone_target_opcode(&ct->tar->id, prev->name, - id, component_subdata, root_map); - OperationKey prev_key(&ct->tar->id, - DEG_NODE_TYPE_BONE, - prev->name, - opcode); - add_relation(prev_key, constraint_op_key, cti->name); - } - if (next) { - opcode = bone_target_opcode(&ct->tar->id, next->name, - id, component_subdata, root_map); - OperationKey next_key(&ct->tar->id, - DEG_NODE_TYPE_BONE, - next->name, - opcode); - add_relation(next_key, constraint_op_key, cti->name); - } - } - } } else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 1abed8bb6a2..1260ce013ea 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -488,10 +488,41 @@ void DepsgraphRelationBuilder::build_rig(Object *object) * For IK chains however, an additional rel is created from IK * to done, with transitive reduction removing this one. */ add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - /* Assume that all bones must be done for the pose to be ready - * (for deformers). */ - add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link"); - add_relation(bone_done_key, pose_cleanup_key, "Cleanup dependency"); + /* B-Bone shape is the real final step after Done if present. */ + if (pchan->bone != NULL && pchan->bone->segments > 1) { + OperationKey bone_segments_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_SEGMENTS); + /* B-Bone shape depends on the final position of the bone. */ + add_relation(bone_done_key, bone_segments_key, "Done -> B-Bone Segments"); + /* B-Bone shape depends on final position of handle bones. */ + bPoseChannel *prev, *next; + BKE_pchan_get_bbone_handles(pchan, &prev, &next); + if (prev) { + OperationKey prev_key(&object->id, + DEG_NODE_TYPE_BONE, + prev->name, + DEG_OPCODE_BONE_DONE); + add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments"); + } + if (next) { + OperationKey next_key(&object->id, + DEG_NODE_TYPE_BONE, + next->name, + DEG_OPCODE_BONE_DONE); + add_relation(next_key, bone_segments_key, "Next Handle -> B-Bone Segments"); + } + /* Pose requires the B-Bone shape. */ + add_relation(bone_segments_key, pose_done_key, "PoseEval Result-Bone Link"); + add_relation(bone_segments_key, pose_cleanup_key, "Cleanup dependency"); + } + else { + /* Assume that all bones must be done for the pose to be ready + * (for deformers). */ + add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link"); + add_relation(bone_done_key, pose_cleanup_key, "Cleanup dependency"); + } /* Custom shape. */ if (pchan->custom != NULL) { build_object(NULL, pchan->custom); @@ -537,9 +568,20 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done"); /* Make sure bone in the proxy is not done before it's FROM is done. */ - add_relation(from_bone_done_key, - bone_done_key, - "From Bone Done -> Pose Done"); + if (pchan->bone && pchan->bone->segments > 1) { + OperationKey from_bone_segments_key(&proxy_from->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_SEGMENTS); + add_relation(from_bone_segments_key, + bone_done_key, + "From Bone Segments -> Bone Done"); + } + else { + add_relation(from_bone_done_key, + bone_done_key, + "From Bone Done -> Bone Done"); + } if (pchan->prop != NULL) { OperationKey bone_parameters(&object->id, diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 44e21656570..3f36b9f7831 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -157,6 +157,7 @@ const char *operationCodeAsString(eDepsOperation_Code opcode) STRINGIFY_OPCODE(BONE_CONSTRAINTS); STRINGIFY_OPCODE(BONE_READY); STRINGIFY_OPCODE(BONE_DONE); + STRINGIFY_OPCODE(BONE_SEGMENTS); /* Particles. */ STRINGIFY_OPCODE(PARTICLE_SYSTEM_EVAL_INIT); STRINGIFY_OPCODE(PARTICLE_SYSTEM_EVAL); diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index d81483526ed..f8b519cb1aa 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -254,6 +254,8 @@ typedef enum eDepsOperation_Code { // TODO: deform mats could get calculated in the final_transform ops... DEG_OPCODE_BONE_READY, DEG_OPCODE_BONE_DONE, + /* B-Bone segment shape computation (after DONE) */ + DEG_OPCODE_BONE_SEGMENTS, /* Particles. --------------------------------------- */ /* Particle System evaluation. */ diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 40581093b28..aec25274ab1 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -1082,7 +1082,12 @@ static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pc if (pchan) { Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix; if (bbone_segments > 1) { - b_bone_spline_setup(pchan, false, bbones_mat); + if (bbone_segments == pchan->runtime.bbone_segments) { + memcpy(bbones_mat, pchan->runtime.bbone_pose_mats, sizeof(Mat4) * bbone_segments); + } + else { + b_bone_spline_setup(pchan, false, bbones_mat); + } for (int i = bbone_segments; i--; bbones_mat++) { mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s); diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 44c9e52cd8e..4d0f4ef1b0f 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -199,6 +199,22 @@ typedef struct bPoseChannelDrawData { float bbone_matrix[0][4][4]; } bPoseChannelDrawData; +struct Mat4; +struct DualQuat; + +typedef struct bPoseChannelRuntime { + int bbone_segments; + char pad[4]; + + /* Rest and posed matrices for segments. */ + struct Mat4 *bbone_rest_mats; + struct Mat4 *bbone_pose_mats; + + /* Delta from rest to pose in matrix and DualQuat form. */ + struct Mat4 *bbone_deform_mats; + struct DualQuat *bbone_dual_quats; +} bPoseChannelRuntime; + /* ************************************************ */ /* Poses */ @@ -287,6 +303,9 @@ typedef struct bPoseChannel { /* Points to an original pose channel. */ struct bPoseChannel *orig_pchan; + + /* Runtime data. */ + struct bPoseChannelRuntime runtime; } bPoseChannel; |