diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2016-11-17 16:34:46 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2016-11-17 16:41:16 +0300 |
commit | 0c322c3000a0ddd7ac58c650f30b29d55afd1a97 (patch) | |
tree | 5698cea30a2d25f6f056e4e89d5028ce9fbb19c8 | |
parent | 16e2c0ef3c08b3a5d81ab21a71fc3c4c37e47e81 (diff) |
Depsgraph: Move rig builder functions to own files
Those routines are rather big and started to be annoying to have
one big file.
Should be no functional changes.
5 files changed, 735 insertions, 594 deletions
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index ab12a8d5b3e..ea839d11071 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -43,9 +43,11 @@ set(SRC intern/builder/deg_builder.cc intern/builder/deg_builder_cycle.cc intern/builder/deg_builder_nodes.cc + intern/builder/deg_builder_nodes_rig.cc intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc intern/builder/deg_builder_relations_keys.cc + intern/builder/deg_builder_relations_rig.cc intern/builder/deg_builder_transitive.cc intern/debug/deg_debug_graphviz.cc intern/eval/deg_eval.cc diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 12050e3e003..1eaacea69eb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -626,14 +626,6 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob) DEG_OPCODE_TRANSFORM_CONSTRAINTS); } -void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) -{ - /* create node for constraint stack */ - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), - DEG_OPCODE_BONE_CONSTRAINTS); -} - /** * Build graph nodes for AnimData block * \param id: ID-Block which hosts the AnimData @@ -829,207 +821,6 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) // TODO... } -/* IK Solver Eval Steps */ -void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) -{ - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - - if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEG_OPCODE_POSE_IK_SOLVER)) - { - return; - } - - /* Operation node for evaluating/running IK Solver. */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan), - DEG_OPCODE_POSE_IK_SOLVER); -} - -/* Spline IK Eval Steps */ -void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) -{ - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - - /* Operation node for evaluating/running Spline IK Solver. - * Store the "root bone" of this chain in the solver, so it knows where to start. - */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan), - DEG_OPCODE_POSE_SPLINE_IK_SOLVER); -} - -/* Pose/Armature Bones Graph */ -void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) -{ - bArmature *arm = (bArmature *)ob->data; - - /* animation and/or drivers linking posebones to base-armature used to define them - * NOTE: AnimData here is really used to control animated deform properties, - * which ideally should be able to be unique across different instances. - * Eventually, we need some type of proxy/isolation mechanism in-between here - * to ensure that we can use same rig multiple times in same scene... - */ - build_animdata(&arm->id); - - /* Rebuild pose if not up to date. */ - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild_ex(ob, arm, false); - /* XXX: Without this animation gets lost in certain circumstances - * after loading file. Need to investigate further since it does - * not happen with simple scenes.. - */ - if (ob->adt) { - ob->adt->recalc |= ADT_RECALC_ANIM; - } - } - - /* speed optimization for animation lookups */ - if (ob->pose) { - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } - } - - /* Make sure pose is up-to-date with armature updates. */ - add_operation_node(&arm->id, - DEPSNODE_TYPE_PARAMETERS, - DEPSOP_TYPE_EXEC, - NULL, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - - /** - * Pose Rig Graph - * ============== - * - * Pose Component: - * - Mainly used for referencing Bone components. - * - This is where the evaluation operations for init/exec/cleanup - * (ik) solvers live, and are later hooked up (so that they can be - * interleaved during runtime) with bone-operations they depend on/affect. - * - init_pose_eval() and cleanup_pose_eval() are absolute first and last - * steps of pose eval process. ALL bone operations must be performed - * between these two... - * - * Bone Component: - * - Used for representing each bone within the rig - * - Acts to encapsulate the evaluation operations (base matrix + parenting, - * and constraint stack) so that they can be easily found. - * - Everything else which depends on bone-results hook up to the component only - * so that we can redirect those to point at either the the post-IK/ - * post-constraint/post-matrix steps, as needed. - */ - - /* pose eval context */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT); - - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); - - /* bones */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - /* node for bone eval */ - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local - DEG_OPCODE_BONE_LOCAL); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose - DEG_OPCODE_BONE_POSE_PARENT); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */ - DEG_OPCODE_BONE_READY); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan), - DEG_OPCODE_BONE_DONE); - - /* constraints */ - if (pchan->constraints.first != NULL) { - build_pose_constraints(ob, pchan); - } - - /** - * IK Solvers... - * - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(scene, ob, pchan, con); - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(scene, ob, pchan, con); - break; - - default: - break; - } - } - } -} - -void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) -{ - ID *obdata = (ID *)ob->data; - build_animdata(obdata); - - BLI_assert(ob->pose != NULL); - - /* speed optimization for animation lookups */ - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } - - add_operation_node(&ob->id, - DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_INIT, - function_bind(BKE_pose_eval_proxy_copy, _1, ob), - DEG_OPCODE_POSE_INIT); - - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_INIT, NULL, - DEG_OPCODE_BONE_LOCAL); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, NULL, - DEG_OPCODE_BONE_READY); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_POST, NULL, - DEG_OPCODE_BONE_DONE); - } - - add_operation_node(&ob->id, - DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_POST, - NULL, - DEG_OPCODE_POSE_DONE); -} - /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc new file mode 100644 index 00000000000..b9c7c3c7f92 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -0,0 +1,275 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph's nodes + */ + +#include "intern/builder/deg_builder_nodes.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#include "intern/builder/deg_builder.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_types.h" +#include "intern/depsgraph_intern.h" + +namespace DEG { + +void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) +{ + /* create node for constraint stack */ + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), + DEG_OPCODE_BONE_CONSTRAINTS); +} + +/* IK Solver Eval Steps */ +void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + + if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEG_OPCODE_POSE_IK_SOLVER)) + { + return; + } + + /* Operation node for evaluating/running IK Solver. */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan), + DEG_OPCODE_POSE_IK_SOLVER); +} + +/* Spline IK Eval Steps */ +void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + + /* Operation node for evaluating/running Spline IK Solver. + * Store the "root bone" of this chain in the solver, so it knows where to start. + */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan), + DEG_OPCODE_POSE_SPLINE_IK_SOLVER); +} + +/* Pose/Armature Bones Graph */ +void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) +{ + bArmature *arm = (bArmature *)ob->data; + + /* animation and/or drivers linking posebones to base-armature used to define them + * NOTE: AnimData here is really used to control animated deform properties, + * which ideally should be able to be unique across different instances. + * Eventually, we need some type of proxy/isolation mechanism in-between here + * to ensure that we can use same rig multiple times in same scene... + */ + build_animdata(&arm->id); + + /* Rebuild pose if not up to date. */ + if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { + BKE_pose_rebuild_ex(ob, arm, false); + /* XXX: Without this animation gets lost in certain circumstances + * after loading file. Need to investigate further since it does + * not happen with simple scenes.. + */ + if (ob->adt) { + ob->adt->recalc |= ADT_RECALC_ANIM; + } + } + + /* speed optimization for animation lookups */ + if (ob->pose) { + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + } + + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&arm->id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + + /** + * Pose Rig Graph + * ============== + * + * Pose Component: + * - Mainly used for referencing Bone components. + * - This is where the evaluation operations for init/exec/cleanup + * (ik) solvers live, and are later hooked up (so that they can be + * interleaved during runtime) with bone-operations they depend on/affect. + * - init_pose_eval() and cleanup_pose_eval() are absolute first and last + * steps of pose eval process. ALL bone operations must be performed + * between these two... + * + * Bone Component: + * - Used for representing each bone within the rig + * - Acts to encapsulate the evaluation operations (base matrix + parenting, + * and constraint stack) so that they can be easily found. + * - Everything else which depends on bone-results hook up to the component only + * so that we can redirect those to point at either the the post-IK/ + * post-constraint/post-matrix steps, as needed. + */ + + /* pose eval context */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT); + + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); + + /* bones */ + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + /* node for bone eval */ + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local + DEG_OPCODE_BONE_LOCAL); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose + DEG_OPCODE_BONE_POSE_PARENT); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */ + DEG_OPCODE_BONE_READY); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan), + DEG_OPCODE_BONE_DONE); + + /* constraints */ + if (pchan->constraints.first != NULL) { + build_pose_constraints(ob, pchan); + } + + /** + * IK Solvers... + * + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ + for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(scene, ob, pchan, con); + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(scene, ob, pchan, con); + break; + + default: + break; + } + } + } +} + +void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) +{ + ID *obdata = (ID *)ob->data; + build_animdata(obdata); + + BLI_assert(ob->pose != NULL); + + /* speed optimization for animation lookups */ + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + + add_operation_node(&ob->id, + DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_INIT, + function_bind(BKE_pose_eval_proxy_copy, _1, ob), + DEG_OPCODE_POSE_INIT); + + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; + pchan != NULL; + pchan = pchan->next) + { + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_INIT, NULL, + DEG_OPCODE_BONE_LOCAL); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, NULL, + DEG_OPCODE_BONE_READY); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_POST, NULL, + DEG_OPCODE_BONE_DONE); + } + + add_operation_node(&ob->id, + DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_POST, + NULL, + DEG_OPCODE_POSE_DONE); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index fe75de5e350..1497a16e47f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1345,391 +1345,6 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) // TODO... } -/* IK Solver Eval Steps */ -void DepsgraphRelationBuilder::build_ik_pose(Object *ob, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map) -{ - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* attach owner to IK Solver too - * - assume that owner is always part of chain - * - see notes on direction of rel below... - */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); - - /* IK target */ - // XXX: this should get handled as part of the constraint code - if (data->tar != NULL) { - /* TODO(sergey): For until we'll store partial matricies in the depsgraph, - * we create dependency between target object and pose eval component. - * - * This way we ensuring the whole subtree is updated from scratch without - * need of intermediate matricies. This is an overkill, but good enough for - * testing IK solver. - */ - // FIXME: geometry targets... - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { - /* TODO(sergey): This is only for until granular update stores intermediate result. */ - if (data->tar != ob) { - /* different armature - can just read the results */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - else { - /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */ - OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - } - else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { - /* vertex group target */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); - add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); - - if (data->tar->type == OB_MESH) { - OperationDepsNode *node2 = find_operation_node(target_key); - if (node2 != NULL) { - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - } - } - else { - /* Standard Object Target */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - - if ((data->tar == ob) && (data->subtarget[0])) { - /* Prevent target's constraints from linking to anything from same - * chain that it controls. - */ - root_map->add_bone(data->subtarget, rootchan->name); - } - } - - /* Pole Target */ - // XXX: this should get handled as part of the constraint code - if (data->poletar != NULL) { - if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { - // XXX: same armature issues - ready vs done? - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { - /* vertex group target */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); - add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); - - if (data->poletar->type == OB_MESH) { - OperationDepsNode *node2 = find_operation_node(target_key); - if (node2 != NULL) { - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - } - } - else { - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - } - - DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n", - pchan->name, data->tar->id.name, data->subtarget, data->rootbone); - - bPoseChannel *parchan = pchan; - /* exclude tip from chain? */ - if (!(data->flag & CONSTRAINT_IK_TIP)) { - OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, - parchan->name, DEG_OPCODE_BONE_LOCAL); - add_relation(solver_key, tip_transforms_key, - DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); - parchan = pchan->parent; - } - - root_map->add_bone(parchan->name, rootchan->name); - - OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, - parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parchan_transforms_key, solver_key, - DEPSREL_TYPE_TRANSFORM, "IK Solver Owner"); - - /* Walk to the chain's root */ - //size_t segcount = 0; - int segcount = 0; - - while (parchan) { - /* Make IK-solver dependent on this bone's result, - * since it can only run after the standard results - * of the bone are know. Validate links step on the - * bone will ensure that users of this bone only - * grab the result with IK solver results... - */ - if (parchan != pchan) { - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent"); - - OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } - else { - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); - } - parchan->flag |= POSE_DONE; - - - root_map->add_bone(parchan->name, rootchan->name); - - /* continue up chain, until we reach target number of items... */ - DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name); - segcount++; - if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */ - - parchan = parchan->parent; - } - - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); -} - -/* Spline IK Eval Steps */ -void DepsgraphRelationBuilder::build_splineik_pose(Object *ob, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map) -{ - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER); - - /* attach owner to IK Solver too - * - assume that owner is always part of chain - * - see notes on direction of rel below... - */ - add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner"); - - /* attach path dependency to solver */ - if (data->tar) { - /* TODO(sergey): For until we'll store partial matricies in the depsgraph, - * we create dependency between target object and pose eval component. - * See IK pose for a bit more information. - */ - // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel"); - } - - pchan->flag |= POSE_DONE; - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result"); - - root_map->add_bone(pchan->name, rootchan->name); - - /* Walk to the chain's root */ - //size_t segcount = 0; - int segcount = 0; - - for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) { - /* Make Spline IK solver dependent on this bone's result, - * since it can only run after the standard results - * of the bone are know. Validate links step on the - * bone will ensure that users of this bone only - * grab the result with IK solver results... - */ - if (parchan != pchan) { - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update"); - - OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } - parchan->flag |= POSE_DONE; - - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result"); - - root_map->add_bone(parchan->name, rootchan->name); - - /* continue up chain, until we reach target number of items... */ - segcount++; - if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ - } - - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); -} - -/* Pose/Armature Bones Graph */ -void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) -{ - /* Armature-Data */ - bArmature *arm = (bArmature *)ob->data; - - // TODO: selection status? - - /* attach links between pose operations */ - OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - - add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]"); - - /* Make sure pose is up-to-date with armature updates. */ - OperationKey armature_key(&arm->id, - DEPSNODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); - - if (needs_animdata_node(&ob->id)) { - ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); - add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); - } - - /* IK Solvers... - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * - We build relations for these before the dependencies - * between ops in the same component as it is necessary - * to check whether such bones are in the same IK chain - * (or else we get weird issues with either in-chain - * references, or with bones being parented to IK'd bones) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ - RootPChanMap root_map; - bool pose_depends_on_local_transform = false; - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(ob, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(ob, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - - /* Constraints which needs world's matrix for transform. - * TODO(sergey): More constraints here? - */ - case CONSTRAINT_TYPE_ROTLIKE: - case CONSTRAINT_TYPE_SIZELIKE: - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_TRANSLIKE: - /* TODO(sergey): Add used space check. */ - pose_depends_on_local_transform = true; - break; - - default: - break; - } - } - } - //root_map.print_debug(); - - if (pose_depends_on_local_transform) { - /* TODO(sergey): Once partial updates are possible use relation between - * object transform and solver itself in it's build function. - */ - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms"); - } - - - /* links between operations for each bone */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); - OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - - pchan->flag &= ~POSE_DONE; - - /* pose init to bone local */ - add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link"); - - /* local to pose parenting operation */ - add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link"); - - /* parent relation */ - if (pchan->parent != NULL) { - eDepsOperation_Code parent_key_opcode; - - /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ - if (root_map.has_common_root(pchan->name, pchan->parent->name)) { - parent_key_opcode = DEG_OPCODE_BONE_READY; - } - else { - parent_key_opcode = DEG_OPCODE_BONE_DONE; - } - - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); - add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]"); - } - - /* constraints */ - if (pchan->constraints.first != NULL) { - /* constraints stack and constraint dependencies */ - build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); - - /* pose -> constraints */ - OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); - add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack"); - - /* constraints -> ready */ - // TODO: when constraint stack is exploded, this step should occur before the first IK solver - add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready"); - } - else { - /* pose -> ready */ - add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready"); - } - - /* bone ready -> done - * NOTE: For bones without IK, this is all that's needed. - * 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, DEPSREL_TYPE_OPERATION, "Ready -> Done"); - - /* assume that all bones must be done for the pose to be ready (for deformers) */ - add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); - } -} - -void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) -{ - OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { - OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local"); - add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready"); - add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); - add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done"); - } -} - /* Shapekeys */ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc new file mode 100644 index 00000000000..3edb2b7acb7 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -0,0 +1,458 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +#include <stdio.h> +#include <stdlib.h> +#include <cstring> /* required for STREQ later on. */ + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_pchanmap.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "intern/depsgraph_types.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +/* IK Solver Eval Steps */ +void DepsgraphRelationBuilder::build_ik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map) +{ + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* attach owner to IK Solver too + * - assume that owner is always part of chain + * - see notes on direction of rel below... + */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); + + /* IK target */ + // XXX: this should get handled as part of the constraint code + if (data->tar != NULL) { + /* TODO(sergey): For until we'll store partial matricies in the depsgraph, + * we create dependency between target object and pose eval component. + * + * This way we ensuring the whole subtree is updated from scratch without + * need of intermediate matricies. This is an overkill, but good enough for + * testing IK solver. + */ + // FIXME: geometry targets... + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { + /* TODO(sergey): This is only for until granular update stores intermediate result. */ + if (data->tar != ob) { + /* different armature - can just read the results */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + else { + /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */ + OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + } + else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { + /* vertex group target */ + /* NOTE: for now, we don't need to represent vertex groups separately... */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); + add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); + + if (data->tar->type == OB_MESH) { + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } + } + } + else { + /* Standard Object Target */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + + if ((data->tar == ob) && (data->subtarget[0])) { + /* Prevent target's constraints from linking to anything from same + * chain that it controls. + */ + root_map->add_bone(data->subtarget, rootchan->name); + } + } + + /* Pole Target */ + // XXX: this should get handled as part of the constraint code + if (data->poletar != NULL) { + if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { + // XXX: same armature issues - ready vs done? + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { + /* vertex group target */ + /* NOTE: for now, we don't need to represent vertex groups separately... */ + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); + add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); + + if (data->poletar->type == OB_MESH) { + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } + } + } + else { + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + } + + DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n", + pchan->name, data->tar->id.name, data->subtarget, data->rootbone); + + bPoseChannel *parchan = pchan; + /* exclude tip from chain? */ + if (!(data->flag & CONSTRAINT_IK_TIP)) { + OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, + parchan->name, DEG_OPCODE_BONE_LOCAL); + add_relation(solver_key, tip_transforms_key, + DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + parchan = pchan->parent; + } + + root_map->add_bone(parchan->name, rootchan->name); + + OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, + parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parchan_transforms_key, solver_key, + DEPSREL_TYPE_TRANSFORM, "IK Solver Owner"); + + /* Walk to the chain's root */ + //size_t segcount = 0; + int segcount = 0; + + while (parchan) { + /* Make IK-solver dependent on this bone's result, + * since it can only run after the standard results + * of the bone are know. Validate links step on the + * bone will ensure that users of this bone only + * grab the result with IK solver results... + */ + if (parchan != pchan) { + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent"); + + OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); + } + else { + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + } + parchan->flag |= POSE_DONE; + + + root_map->add_bone(parchan->name, rootchan->name); + + /* continue up chain, until we reach target number of items... */ + DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name); + segcount++; + if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */ + + parchan = parchan->parent; + } + + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); +} + +/* Spline IK Eval Steps */ +void DepsgraphRelationBuilder::build_splineik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map) +{ + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER); + + /* attach owner to IK Solver too + * - assume that owner is always part of chain + * - see notes on direction of rel below... + */ + add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner"); + + /* attach path dependency to solver */ + if (data->tar) { + /* TODO(sergey): For until we'll store partial matricies in the depsgraph, + * we create dependency between target object and pose eval component. + * See IK pose for a bit more information. + */ + // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel"); + } + + pchan->flag |= POSE_DONE; + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result"); + + root_map->add_bone(pchan->name, rootchan->name); + + /* Walk to the chain's root */ + //size_t segcount = 0; + int segcount = 0; + + for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) { + /* Make Spline IK solver dependent on this bone's result, + * since it can only run after the standard results + * of the bone are know. Validate links step on the + * bone will ensure that users of this bone only + * grab the result with IK solver results... + */ + if (parchan != pchan) { + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update"); + + OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); + } + parchan->flag |= POSE_DONE; + + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result"); + + root_map->add_bone(parchan->name, rootchan->name); + + /* continue up chain, until we reach target number of items... */ + segcount++; + if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ + } + + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); +} + +/* Pose/Armature Bones Graph */ +void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) +{ + /* Armature-Data */ + bArmature *arm = (bArmature *)ob->data; + + // TODO: selection status? + + /* attach links between pose operations */ + OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + + add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]"); + + /* Make sure pose is up-to-date with armature updates. */ + OperationKey armature_key(&arm->id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); + + if (needs_animdata_node(&ob->id)) { + ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); + add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); + } + + /* IK Solvers... + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * - We build relations for these before the dependencies + * between ops in the same component as it is necessary + * to check whether such bones are in the same IK chain + * (or else we get weird issues with either in-chain + * references, or with bones being parented to IK'd bones) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ + RootPChanMap root_map; + bool pose_depends_on_local_transform = false; + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(ob, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(ob, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + + /* Constraints which needs world's matrix for transform. + * TODO(sergey): More constraints here? + */ + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_TRANSLIKE: + /* TODO(sergey): Add used space check. */ + pose_depends_on_local_transform = true; + break; + + default: + break; + } + } + } + //root_map.print_debug(); + + if (pose_depends_on_local_transform) { + /* TODO(sergey): Once partial updates are possible use relation between + * object transform and solver itself in it's build function. + */ + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms"); + } + + + /* links between operations for each bone */ + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); + OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + + pchan->flag &= ~POSE_DONE; + + /* pose init to bone local */ + add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link"); + + /* local to pose parenting operation */ + add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link"); + + /* parent relation */ + if (pchan->parent != NULL) { + eDepsOperation_Code parent_key_opcode; + + /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ + if (root_map.has_common_root(pchan->name, pchan->parent->name)) { + parent_key_opcode = DEG_OPCODE_BONE_READY; + } + else { + parent_key_opcode = DEG_OPCODE_BONE_DONE; + } + + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); + add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]"); + } + + /* constraints */ + if (pchan->constraints.first != NULL) { + /* constraints stack and constraint dependencies */ + build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); + + /* pose -> constraints */ + OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); + add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack"); + + /* constraints -> ready */ + // TODO: when constraint stack is exploded, this step should occur before the first IK solver + add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready"); + } + else { + /* pose -> ready */ + add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready"); + } + + /* bone ready -> done + * NOTE: For bones without IK, this is all that's needed. + * 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, DEPSREL_TYPE_OPERATION, "Ready -> Done"); + + /* assume that all bones must be done for the pose to be ready (for deformers) */ + add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); + } +} + +void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) +{ + OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; + pchan != NULL; + pchan = pchan->next) + { + OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local"); + add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready"); + add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); + add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done"); + } +} + +} // namespace DEG |