Tracking new dependency nodes the easy way.
Suppose a script/ user(via gui) have created some new node, and those nodes creates some other utility nodes that might not be obvious at the first glance. For example, user assign a new phong material to a mesh, which also spawn materialinfo utility node. Or animation key that spawns conversion nodes.
What's the most convenient way to ls newly created node and all it's new utility nodes?
Solution 1 - manually traversing DG connection/ using DG functions
# manually traversing DG connection ... new_phong_node = ... # type: pymel.core.nodetypes.Phong # assume it's connected to a sg node sg_node = new_phong_node.outColor.outputs().node() # assume it's connected to a materialinfo node mi_node = sg_node.message.outputs().node() # you can also get it this way but we go through sg_node for demonstration # mi_node = sg_node.message.outputs.node() print(new_phong_node, sg_node, mi_node) ...
Sure, you can list new connection this way but what if it's a large and deep network? and workflow changes constantly it's impractical to write code this way? perhaps one can try to use cmds, or OpenMaya MItDependencyNodes to get those new nodes.
#eg: new_nodes_and_their_util_nodes = some_node.futures()
Solution 2 - Use API callback to catch an unseen new nodes
But what if some new nodes aren't directly connected on this node's network? You possibly have to check EVERY nodes in the scene to locate an unseen new nodes.
A smarter solution would be to use addNodeAddedCallback callback from MDGMessage class to catch those nodes.
_buf = set() def _catcher(om1_mobj, client_data): _buf.add( pm.PyNode(om1_mobj) ) _cbid = om.MDGMessage.addNodeAddedCallback(_catcher) try: # create new node etc here .... pm.createNode("lambert") .... finally: om.MDGMessage.removeCallback(_cbid) print(_buf)
Solution 3 - Using Pymel's NodeTracker
with pm.NodeTracker() as pm_nodetrack: pm.createNode("lambert") print(pm_nodetrack.getNodes())
Fortunately, pymel has already provided us with convenient wrapper to accomplish what we just did above so we don't have to write boilerplate code every time we wish to use this functionality.