[Bf-blender-cvs] [6e44e4b] depsgraph_refactor: Depsgraph: WIP attempt to resolve some problems with IK chains

Joshua Leung noreply at git.blender.org
Wed Jan 21 12:59:58 CET 2015


Commit: 6e44e4b4968ed5ab4472c769d2d9687941d326da
Author: Joshua Leung
Date:   Thu Jan 22 00:03:48 2015 +1300
Branches: depsgraph_refactor
https://developer.blender.org/rB6e44e4b4968ed5ab4472c769d2d9687941d326da

Depsgraph: WIP attempt to resolve some problems with IK chains

This commit tried to fix the problems which occur when a bone that's
part of an IK chain has a constraint to another bone in the same chain.
Since all constraints are (or should still) handled before the IK solver runs,
that ended up causing a deadlock, since the offending bone would rely on the
"final" (done_node) transform of another bone in the same IK chain, which could
only run after the IK solver runs - but that cannot run as it's waiting on this
constrained bone.

* Added a dedicated "BONE_READY" noop, which sits after the constraints op,
  before the done node, and before any link to an IK solver. This replaces
  all the calls to bone_final_transform() by having a dedicated node which
  can be queried for this purpose

* Simplified the way that bone relationships get set up: The idea is that
  all bones in the same armature will use the "READY" nodes instead of "DONE"
  to avoid any lockups when dealing with IK. This way, we can do without all the
  common-root checks before doing parent links and so forth, as well as just
  setting out all the major relationships at the same time.

  (There is of course the risk that this breaks some old rigs (* see note below))


The result of all these efforts is that all the simple test cases and also the
test file with the offending setup which inspired this fix all work now. However,
it also seems to now be causing a range of weird regressions with production rigs
(notably, strange new unstable popping in Koro and Victor Layout, as well as lag
issues on some simpler IK leg rigs).

===================================================================

M	source/blender/depsgraph/intern/depsgraph_build_nodes.cpp
M	source/blender/depsgraph/intern/depsgraph_build_relations.cpp
M	source/blender/depsgraph/intern/depsnode_opcodes.h

===================================================================

diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cpp b/source/blender/depsgraph/intern/depsgraph_build_nodes.cpp
index be75f51..e0eeeba 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cpp
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cpp
@@ -609,6 +609,10 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
 		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, NULL, // XXX: BKE_eval_bone_done ?
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cpp b/source/blender/depsgraph/intern/depsgraph_build_relations.cpp
index d8048a7..9461e72 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cpp
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cpp
@@ -532,8 +532,17 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
 				}
 				else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) {
 					/* bone */
-					OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE); // XXX: ik vs normal
-					add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+					if (&ct->tar->id == id) {
+						/* same armature - use the "ready" state only, to avoid collisions with IK */
+						/* NOTE: in some cases, this may break (i.e. if the target is in a separate chain which can get safely evaluated first) */
+						OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_READY);
+						add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+					}
+					else {
+						/* different armature - we can safely use the result of that */
+						OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE);
+						add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+					}
 				}
 				else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
 					/* vertex group */
@@ -999,8 +1008,9 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
 	 * - see notes on direction of rel below...
 	 */
 	bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
-	OperationKey transforms_key = bone_transforms_key(ob, pchan);
 	OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
+	
+	OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
 	add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
 
 	/* IK target */
@@ -1013,15 +1023,18 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
 		 * 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 {
-				ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+				/* 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_READY);
 				add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
 			}
 		}
@@ -1036,6 +1049,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
 	// XXX: this should get handled as part of the constraint code
 	if (data->poletar != NULL) {
 		if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+			// XXX: same armature issues - ready vs done?
 			ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget);
 			add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
 		}
@@ -1063,7 +1077,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
 		 * grab the result with IK solver results...
 		 */
 		if (parchan != pchan) {
-			OperationKey parent_key = bone_transforms_key(ob, parchan);
+			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");
 		}
 		parchan->flag |= POSE_DONE;
@@ -1131,7 +1145,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
 		 * grab the result with IK solver results...
 		 */
 		if (parchan != pchan) {
-			OperationKey parent_key = bone_transforms_key(ob, parchan);
+			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");
 		}
 		parchan->flag |= POSE_DONE;
@@ -1167,30 +1181,54 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
 		add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Object Animation");
 	}
 
-	/* links between bones in the same component */
+	/* 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 
-		 * NOTE: although slightly redundant for IK, it is simpler t odo it with this
-		 */
+		/* 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 */
+		// XXX: does this need different handling (as in bottom, commented out loop) when IK is required?
+		if (pchan->parent != NULL) {
+			/* NOTE: here we use "ready" so that it doesn't block IK chains */
+			OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, DEG_OPCODE_BONE_READY);
+			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);
 			
+			/* 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");
 	}
@@ -1222,6 +1260,7 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
 		}
 	}
 
+#if 0
 	/* links between different bones - parenting relationships */
 	for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
 	     pchan != NULL;
@@ -1267,6 +1306,7 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
 			add_relation(transforms_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Bone Final Transforms");
 		}
 	}
+#endif
 }
 
 /* Shapekeys */
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
index b7d5334..ed0955e 100644
--- a/source/blender/depsgraph/intern/depsnode_opcodes.h
+++ b/source/blender/depsgraph/intern/depsnode_opcodes.h
@@ -126,11 +126,13 @@ DEF_DEG_OPCODE(BONE_CONSTRAINTS)
 //DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
 
 /* Bone transforms are ready 
- * - "PRE_IK"            This (internal) noop is used to signal that all pre-IK operations are done
- *                       NOTE: it isn't strictly necessary, as it should be possible to infer this from the data
- * - "FINAL_TRANSFORM"   This noop is used to signal that the bone's final pose transform can be read by others
+ * - "READY"             This (internal) noop is used to signal that all pre-IK operations are done.
+ *                       Its role is to help mediate situations where cyclic relations may otherwise form
+ *                       (i.e. one bone in chain targetting another in same chain)
+ * - "DONE"              This noop is used to signal that the bone's final pose transform can be read by others
  */
 // TODO: deform mats could get calculated in the final_tran

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list