How to find and delete a node in a NodeGraph?
-
I have a redshift material node graph. I would like to delete the default Material (com.redshift3d.redshift4c4d.nodes.core.material) within that graph. I can't figure out how to find this node or how to delete it once I find it.
BaseMaterial* pMat = BaseMaterial::Alloc(Mmaterial); NodeMaterial* pNodeMat = static_cast<NodeMaterial*>(pMat); pNodeMat->AddGraph(RedshiftNodeSpaceIds::nodespace) iferr_return; const maxon::nodes::NodesGraphModelRef& nodeGraph = pNodeMat->GetGraph(nodeSpaceID) iferr_return; const maxon::GraphNode rootNode = nodeGraph.GetRoot(); maxon::NodePath materialNodePath; pNodeMat->GetMaterialNodePath(nodeSpaceID, materialNodePath) iferr_return; materialNode = nodeGraph.GetNode(materialNodePath);
materialNode now contains a node with the id "com.redshift3d.redshift4c4d.nodes.core.material". I only know this because I can see it in the NodeGraph editor in C4D. How do I find this node and how can I delete it?
Thanks!
Kent -
Hi@kbar, I didn't know C++, but I think the method should be the same as python. I have two options for this task:
-
all maxon sdk stuffs, I modified the github example here
-
use my renderEngine library (custom wrapper for node gragh us maxon sdk)
Hoping this helps.
Cheers~
DunHou
maxon sdk
import c4d import maxon doc: c4d.documents.BaseDocument # The active document. def main(): # For each #material in the currently active document get its #nodeMaterial reference. material: c4d.BaseMaterial for material in doc.GetMaterials(): nodeMaterial: c4d.NodeMaterial = material.GetNodeMaterialReference() # To test if a material has a graph for a specific space, we must use the method #HasSpace. # To support 3rd party render engines, you must ask them for their node space ID. for nid in ("net.maxon.nodespace.standard", # Standard Renderer "com.redshift3d.redshift4c4d.class.nodespace"): # Redshift Renderer if not nodeMaterial.HasSpace(nid): continue # This material has a graph for the space #nid, we retrieve it. graph: maxon.GraphModelInterface = nodeMaterial.GetGraph(nid) if graph.IsNullValue(): raise RuntimeError("Found malformed empty graph associated with node space.") result: list[maxon.GraphNode] = [] asset_id = "com.redshift3d.redshift4c4d.nodes.core.material" maxon.GraphModelHelper.FindNodesByAssetId(graph, asset_id, True, result) # start remove with graph.BeginTransaction() as transaction: for i in result: i.Remove() transaction.Commit() c4d.EventAdd() if __name__ == "__main__": main()
renderEngine
import c4d,maxon from renderEngine.redshift import redshift_helper as rs doc: c4d.documents.BaseDocument # The active document. def ModifyMaterial(material: rs.MaterialHelper): if material is None: return # transfer it to a instance of rs.MaterialHelper if isinstance(material, c4d.BaseMaterial): material = rs.MaterialHelper(material) # modification has to be done within a transaction with rs.RSMaterialTransaction(material) as transaction: # return a list of material with giving node id RsMat = material.helper.GetNodes("com.redshift3d.redshift4c4d.nodes.core.material") for mat in RsMat: # remove it material.helper.RemoveShader(mat) if __name__ == "__main__": ModifyMaterial(doc.GetActiveMaterial())
-
-
Hey @kbar,
Thank you for reaching out to us and thank you @Dunhou for providing an answer in Python.
All C++ entity links in my answer intentionally point to the 2023.1 C++ documentation.
NodeMaterial Methods for Creating Graphs
The easiest way to do what you probably want to do, creating an empty graph, is using the method NodeMaterial::CreateEmptyGraph. I would not recommend using ::AddGraph, as this method has been deprecated; this already applies to 2023.¹ When you want to create the default graph, you now should use ::CreateDefaultGraph instead.
You can also compare the 2023.1 Create a Redshift Material C++ example with its 2023.2 variant, as the example itself makes the shift from
::AddGraph
to::CreateEmptyGraph
.Predicting Node IDs in a Default Graph
When you create a non-empty Redshift graph, you must identify nodes in it via their asset ID. A node in a graph is identified by two things, its node ID which is unique to the instance, and the asset ID which is the same for all nodes of the same type.
Fig. I: The two IDs are displayed in the node editor info panel for the selected node. Make sure to have
Preferences\Node Editor\Ids
enabled to also see the node ID in addition to the asset ID.The
2023.1
example mentioned above makes use of asset IDs in this stretch of code to select the RS Material node contained in the (old) default graph:// Find the RS-Material node which is contained within a standard Redshift material graph. This // example assumes that there is exactly one RS-Material node in the graph that is already // connected to the output node (which is true for the RS default material as of S26). maxon::BaseArray<maxon::GraphNode> results; maxon::GraphModelHelper::FindNodesByAssetId( graph, rsmaterialId, false, results) iferr_return; if (results.GetCount() < 1) return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find RS-Material node."_s); maxon::GraphNode rsmaterialNode = results[0];
This also highlights the problem with it, as you are unable to distinguish two node instances of the same type in this manner. The default graph in the standard material system has predictable/persistent node IDs.
Fig. II: The two nodes in the Standard Renderer default graph will always have the IDsmaterial
, andbsdf
.
Fig. III: The two nodes in the Redshift Renderer default material on the other hand will not have predictable IDs, as they are newly hashed for each graph.This forces you then to search the graph over asset IDs just as shown in the
2023.1
example.Resources
- 2024 Python Node Examples: I just added three scripts which cover the very basics in Python. Their code is fully transferable to 2023.X C++.
- 2023.1 Create a Redshift Material: Highlights the '
::AdGraph
or::CreateDefaultGraph
and then sorting out what is what'-worflow discussed above. - 2023.2 Create a Redshift Material: Highlights the '
::CreateEmptyGraph
-workflow of starting with a blank canvas. Especially in the context of Redshift I would recommend using this.
Cheers,
Ferdinand[1] I am aware that our documentation does not mention the deprecation on entities. In this case, the deprecation still has been covered by our old and manual change notes. The new automated changes notes do not cover this anymore. The underlying problem is here that Doxygen does parse C++ attributes, i.e., this:
Is not automatically converted into a
@deprecated
. I would have to mess with the Doxygen parsing to fix this, or pre-parse the frameworks to inject@deprecated
markup. I consider both things too costly as we will move away from Doxygen rather sooner than later anyway. -
Thanks @ferdinand and @Dunhou! Using FindNodesByAssetId has done the trick.
Unfortunately I can't jump to using the latest frameworks for everything just yet, but I will make sure to use the new methods for anything in 2024 onwards.
-
@ferdinand said in How to find and delete a node in a NodeGraph?:
Fig. I: The two IDs are displayed in the node editor info panel for the selected node. Make sure to have Preferences\Node Editor\Ids enabled to also see the node ID in addition to the asset ID.
I didn't know about this! I have been copying and pasting the selected nodes into a text editor up until now, which in itself is a very cool feature.