Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_action.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h8
-rw-r--r--source/blender/blenkernel/intern/action.c18
-rw-r--r--source/blender/blenkernel/intern/armature.c90
-rw-r--r--source/blender/blenkernel/intern/armature_update.c17
-rw-r--r--source/blender/blenkernel/intern/constraint.c32
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc48
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc56
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h2
-rw-r--r--source/blender/draw/intern/draw_armature.c7
-rw-r--r--source/blender/makesdna/DNA_action_types.h19
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;