Blender V5.0
deg_builder_relations_rig.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
13
14#include <cstdlib>
15#include <cstring> /* required for STREQ later on. */
16
17#include "BLI_listbase.h"
18#include "BLI_utildefines.h"
19
20#include "DNA_action_types.h"
21#include "DNA_armature_types.h"
24#include "DNA_object_types.h"
25
26#include "BKE_action.hh"
27#include "BKE_armature.hh"
28#include "BKE_constraint.h"
29
30#include "RNA_access.hh"
31#include "RNA_prototypes.hh"
32
33#include "DEG_depsgraph.hh"
35
42
45
46namespace blender::deg {
47
48/* IK Solver Eval Steps */
50 bPoseChannel *pchan,
51 bConstraint *con,
52 RootPChanMap *root_map)
53{
54 if ((con->flag & CONSTRAINT_DISABLE) != 0) {
55 /* Do not add disabled IK constraints to the relations. If these needs to be temporarily
56 * enabled, they will be added as temporary constraints during transform. */
57 return;
58 }
59
61 /* Attach owner to IK Solver to. */
63 if (rootchan == nullptr) {
64 return;
65 }
66 OperationKey pchan_local_key(
69 OperationKey solver_key(
72 /* If any of the constraint parameters are animated, connect the relation. Since there is only
73 * one Init IK node per armature, this link has quite high risk of spurious dependency cycles.
74 */
75 const bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC);
76 PointerRNA con_ptr = RNA_pointer_create_discrete(&object->id, &RNA_Constraint, con);
77 if (is_itasc || cache_->isAnyPropertyAnimated(&con_ptr)) {
78 add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
79 }
80 add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
81 /* Never cleanup before solver is run. */
82 add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE);
83 /* The ITASC solver currently accesses the target transforms in init tree :(
84 * TODO: Fix ITASC and remove this.
85 */
86 OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key;
87 /* IK target */
88 /* TODO(sergey): This should get handled as part of the constraint code. */
89 if (data->tar != nullptr) {
90 /* Different object - requires its transform. */
91 if (data->tar != object) {
92 ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM);
93 add_relation(target_key, target_dependent_key, con->name);
94 /* Ensure target evaluated copy is ready by the time IK tree is built just in case. */
95 ComponentKey target_cow_key(&data->tar->id, NodeType::COPY_ON_EVAL);
96 add_relation(target_cow_key,
97 init_ik_key,
98 "IK Target Copy-on-Eval -> Init IK Tree",
100 }
101 /* Subtarget references: */
102 if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
103 /* Bone - use the final transformation. */
104 OperationKey target_key(
105 &data->tar->id, NodeType::BONE, data->subtarget, OperationCode::BONE_DONE);
106 add_relation(target_key, target_dependent_key, con->name);
107 }
108 else if (data->subtarget[0] && ELEM(data->tar->type, OB_MESH, OB_LATTICE)) {
109 /* Vertex group target. */
110 /* NOTE: for now, we don't need to represent vertex groups
111 * separately. */
112 ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY);
113 add_relation(target_key, target_dependent_key, con->name);
115 }
116 if (data->tar == object && data->subtarget[0]) {
117 /* Prevent target's constraints from linking to anything from same
118 * chain that it controls. */
119 root_map->add_bone(data->subtarget, rootchan->name);
120 }
121 }
122 /* Pole Target. */
123 /* TODO(sergey): This should get handled as part of the constraint code. */
124 if (data->poletar != nullptr) {
125 /* Different object - requires its transform. */
126 if (data->poletar != object) {
127 ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM);
128 add_relation(target_key, target_dependent_key, con->name);
129 /* Ensure target evaluated copy is ready by the time IK tree is built just in case. */
130 ComponentKey target_cow_key(&data->poletar->id, NodeType::COPY_ON_EVAL);
131 add_relation(target_cow_key,
132 init_ik_key,
133 "IK Target Copy-on-Eval -> Init IK Tree",
135 }
136 /* Subtarget references: */
137 if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
138 /* Bone - use the final transformation. */
139 OperationKey target_key(
140 &data->poletar->id, NodeType::BONE, data->polesubtarget, OperationCode::BONE_DONE);
141 add_relation(target_key, target_dependent_key, con->name);
142 }
143 else if (data->polesubtarget[0] && ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) {
144 /* Vertex group target. */
145 /* NOTE: for now, we don't need to represent vertex groups
146 * separately. */
147 ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY);
148 add_relation(target_key, target_dependent_key, con->name);
150 }
151 }
153 BUILD,
154 "\nStarting IK Build: pchan = %s, target = (%s, %s), "
155 "segcount = %d\n",
156 pchan->name,
157 data->tar ? data->tar->id.name : "nullptr",
158 data->subtarget,
159 data->rootbone);
160 bPoseChannel *parchan = pchan;
161 /* Exclude tip from chain if needed. */
162 if (!(data->flag & CONSTRAINT_IK_TIP)) {
163 parchan = pchan->parent;
164 }
165 root_map->add_bone(parchan->name, rootchan->name);
166 OperationKey parchan_transforms_key(
167 &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY);
168 add_relation(parchan_transforms_key, solver_key, "IK Solver Owner");
169 /* Walk to the chain's root. */
170 int segcount = 0;
171 while (parchan != nullptr) {
172 /* Make IK-solver dependent on this bone's result, since it can only run
173 * after the standard results of the bone are know. Validate links step
174 * on the bone will ensure that users of this bone only grab the result
175 * with IK solver results. */
176 if (parchan != pchan) {
177 OperationKey parent_key(
178 &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY);
179 add_relation(parent_key, solver_key, "IK Chain Parent");
180 OperationKey bone_done_key(
181 &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE);
182 add_relation(solver_key, bone_done_key, "IK Chain Result");
183 }
184 else {
185 OperationKey final_transforms_key(
186 &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE);
187 add_relation(solver_key, final_transforms_key, "IK Solver Result");
188 }
189 parchan->flag |= POSE_DONE;
190 root_map->add_bone(parchan->name, rootchan->name);
191 /* continue up chain, until we reach target number of items. */
192 DEG_DEBUG_PRINTF((::Depsgraph *)graph_, BUILD, " %d = %s\n", segcount, parchan->name);
193 /* TODO(sergey): This is an arbitrary value, which was just following
194 * old code convention. */
195 segcount++;
196 if ((segcount == data->rootbone) || (segcount > 255)) {
197 break;
198 }
199 parchan = parchan->parent;
200 }
202 add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
203
204 /* Add relation when the root of this IK chain is influenced by another IK chain. */
205 build_inter_ik_chains(object, solver_key, rootchan, root_map);
206}
207
208/* Spline IK Eval Steps */
210 bPoseChannel *pchan,
211 bConstraint *con,
212 RootPChanMap *root_map)
213{
216 OperationKey transforms_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
218 OperationKey solver_key(
221 /* Solver depends on initialization. */
222 add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
223 /* Never cleanup before solver is run. */
224 add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup");
225 /* Attach owner to IK Solver. */
226 add_relation(transforms_key, solver_key, "Spline IK Solver Owner", RELATION_FLAG_GODMODE);
227 /* Attach path dependency to solver. */
228 if (data->tar != nullptr) {
229 ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY);
230 add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK");
231 ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM);
232 add_relation(target_transform_key, solver_key, "Curve.Transform -> Spline IK");
234 }
235 pchan->flag |= POSE_DONE;
236 OperationKey final_transforms_key(
238 add_relation(solver_key, final_transforms_key, "Spline IK Result");
239 root_map->add_bone(pchan->name, rootchan->name);
240 /* Walk to the chain's root/ */
241 int segcount = 1;
242 for (bPoseChannel *parchan = pchan->parent; parchan != nullptr && segcount < data->chainlen;
243 parchan = parchan->parent, segcount++)
244 {
245 /* Make Spline IK solver dependent on this bone's result, since it can
246 * only run after the standard results of the bone are know. Validate
247 * links step on the bone will ensure that users of this bone only grab
248 * the result with IK solver results. */
249 OperationKey parent_key(&object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY);
250 add_relation(parent_key, solver_key, "Spline IK Solver Update");
251 OperationKey bone_done_key(
252 &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE);
253 add_relation(solver_key, bone_done_key, "Spline IK Solver Result");
254 parchan->flag |= POSE_DONE;
255 root_map->add_bone(parchan->name, rootchan->name);
256 }
258 add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
259
260 /* Add relation when the root of this IK chain is influenced by another IK chain. */
261 build_inter_ik_chains(object, solver_key, rootchan, root_map);
262}
263
265 const OperationKey &solver_key,
266 const bPoseChannel *rootchan,
267 const RootPChanMap *root_map)
268{
269 bPoseChannel *deepest_root = nullptr;
270 const char *root_name = rootchan->name;
271
272 /* Find shared IK chain root. */
273 for (bPoseChannel *parchan = rootchan->parent; parchan; parchan = parchan->parent) {
274 if (!root_map->has_common_root(root_name, parchan->name)) {
275 break;
276 }
277 deepest_root = parchan;
278 }
279 if (deepest_root == nullptr) {
280 return;
281 }
282
283 OperationKey other_bone_key(
284 &object->id, NodeType::BONE, deepest_root->name, OperationCode::BONE_DONE);
285 add_relation(other_bone_key, solver_key, "IK Chain Overlap");
286}
287
288/* Pose/Armature Bones Graph */
290{
291 /* Armature-Data */
292 bArmature *armature = (bArmature *)object->data;
293 /* TODO: selection status? */
294 /* Attach links between pose operations. */
295 ComponentKey local_transform(&object->id, NodeType::TRANSFORM);
300 add_relation(local_transform, pose_init_key, "Local Transform -> Pose Init");
301 add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK");
302 add_relation(pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup");
303 /* Make sure pose is up-to-date with armature updates. */
304 build_armature(armature);
306 add_relation(armature_key, pose_init_key, "Data dependency");
307 /* Run cleanup even when there are no bones. */
308 add_relation(pose_init_ik_key, pose_cleanup_key, "Init -> Cleanup");
309 /* Relation to the instance, so that instancer can use pose of this object. */
311 OperationKey{&object->id, NodeType::INSTANCING, OperationCode::INSTANCE},
312 "Transform -> Instance");
313
314 /* IK Solvers.
315 *
316 * - These require separate processing steps are pose-level to be executed
317 * between chains of bones (i.e. once the base transforms of a bunch of
318 * bones is done).
319 *
320 * - We build relations for these before the dependencies between operations
321 * in the same component as it is necessary to check whether such bones
322 * are in the same IK chain (or else we get weird issues with either
323 * in-chain references, or with bones being parented to IK'd bones).
324 *
325 * Unsolved Issues:
326 * - Care is needed to ensure that multi-headed trees work out the same as
327 * in ik-tree building
328 * - Animated chain-lengths are a problem. */
329 RootPChanMap root_map;
330 bool pose_depends_on_local_transform = false;
331 LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
332 const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
333
334 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
335 const BuilderStack::ScopedEntry stack_entry = stack_.trace(*con);
336
337 switch (con->type) {
339 build_ik_pose(object, pchan, con, &root_map);
340 pose_depends_on_local_transform = true;
341 break;
343 build_splineik_pose(object, pchan, con, &root_map);
344 pose_depends_on_local_transform = true;
345 break;
346 /* Constraints which needs world's matrix for transform.
347 * TODO(sergey): More constraints here? */
352 /* TODO(sergey): Add used space check. */
353 pose_depends_on_local_transform = true;
354 break;
355 default:
356 break;
357 }
358 }
359 }
360 // root_map.print_debug();
361 if (pose_depends_on_local_transform) {
362 /* TODO(sergey): Once partial updates are possible use relation between
363 * object transform and solver itself in its build function. */
364 ComponentKey pose_key(&object->id, NodeType::EVAL_POSE);
365 ComponentKey local_transform_key(&object->id, NodeType::TRANSFORM);
366 add_relation(local_transform_key, pose_key, "Local Transforms");
367 }
368 /* Links between operations for each bone. */
369 LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
370 const BuilderStack::ScopedEntry stack_entry = stack_.trace(*pchan);
371
372 build_idproperties(pchan->prop);
373 build_idproperties(pchan->system_properties);
374 OperationKey bone_local_key(
375 &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
376 OperationKey bone_pose_key(
377 &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_POSE_PARENT);
378 OperationKey bone_ready_key(
379 &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
380 OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
381 pchan->flag &= ~POSE_DONE;
382 /* Pose init to bone local. */
383 add_relation(pose_init_key, bone_local_key, "Pose Init - Bone Local", RELATION_FLAG_GODMODE);
384 /* Local to pose parenting operation. */
385 add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose");
386 /* Parent relation. */
387 if (pchan->parent != nullptr) {
388 OperationCode parent_key_opcode;
389 /* NOTE: this difference in handling allows us to prevent lockups
390 * while ensuring correct poses for separate chains. */
391 if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
392 parent_key_opcode = OperationCode::BONE_READY;
393 }
394 else {
395 parent_key_opcode = OperationCode::BONE_DONE;
396 }
397
398 OperationKey parent_key(&object->id, NodeType::BONE, pchan->parent->name, parent_key_opcode);
399 add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone");
400 }
401 /* Build constraints. */
402 if (pchan->constraints.first != nullptr) {
403 /* Build relations for indirectly linked objects. */
404 BuilderWalkUserData data;
405 data.builder = this;
406 BKE_constraints_id_loop(&pchan->constraints, constraint_walk, IDWALK_NOP, &data);
407 /* Constraints stack and constraint dependencies. */
408 build_constraints(&object->id, NodeType::BONE, pchan->name, &pchan->constraints, &root_map);
409 /* Pose -> constraints. */
410 OperationKey constraints_key(
411 &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_CONSTRAINTS);
412 add_relation(bone_pose_key, constraints_key, "Pose -> Constraints Stack");
413 add_relation(bone_local_key, constraints_key, "Local -> Constraints Stack");
414 /* Constraints -> ready/ */
415 /* TODO(sergey): When constraint stack is exploded, this step should
416 * occur before the first IK solver. */
417 add_relation(constraints_key, bone_ready_key, "Constraints -> Ready");
418 }
419 else {
420 /* Pose -> Ready */
421 add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready");
422 }
423 /* Bone ready -> Bone done.
424 * NOTE: For bones without IK, this is all that's needed.
425 * For IK chains however, an additional rel is created from IK
426 * to done, with transitive reduction removing this one. */
427 add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
428 /* B-Bone shape is the real final step after Done if present. */
429 if (check_pchan_has_bbone(object, pchan)) {
430 OperationKey bone_segments_key(
431 &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS);
432 /* B-Bone shape depends on the final position of the bone. */
433 add_relation(bone_done_key, bone_segments_key, "Done -> B-Bone Segments");
434 /* B-Bone shape depends on final position of handle bones. */
435 bPoseChannel *prev, *next;
436 BKE_pchan_bbone_handles_get(pchan, &prev, &next);
437 if (prev) {
439 /* Inheriting parent roll requires access to prev handle's B-Bone properties. */
440 if ((pchan->bone->bbone_flag & BBONE_ADD_PARENT_END_ROLL) != 0 &&
441 check_pchan_has_bbone_segments(object, prev))
442 {
444 }
445 OperationKey prev_key(&object->id, NodeType::BONE, prev->name, opcode);
446 add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments");
447 }
448 if (next) {
449 OperationKey next_key(&object->id, NodeType::BONE, next->name, OperationCode::BONE_DONE);
450 add_relation(next_key, bone_segments_key, "Next Handle -> B-Bone Segments");
451 }
452 /* Pose requires the B-Bone shape. */
454 bone_segments_key, pose_done_key, "PoseEval Result-Bone Link", RELATION_FLAG_GODMODE);
455 add_relation(bone_segments_key, pose_cleanup_key, "Cleanup dependency");
456 }
457 else {
458 /* Assume that all bones must be done for the pose to be ready
459 * (for deformers). */
460 add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link");
461
462 /* Bones must be traversed before cleanup. */
463 add_relation(bone_done_key, pose_cleanup_key, "Done -> Cleanup");
464
465 add_relation(bone_ready_key, pose_cleanup_key, "Ready -> Cleanup");
466 }
467 /* Custom shape. */
468 if (pchan->custom != nullptr) {
469 build_object(pchan->custom);
470 add_visibility_relation(&pchan->custom->id, &armature->id);
471 }
472 }
473}
474
475} // namespace blender::deg
Blender kernel action and pose functionality.
bPoseChannel * BKE_armature_ik_solver_find_root(bPoseChannel *pchan, bKinematicConstraint *data)
void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
bPoseChannel * BKE_armature_splineik_solver_find_root(bPoseChannel *pchan, bSplineIKConstraint *data)
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, const int flag, void *userdata)
@ IDWALK_NOP
#define LISTBASE_FOREACH(type, var, list)
#define ELEM(...)
@ DAG_EVAL_NEED_CURVE_PATH
@ IKSOLVER_ITASC
@ POSE_DONE
@ BBONE_ADD_PARENT_END_ROLL
@ CONSTRAINT_DISABLE
@ CONSTRAINT_IK_TIP
@ CONSTRAINT_TYPE_LOCLIKE
@ CONSTRAINT_TYPE_ROTLIKE
@ CONSTRAINT_TYPE_SPLINEIK
@ CONSTRAINT_TYPE_KINEMATIC
@ CONSTRAINT_TYPE_TRANSLIKE
@ CONSTRAINT_TYPE_SIZELIKE
#define CD_MASK_MDEFORMVERT
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_ARMATURE
@ OB_MESH
BMesh const char void * data
DepsgraphBuilderCache * cache_
Definition deg_builder.h:53
virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan)
virtual bool check_pchan_has_bbone(const Object *object, const bPoseChannel *pchan)
virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map)
virtual void build_armature(bArmature *armature)
virtual void build_constraints(ID *id, NodeType component_type, const char *component_subdata, ListBase *constraints, RootPChanMap *root_map)
void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks)
void add_special_eval_flag(ID *id, uint32_t flag)
Relation * add_relation(const KeyFrom &key_from, const KeyTo &key_to, const char *description, int flags=0)
void add_visibility_relation(ID *id_from, ID *id_to)
virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map)
virtual void build_inter_ik_chains(Object *object, const OperationKey &solver_key, const bPoseChannel *rootchan, const RootPChanMap *root_map)
virtual void build_idproperties(IDProperty *id_property)
#define DEG_DEBUG_PRINTF(depsgraph, type,...)
Definition deg_debug.h:43
static ulong * next
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
struct bPose * pose
struct bPoseChannel * parent
ListBase chanbase
static DEGCustomDataMeshMasks MaskVert(const uint64_t vert_mask)
bool has_common_root(const char *bone1, const char *bone2) const
void add_bone(const char *bone, const char *root)