Cyclic dependencies that aren't dependent?

I use a camera and point-of-interest (POI) setup to do all my camera move keyframing, and it’s convenient to have them stay constantly aligned along their common axes. I use Track To constraints for this. The Camera tracks the POI (an Empty) and the POI tracks the Camera. This would seem to be a classic case of cyclic dependency (and the console reports it as such) except that the dependencies are not actually there. The Track To affects the Client’s rotation based on the Target’s location. So Camera rotation – but not location – is constrained. Similar for the POI. There’s a mutual constraint loop but it doesn’t involve the same transform on each object, so where’s the cyclic dependency?

If the same thing was done with Copy Location or Copy Rotation, then there would definitely be a problem because the same transform is affected in both objects – Location modifies Location modifies Location, etc., in a feedback/dependency loop that is not a good thing. But in my setup there’s no feedback from one constraint to the other because separate transforms are involved.

Bottom line – does this kind of mis-identification of a cyclic dependency make any difference at all, or is it just a case of a small but harmless programming error? It also make me wonder if cyclic dependencies are identified by actual functionality – the feedback/dependency loop is detected and flagged – or on the basis of general assumptions about when they’d occur – two object constrain one another using the same constraint so it has to be a cyclic dependency.

I use a similar setup for DOF. Where the I place the POI (empty) in the camera DOF Object field. This produces a cyclic dependency as well, but it still works.

Yep, and that’s why I’m wondering if this kind of setup really is a c-d at all, but rather a valid mutual constraint situation that just happens to be labeled wrong.

It also casts some doubt on how c-d situations are identified in the code – if it’s not valid in these cases, are some valid cases being missed and not labeled?

The problem is that Blender’s depsgraph only knows about dependencies between entire objects, with next to no concept of certain transforms affecting other ones.

The way to visualise this is if you had two boxes (one for the point of interest and one for the camera), and in each box you wrote “location” and “rotation”. Then draw in appropriate directed arrows between the transforms, and finally shade each box completely in black. What you should now see is two black boxes, with one arrow pointing one way, and another pointing in the other. That is how Blender’s depsgraph sees relationships.

Thanks, Aligorith, that answers the main ? – the depsgraph can flag all possible c-d relationships but in the process can also flag those that only appear to be dependent.

Wish I knew what the heck a depsgraph is :wink:

A ‘depsgraph’ (i.e. shorthand for ‘Dependency Graph’) is a type of data-structure used to represent the relationships between some ‘nodes’.

Nodes are kindof like the vertices of a mesh, in that they connected together with links, like the edges between vertices. The differences though, are that instead of representing some position in space, nodes represent some data (in Blender’s case Objects), and that the links between them have a specific direction (i.e. if ob1 is ‘used’ by ob2 in some way, then we would draw an arrow from ob1 pointing to ob2). So, referring back to the previous example I gave, the nodes would be the black boxes, and the arrows would indicate the ways these nodes relate to each other.

From these ‘arrows’ between nodes in the depsgraph, we can usually work out which nodes would need to be calculated first so that the other nodes could be sure that the values they’re getting are up to date. The other consequence is that you can determine which nodes need to be updated when one node that a few others depend on changes, which means costly full-database refreshes on every edit can be minimized.

So the despgraph acts as a way of storing what relationships between some nodes exist, and from those relationships we can determine ways of efficiently propogating changes to other nodes when one node changes.

These ways in Blender currently include: ordering the nodes in a way that the nodes earlier in the dependency chains are evaluated first, and those more dependent are ordered/evaluated later; and tagging which nodes need to updated when one node changes.

However, if you look carefully at this again, we can see that if several nodes have arrows between them forming a loop, i.e. A -> B -> C -> A -> …, the ordering step will fail, since we cannot figure out a way to order these so that all the nodes will have correct values at any one time. This situation here is a what is known as a ‘cyclic dependency’.

If you said, ‘let’s just evaluate them starting from one node which we’ll call the starting node, and stop when we get to this node again’, you’ve practically got Blender’s current cyclic dependency resolution strategy. That is, if we started at node ‘A’, we’d evaluate A, B, C for some timestep t0, then we’d do this again for timestep t1, and so on. However, if you’ll remember, node ‘A’ still has a dependency to node ‘C’ even though we’re ignoring this when we determine the order for evaluating them in this way. So, at timestep t1, when we evaluate node ‘A’, we’d be using the relevant values from ‘C’ which were set in timestep t0 (since ‘C’ hasn’t been updated for this timestep). But, the values for ‘C’ in timestep t0 may be drastically different.

This here is the famous ‘lagging’ problem which you will have noticed when working with some rig containing cyclic dependencies.

Due to this inability to handle cyclic dependencies, Blender’s Dependency Graph is a type of DAG (‘Directed Acyclic Graph’). ‘Directed’ simply refers to the arrows pointing between nodes, ‘Acyclic’ just means that cyclic dependencies cannot exist or be handled in a nice way, and ‘Graph’ simply means a bunch of nodes with links between them in some way.

</end short impromptu lecture on DAG’s>

“Be careful what you wish for…” :wink:

Good info, well presented, thanks, it sheds a lot of light on some otherwise rather shady corners of Blender’s architecture.