Dependency Graph (DG) nodes


The dependency graph (DG) is a collection of entities connected together. Unlike the DAG, these connections can be cyclic, and do not represent a parenting relationship. Instead, the connections in the graph allow data to move from one entity in the graph to another. The entities in the graph which accept and output data are called dependency graph nodes.

Dependency graph nodes are the part of a dependency graph which perform computations. A node takes in a set of input data (supplied by connections to other nodes, or which are simply supplied to the node) and use them to create a set of output data. Dependency graph nodes are used for almost everything in Maya such as model creation, deformation, animation, simulation, and audio processing.

Most objects in Maya are dependency graph nodes, or networks of nodes (several nodes connected together). For example, DAG nodes are dependency graph nodes, and shaders are networks of nodes.

When dependency graph nodes are connected together they can affect DAG nodes and thus affect what is rendered.

This illustration combines a DAG hierarchy with a dependency graph. Transform1, Transform2, Transform3, and Sphere are all DAG nodes (and also dependency graph nodes) while Time is just a dependency graph node.

The x, y, and z scale parameters of Transform3 are driven by time. Alternatively, you can think of the output of Time being plugged into the x, y, and z scale connections of Transform3. When the animation is played back, the two instances of the sphere increase in size.

The data which flows through the graph can be as simple as numbers, or as complicated as a surface. It can also be a completely user-defined object.

The dependency graph consists of a very complex architecture, and a complete explanation of how it works would require a separate manual. A brief explanation is provided instead.

As noted before, the dependency graph is a directed graph, the edges of the graph connect plugs on different nodes. Data is sent along these edges, and includes basic types such as numbers, vectors, and matrices, and complex types such as curves, surfaces, and user defined types.

As part of the definition of Maya nodes, you are required to specify which input attributes affect which output attributes (in the API this is done with the MPxNode::attributeAffects() method).

When an attribute of a node is changed, the dependency graph checks to see if that attribute affects any output. If it does, each of those outputs is marked dirty, meaning that its cached value is stale and needs to be recomputed. Then for each of those output attributes, the dependency graph checks to see if they are the source for a connection. If so, then the connection is followed, and the destination attribute is marked dirty also. This process recurs, and at the end all attributes of nodes in the graph which need to be recomputed are marked dirty. It is important to note that at this time no attributes have been recomputed, instead the state has just been updated so we know which data is no longer valid. The evaluation and re-computation of those invalid attributes occurs as part of a separate step.

Certain events cause the dependency graph to re-evaluate itself, examples being screen refresh, and animation playback. During a refresh for example, the system will walk down the DAG and for each DAG node check to see whether it needs to be re-evaluated (by checking if any plugs on it are dirty), if so, the compute method of the node affecting the plug will be called. This compute method may be dependent on plugs which may also be dirty, so the affecting nodes’ compute methods would also be called, and in this way the pertinent parts of the DG will be re-evaluated, but only those parts that require re-evaluation.

One optimization is that the DG does not re-evaluate the graph unless it needs to. For example, imagine a revolved surface where there are three nodes, a curve DAG node used as input to the second node, a node which revolves the curve and generates a surface, which is the output to the third node, a DAG node which puts the surface into the DAG. If the input curve was modified, the surface would not be regenerated immediately, it may not happen until the next screen refresh. To make sure that the surface does eventually get rebuilt, modifying the curve would cause all plugs connected to the curve’s output plug to be marked dirty, hence the input to the revolve node would be marked dirty (the curve’s output plug itself would not be marked dirty since it has just been recomputed). When declaring attributes it’s necessary to indicate what attributes affect each other, so in the revolve node, the output attribute is dependent on the input attribute, then marking the input attribute dirty causes the output attribute to be marked dirty. The output of the revolve node is connected to the surface node, marking the revolve node’s output dirty marks the surface as being dirty. So, when the DAG is walked during a screen refresh, since the surface is marked dirty, everything that it is dependent on which has also been marked dirty needs to be re-evaluated.

Re-evaluation stops at the first node which doesn’t have any dirty inputs. For example if the number of degrees to revolve a curve was changed but the curve itself was not, then rebuilding the revolved surface would cause the revolve node to be recomputed, but the curve would not be affected.

This is a high level description, the actual implementation provides a great deal of intelligence so that unnecessary evaluations are avoided.

The data flowing through the graph is analogous to water flowing through pipes. The pipes themselves are the connections but unless they have data to redirect and modify they are not actually doing anything.

Extending this analogy, the nodes are like taps, showers, or fountains. They all do something with the water in their own unique way but they must have water to operate.

An interesting side effect of using the DG is that it can make it difficult to directly affect an object.

For example, consider the sphere in the above figure. If no DG node is connected to Transform3 to affect the sphere’s scale, any values set through the UI or API will be the new scale. However, if as in the figure Time affects the scale of the sphere, the effect would be different when Transform3’s scale is additionally modified through the UI or API. If you set the scale it would override the scale being set by Time only until the next re-evaluation of the dependency graph, when the scale of the sphere would again be set by Time and the value you set through the UI or API would be lost.

A more complex example would be a revolved surface. What would happen if you tried to move a CV on the generated surface? The CV would be moved to its new position only until the DG is re-evaluated, at which time the CV would be moved back to the position dictated by the revolve node.

However, fine-tuning or "tweaking" a model is a necessary operation for building complex models and scenes. So Maya has designed a mechanism for handling these tweaks. Mesh shapes have an attribute, pnts, which stores local changes made to the mesh vertices. Any upstream connection to the mesh shape node which generates a new set of vertices for the mesh will not disturb the pnts attribute. The values in the pnts attribute are added to the coordinates of the mesh. For NURBS surfaces and other control point based nodes, the controlPoints attribute stores tweak information. Maya also has implemented a tweak node which will store tweak information for a control point based node. The tweak node is placed between the control point based node and an upstream deforming node which operates on the control points. The tweak node integrates the tweak information in with the deformed control points to generate the final set of control points that is then passed to the shape. Refer to the manual pages for the tweak node as well as the mesh and NURBS surface shape nodes for more information on the attributes which handle tweak information.