1313"""
1414__author__ = "Ferdinand Hoppe"
1515__copyright__ = "Copyright (C) 2023 MAXON Computer GmbH"
16- __date__ = "01/09/2023 "
16+ __date__ = "04/06/2024 "
1717__license__ = "Apache-2.0 License"
1818__version__ = "2024.0.0"
1919
@@ -37,45 +37,69 @@ def main() -> None:
3737 # mix node. These and all other node IDs can be discovered in the node info overlay in the
3838 # bottom left corner of the Node Editor. Open the Cinema 4D preferences by pressing CTRL/CMD + E
3939 # and enable Node Editor -> Ids in order to see node and port IDs in the Node Editor.
40+ idOutputNode : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.node.output" )
41+ idStandardMaterial : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.standardmaterial" )
4042 idTextureNode : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.texturesampler" )
4143 idMixNode : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.rscolormix" )
42- idRsStandardMaterial : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.standardmaterial" )
4344
44- # Instantiate a material, get its node material and the graph for the RS material space.
45+ # Instantiate a material, get its node material, and add a graph for the RS material space.
4546 material : c4d .BaseMaterial = c4d .BaseMaterial (c4d .Mmaterial )
4647 if not material :
4748 raise MemoryError (f"{ material = } " )
4849
4950 nodeMaterial : c4d .NodeMaterial = material .GetNodeMaterialReference ()
50- graph : maxon .GraphModelRef = nodeMaterial . CreateDefaultGraph (
51- maxon . Id ( "com.redshift3d.redshift4c4d.class.nodespace" ) )
51+ redshiftNodeSpaceId : maxon .Id = maxon . Id ( "com.redshift3d.redshift4c4d.class.nodespace" )
52+ graph : maxon . GraphModelRef = nodeMaterial . CreateEmptyGraph ( redshiftNodeSpaceId )
5253 if graph .IsNullValue ():
53- raise RuntimeError ("Could not add RS graph to material." )
54-
54+ raise RuntimeError ("Could not add Redshift graph to material." )
55+
56+ # Open an undo operation and insert the material into the document. We must do this before we
57+ # modify the graph of the material, as otherwise the viewport material will not correctly display
58+ # the textures of the material until the user manually refreshes the material. It is also
59+ # important to insert the material after we added the default graph to it, as otherwise we will
60+ # end up with two undo steps in the undo stack.
61+ if not doc .StartUndo ():
62+ raise RuntimeError ("Could not start undo stack." )
63+
5564 doc .InsertMaterial (material )
56- c4d .EventAdd ()
65+ if not doc .AddUndo (c4d .UNDOTYPE_NEWOBJ , material ):
66+ raise RuntimeError ("Could not add undo item." )
5767
58- # Attempt to find the core material node contained in the default graph setup.
59- result : list [ maxon . GraphNode ] = []
60- maxon . GraphModelHelper . FindNodesByAssetId ( graph , idRsStandardMaterial , True , result )
61- if len ( result ) < 1 :
62- raise RuntimeError ( "Could not find RS Standard node in material." )
63- standardNode : maxon .GraphNode = result [ 0 ]
68+ # Define the user data for the transaction. This is optional, but can be used to tell the Nodes
69+ # API to add the transaction to the current undo stack instead of creating a new one. This will
70+ # then have the result that adding the material, adding the graph, and adding the nodes will be
71+ # one undo step in the undo stack.
72+ userData : maxon . DataDictionary = maxon . DataDictionary ( )
73+ userData . Set ( maxon .nodes . UndoMode , maxon . nodes . UNDO_MODE . ADD )
6474
6575 # Start modifying the graph by opening a transaction. Node graphs follow a database like
6676 # transaction model where all changes are only finally applied once a transaction is committed.
67- with graph .BeginTransaction () as transaction :
77+ with graph .BeginTransaction (userData ) as transaction :
78+
79+ # Add the output, i.e., the terminal end node of the graph, as well as a standard material
80+ # node to the graph.
81+ outNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idOutputNode )
82+ materialNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idStandardMaterial )
83+
6884 # Add two texture nodes and a blend node to the graph.
6985 rustTexNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idTextureNode )
7086 sketchTexNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idTextureNode )
7187 mixNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idMixNode )
7288
89+ # Get the input 'Surface' port of the 'Output' node and the output 'Out Color' port of the
90+ # 'Standard Material' node and connect them.
91+ surfacePortOutNode : maxon .GraphNode = outNode .GetInputs ().FindChild (
92+ "com.redshift3d.redshift4c4d.node.output.surface" )
93+ outcolorPortMaterialNode : maxon .GraphNode = materialNode .GetOutputs ().FindChild (
94+ "com.redshift3d.redshift4c4d.nodes.core.standardmaterial.outcolor" )
95+ outcolorPortMaterialNode .Connect (surfacePortOutNode )
96+
7397 # Set the default value of the 'Mix Amount' port, i.e., the value the port has when no
7498 # wire is connected to it. This is equivalent to the user setting the value to "0.5" in
7599 # the Attribute Manager.
76100 mixAmount : maxon .GraphNode = mixNode .GetInputs ().FindChild (
77101 "com.redshift3d.redshift4c4d.nodes.core.rscolormix.mixamount" )
78- mixAmount .SetDefaultValue (0.5 )
102+ mixAmount .SetPortValue (0.5 )
79103
80104 # Set the path sub ports of the 'File' ports of the two image nodes to the texture URLs
81105 # established above. Other than for the standard node space image node, the texture is
@@ -86,8 +110,8 @@ def main() -> None:
86110 "com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0" ).FindChild ("path" )
87111 pathSketchPort : maxon .GraphNode = sketchTexNode .GetInputs ().FindChild (
88112 "com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0" ).FindChild ("path" )
89- pathRustPort .SetDefaultValue (urlTexRust )
90- pathSketchPort .SetDefaultValue (urlTexSketch )
113+ pathRustPort .SetPortValue (urlTexRust )
114+ pathSketchPort .SetPortValue (urlTexSketch )
91115
92116 # Get the color output ports of the two texture nodes and the color blend node.
93117 rustTexColorOutPort : maxon .GraphNode = rustTexNode .GetOutputs ().FindChild (
@@ -102,7 +126,7 @@ def main() -> None:
102126 "com.redshift3d.redshift4c4d.nodes.core.rscolormix.input1" )
103127 mixInput2Port : maxon .GraphNode = mixNode .GetInputs ().FindChild (
104128 "com.redshift3d.redshift4c4d.nodes.core.rscolormix.input2" )
105- stdBaseColorInPort : maxon .GraphNode = standardNode .GetInputs ().FindChild (
129+ stdBaseColorInPort : maxon .GraphNode = materialNode .GetInputs ().FindChild (
106130 "com.redshift3d.redshift4c4d.nodes.core.standardmaterial.base_color" )
107131
108132 # Wire up the two texture nodes to the blend node and the blend node to the BSDF node.
@@ -113,8 +137,9 @@ def main() -> None:
113137 # Finish the transaction to apply the changes to the graph.
114138 transaction .Commit ()
115139
116- # Insert the material into the document and push an update event.
117- doc .InsertMaterial (material )
140+ if not doc .EndUndo ():
141+ raise RuntimeError ("Could not end undo stack." )
142+
118143 c4d .EventAdd ()
119144
120145if __name__ == "__main__" :
0 commit comments