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
This commit is contained in:
2018-11-22 13:38:03 +03:00
parent e49c66efae
commit 1e820898ff
14 changed files with 226 additions and 86 deletions

View File

@@ -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]))