The Maxon SDK Team is currently short staffed due to the winter holidays. No forum support is being provided between 15/12/2025 and 5/1/2026. For details see Maxon SDK 2025 Winter Holidays.
  • Free plugins all in one : Boghma HUB

    General Talk
    4
    2
    3 Votes
    4 Posts
    2k Views
    S
    Thank you so much. I wand trouble shooting this for a week with Paid ChatGtp (stupidGpt) it couldn’t get it right. It works !!! Thank you.
  • 0 Votes
    4 Posts
    746 Views
    ferdinandF
    Hey @lionlion44, Well, doing what you want to do is only halfway possible. An object being soloed just means setting the flag EHIDE on all othe objects. And while there is OHIDE which can be used to hide scene elements in managers, e.g., an object in the Object Manager, it is not being used by the 'Set as Root/Path Bar'-function of the Object Manager. So, you cannot hook into that. What you can do is just write a simple script which operates both flags for you. But to make this air-tight, you will have to implement a plugin (to avoid accidentally saving a scene with hidden elements). Cheers, Ferdinand Result vid.mp4 Code """Demonstrates how to set the visibility of objects in the viewport and the managers. - When CTRL is not pressed while the script is invoked, the visibility state of the selected objects is set, i.e., everything that is not selected will be hidden. - When CTRL is pressed, the visibility state of the selected objects is cleared. - When HIDE_DESCENDANTS_OF_SELECTED_OBJECTS is set to True, the descendants of selected objects will be considered selected as well. WARNING: The visibility state is written PERMANENTLY into the scene graph, i.e., when one hides objects and saves the scene, the visibility state will be saved as well. One can of course just run the script while pressing CTRL to clear the visibility state of such saved and then loaded back scene, but this could possibly brick scenes for other users. To make this air-tight, one would have to implement a plugin which handles un-hiding objects before a scene is being saved (which is not super trivial in Python atm). Use this script at your own risk. """ __author__ = "Ferdinand Hoppe" __copyright__ = "Copyright 2025, Maxon Computer GmbH" import c4d import mxutils doc: c4d.documents.BaseDocument # The currently active document. op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. # Wether to hide objects that are descendants of selected objects. I.e., when you have A-> B -> C, # and A is selected, B and C will be considered selected as well. HIDE_DESCENDANTS_OF_SELECTED_OBJECTS: bool = True def IsSelected(node: c4d.BaseObject) -> bool: """Returns if #node is selected or if any of its predecessors are selected (when selecting descendants implicitly is enabled). """ while node: if node.GetBit(c4d.BIT_ACTIVE): return True if not HIDE_DESCENDANTS_OF_SELECTED_OBJECTS: break node = node.GetUp() return False def SetObjectVisibility(doc: c4d.documents.BaseDocument, clearSate: bool = False) -> None: """Sets the visibility of the object in the managers and the viewport. """ for node in mxutils.IterateTree(doc.GetFirstObject(), True, True, True): isSelected: bool = clearSate or IsSelected(node) node.ChangeNBit(c4d.NBIT_OHIDE, c4d.NBITCONTROL_CLEAR if isSelected else c4d.NBITCONTROL_SET) node.ChangeNBit(c4d.NBIT_EHIDE, c4d.NBITCONTROL_CLEAR if isSelected else c4d.NBITCONTROL_SET) def main() -> None: """Called by Cinema 4D whhen the """ if not op: c4d.gui.MessageDialog("No object selected.") return state: c4d.BaseContainer = c4d.BaseContainer() if not c4d.gui.GetInputState(c4d.BFM_INPUT_MOUSE, 0, state): raise RuntimeError("Failed to get input state") ctrlIsPressed: bool = state[c4d.BFM_INPUT_QUALIFIER] & c4d.QUALIFIER_CTRL # If Ctrl is pressed, clear the visibility state, otherwise set it. SetObjectVisibility(doc, True if ctrlIsPressed else False) c4d.EventAdd() if __name__ == '__main__': main()
  • 0 Votes
    5 Posts
    1k Views
    M
    Hi @ECHekman sorry it took me more time than I expected. From my meory octane already have a Python module registered in C++. So I assume you want to add symbols to this python module. One important aspect is that the Symbol Parser by itself is completly agnostic of the c4d module therefor you can call it with any Python interpreter. This point is really important because this let you parse your C++ header files whenever you want within your build pipeline. With that's said the Symbol Parser is bundled within the mxutils package which needs the c4d and maxon module. So in order to have it running with any python intepreter you will need to do the following: import sys CI_PROJECT_DIR = r"C:\Users\m_adam.INTERN\Documents\MAXON\gitlab\c4d" # Build path to import the parser_symbol maxon_python_path = os.path.join(CI_PROJECT_DIR, "resource", "modules", "python", "libs") if not os.path.exists(maxon_python_path): raise RuntimeError(f"DEBUG: update_python_symbols - Unable to find {maxon_python_path}") # Get python311 folder where the symbol parser is located mxutils_path, symbol_parser_path = None, None for folder in os.listdir(maxon_python_path): full_path_folder = os.path.join(maxon_python_path, folder) if not os.path.isdir(full_path_folder): continue # We found the mxutils module containing the symbol parser. if os.path.exists(os.path.join(full_path_folder, "mxutils", "symbol_parser")): mxutils_path = os.path.join(full_path_folder, "mxutils") symbol_parser_path = os.path.join(mxutils_path, "symbol_parser") if None in (mxutils_path, symbol_parser_path): raise ImportError(f"Could not find 'symbol_parser' module path in {maxon_python_path}.") sys.path.append(mxutils_path) print(f"DEBUG: Added {mxutils_path} to sys.path.") # Import the symbol parser and do your stuff. import symbol_parser # Do something with it sys.path.remove(mxutils_path) Then the Symbol Parser paradigm is that you first parse your data and then the parser contain Scope that contains member (a name and a value). Therefor once you have parsed your data you can freely output to multiple format if needed. You can also write your own format if you want to. In this case because you are using mostly the Cinema API and not the Maxon API I re-use the same output as the one we use for the c4d Python package. This output is implemented in c4d\resource\modules\python\libs\python311\mxutils\symbol_parser\output_classic_api.py. Everything in the Symbol Parser is open source so feel free to look at it. So to get back to your question find bellow the next code that will parse all the resources files from the Redshift folder and insert them within the "redshift" Python Package. (You usually do not have to do that because Python is parsing automatically the c4d_symbols.h and include such symbols within the c4d Python package this is for the example). With that's said there is basically two ways, one hardcoding the parsed value in your C++ plugin when you register your Python module, the second one using a Python file that will get loaded at the startup of Cinema 4D once your Python module is already loaded and therefor inject symbol into your module. import os import c4d # Only used to retrieve various C4D paths used in this example, but not really necessary otherwise # These imports bellow are not bound to the c4d module therefor they can be used with a standard Python3 interpreter # But this code is written to be executed in the Script Manager, so you may need to adapt the import statement according to how you run this script. from mxutils.symbol_parser.extractor import SymbolParser from mxutils.symbol_parser.output_classic_api import _get_symbol_dict_from_parser def ParseRedshiftResources() -> SymbolParser: # Parse all Redshift ressource files and resolve their values rsDir = os.path.join(os.path.dirname(c4d.storage.GeGetStartupApplication()), "Redshift", "res", "description") parser = SymbolParser(rsDir, parse_mx_attribute=False, parse_define=True, parse_enum=True, parse_static_const=True) # Parse and resolve. Resolve means: # - Transfrom values that depends to others to their actual integer or float values. # - Transform complex values (such as bit mask, arithmetic, etc) into their actual integer or float values. # For more information about what is supported take a look at # https://developers.maxon.net/docs/py/2025_2_0/manuals/manual_py_symbols.html?highlight=symbol%20parser#symbols-parser-features parser.parse_all_files(resolve=True) return parser def OutputPythonFile(parser: SymbolParser): def GeneratePythonFileToBeInjected(parser: SymbolParser) -> str: """Generate a Python file that will inject all parsed symbols into the 'redshift' Python package when this file get imported. This function needs to be called once, most likely during your build pipeline. Once you have generated this Python file you should bundle it with your installer and then install it in the targeted Cinema 4D installation. See PatchCurrentC4DToInjectParsedSymbol for an example of such deployment """ import tempfile tempPath = None # Retrieve a sorted dict containing the symbol name as key and it's value as values # This will flatten all scopes so an enums called SOMETHING with a value FOO in it will result in a symbol named SOMETHING_FOO # If you do not want this behavior feel free to create your own solution, this function is public and declared in # c4d\resource\modules\Python\libs\python311\mxutils\symbol_parser\output_classic_api.py symbolTable = _get_symbol_dict_from_parser(parser) with tempfile.NamedTemporaryFile('w', delete=False) as tmpFile: tempPath = tmpFile.name tmpFile.write("import redshift\n") for name, value in symbolTable.items(): tmpFile.write(f"redshift.{name} = {value}\n") if not os.path.exists(tempPath): raise RunTimeError('Failed to create the Python File to Inject Symbols in "redshift" Python Package') return tempPath def PatchCurrentC4DToInjectParsedSymbol(fileToBeLoaded: str): """This function is going to create a Python file that is going to be called at each startup of Cinema 4D to inject symbols into the "redshift" Python package. This is done by placing the previous file in a place where it can be imported by the C4D Python VM. And by importing this file by editing the python_init.py file located in the preferences. For more information about it please read https://developers.maxon.net/docs/py/2025_2_0/manuals/manual_py_libraries.html?highlight=librarie#executing-code-with-Python-init-py """ import sys import shutil # Pref folder that contains a python_init.py that is laoded once c4d and maxon package is loaded and a libs folder that is part of the sys.path of the c4d Python VM. pyTempDirPath = os.path.join(c4d.storage.GeGetStartupWritePath(), f"Python{sys.version_info.major}{sys.version_info.minor}") # Path to our module that will inject the parsed symbols in the "redshift" Python package pyTempRsDirPath = os.path.join(pyTempDirPath, "libs", "rs_symbols") # Path to the __init__ file of our module that will be called when we import our module # we need to place the file we generated previously in this location. pyTempRsFilePath = os.path.join(pyTempDirPath, "libs", "rs_symbols", "__init__.py") if not os.path.exists(pyTempRsDirPath): os.mkdir(pyTempRsDirPath) if os.path.exists(pyTempRsFilePath): os.remove(pyTempRsFilePath) shutil.copy2(fileToBeLoaded, pyTempRsFilePath) # Now that we have our module that will inject symbols within the "redshift" Python package. We need to get this "rs_symbols" module be called at each startup. # So we use the python_init.py file to get loaded once all plugins are loaded. Therefor the Redshift plugin is already loaded and have already setup its "redshift" Python package. # We will inject a line in this file to load our "rs_symbols" module pyTempInitFilePath = os.path.join(pyTempDirPath, "python_init.py") isImportRsSymbolPresent = False initFileExist = os.path.exists(pyTempInitFilePath) # Because this file me be already present and already patched or contain other content # We should first check if we need to add our import or not if initFileExist: with open(pyTempInitFilePath, 'r') as f: isImportRsSymbolPresent = "import rs_symbols" in f.read() # prepend our import statement to the file if not isImportRsSymbolPresent: with open(pyTempInitFilePath, "w+") as f: content = f.read() f.seek(0, 0) f.write('import rs_symbols\n' + content) pythonFileGeneratedPath = GeneratePythonFileToBeInjected(parser) PatchCurrentC4DToInjectParsedSymbol(pythonFileGeneratedPath) def OutputCppFile(parser): # Retrieve a sorted dict containing the symbol name as key and it's value as values # This will flatten all scope so an enums called SOMETHING with a value FOO in it will result in a symbol named SOMETHING_FOO # If you do not want this behavior feel free to create your own solution, this function is public and declared in # c4d\resource\modules\Python\libs\python311\mxutils\symbol_parser\output_classic_api.py symbolTable = _get_symbol_dict_from_parser(parser) contentToPaste = 'auto mod_rs = lib.CPyImport_ImportModule("redshift");\n' contentToPaste += 'auto modDict = lib.CPyModule_GetDict(mod_rs);\n' for name, value in symbolTable.items(): contentToPaste += f'\nauto name = lib.CPyUnicode_FromString("{name}");\n' contentToPaste += 'if (!name)\n' contentToPaste += ' CPyErr_Print();\n' contentToPaste += f'maxon::py::CPyRef value = lib.CPyLong_FromInt32({value});\n' contentToPaste += 'if (!value)\n' contentToPaste += ' CPyErr_Print();\n' contentToPaste += 'if (!lib.CPyDict_SetItem(modDict, name, value))\n' contentToPaste += ' CPyErr_Print();\n' return contentToPaste def main() -> None: # Parse the Redshift resources and return the parser that hold the parsed values parser = ParseRedshiftResources() # First way: Generate a file that patch the current C4D with a Python file that you need to deploy on the installer. You may prefer this option since you can update this file without having to recompile your plugin. OutputPythonFile(parser) # Second way: Output pseudo C++ code that can be pasted within your C++ plugin after you initialize your custom Python module. You may want to call this whole script before you compile in your build pipeline and put the "cppContent" within a file that will get compiled automatically cppContent = OutputCppFile(parser) if __name__ == '__main__': main() So the system is really modular and being able to run on a regular Python interpreter let you integrate it within your build pipeline to suits your needs. If you have any questions, please let me know. Cheers, Maxime.
  • Load presets args in python?

    Moved Bugs windows python 2025
    7
    1
    0 Votes
    7 Posts
    1k Views
    DunhouD
    It sounds worth a try, but there may be latency issues when it comes to changes, or data changes can be manually processed during the changes Perhaps for my needs, I can force the database to be use GetSceneRepository, anyway, it's worth a try. Thank you for your guidance
  • Move the plane in random effect

    Cinema 4D SDK windows 2025
    2
    0 Votes
    2 Posts
    441 Views
    M
    Hi @Fabio-B Thank you for reaching out to us. Unfortunately, your question is off topic for the forum you have posted in. Please check the Forum Overview for an overview of the scope of the different forums. On this forum we only provide support for third party software developers about the Cinema 4D Software Development Kit. We unfortunately cannot provide end user support, as we lack the tools and the knowledge to do so. To receive end-user support, please visit our Support Center and create a ticket for your issue Cheers, Maxime.
  • 3 Votes
    2 Posts
    1k Views
    S
    Hello. I have a looupdeck., is it possible to link the light Manager to (redshift) to the knobs, So I can control the intensity and Exposure
  • 0 Votes
    4 Posts
    709 Views
    uogygiuolU
    This is fantastic, thank you so much! This works beautifully. I see your confusion with the "offset". This is absolutely my fault in formulating the question. Sorry about that. I also wanted the clones to follow a spline with an individual offset, but then thought to remove this part to not overcomplicate the question and accidentally left some traces. However, in your video you gave me valuable insight in how to achieve this as well. I already have a working sketch where I'm daisy chaining your script with a Spline Effector in the right order. Giving these thoughtful answers is incredibly valuable, you can't believe how motivating this is to go further.
  • 0 Votes
    4 Posts
    959 Views
    ferdinandF
    Hey @Fabio-B, Please note that we cannot provide support for AI generated code. See Support Procedures: Scope of Support for details. When you want the clones to move, or in other words to be animated over time, you will need a noise and cannot use hashes or random values, as they are not interpolated, i.e., continous. """Realizes an effector that attracts MoGraph particles spherically around its origin. Add the example to a Matrix object to understand its effect. In Full Control mode we can realize a true attraction force as we have full control over the particle values. Compare this example to Parameter Control mode to understand the difference. """ import c4d import mxutils op: c4d.BaseObject # The Python Effector object containing this code. gen: c4d.BaseObject # The MoGraph Generator executing `op`. doc: c4d.documents.BaseDocument # The document `op` and `gen`are contained in. def main() -> bool: """Called by Cinema 4D to evaluate the effector. """ # Get the particle data for the effector #op. Get out when either the data cannot be retrieved. data: c4d.modules.mograph.MoData = c4d.modules.mograph.GeGetMoData(op) if data is None: return 1.0 # Get the matrices of the particles. This is the array we will modify. matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX) # For each particle write a new persistent random height value, hashed over the index of the # particle. This will cause the height each time to be the same, as long as the index of the # particle does not change. One could also hash the position of the original particle to get a # height value that is not dependent on the index of the particle (e.g., when the user changes # the order of the particles in the Matrix object). for i in range(data.GetCount()): pos: c4d.Vector = matrices[i].off y: float = c4d.utils.noise.Noise(matrices[i].off, doc.GetTime().Get()) * 25.0 matrices[i].off = c4d.Vector(pos.x, y, pos.z) # Hash a height value over the position of the particle. # y: float = mxutils.g_random.HashVectorToNumber(matrices[i].off) * 25.0 # Write the new data back. data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent()) return True Recording 2025-05-02 141611.mp4 Cheers, Ferdinand
  • C4D Python: Redshift IPR Start/Stop Control

    Cinema 4D SDK python windows 2025
    5
    0 Votes
    5 Posts
    878 Views
    M
    @hoganXYZ hi if it does not appear in the script log then there is no clear rules. Sometimes there is another way sometimes now it depends on how it is implemented. For the one you asked I do not think it is possible. Best bet would be to ask Redshift on their forum. Cheers, Maxime.
  • lhit from BaseVolumeData

    Cinema 4D SDK r21 python windows
    3
    0 Votes
    3 Posts
    586 Views
    JH23J
    Hey @m_adam, Thanks for the reply! What you’re saying makes a lot of sense C++ is clearly the better option for this kind of stuff, especially when you need more control and better performance. I haven’t had much chance to dive into C++ yet, but I’m well aware it’s way more powerful than Python when it comes to working with the engine. It’s a bit of a shame that there’s no way to directly access polygon info from Python, since that’s exactly what I needed. But still, I really appreciate you taking the time to explain it. Cheers, James H.
  • DrawHudText interferes with Polygon Pen Tool etc

    Cinema 4D SDK
    4
    0 Votes
    4 Posts
    842 Views
    i_mazlovI
    Hi @FlavioDiniz, thanks for providing more information on the issue. Regarding your "Issue 2". I see no reason for the background color (and other properties) to not work in your setup, hence I've created a bug report for that (ITEM#587756). Thanks for reporting the issues you face during your development. We are happy to handle your "Issue 1" about "constantly unsaved document" in a separate thread, once you create it yourself. Cheers, Ilia
  • 0 Votes
    3 Posts
    531 Views
    E
    Thanks Ferdinand, that was kind of what I expected the awnser to be. I'll use a creative solution that doesnt trigger an unnessesary recreation of the Extrude cache
  • 0 Votes
    2 Posts
    734 Views
    ferdinandF
    Hey @RTF, Thank you for reaching out to us. There is no fully automatic way to do this, as it is up to third parties to expose their APIs to Python. When a vendor does not offer a Python API, you can do two things: Simply define the symbols yourself in your Python code, they are just integer values after all. With mxutils.ImportSymbols you can import symbols from a resource, e.g., a symbols.h file. It is (a part of) the very mechanism we use to automatically expose the symbols from the native Cinema 4D C++ API to the Python API. Cheers, Ferdinand
  • Cache Proxy Tag

    Cinema 4D SDK 2025 c++ windows
    5
    0 Votes
    5 Posts
    787 Views
    J
    @ferdinand Thanks for the detailed response, unfortunately what I'm trying to do doesn't seem viable. John Thomas
  • Graphic card

    General Talk off-topic
    4
    0 Votes
    4 Posts
    1k Views
    P
    Great input, thanks. I will have a look at the Mac mini, if not, I will go back to a windows desktop. Again, thank you both. Regards, pim
  • Maxon API for Python

    Cinema 4D SDK python 2025 windows
    3
    0 Votes
    3 Posts
    542 Views
    ThomasBT
    @ferdinand Thank you for your detailed explanation, it shed some light on the whole matter for me.
  • Set RenderData framerate causing C4D to crash

    Moved Bugs python 2025
    4
    0 Votes
    4 Posts
    20k Views
    M
    Hi I was able to reproduce the issue and fix it for the next version. The bug is that setting RDATA_FRAMERATE require the RenderData to be part of a document in case the "Use Project Frame Rate" is enabled on the render settings. If this is enabled and this is enabled by default the value you enter will be disregarded. "Use Project Frame Rate" is a new setting added in 2025.2. I will ping you once the fix is available. Cheers, Maxime.
  • 0 Votes
    5 Posts
    947 Views
    i_mazlovI
    Hi @d_keith, I would kindly ask you to check our Support Procedures, namely the "How To Ask Questions" paragraph: Singular Question: The initial posting of a support topic must contain a singular question. Do not ask ten things at once, that makes it extremely hard to answer topics. Break up your questions into multiple topics. Here you effectively have 4 different questions about Asset Browser, and these are candidates for 4 different threads on the forum. In your further postings please try to follow the aforementioned rules. Regarding your questions: Should I be able to mount a directory and have it auto-create a DB? Mounting database is effectively executing the AssetDataBasesInterface.SetDatabases. It has nothing to do with creating database neither semantically, nor is this mentioned in the docu. If you need to create repository, please use maxon.AssetInterface.CreateRepositoryFromUrl(), it will scan the directory for being already a database and create proper dir structure if it's not. Any idea why I need to re-try creating the Repo for it to work? If you face any errors in the script, please always attach at least the error message! In this case I assume you receive the following error, when executing the maxon.AssetRepositoryTypes.AssetDatabase() for the first time after Cinema 4D started. Looks like a bug to me, I've created a bug report for that (ITEM#585831). The error message: Traceback (most recent call last): File "console", line 1, in <module> File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\interface.py", line 5049, in __call__ self._cachedObj.R = _maxon_mapping.GetAssociatedDataType(dt) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Exception: unable to find datatype As a workaround you can just execute the following line first in your main(): maxon.AssetRepositoryTypes.AssetDatabase() ... about multiple DBs ... You're giving your databases unique IDs with the line repo_id = maxon.AssetInterface.MakeUuid(str(url), True). If you need them to be the same, just pick one instead, e.g. repo_id = maxon.Id('net.maxon.sdk.cool.things.repo') ... revealing assets doesn't work... I've created a bug report for that, as it looks like a bug with refreshing in the Asset Browser. As a workaround you can reload databases and reopen the AB before reveling your assets, e.g.: def RepenAssetBrowser(): CID_ASSET_BROWSER = 1054225 # Close the Asset Browser if it's alredy opened if c4d.IsCommandChecked(CID_ASSET_BROWSER): c4d.CallCommand(CID_ASSET_BROWSER) # Open again c4d.CallCommand(CID_ASSET_BROWSER) def main(): # ... # assets = [] # ... # assets.append(asset) # ... maxon.AssetDataBasesInterface.ReloadAssetRepositories(True) RepenAssetBrowser() maxon.AssetManagerInterface.RevealAsset(assets) Cheers, Ilia
  • 0 Votes
    3 Posts
    763 Views
    K
    Hi @ferdinand , Thanks for the clarification. I will contact user support and request this as a feature.
  • 0 Votes
    3 Posts
    507 Views
    I
    Hi Ferdinand, Thanks a lot for the clear explanation and for taking the time to share the code. The part about accessing BaseVideoPost and using REDSHIFT_RENDERER_EMISSION_ENABLE was spot on. Exactly what I needed. Works perfectly! Really appreciate it. Anthony