How to compare a port value has been changed?
-
Hi community,
I would like to know if there is a way to obtain the default value of a port(maxon.GraphNode), then catch which port in the graph is changed. I'm not sure if I missed something, but I didn't find any relevant methods in the document.
Any suggestions are welcomed!
Cheers~
DunHou -
Hi @Dunhou there is the method GraphModelInterface.GetModificationStamp which return you a TimeStamp of the last change (aka the last committed transaction).
Then with this stamp you can use GraphModelInterface.GetModificationsSince that will return you which GraphNode (so port since ports are node) are modified.
With that's said currently GetModificationsSince only accept list and not directly a callback, if you want to use a callback you need to use _GetModificationsSinceComplex.Find bellow a code example
import c4d import maxon def main(): # Retrieve the selected baseMaterial mat = c4d.BaseMaterial(c4d.Mmaterial) if mat is None: raise ValueError("Cannot create a BaseMaterial") # Retrieve the reference of the material as a node Material. nodeMaterial = mat.GetNodeMaterialReference() if nodeMaterial is None: raise ValueError("Cannot retrieve nodeMaterial reference") # Define the ID of standard material node space and print a warning when the active node space # is not the the standard material node space. nodeSpaceId = maxon.Id("net.maxon.nodespace.standard") if nodeSpaceId != c4d.GetActiveNodeSpaceId(): print (f"Warning: Active node space is not: {nodeSpaceId}") # Add a graph for the standard node space. addedGraph = nodeMaterial.CreateDefaultGraph(nodeSpaceId) if addedGraph is None: raise ValueError("Cannot add a graph node for this node space") # Retrieve the Nimbus reference for a specific node space from which we # will retrieve the graph. One could also use 'addedGraph' defined above. nimbusRef = mat.GetNimbusRef(nodeSpaceId) if nimbusRef is None: raise ValueError("Cannot retrieve the nimbus ref for that node space") # Retrieve the graph corresponding to that node space. graph = nimbusRef.GetGraph() if graph is None: raise ValueError("Cannot retrieve the graph of this nimbus ref") # Retrieve the end node of this graph endNodePath = nimbusRef.GetPath(maxon.NIMBUS_PATH.MATERIALENDNODE) endNode = graph.GetNode(endNodePath) if endNode is None: raise ValueError("Cannot retrieve the end-node of this graph") # Retrieve the predecessors. Function have been moved in R26. predecessor = list() maxon.GraphModelHelper.GetDirectPredecessors(endNode, maxon.NODE_KIND.NODE, predecessor) bsdfNode = predecessor[0] if bsdfNode is None: raise ValueError("Cannot retrieve the node connected to end-node") # Retrieve the outputs list of the BDSF node if bsdfNode is None and not bsdfNode.IsValid() : raise ValueError("Cannot retrieve the inputs list of the bsdfNode node") bsdfNodeInputs = bsdfNode.GetInputs() colordePort = bsdfNodeInputs.FindChild("color") if colordePort is None: return stamp = graph.GetModificationStamp() with graph.BeginTransaction() as transaction: # Define the value of the Color's port. colordePort.SetPortValue(maxon.ColorA(1, 0, 0, 1)) transaction.Commit() # Get the change via a list modifieds = [] graph.GetModificationsSince(stamp, modifieds, True) for node, flag in modifieds: print(flag, node) # Get the change via a callback, due to a bug that is going to be fixed, you can call GetModificationsSince with a callback def callback(node: maxon.GraphNode, flag: maxon.GraphModelInterface.MODIFIED): print(flag, node) return True graph._GetModificationsSinceComplex(stamp, callback, True) doc.InsertMaterial(mat) c4d.EventAdd() if __name__ == "__main__": main()
Sadly there is a missing bit in Python, since in C++ we have the concept of obverser, which allow for a lambda to be executed when a particular event occurs. Sadly observer are not yet implemented in Python, it's on the to-do list but for the moment it's not there. And in C++ there is the observer ObservableTransactionCommitted, which let you react to a graph transaction commit. So for the moment your best bet is to monitor for EVMSG_CHANGE or use a Timer to monitor the timestamp and check if it changed.
Cheers,
Maxime. -
Hey @m_adam ,
Thanks for that quick answer and a sweet codes for
GraphModelInterface.GetModificationStamp
I took a look at this, but these might be some details I still need.For example, I get a material from others. I want to check the material:
- oh, He/She modified the ior value to 2. That is a change applied to result.
- also He/She changed roughness 0 -> 0.2 -> 0. It has been modified but that is a default value, I didn't want to catch this.
Can we get the this stored value here, aka the default value we create the new material?
Cheers~
DunHou