13
13
"""
14
14
__author__ = "Ferdinand Hoppe"
15
15
__copyright__ = "Copyright (C) 2023 MAXON Computer GmbH"
16
- __date__ = "01/09/2023 "
16
+ __date__ = "04/06/2024 "
17
17
__license__ = "Apache-2.0 License"
18
18
__version__ = "2024.0.0"
19
19
@@ -37,45 +37,69 @@ def main() -> None:
37
37
# mix node. These and all other node IDs can be discovered in the node info overlay in the
38
38
# bottom left corner of the Node Editor. Open the Cinema 4D preferences by pressing CTRL/CMD + E
39
39
# 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" )
40
42
idTextureNode : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.texturesampler" )
41
43
idMixNode : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.rscolormix" )
42
- idRsStandardMaterial : maxon .Id = maxon .Id ("com.redshift3d.redshift4c4d.nodes.core.standardmaterial" )
43
44
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.
45
46
material : c4d .BaseMaterial = c4d .BaseMaterial (c4d .Mmaterial )
46
47
if not material :
47
48
raise MemoryError (f"{ material = } " )
48
49
49
50
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 )
52
53
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
+
55
64
doc .InsertMaterial (material )
56
- c4d .EventAdd ()
65
+ if not doc .AddUndo (c4d .UNDOTYPE_NEWOBJ , material ):
66
+ raise RuntimeError ("Could not add undo item." )
57
67
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 )
64
74
65
75
# Start modifying the graph by opening a transaction. Node graphs follow a database like
66
76
# 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
+
68
84
# Add two texture nodes and a blend node to the graph.
69
85
rustTexNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idTextureNode )
70
86
sketchTexNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idTextureNode )
71
87
mixNode : maxon .GraphNode = graph .AddChild (maxon .Id (), idMixNode )
72
88
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
+
73
97
# Set the default value of the 'Mix Amount' port, i.e., the value the port has when no
74
98
# wire is connected to it. This is equivalent to the user setting the value to "0.5" in
75
99
# the Attribute Manager.
76
100
mixAmount : maxon .GraphNode = mixNode .GetInputs ().FindChild (
77
101
"com.redshift3d.redshift4c4d.nodes.core.rscolormix.mixamount" )
78
- mixAmount .SetDefaultValue (0.5 )
102
+ mixAmount .SetPortValue (0.5 )
79
103
80
104
# Set the path sub ports of the 'File' ports of the two image nodes to the texture URLs
81
105
# established above. Other than for the standard node space image node, the texture is
@@ -86,8 +110,8 @@ def main() -> None:
86
110
"com.redshift3d.redshift4c4d.nodes.core.texturesampler.tex0" ).FindChild ("path" )
87
111
pathSketchPort : maxon .GraphNode = sketchTexNode .GetInputs ().FindChild (
88
112
"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 )
91
115
92
116
# Get the color output ports of the two texture nodes and the color blend node.
93
117
rustTexColorOutPort : maxon .GraphNode = rustTexNode .GetOutputs ().FindChild (
@@ -102,7 +126,7 @@ def main() -> None:
102
126
"com.redshift3d.redshift4c4d.nodes.core.rscolormix.input1" )
103
127
mixInput2Port : maxon .GraphNode = mixNode .GetInputs ().FindChild (
104
128
"com.redshift3d.redshift4c4d.nodes.core.rscolormix.input2" )
105
- stdBaseColorInPort : maxon .GraphNode = standardNode .GetInputs ().FindChild (
129
+ stdBaseColorInPort : maxon .GraphNode = materialNode .GetInputs ().FindChild (
106
130
"com.redshift3d.redshift4c4d.nodes.core.standardmaterial.base_color" )
107
131
108
132
# 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:
113
137
# Finish the transaction to apply the changes to the graph.
114
138
transaction .Commit ()
115
139
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
+
118
143
c4d .EventAdd ()
119
144
120
145
if __name__ == "__main__" :
0 commit comments