Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    How to find and delete a node in a NodeGraph?

    Cinema 4D SDK
    c++ 2023
    3
    5
    1.4k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • kbarK
      kbar
      last edited by kbar

      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

      https://www.gamelogicdesign.com
      https://www.plugins4d.com

      DunhouD ferdinandF 2 Replies Last reply Reply Quote 0
      • DunhouD
        Dunhou @kbar
        last edited by

        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())
        

        https://boghma.com
        https://github.com/DunHouGo

        1 Reply Last reply Reply Quote 1
        • ferdinandF
          ferdinand @kbar
          last edited by ferdinand

          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.

          3d4206a0-ecaa-4eca-8fd4-f880d943fa42-image.png

          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.

          95e16d67-fd76-4f2e-aa25-5075d4064711-image.png
          Fig. II: The two nodes in the Standard Renderer default graph will always have the IDs material, and bsdf.

          df209011-7ad7-4010-ba00-17061a3018a7-image.png
          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:

          8fc51e0c-3acd-4bcb-9c9f-5d0ab5042b54-image.png

          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.

          MAXON SDK Specialist
          developers.maxon.net

          kbarK 1 Reply Last reply Reply Quote 1
          • kbarK
            kbar
            last edited by

            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.

            https://www.gamelogicdesign.com
            https://www.plugins4d.com

            1 Reply Last reply Reply Quote 0
            • kbarK
              kbar @ferdinand
              last edited by

              @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.

              https://www.gamelogicdesign.com
              https://www.plugins4d.com

              1 Reply Last reply Reply Quote 0
              • First post
                Last post