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

    Change texture node colorspace

    Cinema 4D SDK
    2024 python windows
    2
    6
    798
    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.
    • D
      DEDAAN
      last edited by DEDAAN

      Hi
      I'm trying to change the colorspace of the selected texture nodes in a existing node material.

      I came across these topics but am unable to get it to work.
      https://developers.maxon.net/forum/topic/14331/editing-rs-nodes-with-python
      https://developers.maxon.net/forum/topic/14236/change-the-colorspace-of-redshift-texture-node/4?_=1672651116634

      Since I'm not very experienced with python, and especially for cinema I took this scripts as a starting point;
      https://github.com/PluginCafe/cinema4d_py_sdk_extended/blob/master/scripts/05_modules/node/access_graph_entities_2024_2.py

      This is what I have currently, but I'm getting the following error;

      Traceback (most recent call last):
        File "scriptmanager", line 73, in <module>
        File "scriptmanager", line 63, in main
      TypeError: 'InternedId' object is not callable
      

      Anyone able to help me out? 🙂

      import c4d
      import maxon
      
      doc: c4d.documents.BaseDocument # The active document.
      
      def main():
          # For the selected mateiral in the currently active document ...
          for material in doc.GetActiveMaterials():
              # ... get its node material reference and step over all materials which do not have a
              # Redshift graph or where the graph is malformed.
              nodeMaterial = c4d.NodeMaterial = material.GetNodeMaterialReference()
              if not nodeMaterial.HasSpace("com.redshift3d.redshift4c4d.class.nodespace"):
                  continue
      
              graph = maxon.GraphModelRef = nodeMaterial.GetGraph(
                  "com.redshift3d.redshift4c4d.class.nodespace")
              if graph.IsNullValue():
                  raise RuntimeError("Found malformed empty graph associated with node space.")
      
              # Get the root of the graph, the node which contains all other nodes.
              root = maxon.GraphNode = graph.GetRoot()
      
              # 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):
      
                  # There is a difference between the asset ID of a node and its ID. The asset ID is
                  # the identifier of the node template asset from which a node has been instantiated.
                  # It is more or less the node type identifier. When we have three RS Texture nodes
                  # in a graph they will all have the same asset ID. But their node ID on the other hand
                  # will always be unique to a node.
                  assetId = maxon.Id = node.GetValue("net.maxon.node.attribute.assetid")[0]
                  nodeId = maxon.Id = node.GetId()
      
                  # Step over everything that is not a Texture node, we could also check here for a node
                  # id, in case we want to target a specific node instance.
                  if assetId != maxon.Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler") and node.GetBit(c4d.BIT_ACTIVE):
                      print("texture node found")
                      port = node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.texturesampler.tspace_id")
                      port.SetDefaultValue("RS_INPUT_COLORSPACE_RAW ")
      
      
      
      
      
      if __name__ == "__main__":
          main()
      
      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @DEDAAN
        last edited by ferdinand

        Welcome to the Maxon developers forum and its community, it is great to have you with us!

        Getting Started

        Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

        • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
        • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
        • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

        It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.

        About your First Question

        Hey, could you please share your full source code, the code snippet you shared only has 48 lines, so your error traceback cannot apply. There is also no InternedId in your code, which adds to the fact that this traceback cannot stem from the code you show us.

        But I have nevertheless a good idea what is going wrong for you, stuff like this (there are many instances of this in your code) is wrong:

         root = maxon.GraphNode = graph.GetRoot()
        

        What you are probably trying to imitate here, is the type hinting I tend to use in the code I write. I.e., the correct way to write this would be:

         root: maxon.GraphNode = graph.GetRoot() # A type hint is preceded by a colon, not the equal sign
        

        This line means: "Get the return value of #graph.GetRoot() and assign it to #root". The type hinting part (: maxon.GraphNode) is optional and just means: "I am also claiming that the return type of GetRoot is of type maxon.GraphNode." Type hints do not have to hold true, I could have also written there bool (which is not true) and the code would just run fine. Type hints can be used by static type checkers and then have an impact on the runtime behaviour of code, but I just use type hinting in examples as it tends to make code more verbose, it is easier to see what is going on. Type hints are fully optional and the following line is functionality wise 100% identical:

         root = graph.GetRoot()
        

        When you do what you did, you will overwrite the type, e.g.:

        foo = maxon.InternedId = 5
        
        # This line will now raise "TypeError: 'InternedId' object is not callable" because we both set the 
        # variable #foo and the type attribute InternedId of the maxon module to the (integer object) "5".
        # So, for Python this now reads like "myId = 5()" and it is politely telling us that it thinks that we
        # are a bit stupid by trying to call a number.
        myId = maxon.InternedId()
        
        # Just demonstrate the effect, this will print (5, 5, 5, 5)
        a = b = c = d = 5
        print(a, b, c, d)
        

        So, long story short, you must either not use type hints or use : instead of = to use the correct syntax for them.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 1
        • D
          DEDAAN
          last edited by

          Hey, thanks for the help!

          I've changed type hinting, just to make sure that was not the source of the problem.
          The weird thing is, this is the whole script, so I have no clue where the traceback error is coming from.
          InternedId is indeed not in my code.

          Even this script is giving that error now and that one was working just fine earlier today 🤔
          https://github.com/PluginCafe/cinema4d_py_sdk_extended/blob/master/scripts/05_modules/node/access_graph_entities_2024_2.py

          import c4d
          import maxon
          
          doc: c4d.documents.BaseDocument # The active document.
          
          def main():
              # For the selected mateiral in the currently active document ...
              for material in doc.GetActiveMaterials():
                  # ... get its node material reference and step over all materials which do not have a
                  # Redshift graph or where the graph is malformed.
                  nodeMaterial: c4d.NodeMaterial = material.GetNodeMaterialReference()
                  if not nodeMaterial.HasSpace("com.redshift3d.redshift4c4d.class.nodespace"):
                      continue
          
                  graph: maxon.GraphModelRef = nodeMaterial.GetGraph(
                      "com.redshift3d.redshift4c4d.class.nodespace")
                  if graph.IsNullValue():
                      raise RuntimeError("Found malformed empty graph associated with node space.")
          
                  # Get the root of the graph, the node which contains all other nodes.
                  root: maxon.GraphNode = graph.GetRoot()
          
                  # 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):
          
                      # There is a difference between the asset ID of a node and its ID. The asset ID is
                      # the identifier of the node template asset from which a node has been instantiated.
                      # It is more or less the node type identifier. When we have three RS Texture nodes
                      # in a graph they will all have the same asset ID. But their node ID on the other hand
                      # will always be unique to a node.
                      assetId: maxon.Id = node.GetValue("net.maxon.node.attribute.assetid")[0]
                      nodeId: maxon.Id = node.GetId()
          
                      # Step over everything that is not a Texture node, we could also check here for a node
                      # id, in case we want to target a specific node instance.
                      if assetId != maxon.Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler") and node.GetBit(c4d.BIT_ACTIVE):
                          continue
          
                      print("texture node found")
                      port = node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.texturesampler.tspace_id")
                      port.SetPortValue("RS_INPUT_COLORSPACE_RAW ")
          
          if __name__ == "__main__":
              main()
          
          Traceback (most recent call last):
            File "scriptmanager", line 45, in <module>
            File "scriptmanager", line 37, in main
          TypeError: 'InternedId' object is not callable
          
          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by ferdinand

            I do not have a scene with which I could run this (creating a Redshift material won't be enough to get to line 45), but since you attempt there to instantiate an ID (maxon.Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler")), I would say this is still the old issue. You have to restart your Cinema 4D when you bricked your types in this manner. You interpreter-runtime-persistently overwrote what maxon.InternedId etc. means with your old script(s).

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • D
              DEDAAN
              last edited by

              Okay, I was able to get it to work, now I just need some kind of way to get the selected nodes, is there any way to do this?
              node.GetBit(c4d.BIT_ACTIVE) doesn't seem to work with the new nodes and I'm unable to find a solution so far.

              Cheers,
              Daan

              1 Reply Last reply Reply Quote 0
              • ferdinandF
                ferdinand
                last edited by

                Please open a new topic for new subjects. See our Support Procedures: Asking Questions. GetBit is a BaseList2D method, your node is not a BaseList2D.

                MAXON SDK Specialist
                developers.maxon.net

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