SetPortValue for Texture node ColorSpace
-
I checked the forum, and there are few posts that asked the same question yet I still can't get it to work.
Here is my code:# Add a Texture node to the graph idTextureNode: maxon.Id = maxon.Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler") textureNode: maxon.GraphNode = graph.AddChild(maxon.Id(), idTextureNode) # Ensure the Texture node was created successfully if textureNode.IsNullValue(): print("Error: Texture node creation failed.") return # Set the Color Space port value to RAW colorSpacePort: maxon.GraphNode = textureNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.texturesampler.colorspace") if colorSpacePort: try: colorSpacePort.SetPortValue("RS_INPUT_COLORSPACE_RAW ") except Exception as e: print(f"Failed to set color space value: {e}") # Commit the transaction transaction.Commit()
I get this:
Failed to set color space value: no target to copy for '<net.maxon.graph.interface.graphmodel>'
All I'm trying to do is set the color space to RAW for incoming normal bitmaps later.
I'm new to coding, so I am sure I'm doing something wrong here. Help is much appreciated.Thank you.
-
Hello @Matthew_H,
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: How to Ask Questions.
About your First Question
Please make sure to give us complete, i.e., executable code examples in the future. Any time we must spend on getting to a starting point for a user problem will be subtracted from the time we can spend on a problem. I took in this case one of our existing code examples, but in other cases we might even refuse to answer until the user posts executable code.
Your code contains three problems:
- Validity testing of a node is currently not yet possible via truth testing.
- You do not correctly access the Color Space child port in the port bundle Filename.
- The value you are tyring to write is incorrect (there is an extra white space at the end of the string).
When we add all ports to an RS Texture node, it becomes more obvious that the Color Space port is part of a Filename port bundle.
Find below a code example using one of our Redshift code examples.
Cheers,
FerdinandResult
Code
The relevant code is within the snip markers:
#coding: utf-8 """Demonstrates setting up a Redshift node material composed out of multiple nodes. Creates a new node material with a graph in the Redshift material space, containing two texture nodes and a mix node, in addition to the default RS Standard Material and Output node of the material. Topics: * Creating a node material and adding a graph. * Adding nodes to a graph. * Setting the value of ports without wires. * Connecting ports with a wires. """ __author__ = "Ferdinand Hoppe" __copyright__ = "Copyright (C) 2023 MAXON Computer GmbH" __date__ = "04/06/2024" __license__ = "Apache-2.0 License" __version__ = "2024.0.0" import c4d import maxon doc: c4d.documents.BaseDocument # The active document. def main() -> None: """Runs the example. """ # The asset URLs for the "RustPaint0291_M.jpg" and "Sketch (HR basic026).jpg" texture assets in # "tex/Surfaces/Dirt Scratches & Smudges/". These could also be replaced with local texture URLs, # e.g., "file:///c:/textures/stone.jpg". These IDs can be discovered with the #-button in the info # area of the Asset Browser. urlTexRust: maxon.Url = maxon.Url(r"asset:///file_edb3eb584c0d905c") urlTexSketch: maxon.Url = maxon.Url(r"asset:///file_3b194acc5a745a2c") # The node asset IDs for the two node types to be added in the example; the texture node and the # mix node. These and all other node IDs can be discovered in the node info overlay in the # bottom left corner of the Node Editor. Open the Cinema 4D preferences by pressing CTRL/CMD + E # and enable Node Editor -> Ids in order to see node and port IDs in the Node Editor. idOutputNode: maxon.Id = maxon.Id("com.redshift3d.redshift4c4d.node.output") idStandardMaterial: maxon.Id = maxon.Id("com.redshift3d.redshift4c4d.nodes.core.standardmaterial") idTextureNode: maxon.Id = maxon.Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler") idMixNode: maxon.Id = maxon.Id("com.redshift3d.redshift4c4d.nodes.core.rscolormix") # Instantiate a material, get its node material, and add a graph for the RS material space. material: c4d.BaseMaterial = c4d.BaseMaterial(c4d.Mmaterial) if not material: raise MemoryError(f"{material = }") nodeMaterial: c4d.NodeMaterial = material.GetNodeMaterialReference() redshiftNodeSpaceId: maxon.Id = maxon.Id("com.redshift3d.redshift4c4d.class.nodespace") graph: maxon.GraphModelRef = nodeMaterial.CreateEmptyGraph(redshiftNodeSpaceId) if graph.IsNullValue(): raise RuntimeError("Could not add Redshift graph to material.") # Open an undo operation and insert the material into the document. We must do this before we # modify the graph of the material, as otherwise the viewport material will not correctly display # the textures of the material until the user manually refreshes the material. It is also # important to insert the material after we added the default graph to it, as otherwise we will # end up with two undo steps in the undo stack. if not doc.StartUndo(): raise RuntimeError("Could not start undo stack.") doc.InsertMaterial(material) if not doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, material): raise RuntimeError("Could not add undo item.") # Define the user data for the transaction. This is optional, but can be used to tell the Nodes # API to add the transaction to the current undo stack instead of creating a new one. This will # then have the result that adding the material, adding the graph, and adding the nodes will be # one undo step in the undo stack. userData: maxon.DataDictionary = maxon.DataDictionary() userData.Set(maxon.nodes.UndoMode, maxon.nodes.UNDO_MODE.ADD) # Start modifying the graph by opening a transaction. Node graphs follow a database like # transaction model where all changes are only finally applied once a transaction is committed. with graph.BeginTransaction(userData) as transaction: # Add the output, i.e., the terminal end node of the graph, as well as a standard material # node to the graph. outNode: maxon.GraphNode = graph.AddChild(maxon.Id(), idOutputNode) materialNode: maxon.GraphNode = graph.AddChild(maxon.Id(), idStandardMaterial) # Add two texture nodes and a blend node to the graph. rustTexNode: maxon.GraphNode = graph.AddChild(maxon.Id(), idTextureNode) sketchTexNode: maxon.GraphNode = graph.AddChild(maxon.Id(), idTextureNode) mixNode: maxon.GraphNode = graph.AddChild(maxon.Id(), idMixNode) # Get the input 'Surface' port of the 'Output' node and the output 'Out Color' port of the # 'Standard Material' node and connect them. surfacePortOutNode: maxon.GraphNode = outNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.node.output.surface") outcolorPortMaterialNode: maxon.GraphNode = materialNode.GetOutputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.standardmaterial.outcolor") outcolorPortMaterialNode.Connect(surfacePortOutNode) # Set the default value of the 'Mix Amount' port, i.e., the value the port has when no # wire is connected to it. This is equivalent to the user setting the value to "0.5" in # the Attribute Manager. mixAmount: maxon.GraphNode = mixNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.rscolormix.mixamount") mixAmount.SetPortValue(0.5) # Set the path sub ports of the 'File' ports of the two image nodes to the texture URLs # established above. Other than for the standard node space image node, the texture is # expressed as a port bundle, i.e., a port which holds other ports. The texture of a texture # node is expressed as the "File" port, of which "Path", the URL, is only one of the possible # sub-ports to set. pathRustPort: maxon.GraphNode = rustTexNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0").FindChild("path") pathSketchPort: maxon.GraphNode = sketchTexNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0").FindChild("path") pathRustPort.SetPortValue(urlTexRust) pathSketchPort.SetPortValue(urlTexSketch) # --- Snip --------------------------------------------------------------------------------- # This was not correct, the color space port is not a child of the texture node, but of its # Filename port bundle. So, it must be texturesampler.tex0 and not texturesampler. And since # it is a port within a port, you need two FindChild calls to get to it. # colorSpacePort: maxon.GraphNode = textureNode.GetInputs().FindChild( # "com.redshift3d.redshift4c4d.nodes.core.texturesampler.colorspace") colorSpacePort: maxon.GraphNode = rustTexNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0").FindChild("colorspace") # When you want to check if a retrieved graph node is valid, simple truth testing does # unfortunately not (yet) work (Maxime has it on his bucket list). Instead, you must call: if not colorSpacePort.IsValid(): raise RuntimeError("Could not find the color space port.") # Set the color space of the texture node to "RS_INPUT_COLORSPACE_RAW". colorSpacePort.SetPortValue("RS_INPUT_COLORSPACE_RAW") # --- Snip --------------------------------------------------------------------------------- # Get the color output ports of the two texture nodes and the color blend node. rustTexColorOutPort: maxon.GraphNode = rustTexNode.GetOutputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor") sketchTexColorOutPort: maxon.GraphNode = sketchTexNode.GetOutputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor") mixColorOutPort: maxon.GraphNode = mixNode.GetOutputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.rscolormix.outcolor") # Get the fore- and background port of the blend node and the color port of the BSDF node. mixInput1Port: maxon.GraphNode = mixNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.rscolormix.input1") mixInput2Port: maxon.GraphNode = mixNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.rscolormix.input2") stdBaseColorInPort: maxon.GraphNode = materialNode.GetInputs().FindChild( "com.redshift3d.redshift4c4d.nodes.core.standardmaterial.base_color") # Wire up the two texture nodes to the blend node and the blend node to the BSDF node. rustTexColorOutPort.Connect(mixInput1Port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) sketchTexColorOutPort.Connect(mixInput2Port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) mixColorOutPort.Connect(stdBaseColorInPort, modes=maxon.WIRE_MODE.NORMAL, reverse=False) # Finish the transaction to apply the changes to the graph. transaction.Commit() if not doc.EndUndo(): raise RuntimeError("Could not end undo stack.") c4d.EventAdd() if __name__ == "__main__": main()
-
Thank you so much, this was very helpful to learn.
All the best.