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

    Link StoreColorToAOV to Existing AOV (Python)

    Cinema 4D SDK
    windows 2025
    3
    11
    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.
    • I
      itstanthony
      last edited by

      Cinema 4D: 2025.2.1
      Redshift: 2025.4.2

      Hi,

      In my script, I dynamically create a Store Color To AOV node and connect shader outputs to it. Everything works well except one key part:

      I'm trying to assign a custom AOV (defined in the Redshift AOV Manager)—for example, "BaseColor"—to the AOV Name field (e.g. AOV Name 0) of the node via Python.

      I'm currently using:

      aov_node.SetValue(c4d.DescID(c4d.DescLevel(1000 + index)), "BaseColor")
      

      The name appears in the dropdown UI, but it’s not actually linked dynamically to the AOV name of the Store Color To AOV node.

      Question:
      How can I properly assign dynamically a custom AOV name from the AOV Manager to the StoreColorToAOV node so it is correctly recognized during rendering?

      Thanks a lot in advance for your help!
      2025-05-20 20_24_35-Node Editor _.png

      DunhouD 1 Reply Last reply Reply Quote 0
      • DunhouD
        Dunhou @itstanthony
        last edited by

        Hi @itstanthony ,

        To add AOV to Redshift, you need use redshift.RendererSetAOVs to add a c4d.redshift.RSAOV object to your RS videopost.

        But I think the Redshift module has never been released and is not supported. I used this module to make a very clumsy wrapper( Renderer ), although not very elegant, it works.

        Hope the Redshift team can release the API as soon as possible.

        Cheers~
        DunHou

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

        1 Reply Last reply Reply Quote 0
        • I
          itstanthony
          last edited by

          Hi @DunHou,

          Thanks again for your insights and for sharing your experience with the Redshift module!

          Just to clarify, I’m trying to understand how to retrieve the list of available AOVs already preconfigured in the AOV Manager, find one named “BaseColor” for example, and set it as the value for the “AOV Name 0” parameter in a Store Color To AOV node.

          I know full script solutions aren’t expected here, but if you could point me to relevant Maxon IDs or documentation to manipulate these parameters, it would be greatly appreciated.

          Thanks again for your help!
          Cheers,
          Anthony

          2025-05-21 08_02_39-Script Manager.png

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

            Hey @itstanthony,

            Thank you for reaching out to us. Please have a look at Support Procedures: How to ask questions, what you provided there is not reproducible for us, I mostly have to guess what you are doing.

            The code snippet you gave us unfortunately does not make too much sense, I also do not really understand what you mean with the phrase 'dynamically linked' you use multiple times. When I interpret a bit, my understanding is that you want to set the string literal 'BasseColor' on the 'AOV Name 0' input port of a Store Color To AOV node.

            Your line of code makes very little sense to me. Not only that you use SetValue (which is for attributes) and not SetPortValue, you are passing a DescID to SetValue which makes absolutely no sense at all. This code will raise an exception and I must assume you used to AI to generate it. Please see Scope of Support: About AI-Supported Development.

            When you really want to use our low level Nodes API, I would recommend having a look at our Python code examples. But you then also have to be able "to swim to some degree on your own". Setting an AOV name string literal on a Store Color to AOV node, would go something like this:

            storeAovNode: maxon.GraphNode # A 'Store Color to AOV' node you got hold of somehow.
            
            # Get the name part of the '0' port group (when we look into the resource editor, we can see that
            # these are not actually port bundles but just groups, so there is no nesting going on here). Then
            # set the name of the AOV to 'BaseColor'.
            namePort: maxon.GraphNode = storeAovNode.GetInputs().FindChild(
                "com.redshift3d.redshift4c4d.nodes.core.storecolortoaov.aov_input0.name")
            namePort.SetPortValue("BaseColor")
            

            I would however more recommend graph descriptions for you, because to put it bluntly, when you already struggle with this relatively simple task in the Nodes API, you are probably not going to have a good time with all the hidden complexity there.

            Cheers,
            Ferdinand

            Result

            6de74506-1c56-4a2d-bed2-4047d15b0a15-image.png

            Code

            """Creates a Redshift material with a simple graph, where a "Store Color To AOV" node is used to
            connect a color to the AOV input of the material.
            """
            
            import c4d
            import maxon
            
            doc: c4d.documents.BaseDocument  # The currently active document.
            op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
            
            def main() -> None:
                """Called by Cinema 4D when the script is being executed.
                """
                # Creates a material with the name "Hello World" and gets its Redshift graph.
                graph: maxon.NodesGraphModelRef = maxon.GraphDescription.GetGraph(
                    name="Hello World", nodeSpaceId=maxon.NodeSpaceIdentifiers.RedshiftMaterial)
            
                # The #GetGraph call above created an empty graph, so we now fill it with some content with a
                # graph description, this mostly works in a WYSIWYG way where you can just type out the things
                # you see (but you still have to read the docs).
                maxon.GraphDescription.ApplyDescription(graph,
                    {
                        # Define the outmost node of the graph, the output end node.
                        "$type": "Output",
                        # Connect to its "Surface" input port an "Store Color To AOV" node.
                        "Surface": {
                            "$type": "Store Color To AOV",
                            # Connect to its "AOV Input 0" input port a "Color" node and give it an ID, as we
                            # want to reuse that node later.
                            "AOV Input 0": {
                                "$type": "Color",
                                "Inputs/Color": maxon.Vector(1, 0, 0),
                                "$id": "AoVColor"
                            },
                            # Set the name of the AOV to "BaseColor", this assumes that an AOV with that name
                            # already exists, it will not create the AOV for you.
                            "AOV Name 0": "BaseColor",
                            # As the input of the "Store Color To AOV", define a "Standard Material" node which
                            # also uses #AoVColor as its base color.
                            "Beauty Input":  {
                                "$type": "Standard Material",
                                "Base/Color": "#AoVColor",
                            }
                        }
                    }
                )
            
            if __name__ == '__main__':
                main()

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • I
              itstanthony
              last edited by

              Hi @ferdinand,

              Thanks a lot for the clarification and fair enough about the snippet I posted earlier, I get that it might’ve caused some confusion.

              I really appreciate you taking the time to share both code examples. That gives me a much clearer starting point, and I’ll take the time to go through them and explore the API more carefully.

              Thanks again for your help!

              Cheers,
              Anthony

              DunhouD 1 Reply Last reply Reply Quote 0
              • DunhouD
                Dunhou @itstanthony
                last edited by

                hey @itstanthony ,

                I don't quite understand what you're saying about “find one named “BaseColor” for example, and set it as the value for the “AOV Name 0” parameter in a Store Color To AOV node.”

                I assume you want to find an AOV named BaseColor in the AOV Manager and change its settings? I'm not sure if this is what you want.

                relevant Maxon IDs or documentation to manipulate these parameters - you should look at redshift resource folder, but if you only need some id about rs aov, you can also check redshift_id.py

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

                1 Reply Last reply Reply Quote 1
                • I
                  itstanthony
                  last edited by

                  Thanks @Dunhou for the pointers to redshift_id.py; it really helped me identify the ports properly.
                  Also, thanks to @ferdinand for the earlier script and support—that was extremely helpful.

                  I can connect standard PBR ports to storeColorToAOV without issues, but EmissionColor and OverallTint don’t connect in my test.

                  However, connecting these textures directly to the material works fine.
                  Could the order of connections affect their recognition? Or do these ports need to be exposed (made visible/available) before they can be connected via storeColorToAOV?

                  Thanks again for your help!

                  Here is a minimal example reproducing the issue:

                  import c4d
                  import maxon
                  
                  REDSHIFT_NODE_SPACE_ID = "com.redshift3d.redshift4c4d.class.nodespace"
                  
                  def main() -> None:
                      graph: maxon.NodesGraphModelRef = maxon.GraphDescription.GetGraph(
                          name="Simple PBR Material", nodeSpaceId=maxon.NodeSpaceIdentifiers.RedshiftMaterial)
                  
                      maxon.GraphDescription.ApplyDescription(graph,
                          {
                              "$type": "Output",
                              "Surface": {
                                  "$type": "Store Color To AOV",
                  
                                  "AOV Input 0": {
                                      "$type": "Color",
                                      "Inputs/Color": maxon.Vector(1, 1, 1),
                                      "$id": "BaseColorNode"
                                  },
                                  "AOV Name 0": "BaseColor",
                  
                                  "AOV Input 1": {
                                      "$type": "Color",
                                      "Inputs/Color": maxon.Vector(0.0, 0.0, 0.0),
                                      "$id": "MetallicNode"
                                  },
                                  "AOV Name 1": "Metallic",
                  
                                  "AOV Input 2": {
                                      "$type": "Color",
                                      "Inputs/Color": maxon.Vector(0.5, 0.5, 0.5),
                                      "$id": "RoughnessNode"
                                  },
                                  "AOV Name 2": "Roughness",
                  
                                  "AOV Input 3": {
                                      "$type": "Color",
                                      "Inputs/Color": maxon.Vector(0.5, 0.5, 1),
                                      "$id": "NormalMapNode"
                                  },
                                  "AOV Name 3": "Normal",
                  
                                  "AOV Input 4": {
                                      "$type": "Color",
                                      "Inputs/Color": maxon.Vector(1, 1, 1),
                                      "$id": "AOColorNode"
                                  },
                                  "AOV Name 4": "AO",
                  
                                  "AOV Input 5": {
                                      "$type": "Color",
                                      "Inputs/Color": maxon.Vector(0, 0, 0),
                                      "$id": "EmissiveColorNode"
                                  },
                                  "AOV Name 5": "Emissive",
                  
                                  "Beauty Input":  {
                                      "$type": "Standard Material",
                  
                                      "Base/Color": "#BaseColorNode",
                                      "Base/Metalness": "#MetallicNode",
                                      "Reflection/Roughness": "#RoughnessNode",
                                      "Geometry/Bump Map": "#NormalMapNode",
                                      "Geometry/Overall Tint": "#AOColorNode",
                                      "Emission/Color": "#EmissiveColorNode",
                                  }
                              }
                          }
                      )
                  
                  if __name__ == '__main__':
                      main()
                  

                  The error message:

                  Traceback (most recent call last):
                    File "D:\C4D Setup\scripts\PBRtoAOV\PBRtoAOV_Final.py", line 73, in <module>
                      print("Matériau PBR avec AOV créé avec succès!")
                      ^^^^^^
                    File "D:\C4D Setup\scripts\PBRtoAOV\PBRtoAOV_Final.py", line 10, in main
                      maxon.GraphDescription.ApplyDescription(graph,
                    File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\frameworks\nodes.py", line 548, in ApplyDescription
                      res: DataDictionary = GraphDescription._ApplyDescription(
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                    File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\decorators.py", line 495, in Auto
                      ExecStaticMethod(*args)
                  Exception: The input port reference 'Geometry/Overall Tint' has a value which resolves to more than one node. In:
                  { <- Error in this scope ->
                     $type: Standard Material
                     Base/Color: #BaseColorNode
                     Base/Metalness: #MetallicNode
                     Reflection/Roughness: #RoughnessNode
                     Geometry/Bump Map: #NormalMapNode
                     Geometry/Overall Tint: #AOColorNode
                     Emission/Color: #EmissiveColorNode
                  }
                  
                  # Result with these lines commented:   
                  # Geometry/Overall Tint: #AOColorNode
                  # Emission/Color: #EmissiveColorNode
                  

                  83a21098-e6f5-4893-8c34-3ca4ced84c87-image.png

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

                    Hey @itstanthony,

                    That is a bit of a odd one. So, your code is absolutely correct, and I was just as puzzled as you are why this is not working.

                    First of all, I wrote the error "The input port reference 'Geometry/Overall Tint' has a value which resolves to more than one node" a bit misleadingly, as it also covers the case where the a port reference matches nothing. I just fixed the error handling there, in a future release (not the next one) of Cinema 4D, this error will now be as follows (this also contains other changes I applied before to error handling in general and for graph descriptions in particular):

                    Exception: (net.maxon.error.parsing) The node reference '#AOColorNode' passed to the port 'Geometry/Overall Tint' is ambigous as it resolves to '0' nodes. In:
                    
                    { <- Error in this scope (keys might appear out of order) ->
                       "$type": "Standard Material"
                       "Base/Color": "#BaseColorNode"
                       "Base/Metalness": "#MetallicNode"
                       "Reflection/Roughness": "#RoughnessNode"
                       "Geometry/Bump Map": "#NormalMapNode"
                       "Geometry/Overall Tint": "#AOColorNode"
                       "Emission/Color": "#EmissiveColorNode"
                    }
                    

                    As to why this happens, I have absolutely no clue. I just stepped through the graph description code, and everything is fine. After the #NormalMapNode, the Nodes API just simply does not return the nodes created earlier there within the same transaction, and you therefore do not find them. When you comment out these last two lines, you will end up with a graph which contains these two nodes with the defined IDs. There must be some caching optimization or something like this be going on, but I have no idea where this is happening, I will have to take a deeper look at that.

                    But luckily, graph descriptions offer a way out of that: Partial descriptions. With them you can avoid having to embed nodes that are referenced multiple times into the same description and with that in the same transaction.

                    It will then look liket this (note that naming the nodes and the changes to the IDs are not necessary, I was just cleaning up the graph into a state of how I would write that):

                    import c4d
                    import maxon
                    
                    def main() -> None:
                        graph: maxon.NodesGraphModelRef = maxon.GraphDescription.GetGraph(
                            name="Simple PBR Material", nodeSpaceId=maxon.NodeSpaceIdentifiers.RedshiftMaterial)
                    
                        maxon.GraphDescription.ApplyDescription(graph,
                            [
                                {
                                    "$type": "Color",
                                    "Basic/Name": "Base Color",
                                    "Inputs/Color": maxon.Vector(1, 1, 1),
                                    "$id": "base_color"
                                },
                                {
                                    "$type": "Color",
                                    "Basic/Name": "Metallic",
                                    "Inputs/Color": maxon.Vector(0.0, 0.0, 0.0),
                                    "$id": "metallic_color"
                                },
                                {
                                    "$type": "Color",
                                    "Basic/Name": "Roughness",
                                    "Inputs/Color": maxon.Vector(0.5, 0.5, 0.5),
                                    "$id": "roughness_color"
                                },
                                {
                                    "$type": "Color",
                                    "Basic/Name": "Normal",
                                    "Inputs/Color": maxon.Vector(0.5, 0.5, 1),
                                    "$id": "normal_color"
                                },
                                {
                                    "$type": "Color",
                                    "Basic/Name": "AO",
                                    "Inputs/Color": maxon.Vector(1, 1, 1),
                                    "$id": "ao_color"
                                },
                                {
                                    "$type": "Color",
                                    "Basic/Name": "Emissive",
                                    "Inputs/Color": maxon.Vector(0, 0, 0),
                                    "$id": "emissive_color"
                                },
                                {
                                "$type": "Output",
                                "Surface": {
                                    "$type": "Store Color To AOV",
                    
                                    "AOV Input 0": "#base_color",
                                    "AOV Name 0": "BaseColor",
                    
                                    "AOV Input 1": "#metallic_color",
                                    "AOV Name 1": "Metallic",
                    
                                    "AOV Input 2": "#roughness_color",
                                    "AOV Name 2": "Roughness",
                    
                                    "AOV Input 3": "#normal_color",
                                    "AOV Name 3": "Normal",
                    
                                    "AOV Input 4": "#ao_color",
                                    "AOV Name 4": "AO",
                    
                                    "AOV Input 5": "#emissive_color",
                                    "AOV Name 5": "Emissive",
                    
                                    "Beauty Input": {
                                        "$type": "Standard Material",
                    
                                        "Base/Color": "#base_color",
                                        "Base/Metalness": "#metallic_color",
                                        "Reflection/Roughness": "#roughness_color",
                                        "Geometry/Bump Map": "#normal_color",
                                        "Geometry/Overall Tint": "#ao_color",
                                        "Emission/Color": "#emissive_color",
                                    }
                                }
                            }
                            ]
                        )
                    
                    if __name__ == '__main__':
                        main()
                    

                    Resulting in this graph:

                    3100eb22-5684-4b3c-8358-82ba5de9f19b-image.png

                    I hope this helps and cheers,
                    Ferdinand

                    MAXON SDK Specialist
                    developers.maxon.net

                    1 Reply Last reply Reply Quote 0
                    • I
                      itstanthony
                      last edited by

                      Hey @ferdinand

                      Thanks a lot for the clear explanation, it really helped. Your tip about partial descriptions completely fixed the issue.

                      Also, the clarification on that confusing error message makes a lot more sense now. It’s great that it’ll be improved in a future Cinema 4D update. I really appreciate your transparency and all the work you’re doing to make this easier.

                      Thanks again for your help and for taking the time to explain everything so clearly!

                      Cheers,
                      Anthony

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

                        Good to hear, one thing I forgot to mention, and you might not be aware of (and are not yet reflected in the GraphDescription manual or the Nodes API examples), is that you are writing there render space values, i.e., likely ACEScg values and not sRGB values as you usually would as a user.

                        See open_color_io_2025_2.py for the technical details, but to write values as sRGB, as you probably intend to, you would have to do this:

                        import c4d
                        import maxon
                        
                        doc: c4d.documents.BaseDocument # The active document
                        
                        def main() -> None:
                            converter: c4d.modules.render.OcioConverter = doc.GetColorConverter()
                            graph: maxon.NodesGraphModelRef = maxon.GraphDescription.GetGraph(
                                name="Simple PBR Material", nodeSpaceId=maxon.NodeSpaceIdentifiers.RedshiftMaterial)
                            
                            # With Cinema 4D 2025.2.0 OCIO handling became mandatory. To define maxon colors/vectors
                            # in sRGB space, we have to do this. For pure white/black this is inconsequential, as there an
                            # an sRGB value is same value as in our standard render space of Cinema 4D: ACEScg. But the
                            # The sRGB color (1, 0, 0) is for example the ACEScg value (0.61, 0.07, 0.02).
                            cWhite: c4d.Vector = converter.TransformColor(
                                c4d.Vector(1), c4d.COLORSPACETRANSFORMATION_OCIO_SRGB_TO_RENDERING)
                            mWhite: maxon.Color = maxon.Color(cWhite.x, cWhite.y, cWhite.z)
                        
                            cBlack: c4d.Vector = converter.TransformColor(
                                c4d.Vector(0), c4d.COLORSPACETRANSFORMATION_OCIO_SRGB_TO_RENDERING)
                            mBlack: maxon.Color = maxon.Color(cBlack.x, cBlack.y, cBlack.z)
                        
                            cGray: c4d.Vector = converter.TransformColor(
                                c4d.Vector(0.5), c4d.COLORSPACETRANSFORMATION_OCIO_SRGB_TO_RENDERING)
                            mGray: maxon.Color = maxon.Color(cGray.x, cGray.y, cGray.z)
                        
                            cPurple: c4d.Vector = converter.TransformColor(
                                c4d.Vector(0.5, 0.5, 1.0), c4d.COLORSPACETRANSFORMATION_OCIO_SRGB_TO_RENDERING)
                            mPurple: maxon.Color = maxon.Color(cPurple.x, cPurple.y, cPurple.z)
                        
                            # Clear the graph to start fresh
                        
                            maxon.GraphDescription.ApplyDescription(graph,
                                [
                                    {
                                        "$type": "Color",
                                        "Basic/Name": "Base Color",
                                        "Inputs/Color": mWhite,
                                        "$id": "base_color"
                                    },
                                    {
                                        "$type": "Color",
                                        "Basic/Name": "Metallic",
                                        "Inputs/Color": mBlack,
                                        "$id": "metallic_color"
                                    },
                                    {
                                        "$type": "Color",
                                        "Basic/Name": "Roughness",
                                        "Inputs/Color": mGray,
                                        "$id": "roughness_color"
                                    },
                                    {
                                        "$type": "Color",
                                        "Basic/Name": "Normal",
                                        "Inputs/Color": mPurple,
                                        "$id": "normal_color"
                                    },
                                    {
                                        "$type": "Color",
                                        "Basic/Name": "AO",
                                        "Inputs/Color": mWhite,
                                        "$id": "ao_color"
                                    },
                                    {
                                        "$type": "Color",
                                        "Basic/Name": "Emissive",
                                        "Inputs/Color": mBlack,
                                        "$id": "emissive_color"
                                    },
                                    {
                                    "$type": "Output",
                                    "Surface": {
                                        "$type": "Store Color To AOV",
                        
                                        "AOV Input 0": "#base_color",
                                        "AOV Name 0": "BaseColor",
                        
                                        "AOV Input 1": "#metallic_color",
                                        "AOV Name 1": "Metallic",
                        
                                        "AOV Input 2": "#roughness_color",
                                        "AOV Name 2": "Roughness",
                        
                                        "AOV Input 3": "#normal_color",
                                        "AOV Name 3": "Normal",
                        
                                        "AOV Input 4": "#ao_color",
                                        "AOV Name 4": "AO",
                        
                                        "AOV Input 5": "#emissive_color",
                                        "AOV Name 5": "Emissive",
                        
                                        "Beauty Input": {
                                            "$type": "Standard Material",
                        
                                            "Base/Color": "#base_color",
                                            "Base/Metalness": "#metallic_color",
                                            "Reflection/Roughness": "#roughness_color",
                                            "Geometry/Bump Map": "#normal_color",
                                            "Geometry/Overall Tint": "#ao_color",
                                            "Emission/Color": "#emissive_color",
                                        }
                                    }
                                }
                                ]
                            )
                        
                        if __name__ == '__main__':
                            main()
                        

                        MAXON SDK Specialist
                        developers.maxon.net

                        1 Reply Last reply Reply Quote 0
                        • I
                          itstanthony
                          last edited by

                          Thank you very much for pointing this out.
                          I knew that Cinema 4D’s UI includes a “Linear Numeric Values” button to switch between color spaces, but I wasn’t aware of how to properly handle this conversion in code until you showed me.

                          Your reference to the open_color_io_2025_2.py example is really helpful for better understanding how to manage color spaces in scripts.

                          Thanks again for the great insight!

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