Accessing Information Node Graphs

Covers how to access, add, or remove information from a graph. There are currently two ways to use and store node systems. The first is via scene nodes, where only one node system per document does exist. The second is via material nodes, where multiple node systems can exist per material and available node space.

Where to Find Identifiers

The node system and the Maxon API heavily uses IDs to identify uniquely an object (datatype, parameter etc). This ID must be known to find a node or a port within the node system. The true node ID must be unique within the entire graph system, while the IDs of ports must be unique only within the true node itself. The node can be composed of several attributes. Those attributes can be exported by the Resource Editor as symbols and, instead of using the value, the symbols will be used. Those symbols are organized by namespaces. In the node editor, there is a command to display, in the info palette, the ID and/or the asset ID of the selected element. If the option does not exist in the View menu, just start Cinema 4D using this parameter g_showNodeIds=true.

For example, in the scene editor:

  • add the trigonometry node from the math category,
  • activate the menu, <e>View ->Show ID, and
  • check in the info palette what is the value of the ID.

The value should be net.maxon.node.trigonometry. This ID can be searched in the framework directory to find the associated symbol. The symbol is declared in nodes_math.h below the namespace TRIGONOMETRY. All the hierarchy must be named to retrieve the correct ID. In the case of the node trigonometry, it will be maxon::NODE::TRIGONOMETRY. To retrieve the ID of the node itself from the symbol, the function GetId() must be used like so: maxon::NODE::TRIGONOMETRY::GetId(). Inside the namespace of a node, there are also the symbols for the ports that are a child of the node. The input port symbol will be maxon::NODE::TRIGONOMETRY::IN. Note that, to retrieve the IDs value, the function GetId() is not needed in the case of a port but mandatory for the node. Our symbols are exported to header files. Those header files can be found in Maxon frameworks. For example, the directory nodes/frameworks/definition contains a lot of symbols.

Add a Graph to a Material

A node material can contain multiple node systems; one system for each node space. With the function NodeMaterial::HasSpace one can know if the node space with the given identifier was instantiated for the material.

A node system can be added with the following function: NodeMaterial::AddGraph. This will create the node system if it does not exist already. To add the graph, one has to provide a known NodeSpace identifier or retrieve the identifier of the current NodeSpace identifier with GetActiveNodeSpaceId().

// Create a node-based material and insert it in the document.
// Create a NodeMaterial
NodeMaterial* nodeMaterial = static_cast<NodeMaterial*>(BaseMaterial::Alloc(Mmaterial));
if (nodeMaterial == nullptr)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
// Retrieve the ID of the currently active node space.
const maxon::Id currentNodeSpaceID = GetActiveNodeSpaceId();
// It is however usually best not to rely on the active node space ID in code, as this usually
// leads to assumptious code. Instead, one should define or retrieve node space IDs directly.
// The ID for the standard renderer node space of Cinema 4D.
const maxon::Id standardMaterialSpaceId = maxon::nodes::MaterialNodeSpaces::Standard.GetId();
// The ID for the redshift renderer node space. It currently must be defined manually.
const maxon::Id redshiftMaterialSpaceId("com.redshift3d.redshift4c4d.class.nodespace");
// Create a node graph for the standard material space for this material, containing the the
// default graph setup, i.e., a so called "end node" which takes in all the outputs of the graph,
// and depending on the node space, usually also at least one fundamental node such as a BSDF node.
nodeMaterial->CreateDefaultGraph(standardMaterialSpaceId) iferr_return;
// A node material can multiple node spaces so that the same material produces different outputs
// for different node spaces.
// Create an empty graph for the Redshift space.
nodeMaterial->CreateEmptyGraph(redshiftMaterialSpaceId) iferr_return;
// Insert the material to the document.
doc->InsertMaterial(nodeMaterial);
maxon::Id GetActiveNodeSpaceId()
static BaseMaterial * Alloc(Int32 type)
Definition: c4d_basematerial.h:391
maxon::Result< void > CreateDefaultGraph(const maxon::Id &spaceId)
Definition: c4d_basematerial.h:489
maxon::Result< void > CreateEmptyGraph(const maxon::Id &spaceId)
Definition: c4d_basematerial.h:496
Definition: apibaseid.h:243
#define Mmaterial
Standard material.
Definition: ge_prepass.h:1008
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:67
const char * doc
Definition: pyerrors.h:226
#define iferr_return
Definition: resultbase.h:1524

