• Educational Licenses

    Cinema 4D SDK python windows 2025
    5
    1
    0 Votes
    5 Posts
    30 Views
    lasselauchL
    Thanks for all the info, Ferdinand! And thank you for the input about the booting phase, I'll definitely adjust this for the next version! Cheers, Lasse
  • set GvNode value via python

    Cinema 4D SDK windows python 2026
    4
    1
    0 Votes
    4 Posts
    57 Views
    DunhouD
    Thanks for @ferdinand awesome answer! I found DescLevel and DescId always confused to me, but them do can access more than simple set item, time to dive deeper to the DescLevel part Cheers~ DunHou
  • 0 Votes
    5 Posts
    115 Views
    M
    Hey ferdinand, I mixed different questions - I'll keep to the theoretical part to keep the Post relevant to the original question. I appreciate the informative post as always. Parametric concept of a spline is clear to me -> that's why i asked about "C4D can not get more precise than a 0° degree line object ?" which was formulated to lose as 0° is mathematical problematic? and I know 0.1 would be better. sorry about that. The tip about spline 'Adaptive' setting was a good hint, I never use it in work so I forgot about it. So to summarize regarding my question. The Line object always samples what the user has set in the spline settings and not by a unknown internal setting (for example to give good viewport performance, or nice equal sections) And its a better fit for my application, hence there is no "linear transport" shenanigans going on. And if I want to display a high resolution of my calculation, I make an internal copy of that spline and edit the spline settings, instead of sampling a low division spline with spline helper. Normalization / Jagged lines: I use Menger-Krümmung. -> will open a new topic. Your code might come in handy when I'll extend the plugin to polygon meshes. ... ... ... Remark as humans cannot see that level of detail. I have to disagree on this topic. As a tell tale we import CAD data here into C4D to evaluate the work of the engineers. Not long ago I said to our surface engineer. "take a look at the end of that surface something feels off, it looks like the surface is lifting" -> The engineer reportet back "you just spoted a 0.001mm surface deviation of an unconstrained spline ending I did not set." We could argue that the seen result was in fact not 0.001mm but perhaps to surface setup more than 1mm, (or by some rounding error C4D normal tag shading where continuous and then stagnant for 1 pixel) but my point is settings in precision are important and carry through till the final product. Even though a setting of 0.1° for a spline might might be unsuitable in most cases (rendering, performance, ...) it is not for evaluation. So even C4D and all that rounding / conversion / floating point precision might look like unrealiable, unecessary or even esotheric it caries through to a certain degree and its more reliable than you think. (Yes we evaluate in the original CAD Program, but the tale is that I saw something even after importing it into C4D) As reference to why I need this: Blender Plugin: Surface Diagnostics - Josef Ludvík Böhm Thank You
  • 0 Votes
    7 Posts
    191 Views
    ferdinandF
    Hey, almost forgot: We have fixed this, an upcoming release will contain the fix . We, however, went with a fix removing the offending call instead of fixing the incorrect progress handler method (which was the issue). So, in other words: The workaround I showed here won't work in future versions, as the number of progress calls will be halved. Before one got two calls per update when rendering with the preview renderer: One for the correctly working image progress update and one for the buggy generic progress update. We have removed the latter. Halving the number of calls is more technically correct, since it made no sense to call the progress hook twice per update but will break any plugins that relied on that incorrect behaviour. Cheers, Ferdinand
  • 0 Votes
    14 Posts
    455 Views
    ferdinandF
    FYI, there has been a verified fix for the Booleans crash, it will be included in an upcoming release of Cinema 4D.
  • Several Asset Browser Issues

    Cinema 4D SDK 2026 2025 python
    7
    0 Votes
    7 Posts
    310 Views
    B
    Hi @ferdinand Thank you for the reply and I totally understand your point. I think I will try to find another solution and will adjust my rigs to maybe get rid of the python tag thats causing the issue. I wasn't aware that this is considered "dark magic" python code^^ haha Thank you once again for your efforts! Cheers, Ben
  • Setting Preferences via script

    Cinema 4D SDK python 2025 2026
    5
    0 Votes
    5 Posts
    153 Views
    ferdinandF
    Hello @CJtheTiger, I am not quite sure how your question is meant, and generally new questions should constitute new topics. When you are asking, if when there is an ID_FOO: int = 12345 in V1, if we then just silently switch out the numeric value to ID_FOO: int = 54321 in V2, then the answer is sort of yesn't. We try to keep identifiers persistent. And for things like plugin IDs this is true without ifs and buts. I.e., once Ocube: int = 5159 has been defined, it will stay like this. But parameter values, e.g., PRIM_CUBE_LEN: int = 1100, can technically change. The goal is also to keep them persistent but in ABI breaking releases we sometimes have to modify descriptions. That is why we recommend that you always use symbols and not numbers. Cheers, Ferdinand
  • Editable Object Plugin returns Null after scaling

    Cinema 4D SDK python
    4
    0 Votes
    4 Posts
    167 Views
    ferdinandF
    Hey @JH23, there is no need to apologize for a lack of context. Now that I read your first posting again, it is actually perfectly clear what you are asking for. I just did not read it properly, my bad, sometimes this happens when I am in a hurry. The answer to your question is not trivial, but the TLDR is that you have only little control over it. There exist two commands, 'Current State to Object' (CSTO) and 'Make Editable' (ME). CSTO is basically the less aggressive version of ME, where it runs through all the elements of a cache of something and tries to collapse them gracefully (which could result in output that is still collapsible itself). ME more aggressively flattens the cache hierarchy. For both commands, at the very basic level, there is the distinction between generators and and non-generators. When you CSTO some generator object which just holds another generator in its cache (imagine your GetVirtualObjects or main just returning c4d.BaseObject(c4d.Ocube)), it will just return a copy of that generator (which is still a generator, i.e., something that has a cache). But when your generator returns a non-generator, i.e., a discrete PolygonObject, it will wrap the copy of this cache in a null when returning it. But that is not all of it. Because, there are also functions such as TransferDynamicProperties and OptimizeHierarchy which ensure that relevant scene data is kept and the output is as compact as possible. They run after ME/CSTO by further manipulating the ME/CSTO output. The original MEed/CSTOed object might have had a transform which must be copied onto the flattened output, so that it has the same transform in world space. Objects often also hold hidden data in form of tags in Cinema 4D which might have to be copied from the original object onto the flattened result. This all might lead to the functions either removing unnecessary null objects which before have been created by ME/CSTO or adding new ones. That your scale manipulations result in an extra null is a bit surprising, but that must have to do with the transform normalization code which runs after ME/CSTO. At first I thought, it might transfer the scale to the null object, so that it can normalize the scale of the cache. But that is not the case, it is still the cache object which has the scale 2 when you CSTO/ME your generator. I would really have to debug this in detail, to find out why exactly this happens. But in general, I would advise against scaling the matrix/transform of an object, and instead, apply the scale to the points of a discrete PolygonObject or the parameters of a BaseObject itself. Transforms which have axis components of non-unit length (i.e., a scale != 1.0), often lead to problems. The important message is that even when you find a solution which gives you the desired flat cache for this problem (by for example scaling the points), there could be countless other scenarios such as a user having a MoGraph tag on your generator or something like that, where then MEing or CSTOing would result in a null + cache output. You should not build your code on the assumption that the MEed or CSTOed output of your generator will always be flat (or the opposite), because you simply cannot guarantee that. Not the most satisfying answer, I know, but I hope it helps to clarify the situation. Cheers, Ferdinand Here is how you could post process points with a transform: def main(): obj: c4d.PointObject = Cube() # We could of course also just pass this #transform into your #Cube function, to do it right # there. But we are making a point of doing this as a post processing step (so that we can do # this at any point in time). We scale all points by a factor of 2 and rotate them 45° on the # Y axis in the coordinate system of the object. When we now CTSO your object, we have a flat # output. transform: c4d.Matrix = (c4d.utils.MatrixScale(c4d.Vector(2, 2, 2)) * c4d.utils.MatrixRotY(c4d.utils.DegToRad(45))) obj.SetAllPoints([n * transform for n in obj.GetAllPoints()]) obj.Message(c4d.MSG_UPDATE) return obj
  • 1 Votes
    4 Posts
    231 Views
    ferdinandF
    Hey Jacob, Thank you for the added data. First of all, I have invited you to the forum to end this middle man communication, which is a bit odd. The pyz file is part of python ... I am aware of what pyz is, I just pointed this out because I of course looked inside your package and found all the py_armor obfuscated code and the injected binaries in there. So, I pointed out that this is bit more than just "packaged in a pyz file for ease of distribution [...]" as Lasse/you put it, the goal is here clearly obfuscation. Which is also relevant for support, as it limits what you and I can see (without getting hacky). My finding with the 10mb file freeze comes from my trial and error ... mean[t] when you run a script from Extensions -> User Scripts. Your code also freezes when you load it as a Script Manager script. That is what I did with the last package from Lasse, and now also yours. The code in your script is again wrong, which is why it won't freeze until you fix it. This is the code I found: [image: 1760086817339-2bd4290e-78b2-43d4-936d-1e2a7eaf366b-image.png] And I fixed it then to this. When I ran it then, Cinema 4D froze for two minutes or so, after that it opened a myriad of dialogs to then terminate into two crash dialogs (it was pure luck that I let it run for so long, Lasses previous version might have acted similar, but there I killed the C4D process, as soon as I saw the 'beach ball of death' cursor on MacOS). [image: 1760086755748-69fcb5da-ac49-477e-8f70-9daeb1daa1aa-image.png] Please read my answer below carefully, as I already pointed out most of this in my previous posting. I would STRONGLY suggest debugging this without obfuscation. Maxon also cannot debug larger sections of code or test further packages for you. I understand that obfuscation might not be your choice, but it will make your life harder in debugging this, as you always fly blind. We of course still will provide support, but you have to provide more than "it does not work/crashes/freezes, please help us", especially when this is not code tied to our APIs. Attach a debugger from the Script Manager and see why your code crashes/freezes (see link in last posting when unsure how to do this). But you need an un-obfuscated code base for this to make any sense. Defer your loading to a later point, e.g., C4DPL_PROGRAM_STARTED, when you have issues in the direct plugin registration context. In that case you would always register your plugin, but then only execute it when the your own license check succeeded. But you absolutely cannot ship a plugin which freezes Cinema 4D for multiple minutes on startup or when invoking your plugin because your licensing takes so long. When we see this in the wild, we will have to blacklist your plugin IDs, as this damages the brand Cinema 4D. Please use threading then to not block the main thread with your long running code. What I did not notice before is that you apparently try to open multiple dialogs (for me it opened multiple dialogs when I ran the script). The GUI and many other systems are not yet available when Cinema 4D is still booting, e.g., in the splash screen. You can expect all systems to be up and running when C4DPL_STARTACTIVITY is emitted, but it is better to wait for C4DPL_PROGRAM_STARTED for long running tasks (i.e., the two events I tested in my previous posting). Please also keep in mind that Cinema 4D has its own anti-piracy measures. Python plugins are sort of special in that they work slightly different than native C++ plugin modules (the Python C++ module shipped by Maxon sort of acts as a surrogate for Python plugins in the module registration phase). But Cinema 4D won't allow plugin threads to start their own processes at this point (which you might be trying to do with your injected binaries), and threading should also be avoided at this point, as the job system of Cinema 4D might be still booting. What you are meant to do in PluginStart (or the __main__ context of a pyp file), is register your plugins. You can run some quick logic there, but you are certainly not meant to start communicating with servers and opening GUIs there. You can read here a bit more about this from a C++ system perspective. I would recommend to do your license check in the background in its own thread once C4DPL_PROGRAM_STARTED has been emitted (so that you can also open dialogs to signal errors). An alternative would be to do it when the user clicks the button of your command. But you should also here put it into its own thread, so that it does not block everything else. Cheers, Ferdinand
  • 0 Votes
    3 Posts
    130 Views
    gheyretG
    Thank you for the C++ code—it's been very helpful! Cheers!
  • Set VERTEXCOLOR in PaintTool

    Cinema 4D SDK python r25 windows
    3
    0 Votes
    3 Posts
    119 Views
    R
    @m_adam Thank you so much for the help, that works perfectly and thank you for showing me both methods, that's very helpful and appreciated!
  • 0 Votes
    4 Posts
    209 Views
    M
    I'm not sure I understand you correctly, you do not have to use QuickTabRadio bar with resource, you just retrieve the int value of the parameter, in the case of the previous example I share with a GetInt32(c4d.MGCLONER_VOLUMEINSTANCES_MODE). If you can provide a code example of what is blocking you that would be nice. You can find a non-exhaustive list of type of control available in *res file within the C++ documentation in Description Resource. Cheers, Maxime.
  • 0 Votes
    2 Posts
    140 Views
    M
    Hey you need to react to MSG_GETCUSTOM_NAME_ADDITION and return a dict with the expected string with the "res" key. You need to register your object with c4d.OBJECT_CUSTOM_NAME_ADDITION to have the additional name displayed in the Object Manager. Cheers, Maxime.
  • exporting usd with python

    Cinema 4D SDK 2025 python windows
    2
    0 Votes
    2 Posts
    198 Views
    ferdinandF
    Hey @lionlion44, Thank you for reaching out to us. I doubt that this will not work in Python, it is just that we have not documented the symbols there yet. But you can find them in the C++ docs: [image: 1757607809636-6e23eada-2198-4c34-84bf-a576bbdd0ef9-image.png] I.e., it will be c4d.FORMAT_USDIMPORT and c4d.FORMAT_USDEXPORT. Cheers, Ferdinand
  • Maxon One Fall SDK Release

    News & Information news cinema 4d zbrush c++ python sdk
    3
    2 Votes
    3 Posts
    2k Views
    ferdinandF
    Thanks for pointing it out, changed it
  • GetRad() / GetMp() update issue

    Cinema 4D SDK windows python 2025
    2
    0 Votes
    2 Posts
    190 Views
    ferdinandF
    Hey @datamilch, Thank you for reaching out to us. GetRad and GetMp express the locally aligned bounding box of an object. I.e., the bounding box in the coordinate system of the object. For a world space aligned bounding box we once had this thread, the Cinema API does not offer this out of the box. So, transforming an object will never change its bounding box. What will change the bounding box of an object, is changing its size or changing the parameters of a generator object. When you change the parameters of a generator or when your instantiate a new object, you will have to execute the passes (BaseDocument.ExecutePasses) on a document that contains the object to see the correct bounding box - or wait for the next scene update. PS: Your script is also running illegal code. You cannot modify the active document off-main-thread. I assume the is a script for a Python generator object. Its main function runs off-main-thread and you call there your csto which in turn calls SendModelingCommand on the active document. This will all sooner or later crash. https://developers.maxon.net/docs/py/2025_3_1/manuals/manual_threading.html#threading-information Cheers, Ferdinand
  • 0 Votes
    11 Posts
    468 Views
    A
    @ferdinand Thank you for your in-depth analysis. It would have taken me way too long to figure this out lol, especially finding "CUSTOMDATA_BLEND_LIST". The first example seems to work for me, but like you said, it may not be reliable. The Python node example also works great. Again, thank you for your time.
  • Can I get keyboard input mode?

    Cinema 4D SDK windows python c++ 2025
    4
    1
    0 Votes
    4 Posts
    269 Views
    ferdinandF
    Hey @Dunhou, I have edited your posting. It is fine to mention the beta forum, but we would rather not see its name written here. When you are talking about 'C++', I assume you are talking here about the Windows SDK/API, as for example GetGUIThreadInfo. I would doubt that you get very far with that here. Cinema 4D is very OS agnostic and we have our whole GUI decoupled from the OS. The little rename window in our tree view control is not an OS rename dialog. I am not even sure if this is something with an HWND handle which you could address so that you could intercept keyboard events to it, or if this is just a virtual window within our API. For this IMM thing to work, we would have to use the IME API in Cinema 4D, so that our text edit gadgets support it. I also do not quite understand what you are trying to do. The missing piece is here probably that our text edit gadget does not send its current content to the IME API (at a glance, via ImmSetCompositionStringW as shown here). And as a third party, you cannot really fix that. Because you (a) do not own the implementation and you (b) are not informed about an edit event, so you cannot just write a plugin which sends the object name to the IME API. Cheers, Ferdinand
  • 0 Votes
    4 Posts
    178 Views
    ferdinandF
    Hey, thanks for the extended code, but I still cannot run this, as it is only a fragment So, I only have a very rough understanding of what is going wrong. A likely issue apart from you just having a bug in your hit logic, is that you use the wrong coordinate system. if msg[c4d.BFM_INPUT_DEVICE] == c4d.BFM_INPUT_MOUSE \ and msg[c4d.BFM_INPUT_CHANNEL] == c4d.BFM_INPUT_MOUSELEFT \ and msg[c4d.BFM_INPUT_VALUE]: local_x = msg[c4d.BFM_INPUT_X] local_y = msg[c4d.BFM_INPUT_Y] scroll_y = self.dialog.get_scroll_offset() I would have to check myself, but there is some inconsistency with which dialogs send mouse input messages regarding the used coordinate system. Sometimes they send messages in the coordinate system of the dialog and sometimes messages in the coordinate system of the gadget. Just print out your (local_x and local_y) and check if the values make sense as local coordinates as you seem to treat them. On GeUserArea are multiple coordinate conversion methods. I think BFM_INPUT in this context is in local user area coordinates but I am not sure, it could also be that you have to convert them. The other thing is of course that you add this self.dialog.get_scroll_offset() on top of things. I assume this is sourced by something like GeDialog.GetVisibleArea? There you could also unintentionally mix coordinate systems. Cheers, Ferdinand
  • 0 Votes
    3 Posts
    298 Views
    d_keithD
    Thanks for the response! I appreciate the ASSETDATA_FLAG_MULTIPLEUSE tip. My hope was that there was some sort of existing RenameAsset SDK method that would also update all references to that asset without implementing custom handling for various element types (Redshift Nodal Material, Cinema 4D Classic Material, Arnold Dome Light, XRef, etc). Evidently such a public python SDK method doesn't exist. My example code was texture specific as that's the part of the problem that's most pressing to me and I was able to implement with custom per-type handling - if I manage to get other types working, I'll attempt to update over time.