When you are working with Dependency Graph and custom node, sometimes in compute() function call you want to check if an input attribute is changed or its value is still up to date. At first glance, the most straightforward approach to tackle this down is to use MDataBlock::isClean(). This function will return false if your attribute value is not valid any more, which means you will need to either retrieve or recalculate a new value on this attribute.
However this approach is only effective when your input attribute has incoming connections, which is not always the case. In fact, in some situations where you want to check if you input attribute’s value is valid or not, that input attribute may not have any incoming connection.
For example, let’s assume a situation like this: On a custom node, input attribute A and input attribute B are required to compute output attribute C; the calculation portion dependent on B is quite expensive, the calculation portion dependent on attribute A is relatively simple; input attribute A does not have an incoming connection and most of the time user just set A’s value directly by setAttr. In this situation, you would like to optimize node calculation by differentiating which attribute value has been changed: if A has been changed, you could use the cached calculation portion dependent on B and speed up the calculation for output C; if B has been changed, you would need to redo the calculation completely.
In this scenario, MDataBlock::isClean() on A will always return “True”, you will not be able to tell if A’s value has been changed by this approach. You could set attribute A to be internal attribute and save a local copy of A’s value and use MPxNode::setInternalValueInContext() to find out if the attribute value has been changed.
Another better approach, which encompasses all the above situations is to maintain your own flag of whether the attribute is dirty and override MPxNode::setDependentsDirty(). In MPxNode::setDependentsDirty(), set the flag to be dirty if the passed-in dirty plug is the attribute you are watching, then in compute() check the value of this flag and reset it.
To summarize, there are 3 ways to check if an input attribute is changed or its value is not good anymore:
1. MDataBlock::isClean(), but this one only works in the situation that this input attribute has an incoming connection from other attributes of other nodes. When the connected upstream attributes get dirty, it will mark the connection and this input attribute dirty.
2. Set the attribute as an internal attribute by MFnAttribute::setInternal(), and in MPxNode::setInternalValueInContext() find out if the attribute value has been changed. This only works when there is no incoming connection on this attribute.
3. Maintain your own flag of whether the attribute is dirty and override MPxNode::setDependentsDirty() to set corresponding flag value based on passed-in dirty plug. This is by far the most efficient approach and thus the recommended way.
Comments
You can follow this conversation by subscribing to the comment feed for this post.