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
path: root/source
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2018-11-22 13:38:03 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2018-11-23 23:19:23 +0300
commit1e820898ff4dfc734710a6640ca7bafc0bfc69db (patch)
tree8f68fba82219df0295d89581e49e105ff907ba80 /source
parente49c66efae9d9fb85154ca4b3073ae3733400708 (diff)
Depsgraph: add a new operation node for computing B-Bone segments.
Computing the shape of a B-Bone is a quite expensive operation, and there are multiple constraints that can access this information in a variety of useful ways. This means computing the shape once per bone and saving it is good for performance. Since the shape may depend on the position of up to two other bones, often in a "cyclic" manner, this computation has to be a separate node with its own dependencies. Reviewers: sergey Differential Revision: https://developer.blender.org/D3975
Diffstat (limited to 'source')
-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;