Getting a Graph from a Material

NodeMaterial::GetGraph can be used to retrieve the node graph from the material for the given node space identifier.

// Retrieve a graph from a NodeMaterial
const maxon::NimbusBaseRef nimbusRef = nodeMaterial->GetNimbusRef(currentNodeSpaceID);
if (nimbusRef == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
const maxon::nodes::NodesGraphModelRef& nodeGraph = nimbusRef.GetGraph();
// Check if the NodeGraph is read only
if (nodeGraph.IsReadOnly())
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "NodeGraph is read only"_s);
maxon::NimbusForwardRef GetNimbusRef(const maxon::Id &spaceId) const
Definition: c4d_baselist.h:3010

Remove a Graph from a Material

NodeMaterial::RemoveGraph can be used to remove a node graph for the provided node space identifier if there is a graph.

// Remove a Graph System from a NodeMaterial by using the RemoveGraph function with the proper Node Space ID
nodeMaterial->RemoveNimbusRef(currentNodeSpaceID);
// Check if the Material have a NimbusRef or not for the current Node Space.
if (!nodeMaterial->GetNimbusRef(currentNodeSpaceID))
ApplicationOutput("Node System doesn't exist for node space @", currentNodeSpaceID);
void RemoveNimbusRef(const maxon::Id &spaceId)
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204

Get the Scene Node Graph

There is only one scene node per document. It can be retrieved from the document itself.

// Retrieve the current scene node of the document
// Retrieve the Id of the current Node Space ID.
const maxon::Id currentNodeSpaceID = GetActiveNodeSpaceId();
// Find the SceneHook to retrieve the NimbusRef
BaseSceneHook* neutronSH = doc->FindSceneHook(Int32(SCENENODES_IDS::SCENEHOOK_ID));
if (neutronSH == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
// Retrieve the NimbusBaseRef of the Scene Node.
maxon::NimbusBaseRef sceneNode = neutronSH->GetNimbusRef(maxon::neutron::NODESPACE);
if (sceneNode == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION, "Couldn't retrieve the sceneNode"_s);
// Retrieve the node graph from the NimbusBaseRef
const maxon::nodes::NodesGraphModelRef& nodeGraph = sceneNode.GetGraph();
if (nodeGraph.IsReadOnly())
return maxon::IllegalStateError(MAXON_SOURCE_LOCATION, "NodeGraph is read only"_s);
// Retrieve the root for the node graph
maxon::GraphNode root = nodeGraph.GetRoot();
// Output all the node present at the root level.
{
ApplicationOutput("node is @", child);
return true;
Definition: c4d_basedocument.h:52
Bool Message(Int32 type, void *data=nullptr)
Definition: c4d_baselist.h:1582
Result< Bool > GetChildren(const ValueReceiver< const GraphNode & > &callback, NODE_KIND mask=NODE_KIND::ALL_MASK) const
Definition: graph.h:1192
Definition: graph.h:2014
Definition: resultbase.h:766
maxon::Int32 Int32
Definition: ge_sys_math.h:56
@ SCENEHOOK_ID
SceneHook ID.
static constexpr Int32 MSG_CREATE_IF_REQUIRED
Definition: neutron_ids.h:67
static constexpr LiteralId NODESPACE
Neutron node space identifier.
Definition: neutron_ids.h:152
#define iferr_scope
Definition: resultbase.h:1389