administrators

Private

Posts

  • RE: EventAdd doesn't work with a modal dialog in C4D 2026

    Hey @aturtur,

    Thank you for reaching out to us. EventAdd will never really work in script manager scripts in the sense you mean it, unless you use hacks like dangling async dialogs (which as I always point out are a really bad idea).

    The reason is that Script Manager scripts are blocking, i.e., all scene and GUI execution is being halted until the script finishes. You can hack yourself around this with a dangling async dialog, i.e., a dialog that lives beyond the life time of its script. But that is not a good idea, you should implement some form of plugin to host your asnyc dialog, as you otherwise risk crashes.

    A modal dialog is just an extension of this. It is right in the name, it is modal, i.e., synchronous. All scene and GUI execution is being halted while this dialog is open and only resumes once it closes. When you want updates while your dialog is open, you need an async dialog (and a plugin which hosts it).

    Cheers,
    Ferdinand

    Since you also might misunderstand the nature of EventAdd() I am also putting here the C++ docs I updated a few weeks ago, to better reflect the nature of it (not yet live):

    /// @brief Enqueues an update event for the active document.
    /// @details Only must be called when modifying the active document and is without meaning for other documents. The typical example of using `EventAdd` is after adding or removing elements from the active document; and wanting these changes to be reflected in the UI. The function itself is technically thread-safe, but the vast majority of operations that require calling `EventAdd` are not thread-safe and must be called from the main thread (and therefore calling this function is usually main thread bound). The function also does not enqueue a dedicated event item, but rather sets a flag that is checked when the next update event is processed. Therefore, calling `EventAdd` multiple times in one function scope is unnecessary overhead which must be avoided. Because such multiple event flags cannot be consumed while a function on the main thread is still running, and instead the event will only be consumed after that function returns.
    /// @code
    /// Result<void> AddCubes()
    /// {
    ///   CheckState(maxon::ThreadInterface::IsMainThread(), "AddCubes must be called from the main thread."_s);
    ///
    ///   // EventAdd(); // We could also technically call it here with the same effect. The event
    ///                  // will only happen after this function returns.
    ///
    ///   BaseDocument* doc = GetActiveDocument();
    ///   for (int i = 0; i < 10; ++i)
    ///   {
    ///     BaseObject* cube = BaseObject::Alloc(Ocube);
    ///     if (!cube)
    ///       return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Failed to allocate cube object."_s);
    ///
    ///	    doc->InsertObject(cube);
    ///
    ///     // Calling EventAdd here would have no extra effect, since this event cannot be consumed while
    ///     // our main thread function is still running. And such extra calls on a large scale can cause
    ///     // considerable overhead.
    ///   }
    ///
    ///   // Notify C4D that the active document has changed. The very end of a function or scope is the
    ///   // canonical place to call EventAdd().
    ///   EventAdd();
    /// }
    /// @endcode
    /// @see The article @link page_manual_coremessages Core Messages@endlink for more information.
    /// @param[in] eventflag					The event to add: @enumerateEnum{EVENT}
    
  • RE: Render Token Questions

    @tommyf said in Render Token Questions:

    The frame padding I was referring to are in regards to the frame numbering that is written out when selecting a render pattern in the output settings that you would find under Render Settings > Save > Name where the one we typically use is Name.0000.TIF.

    Yes, that was already my hunch, as described above, and you cannot alter this numbering with render tokens, you can only add your own. When you want to change this numbering, you would have to write yourself a post processor as lined out above. Technically, you could also just run this outside of Cinema 4D, e.g.,

    commandline.exe -someScene.c4d ...
    c4dpy.exe renameScript.py -someScene.c4d
    # Or just even just a CPython instance (or any other scripting language), the problem here is
    # that you could not access the the render settings of the scene and would have to rely on conventions.
    python  renameScript.py -someScene.c4d
    

    Based on how you answered my questions it sounds like as long as I load the plugin script that contains the registration code that I could create custom tokens that way. I can also therefore create my own $frame token with my own frame padding (python str.zfill method) for frame numbers however there is no way to override the 4 digit frame padding that comes from the render settings name field.

    Yes. But you could not name it $frame, because that would collide with the builtin token of the same name.

    When the pattern my_render_frame-000001_001.tif works for you, I would definitely go for the render token. When you absolutely have to change the postfix set by Cinema 4D, that is possible too, but much more work. The work lies there not in actually renaming the files, that is somewhat trivial. The work lies in supporting all the ways a rendering can happen. When you are locked into using the commandline on your farm only, that would simplify things and drive down the costs of doing this (i.e., you would not support picture viewer, teams, editor, etc. renderings).

    Cheers,
    Ferdinand

  • RE: Xref Material reference

    Hello @Jespersather,

    thank you for reaching out to us. This is a developer forum, not an end user support forum. We cannot help you here with your end user issues. Please use our Support Center to get end user support for Cinema 4D.

    I have moved your topic into General Talk.

    Cheers,
    Ferdinand

  • RE: Render Token Questions

    Hello @tommyf,

    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

    Thank you for reaching out to us. Please do not hijack other threads with your questions and split up multiple questions into multiple topics in the future. Please read our support procedures, I have forked your questions.

    Do the token registrations get stored within the project files themselves or do they get stored in local machine or user settings for c4d. Meaning that if we wanted to implement this for our render farm we'd have to register the token on each one of the machines.

    Implementing a custom render token can be done with our C++ or Python API (here is an example for Python). So, you will need such plugin on each machine where you want to use that token. Not quite sure how the rest of your question is meant, 'registering a token (or any other plugin)' just means that the plugin is present when Cinema 4D is booting.

    Depending on how 1 is answered is it possible to support multiple $frame padding configurations?

    Since you do not explain what you would consider '4 to 6 digit frame padding', I can only speculate. My guess would be that you want to replace the frame counter provided by Cinema 4D in file names, e.g., transform my_render_001.tif, my_render_002.tif, etc. into my_render_0001.tif, my_render_0002.tif, etc.

    If that is what you mean, then no, that is not possible with tokens. The frame counter is something added by Cinema 4D you cannot influence as a user (as it depends on the render settings).

    You could either implement a token which adds your own frame counter to a file name (my_render_frame-0001_001.tif, my_render_frame-0002_002.tif, etc.) or you could write a postprocessor which hooks into MSG_MULTI_RENDERNOTIFICATION to catch a finished rendering and then post-process the files it created on disk. But the latter could get complicated.

    Also depending on how 1 is answered, are the token registrations permanent or are we going to have to register the custom token every time we launch c4d or whenever we want to change it.

    As explained above, I do not really understand what you are asking for. A registration is not something you do manually as a human, but rather some code that runs.

    Cheers,
    Ferdinand

  • RE: C++ SDK Matrix object style distribution

    Hello @dex,

    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

    Thank you for reaching out to us.

    Does C++ SDK allows you to create some sort of a custom Matrix Object style distribution?

    The SDK does not allow you create any MoGraph generators, the only thing you can implement are effectors and fields. A generator is effectively just an ObjectData plugin which generates some MoData stored as a tag on it, and then depending on the generator type, also generates some cache and/or viewport output. What a MoGraph generator does is not strongly defined, therefore each generator might have to be handled differently by our Core API; which makes it impossible to create a custom one.

    In the case of a Matrix object linked in a Cloner object in object mode, the custom behavior is that the Cloner will read the MoData tag of the Matrix object when it sees an Omgmatrix being linked. You could create an ObjectData plugin which generates the same MoData tag as the Matrix object, but it would not be recognized by the Cloner as a Matrix object, and thus not be treated as such. But you could create your own infrastructure which picks up on that. But in general, implementing your own generators within the MoGraph system is not possible and also not trivial.

    It is important that the points encode position, orientation and size or scale and that the cloner can read that data and apply it to instances.

    The most straight forward way to achieve what you want, would be probably to implement a custom effector which overrides the particle data to your liking. The only limitation of effectors is that they cannot change the particle count. A way out could be here to create some driver logic, e.g., a tag on the cloner which drives both the cloner and an instance of your custom generator in tandem. If you do that you have to be a bit careful with not violating threading restrictions or creating dirtiness feedback loops, but it is possible.

    The other alternative could be to just implement a polygon object ObjectData and generate tiny polygons for each (position, orientation, scale) tuple you want to have. Then in the cloner, you just clone in polygon mode onto your object and enable 'Enable Scaling', so that the particles are also scaled according to the size of the polygons.

    Cheers,
    Ferdinand

  • RE: [Cinema 4D/Redshift] How to insert knots into a Redshift Ramp Node

    Hello @pislices,

    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

    Thank you for reaching out to us. The Nodes API, i.e., the API you are using since you show us the Node Editor, is a Maxon and not a Cinema API, so it uses entities from the maxon and not c4d namespace in Python (you linked to c4d.Gradient article for the old Redshift Xpresso Nodes - which are part of the Cinema API). E.g., the Nodes API uses maxon.GradientInterface and not c4d.Gradient. Under the hood, the Cinema API type is usually just a thin wrapper for the Maxon API type, but that does not really matter for us here.

    What comes on top of this, is that the Nodes API abstracts all data types it uses and decomposes them accordingly into port bundles (a data type) and variadic ports (a list of dynamically addable or removable ports for things such as points, gradient knots, or the layers of a shader). See here for details on these two concepts.

    So, to add/remove or manipulate knots of a gradient, you do not get the data as a whole, modify it, and then write all data back, but manipulate ports which represent individual gradient knots. In short, you get the port bundle which represents the gradient on your node. This port then usually has a child port which is a port bundle which holds all the knots of the gradient. You can add or remove ports form/to that bundle to modify the gradient. To edit a knot, you write to the attributes of the port which represents that knot.

    Graph descriptions offer an abstraction for this not entirely trivial subject (see also the link for variadic ports and port bundles, it also contains some example code for graph descriptions on that subject).

    Cheers,
    Ferdinand

  • RE: Set View Transform in Picture Viewer

    Hey @ECHekman,

    Thank you for reaching out to us. The answer to your question is sort of yesn't. You can set the embedded view transform of a bitmap, which by default will be used by the Picture Viewer. The Picture Viewer like most managers in Cinema 4D is sealed, and we do not want to change that. So, you cannot change what view transform override is used by the Picture Viewer (when the user chooses to ignore the view transform embedded into an image).

    See Manage Bitmap OCIO Color Profiles for details.

    Cheers,
    Ferdinand

  • RE: Debugging in VS Code does not pause at breakpoints

    Hey @idealflaw,

    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

    Thank you for reaching out to us and please excuse the delay. But for now I can only confirm the issue, as I have no found a quick fix for this. Oddly enough, on my machine it does not work, but on the machine of a colleague it does. My hunch would be that either something (firewall) is interfering with the debugger server communication or VS Code mixes something up with the vanilla CPython environment. But that cannot really be, because then the code should not run due to missing dependencies. I also tried making the launch environment explicit but that did not do anything either (no surprise again because it does find the C4D python environment with an explicit launch.json, otherwise the code would not run at all).

    This problem only exists on MacOS, Windows is not affected. I have moved this topic into bugs and I cannot give an ETA when we will fix this.

    Sorry for the trouble,
    Ferdinand

    Reproduction Steps

    1. Attach to VS Code to Cinema 4D 2026.1 on MacOS.
    2. Run the script attached below and that a breakpoint on line 10.
    3. Run the script with the debugger attached.

    Result

    1. The debug environment will open and the debugger will attach.
    2. The code will neither halt on the manual stop set one line 10, nor on the raised exception. It will just run as if it would be running without a debugger.

    OK Windows 2026.1
    NOK MacOS 2026.1

    import c4d
    
    def main() -> None:
        """Called by Cinema 4D when the script is being executed.
        """
        a: int = 42
        b: float = 3.14
        c: float = a + b
        
        if c > 45:
            raise ValueError("c is too large!")
        else:
            print(f"c is {c}.")
    
    
    if __name__ == '__main__':
        main()
    
  • RE: We can update the Python API to align with the C++API

    Hey @Dunhou,

    Thank you for reaching out to us. We agree that this would be desirable. These methods are actually already wrapped but we hide them for now in the Python SDK. Find the reasons below.

    1. ExecuteJavascript: I just did remove the bindings of the Python API for that method in the current beta and also switched the C++ method to internal. The reason for that decision was is that we have security concerns about attackers being able to execute arbitrary JS in a web browser opened in Cinema 4D.
    2. SetWebMessageCallback: This is intended solution, i.e., the JS you want to execute must be already embedded into the HTML which is running in the HtmlView. On Windows/WebView2 it uses web messages, on MacOS/WebKit a custom solution emulating them. And SetURLCallback is then the way to get data back from the JS VM.
    3. For 2026.1 I already wrote examples for these methods, but on the last meters we discovered that something not only broke the Python bindings but the whole "execute JS" in the WebView2/WebKit bindings.

    My last info is that something broke there due to a project update, and that the two devs involved in it will have a look. I'll give them another bump and report here if there are any updates.

    Cheers,
    Ferdinand

  • RE: Creating custom asset nodes via Python API

    Good to hear that things worked out for you!