nodes_material_access

Demonstrates accessing node materials and their graph contents in a scene.

nodes_material_access.py

#coding: utf-8
"""Demonstrates accessing node materials and their graph contents in a scene.

Topics:
    * Accessing node materials in a document.
    * Testing for and accessing graphs for node spaces in a node material.
    * Iterating over nodes in a graph.
"""
__author__ = "Ferdinand Hoppe"
__copyright__ = "Copyright (C) 2026 MAXON Computer GmbH"
__date__ = "01/09/2023"
__license__ = "Apache-2.0 License"
__version__ = "2024.0.0"


import c4d
import maxon

doc: c4d.documents.BaseDocument # The active document.

def main():
    """
    """
    # Node materials are instances of the Cinema API material type #BaseMaterial. The node data
    # is attached to them as a #NodeMaterial. We can retrieve a #NodeMaterial instance for each 
    # #BaseMaterial instance, whether or not this material actually is a node material or not.
    # Because of that, we must iterate over all material in a document to find node materials and 
    # retrieve the #NodeMaterial for each of them.

    # 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.")
            
            # Now we iterate over all items in the graph.
            print (f"\nThe material '{material.GetName()}' has a graph in the node space '{nid}'.")
            root: maxon.GraphNode = graph.GetViewRoot()

            # Iterate over the direct children of the graph root.
            node: maxon.GraphNode
            for node in root.GetChildren():
                print (f"\tDirect child of graph root: {node.GetId()}")
            
            print ("\t" + "-" * 60)
            # Iterate over all nodes in the graph, i.e., unpack things like nodes nested in groups. 
            # With the mask argument we could also include ports in this iteration.
            for node in root.GetInnerNodes(mask=maxon.NODE_KIND.NODE, includeThis=False):
                print (f"\tNode in the graph: {node}")
            
    c4d.EventAdd()


if __name__ == "__main__":
    main()