@ferdinand
Thanks for the clarification. I saw you replying to other post and thought: "Perhaps he didn't see or there is no easy answer"
It's nice to know someone will have a further look and come back to it later on. On some support forums that's not always the case.
I had my collegues try the function aswell and it doesn't work for them either. Let's hope Maxime know's what's happening.
Latest posts made by wen
-
RE: adding assets to a userdatabase in the assetbrower with Python
-
RE: adding assets to a userdatabase in the assetbrower with Python
@ferdinand Could you or someone else please confirm this code works on your end? It's from the examples. I tried it in 2023 and 2025 and can't really think of anything to get it running. I had a look at the decorators.py that's trowing the error but that stuff's a bit over my head.
Thanks, Bart
import maxon def CreateRepositories(): """Creates repositories for all user databases. Doing this is usually not necessary for performing light- to medium-sized asset operations, and the user preferences repository can then be used instead. Only when there is a substantial amount of assets that must be processed, a repository should be constructed to limit the search space for search operations. The method CreateRepositoryFromUrl() used in this example can also be used to create a repository and its underlying database from scratch when the provided URL points to location where no database has been established yet. """ # Wait for all asset databases to be loaded, abort when this is not possible. if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading(): return RuntimeError("Could not load asset databases.") # Get the default language of Cinema 4D (en-US) for retrieving the repository names. defaultLanguage = maxon.Resource.GetDefaultLanguage() # Iterate over all currently mounted databases and create an asset repository for each of them. # Doing this is usually not necessary as user asset databases are automatically part of the # the user preferences repository which is easier to retrieve. Creating a repository for a # specific user asset database can be useful to speed up asset searches. for database in maxon.AssetDataBasesInterface.GetDatabases(): # Create a unique identifier for the repository. rid = maxon.AssetInterface.MakeUuid(str(database._dbUrl), True) # Repositories can be composed out of other repositories which are called bases. In this # case no bases are used to construct the repository. But with bases a repository for all # user databases could be constructed for example. bases = maxon.BaseArray(maxon.AssetRepositoryRef) # Create a writable and persistent repository for the database URL. If #_dbUrl would point # to a location where no database has been yet stored, the necessary data would be created. repository = maxon.AssetInterface.CreateRepositoryFromUrl( rid, bases, database._dbUrl, True, False, False) if not repository: raise RuntimeError("Repository construction failed.") # Access some properties of the newly created repository. repoId = repository.GetId() isWriteable = repository.IsWritable() name = repository.GetRepositoryName(defaultLanguage) print(f"{repository} ({name}): id - {repoId}, writeable: {isWriteable}") CreateRepositories()
-
RE: adding assets to a userdatabase in the assetbrower with Python
@ferdinand
Trying the CreateRepositories() function from the example I'm getting an error. I did not make any changes to the code. Did something change internally perhaps?Traceback (most recent call last): File "scriptmanager", line 42, in <module> File "scriptmanager", line 32, in CreateRepositories File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\decorators.py", line 495, in Auto ExecStaticMethod(*args) TypeError: unable to convert builtins.NativePyData to @net.maxon.interface.class-cR
This line seems to be the problem:
repository = maxon.AssetInterface.CreateRepositoryFromUrl(rid, bases, database._dbUrl, True, False, False)
-
RE: adding assets to a userdatabase in the assetbrower with Python
Hi @ferdinand
Going over it a bit more indepth I see this could work for what I want. It does leave me with a question though:
# Iterate over all currently mounted databases and create an asset repository for each of them. # Doing this is usually not necessary as user asset databases are automatically part of the # the user preferences repository which is easier to retrieve. Creating a repository for a # specific user asset database can be useful to speed up asset searches.
I was under the assumption userdatabases are by default already part of some other repository than the standard ones. Here it's stated they automaticlally become part of the user preferences repository. Does that mean I can somehow specify which database to use if there are multiple in the user preferences repository?
-
adding assets to a userdatabase in the assetbrower with Python
I'm trying to add my materials to the asset browser through a python script. I'm basing my script on the code examples from: https://github.com/Maxon-Computer/Cinema-4D-Python-API-Examples/tree/master/scripts/05_modules/assets
The thing I can't seem to figure out is how to add an asset to a user database instead of one of the standard databases.
In the examples a repository is given as an argument to the storeAssetStruct function who's result is passed to the CreateMaterialAsset function that stores the asset to the assetbrowser.repository = maxon.AssetInterface.GetUserPrefsRepository() storeAssetStruct = maxon.StoreAssetStruct(assetCategoryId, repository, repository) assetDescription = maxon.AssetCreationInterface.CreateMaterialAsset(doc, mat, storeAssetStruct, assetId, assetName, assetVersion, assetMetadata, True)
From what I understand the UserPrefsRepository tells the function to use the standard database Preferences. This leads me to think I would need to find the repository for the userdatabases. I can find the database object but have no clue how to get to the repository from there. Can you point me in the right direction?
Thanks, Bart
-
RE: connect material to reference node
Hi Ferdinant,
I didn't understand what you meant regarding the difference of setting an attribute and a port. I was trying to set the object slot as an attr in SetValue. But the presence of a separate command makes it clear. I changed SetValue to SetPortValue and it works.
I found the examples on github before but the graph descriptions page is new to me. I'll have a look.
Thanks!
Bart -
RE: connect material to reference node
@ferdinand
Hi Ferdinant,
Thanks for helping out. I am however still not able to achieve what I want to do with your example. I see i forgot to specify the "object" port resulting in a null value.I am however still running in to the same error as before:
Traceback (most recent call last): File "C:\C4D_LIB\scripts\SetupMUS.py", line 180, in <module> new_materials.append(create_redshift_material(line, keys)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\C4D_LIB\scripts\SetupMUS.py", line 130, in create_redshift_material reference_input_port.SetValue(materialUuid) TypeError: GraphNode.SetValue() missing 1 required positional argument: 'value'
I did not want to post the whole script as it's a bit messy still but perhaps it helps to clarify what I'm doing.
I'm importing an excelsheet containing the names of the materials i want to setup. The creating of the materials works. I'm running into trouble trying to link other materials to the reference nodes i created.import c4d # Import the Cinema 4D module import maxon import pandas as pd # Import the pandas library for data manipulation import numpy as np # Import the numpy library for numerical operations # Reference to the active Cinema 4D document doc: c4d.documents.BaseDocument def read_mus(file_path: str) -> tuple: """Reads an Excel file and returns its content as a list of lists and the column keys.""" df = pd.read_excel(file_path) # Read the Excel file into a pandas DataFrame keys = df.keys() mus = df.apply(lambda row: [int(value) if isinstance(value, np.int64) else value for value in row], axis=1).tolist() #process each row (axis=1) of the DataFrame and convert certain values to integers. if is_nan(mus): c4d.gui.MessageDialog("MUS contains empty fields. Please fill those with a material.") raise RuntimeError("{0} has NaN values".format(file_path)) else: return mus, keys def is_nan(list_of_lists): """check list for NaN values""" flattened_list = [item for sublist in list_of_lists for item in sublist] return (pd.Series(flattened_list).isna().any()) def find_reference_material(reference_node) -> c4d.Material: scene_materials = doc.GetMaterials() for mat in scene_materials: if mat.GetName() == reference_node.GetValue(maxon.NODE.BASE.NAME): return mat def get_materialUuid(): pass def create_redshift_material(mus_line: list, keys: list) -> None: """Creates a Redshift material based on the provided data.""" material_id, material_name, add_print, *cima_materials = mus_line cimas = keys[3:] # Define the node asset IDs for various Redshift nodes node_ids = { "output": maxon.Id("com.redshift3d.redshift4c4d.node.output"), "standard_material": maxon.Id("com.redshift3d.redshift4c4d.nodes.core.standardmaterial"), "reference": maxon.Id("com.redshift3d.redshift4c4d.node.reference"), "userdata_int": maxon.Id("com.redshift3d.redshift4c4d.nodes.core.rsuserdatainteger"), "shader_switch": maxon.Id("com.redshift3d.redshift4c4d.nodes.core.rsshaderswitch"), "material_blender": maxon.Id("com.redshift3d.redshift4c4d.nodes.core.materialblender"), "texture": maxon.Id("com.redshift3d.redshift4c4d.nodes.core.texturesampler"), } # Create a new material material: c4d.BaseMaterial = c4d.BaseMaterial(c4d.Mmaterial) if not material: raise MemoryError("Material creation failed.") material.SetName("{0}_{1}".format(str(material_id).zfill(2),material_name )) # Create an empty graph for the Redshift material space node_material: c4d.NodeMaterial = material.GetNodeMaterialReference() graph: maxon.GraphModelRef = node_material.CreateEmptyGraph(maxon.Id("com.redshift3d.redshift4c4d.class.nodespace")) if graph.IsNullValue(): raise RuntimeError("Could not add Redshift graph to material.") # Start an undo operation if not doc.StartUndo(): raise RuntimeError("Could not start undo stack.") # Insert the material into the document doc.InsertMaterial(material) if not doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, material): raise RuntimeError("Could not add undo item.") # Define user data for the transaction user_data: maxon.DataDictionary = maxon.DataDictionary() user_data.Set(maxon.nodes.UndoMode, maxon.nodes.UNDO_MODE.ADD) # Retrieve the current node space Id nodespaceId = c4d.GetActiveNodeSpaceId() # Retrieve the Nimbus reference for a specific nodeSpace nimbusRef = material.GetNimbusRef(nodespaceId) if nimbusRef is None: raise ValueError("Cannot retrieve the nimbus ref for that node space") # Begin a transaction to modify the graph with graph.BeginTransaction(user_data) as transaction: out_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["output"]) out_surface_port: maxon.GraphNode = out_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.node.output.surface") out_node.SetValue(maxon.NODE.BASE.NAME, material_name) out_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.node.output.materialid").SetPortValue(material_id) # Add user data integer node userdata_int_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["userdata_int"]) userdata_int_output_port: maxon.GraphNode = userdata_int_node.GetOutputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.rsuserdatainteger.out") userdata_int_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.rsuserdatainteger.attribute").SetPortValue("CIMA") userdata_int_node.SetValue(maxon.NODE.BASE.NAME, "CIMA SELECTOR") # Add shader switch node shader_switch_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["shader_switch"]) shader_switch_select_port: maxon.GraphNode = shader_switch_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.rsshaderswitch.selector") shader_switch_output_port: maxon.GraphNode = shader_switch_node.GetOutputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.rsshaderswitch.outcolor") print_added = False # Create and connect MaterialBlender and Reference nodes for num, material_reference in enumerate(cima_materials): scaffold_node : maxon.GraphNode = graph.AddChild(maxon.Id(), maxon.Id("net.maxon.node.scaffold")) scaffold_node.SetValue(maxon.NODE.BASE.NAME, cimas[num]) material_blender_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["material_blender"]) material_blender_node.SetValue("net.maxon.node.attribute.scaffoldid", scaffold_node.GetId()) reference_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["reference"]) reference_node.SetValue("net.maxon.node.attribute.scaffoldid", scaffold_node.GetId()) reference_node.SetValue(maxon.NODE.BASE.NAME, cima_materials[num]) #use "material_blender_node.GetInputs().GetChildren()" to list al the ports material_blender_base_port: maxon.GraphNode = material_blender_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.materialblender.basecolor") material_blender_blend1_port: maxon.GraphNode = material_blender_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.materialblender.blendcolor1") material_blender_material1_port: maxon.GraphNode = material_blender_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.materialblender.layercolor1") material_blender_output_port: maxon.GraphNode = material_blender_node.GetOutputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.materialblender.out") reference_output_port: maxon.GraphNode = reference_node.GetOutputs().FindChild("com.redshift3d.redshift4c4d.node.reference.output.") reference_input_port: maxon.GraphNode = reference_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.node.reference.object") reference_output_port.Connect(material_blender_base_port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) materialUuid: maxon.Uuid = nimbusRef.BaseList2DToUuid(find_reference_material(reference_node)) #reference_input_port.SetValue(materialUuid) shader_switch_shader_port: maxon.GraphNode = shader_switch_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.rsshaderswitch.shader"+str(num)) if add_print: if not print_added: print_added = True texture_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["texture"]) texture_output_port: maxon.GraphNode = texture_node.GetOutputs().FindChild("com.redshift3d.redshift4c4d.nodes.core.texturesampler.outcolor") reference_node: maxon.GraphNode = graph.AddChild(maxon.Id(), node_ids["reference"]) reference_node.SetValue(maxon.NODE.BASE.NAME, "Print Color") reference_node.SetValue("net.maxon.node.attribute.scaffoldid", scaffold_node.GetId()) reference_output_port: maxon.GraphNode = reference_node.GetOutputs().FindChild("com.redshift3d.redshift4c4d.node.reference.output.") texture_output_port.Connect(material_blender_blend1_port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) reference_output_port.Connect(material_blender_material1_port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) material_blender_output_port.Connect(shader_switch_shader_port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) material_blender_node.SetValue(maxon.NODE.BASE.NAME, cimas[num]) # Optionally add texture node # Connect the nodes userdata_int_output_port.Connect(shader_switch_select_port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) shader_switch_output_port.Connect(out_surface_port, modes=maxon.WIRE_MODE.NORMAL, reverse=False) # Commit the transaction transaction.Commit() # End the undo operation if not doc.EndUndo(): raise RuntimeError("Could not end undo stack.") return material def alert_material_names(message, materials): """Pops up a message window with the message followed by the names of the materials""" for mat in materials: message += (mat.GetName()+"\n") c4d.gui.MessageDialog(message) # Entry point of the script """Only run this if this script called directly and not imported""" if __name__ == "__main__": excel_path = r"C:\Users\wen\Desktop\MUS.xlsx" # Specify the path to the Excel file #excel_path = c4d.storage.LoadDialog(title = "Load EXCEL Document") mus, keys = read_mus(excel_path) new_materials = [] for line in mus: new_materials.append(create_redshift_material(line, keys)) alert_material_names("The following materials have been created: \n", new_materials) # Refresh the Cinema 4D interface c4d.EventAdd()
-
connect material to reference node
Hi Forum,
I'm trying to connect a material to a reference node. Icouldn't find any examples with the reference node in the code examples. I'm assuming i do this with SetValue() similar to setting the name, like this:
reference_node.SetValue(maxon.NODE.BASE.NAME, material_reference)
So I'm trying things like:
reference_input_port: maxon.GraphNode = reference_node.GetInputs().FindChild("com.redshift3d.redshift4c4d.node.reference") reference_input_port.SetValue(maxon.NODE.BASE.CONNECTNODE, find_reference_material(reference_node))
unfortunately that doesn't work as it's the wrong attr and crashes cinema4d.
Can somebody help me and tell how i can findout what the attr is I should be using?Thanks,
Bart -
RE: Access renderer specific settings with python
Hi Ferdinand,
I am indeed running R22. Your comment about using the document associated with the render was spot on. I assumed they would be the same document but apparently they are not. After changing this it works as expected.
I've included a working example incase someone else is looking for the same thing.
Render_viewTransform.c4dGot a new question though, what do you mean with:
"In R25 Redshift does not have a "Raw" color profile anymore"
Had a look at R25 and didn't see anything different in that regard.Thanks!
-
RE: Access renderer specific settings with python
Hi Ferdinant,
Thanks for the example.
I'm trying to use a python tag to set the view to raw when doing final renders and have it on SDR during interactive renders.
The settings are being set but somehow this doesnt trigger an update it appears. Only when manually forcing an update on the rendersetting it is changed. This is the code I'm using:import c4d import redshift def changeSettings(obj, videoPost, isRendering): if isRendering: segs = 24 view = r"Raw" else: segs = 3 view = r"ACES 1.0 SDR-video" # avoid applying redundant changes if obj[c4d.PRIM_SPHERE_SUB] != segs: print("Setting to %d" %segs) obj[c4d.PRIM_SPHERE_SUB] = segs print(view) videoPost[c4d.REDSHIFT_RENDERER_COLOR_MANAGEMENT_OCIO_VIEW] = view obj.Message(c4d.MSG_CHANGE) # EvenAdd is only needed when modifying the active document if doc == c4d.documents.GetActiveDocument(): c4d.EventAdd() def main(): pass def message(msgType, data): print # Check for final renders if msgType==c4d.MSG_MULTI_RENDERNOTIFICATION: redshiftRenderEngineId = 1036219 my_render_data = c4d.documents.GetActiveDocument().GetActiveRenderData() videoPost = my_render_data.GetFirstVideoPost() while (videoPost): if videoPost.CheckType(redshiftRenderEngineId): break videoPost = videoPost.GetNext() started = data["start"] if started: print("Render Started") else: print("Render Finished") changeSettings(op.GetObject(), videoPost, started)
I've also incuded a test file
Render_viewTransform.c4d