• 0 Votes
    3 Posts
    628 Views
    gheyretG
    @manuel Cool ! Thank you ~
  • How to implement a license check on a python plugin?

    Cinema 4D SDK python
    5
    0 Votes
    5 Posts
    1k Views
    ThomasBT
    @manuel Hi Manuel, I just wanted to let you know that I have decided on your suggestion and have decided on a license system with serial numbers that are automatically created and delivered upon purchase and in combination with a kind of license server that controls the licenses..... thank you for the hints
  • TreeView for ObjectData plugin

    Cinema 4D SDK python r23
    2
    0 Votes
    2 Posts
    583 Views
    M
    Hi Mike this is unfortunately not possible, even in C++ for more info please look at Info for ITEMTREE/customgui_itemtree. Cheers, Maxime.
  • Button Hover -> Helptext - searching for example

    Moved Cinema 4D SDK
    5
    0 Votes
    5 Posts
    953 Views
    M
    I use CreateLayout ... no description file ... but as I wrote probably a little bit to cryptic I am fine for now. Thanks for the reply Manuel. Cheers mogh
  • 0 Votes
    4 Posts
    972 Views
    ferdinandF
    Hey @mogh, just to clarify: I found that bit of the documentation before you pointed it out, but in my mind I could not link "needs a document" to "the object has to be present" ... Well, the documentation clearly states it: doc (Optional[c4d.documents.BaseDocument]) – The document for the operation. Should be set if possible. Must be set for MCOMMAND_JOIN, MCOMMAND_MAKEEDITABLE, MCOMMAND_CURRENTSTATETOOBJECT and MCOMMAND_SPLINE_PROJECT. If you set the document, the objects which you pass to this function have to be in the same document. So pay attention that you use one send_modeling_command per document for objects. But that could be more visible. I'll see if I can rework the function documentation a bit to make that important information more prominent. Cheers, Ferdinand
  • C4D Threading in python doesn't work as expect .

    Cinema 4D SDK sdk python 2023
    9
    0 Votes
    9 Posts
    2k Views
    DunhouD
    @ferdinand thanks for your generoso help. I already send you an email with an zip file , and some notes in the front of the codes. Have a good day!
  • How to get the bounding box for the whole scene

    Cinema 4D SDK python
    5
    0 Votes
    5 Posts
    3k Views
    ferdinandF
    Hey @mogh, Thank you for pointing out that problem. No, there is no Vector(0, 0, 0) being added, there was simply a small bug in my code. self.min: c4d.Vector = c4d.Vector(sys.float_info.max) self.max: c4d.Vector = c4d.Vector(sys.float_info.min) float_info.min is 2.2250738585072014e-308, i.e., the smallest representable increment of the float type, not the lower representable boundary. So, the code did initialize the max-value boundary as ~(0, 0, 0) which then caused values to be discarded which should not be discared. I of course meant here the following: self.min: c4d.Vector = c4d.Vector(sys.float_info.max) self.max: c4d.Vector = c4d.Vector(-sys.float_info.max) Fixing this should fix your problems. I have updated my original posting to not mislead future readers. Cheers, Ferdinand
  • Subprocess can't detect system installed utilities

    General Talk r23 python
    3
    0 Votes
    3 Posts
    962 Views
    mikeudinM
    Thank you @ferdinand !
  • Trying to programmatically create vertex color tag

    Cinema 4D SDK
    2
    0 Votes
    2 Posts
    876 Views
    ferdinandF
    Hello @zauhar, thank you for reaching out to us. Your code does look mostly fine and is working for me. The line op = Default makes little sense and you are of course missing things like imports, a context guard and a main function. Not all of them are absolutely necessary, but it is strongly advised to use them all, especially for novice users. Find a code example below. Vertex colors are also not automatically rendered as the diffuse color in Cinema 4D, one must use a VertexMap shader for that. Please consult the user manual or end-user support for end-user questions, we cannot deliver such support here. Cheers, Ferdinand The result for two polygon objects, the color of a vertex depends on its position in global space. [image: 1676539052471-0e9b3117-e70a-4495-8001-cbe0a6b0a2e4-image.png] Code """Creates vertex-color tag on the currently selected polygon object and makes it the active tag. Must be run as a Script Manager scrip with a polygon object selected. The color of each vertex will depend on its position in global space. """ import c4d import typing GRADIENT_MIN: float = -200.0 # The lower boundary of the gradient. GRADIENT_MAX: float = 200.0 # The upper boundary of the gradient. op: typing.Optional[c4d.BaseObject] # The active object, can be `None`. def main() -> None: """Runs the example. """ # Check that there is indeed a selected object and that it is a polygon object. if not isinstance(op, c4d.PolygonObject): raise TypeError("Please select a polygon object.") # Get its point count and allocate a vertex color tag with that count. count: int = op.GetPointCount() tag: c4d.VertexColorTag = c4d.VertexColorTag(count) if not isinstance(tag, c4d.VertexColorTag): raise MemoryError("Could not allocate tag.") # We are going to make it a little bit more exciting and write a gradient based on the global # coordinate y-component of a vertex. # Set the tag to defining colors only once per vertex instead of having N colors per vertex, # where N is the number of polygons attached to it. tag.SetPerPointMode(True) # Get the global matrix of the polygon object and all its points in global space. mg: c4d.Matrix = op.GetMg() globalPoints: list[c4d.Vector] = [mg * p for p in op.GetAllPoints()] # Define a callable with which we can get the gradient color of a point over its index. GetGradientColor = lambda i : c4d.Vector4d( c4d.utils.RangeMap(globalPoints[i].y, GRADIENT_MIN, GRADIENT_MAX, 0, 1, True), 0, 0, 1) # Get the data pointer of the tag and start writing data. dataW: object = tag.GetDataAddressW() for i in range(count): c4d.VertexColorTag.SetPoint(dataW, None, None, i, GetGradientColor(i)) # Insert the tag into the selected object, make it the active tag, and push an update event. op.InsertTag(tag) tag.SetBit(c4d.BIT_ACTIVE) c4d.EventAdd() if __name__ == "__main__": main()
  • List All Nodes With No Filter?

    Cinema 4D SDK python 2023
    3
    0 Votes
    3 Posts
    804 Views
    B
    RE: Yes, GraphModelHelper.ListAllNodes requires at least one attribute to be set in the data dictionary. Gotcha. Thanks for the clarification. Anyway, the suggested alternative (i.e. write a separate iterator) still works as expected. Same as before.
  • 0 Votes
    26 Posts
    21k Views
    M
    Hello @ThomasB , without further questions or postings, we will consider this topic as solved by Friday 02/06/2023 and flag it accordingly. Thank you for your understanding, Maxime.
  • 0 Votes
    4 Posts
    3k Views
    ferdinandF
    Hello @Tng, Please excuse the very long waiting time, I simply overlooked the question in your answer. One question regarding Assets from the asset browser, in the case of a random machine that is rendering via command-line, is the Asset stored in the Project File or will it be downloaded if's missing ? Assets will be automatically downloaded when they are accessed and not already localized. The type maxon.Url hides all that complexity away with its different URL schemes. The Asset API manual provides an example for how to manually download an asset. But doing that is not possible in the Python API, here one must always rely on the automated asset access mechanisms. Assets can be stored in project files (via BaseDocument.GetSceneRepository) but are usually not, and instead reside in the user preferences directory bound user preferences repository. Once a remote asset has been accessed, a copy of its primary data, e.g., the texture, the model, etc., resides as a cache in the user preferences of that Cinema 4D installation. That cache will only be updated when the primary or secondary (i.e., metadata) of that asset change. Cheers, Ferdinand PS: I have closed this thread due to its age. Please feel free to reopen it when you have more questions.
  • Relative File Path Not Recognize by Plug-in?

    Cinema 4D SDK 2023 python
    5
    0 Votes
    5 Posts
    1k Views
    ferdinandF
    Hello @bentraje, Yes, the Python variant of GeGetPluginPath is not that useful as it just calls the C++ implementation which will then return the Python module path because the Python module is the C++ plugin which is calling GeGetPluginPath in that case. I will make the function description a bit more clear about that and also add a little example snippet for the module attribute __file__. And as what I would consider a fun fact: The __file__ attribute of modules is one of the many things where the language Python took inspiration from C/C++. In C++, __FILE__ is the macro which refers to the source file it is referenced in. I used this for example recently in the C++ Color Management examples to load an ICC file which is located next to a source file. But since users are usually not in the habit of compiling their C++ code themselves, or if they do, then want to move the resulting binary to a different place, __FILE__ is much less useful than __file__ as C++ there is a difference between the source and the executable. Cheers, Ferdinand
  • 0 Votes
    3 Posts
    732 Views
    mikeudinM
    Thank you @ferdinand ! Will chek it!
  • Change Bodypaint Active Channel Color

    Cinema 4D SDK python
    3
    1
    0 Votes
    3 Posts
    713 Views
    A
    Hi @m_adam. Thanks for the information! I needed this feature to generate UV texture, where polygon selection tags colorizes the texture with different colors. And since "Fill Layer, Fill Polygons and Outline Polygons" commands uses color from current "Channel Color" I needed option to change the color with a script. [image: 1675761996302-g89cotievo.png] c4d.CallCommand(170150) # Fill Layer c4d.CallCommand(170151) # Fill Polygons c4d.CallCommand(170152) # Outline Polygons But if this is not possible, one workaround that come to mind is to use "UV to Mesh" Scene Nodes Deformer/Capsule and render actual mesh with aligned camera. Cheers, Arttu
  • Treeview does not refresh

    Cinema 4D SDK r20 python
    5
    0 Votes
    5 Posts
    2k Views
    H
    Hello @ferdinand, sorry for coming back this late. Work kept me quite busy. @ferdinand so, I had a play with your code example. It works like a charm and also seems to have a lot of potential for all kinds of update/dirty checking issues. Thanks again @ferdinand for your help, the effort you always put into answering our questions and the eloborate examples you come up with! Cheers, Sebastian
  • Snap to grid while MouseDrag()

    Cinema 4D SDK 2023 python
    2
    0 Votes
    2 Posts
    525 Views
    ferdinandF
    Hello @pim, Thank you for reaching out to us. It depends a bit on what you expect to happen here. There is the snapping module of Cinema 4D but you cannot actually get values out of it, i.e., you cannot compute the snapped value of x with it, you can only define the snap settings with it. But when I understand your correctly, you just want to quantize some mouse inputs for a plugin and for that you must indeed compute the values yourself. It is best to also draw a snapping location onto the screen, so that user can see where the actual input is in relation to the mouse. How the snapping works in detail depends on what you want to do exactly when quantizing your plane drawing. The snapping module might become relevant here, because with it you can retrieve the working planes, which might be useful when placing planes. Cheers, Ferdinand
  • How do you collapse complex dependies in order?

    Cinema 4D SDK 2023 python
    2
    0 Votes
    2 Posts
    712 Views
    ferdinandF
    Hello @fss, Thank you for reaching out to us. The Cinema 4D classic API has no dependency graph for its scene elements. If you want such information, you must gather it yourself. This is however a non-trivial task. You also have been asking this same question multiple times both here on the forum and via mail, with both Manuel and I giving you multiple times the same answer. To "collapse" things, you must use 'Current State to Object (CSTO)' and then join the results, as first reducing things to their current cache state (CSTO) will remove the dependencies between things. You can/could also do this manually, just as the joining operation, but it is then up to you to develop that. Please understand that we will not answer the same question over and over again. We enjoy and encourage discussions with users, but as stated in our forum guidelines: We cannot provide support for [...] code design that is in direct violation of Cinema's technical requirements [...] Find below an example. Cheers, Ferdinand Result for the fairly complex Mograph asset Example Scenes\Disciplines\Motion Graphics\01 Scenes\Funny Face.c4d: [image: 1675690420936-connect_and_delete.gif] Code '''Example for mimicking the "Connect & Delete" command in Python. Must be run from the Script Manager with the root objects selected whose local hierarchies should be collapsed. ''' import c4d import typing def Collapse(objects: list[c4d.BaseObject]) -> None: """Collapses all items in #objects as individual root nodes into singular objects. This function mimics the behaviour of the builtin (but unexposed) "Connect & Delete" command by first running the "CSTO" and then "JOIN" command. With setups complex enough, this can still fail due to the non-existent dependency graph of the classic API (when one does CSTO things in the wrong order). In 99.9% of the cases this will not be the case, but one should get the inputs with #GETACTIVEOBJECTFLAGS_SELECTIONORDER as I did below to give the user more control. (or alternatively do not batch operate). """ if len(objects) < 1: raise RuntimeError() doc: c4d.documents.BaseDocument = objects[0].GetDocument() doc.StartUndo() # CSTO all local hierarchies in #objects and replace these root nodes with their collapsed # counter parts. result = c4d.utils.SendModelingCommand(c4d.MCOMMAND_CURRENTSTATETOOBJECT, objects, c4d.MODELINGCOMMANDMODE_ALL, c4d.BaseContainer(), doc, c4d.MODELINGCOMMANDFLAGS_NONE) if not result or len(result) != len(objects): raise RuntimeError() for old, new in zip(objects, result): parent, pred = old.GetUp(), old.GetPred() doc.AddUndo(c4d.UNDOTYPE_DELETEOBJ, old) old.Remove() doc.InsertObject(new, parent, pred) doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, new) # Join the CSTO results root by root object, and then replace the CSTO results with the final # collapsed result. JOIN is a bit weird when it comes to transforms, so we must store the # transform of the to be joined object, then zero it out, and finally apply it to the joined # result again. for obj in result: mg: c4d.Matrix = obj.GetMg() obj.SetMg(c4d.Matrix()) joined = c4d.utils.SendModelingCommand(c4d.MCOMMAND_JOIN, [obj], c4d.MODELINGCOMMANDMODE_ALL, c4d.BaseContainer(), doc, c4d.MODELINGCOMMANDFLAGS_NONE) if not joined: raise RuntimeError() parent, pred = obj.GetUp(), obj.GetPred() doc.AddUndo(c4d.UNDOTYPE_DELETEOBJ, obj) obj.Remove() new: c4d.BaseObject = joined[0] new.SetMg(mg) doc.InsertObject(new, parent, pred) doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, new) doc.EndUndo() c4d.EventAdd() doc: c4d.documents.BaseDocument # The active document op: typing.Optional[c4d.BaseObject] # The active object, can be None. def main() -> None: """Runs the #Collapse() function on all currently selected objects as root nodes. """ selection: list[c4d.BaseObject] = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER) if len(selection) < 1: print("Please select at least one root object.") else: Collapse(selection) if __name__ == "__main__": main()
  • 0 Votes
    7 Posts
    2k Views
    B
    @ferdinand Thanks for the response. With the illustration code you provided, I misunderstood the documentation. Thanks for the clarification. Basically, I thought the PluginMessage/RegisterPlugin functions should be method (i.e. they should be under the class of the plugin data, command data etc). They actually live outside the classes. It now works as expected. Thanks!