• Can I convert a BaseBitmap into a Image file in memory?

    windows python 2024
    3
    0 Votes
    3 Posts
    663 Views
    DunhouD
    Hey @ferdinand , oops, I have an impression of this topic and tried to recall it, but I couldn't find any keywords in my mind at the time. I must have gone crazy. And the key is the GetData(), I have no concept of file composition and did not realize that what is returned here is the data required for an image file. Thank you very much. Cheers~ DunHou
  • Python Api: Document Events

    python
    8
    0 Votes
    8 Posts
    2k Views
    ferdinandF
    Hey @paulgolter, yes, this is okay. What you should not do, is traverse the whole scene graph, i.e., every object, shader, material, scene hook, track, curve, key etc that are to be found in a scene; just to get hold of all cube objects for example. For performance critical operations, we should always only traverse what we really need . But you just traverse the objects which is totally fine. I personally would avoid recursion, passing around a list, and not using an iterator, as this all makes things slower. Especially recursion/function calls are not cheap in Python. For the next major release we added some premade scene traversal functions in Python. I have attached one of the functions which will be exposed below. But your function is probably fine too, this is all very nitpicky. You do not use full recursion which is the most important thing. Everything else is probably nerd-talk. Cheers, Ferdinand def IterateTree(node: c4d.GeListNode | None, yieldSiblings: bool = False, rewindToFirstSibling: bool = False, rewindToRoot: bool = False) -> typing.Iterator[c4d.GeListNode]: """Yields nodes that are hierarchically related to `node`. .. note:: This function walks a node tree in a purely iterative manner, which makes it fast and robust for medium to large trees. For small trees (<= 100 nodes) `RecurseTree` is slightly faster. This function is usually the faster and safer choice compared to `RecurseTree` as the performance gain for large trees is significant while the loss for small trees is negligible. .. note:: To also yield non-hierarchical relationships, use `RecurseGraph` instead. :param node: The root node to start iterating from. :type node: c4d.GeListNode or None :param yieldSiblings: Whether to yield the next siblings of the current node, defaults to `False`. :type yieldSiblings: bool, optional :param rewindToFirstSibling: Whether to rewind the node to its first sibling before the iteration is carried out, defaults to `False`. :type rewindToFirstSibling: bool, optional :param rewindToRoot: Whether to rewind the node to its root before the iteration is carried out, defaults to `False`. :type rewindToRoot: bool, optional :return: An iterator that yields the descendants of the passed `node`. :rtype: typing.Iterator[c4d.GeListNode] :raises RuntimeError: If the UUID of a node could not be retrieved. :Example: .. code-block:: python import c4d from mxutils import CheckType, IterateTree # For the object tree: # # A # |___B # | |___C # | |___D # | | |___E # | |___F # G # Find the object named "D" in the scene. d: c4d.BaseObject = CheckType(doc.FindObject("D")) # Will yield D and E. for node in IterateTree(d): print (node) # Will yield D, E, and F. But not C as we start out at D and #yieldSiblings only looks # downwards, at next siblings and not previous ones. for node in IterateTree(d, yieldSiblings=True): print (node) # Will yield C, D, E, and F. Because we rewind to the first sibling of D - which is C. for node in IterateTree(d, yieldSiblings=True, rewindToFirstSibling=True): print (node) # Will yield A, B, C, D, E, and F. But not G, as we do not yield siblings. for node in IterNodeTree(d, rewindToRoot=True): print (node) # Will always yield the whole tree, no matter where we start. for node in IterateTree(d, True, True, True): print (node) """ def iter(node: c4d.GeListNode) -> typing.Iterator[c4d.GeListNode]: """Iterates over the descendants of the passed `node`. """ # The visited nodes and the node to stop iteration at. visited: dict[bytes, c4d.GeListNode] = {} terminal: c4d.GeListNode = node # Walking a tree iteratively is faster for medium to large trees than a recursive or # semi-recursive traversal. See: https://developers.maxon.net/forum/topic/13684 while node: # We could use GeListNode.__hash__ here, but it turns out that it is much slower than # doing it manually with MAXON_CREATOR_ID (sic!). Probably because of the overhead of # __hash__ hashing the UUID into an integer? nodeUuid: bytes = bytes(node.FindUniqueID(c4d.MAXON_CREATOR_ID)) if nodeUuid is None: raise RuntimeError(f"Could not retrieve UUID for {node}.") # Yield the node when it has not been encountered before. if visited.get(nodeUuid) is None: yield node visited[nodeUuid] = True # Walk the graph in a depth first fashion. getDown: c4d.GeListNode | None = node.GetDown() getNext: c4d.GeListNode | None = node.GetNext() getDownUuid: bytes | None = getDown.FindUniqueID(c4d.MAXON_CREATOR_ID) if getDown else None if getDown and getDownUuid is None: raise RuntimeError(f"Could not retrieve UUID for {getDown}.") if getDown and visited.get(bytes(getDownUuid)) is None: node = getDown elif node == terminal: break elif getNext: node = getNext else: node = node.GetUp() # --- End of iter() ---------------------------------------------------------------------------- if not isinstance(node, c4d.GeListNode): return # Set the starting node. # if rewindToRoot: # node = GetRootNode(node) # if rewindToFirstSibling: # node = GetFirstSiblingNode(node) # Traverse the hierarchy. while node: yield from iter(node) if not yieldSiblings: return node = node.GetNext()
  • How to change the value here using python

    2024 python
    8
    1
    0 Votes
    8 Posts
    2k Views
    F
    @ferdinand Thanks so much for such a detailed response. Learned a lot. My problem is solved. Thank you very much.
  • Hide the illumination group in node materials

    c++
    2
    0 Votes
    2 Posts
    644 Views
    ferdinandF
    Hey @bojidar, Thank you for reaching out to us. I assume you are talking about NodeMaterial cases, i.e., a material realized by the Nodes API. [image: 1722273375699-a78c9ce8-3a6c-4903-8428-625e0f8add14-image.png] Something like a NodeMaterial does not actually exist under the hood. A NodeMaterial is just a modified Material (i.e., the type Mmaterial) where pretty much everything except for the Viewport (and previously Illumination) tab is being hidden. This is done by us overriding GetDDescription in Material. By default not the whole illumination tab is hidden, but only everything below the check box "Portal" (don't ask me why). I just had a look: And for Redshift we recently added a section in Material::GetDescription where we check for a material being part of the Redshift node space and then hide the full tab. Since third parties do not own/overwrite Material, their node material then looks different, without them being able to change that (here at the example of V-Ray): [image: 1722273065911-e03ce790-eb53-43dc-a604-ddfe5a7bace6-image.png] For me it looks a bit like that we unintentionally left that group there. Maybe physical render node materials were/are still using that? But at least I do not see a reason why light portals and polygon lights must be standardized in this manner (we hide that group except for physical). I would recommend reaching out to us with a mail and the request to remove that "feature", i.e., make this more a program management than a programming thing. I cannot guarantee that we will do this, as there might be some special material management reasons why this has been done, but the starting point would be to have a PM discussion. Cheers, Ferdinand
  • 0 Votes
    3 Posts
    670 Views
    kangddanK
    @ferdinand Thank you !
  • How to scale all objects in a scene at once?

    2
    0 Votes
    2 Posts
    916 Views
    ferdinandF
    Hello @j_vogel, 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: Asking Questions. About your First Question As lined out above, please follow our support procedures. Thread necromancy usually leads to problems, at least when that much time has passed, I have forked this thread. Please also follow our rules about Support Procedures: Asking Questions, in short, we do not answer "please implement this or that for me". The parameter DOCUMENT_DOCUNIT in a document is just something that is added to things like the coordinate manager, to set the unit and a multiplier for the numbers shown there. It will not scale the actual geometries (as it otherwise would be destructive) and therefore does not affect the view port. To scale all elements in the scene, you must scale all elements . You can use the command which we implemented for that, what is talked about above and which can be invoked with the button in the document scale settings. But you then have to use its UI, which is I guess not what you want. So, you would have write something like that yourself. But there is currently no premade scene traversal in Python which can be a bit daunting for beginners (will change with the next major release). Carrying out the scaling itself is not that hard, although this complexity can also vary based on the content. Since I know you have beta access: You can also pick the latest beta build, the traversal stuff is already in there. Cheers, Ferdinand Code """Demonstrates how to scale all objects in a scene by a given factor. """ import c4d SCALE_FACTOR: c4d.Vector = c4d.Vector(2) # Scale factor for the objects, we pick a uniform scale of 2. doc: c4d.documents.BaseDocument # The currently active document. def IterateTree(node: c4d.GeListNode, yieldSiblings: bool = False) -> c4d.GeListNode: """Iterates over all descendants of the given #node and optionally its next siblings. In the next major release, there will be (finally) built-in scene traversal functions in Python. The one to pick for this case would be `mxutils.IterateTree`. Its signature is compatible with what I did here. """ def iterate(node: c4d.GeListNode) -> c4d.GeListNode: if not node: return yield node for child in node.GetChildren(): yield from iterate(child) while node: yield from iterate(node) node = node.GetNext() if yieldSiblings else None def main() -> None: """Called by Cinema 4D when the script is being executed. """ # Iterate over all objects in the document and scale them. for node in IterateTree(doc.GetFirstObject(), yieldSiblings=True): node.SetMl(node.GetMl() * c4d.utils.MatrixScale(SCALE_FACTOR)) c4d.EventAdd() if __name__ == '__main__': main() edit: you should of course use the local and not global matrix, as you otherwise will scale things multiple times.
  • Importing pythonapi from ctypes freezes C4D

    s24 macos python
    7
    0 Votes
    7 Posts
    2k Views
    ferdinandF
    Hey @lasselauch, We are not able to reproduce this crash on an Intel, M1, or M3 MacBook with 2024.4.0. Please provide and submit a crash report when this is still a problem for you. I would also recommend reinstalling Cinema 4D to rule out that your installation was damaged. Cheers, Ferdinand
  • Adding image to GeDialog - Python Plugin/Script

    python
    8
    0 Votes
    8 Posts
    2k Views
    DunhouD
    @ferdinand fine for that, like I think, this is not perfect solution for this, thanks for your confirm! Cheers~ DunHou
  • Transform coordinates of a polygon's points

    5
    0 Votes
    5 Posts
    2k Views
    i_mazlovI
    Hi @SmetK, Please note that we have a great Matrix Manual with code samples. You can also check our github repository for the geometry examples, e.g. the Polygon Object example. For your further questions I kindly encourage you to create new thread and shape your posting according to how it's described in our Support Procedures: Asking Question. Cheers, Ilia
  • Importing/loading sound file to scene via Python

    python 2024 windows
    4
    1
    0 Votes
    4 Posts
    858 Views
    i_mazlovI
    Hi @ezeuz, Great to hear you've figured it out and thanks for sharing the solution with the community! Cheers, Ilia
  • Clearing the list of a ComboBox (Dropdown) - Python API

    python
    3
    0 Votes
    3 Posts
    954 Views
    E
    @ferdinand Thanks a ton again! Yeah that dynamic UI is indeed something that fits perfectly with my current case, and possibly some other features I want to implement. Tho, I will revisit it later once I get to creating an MVP for my plugin. So I will use FreeChildren() for now.
  • Memory Leak? How to fix loosing memory with python generator?

    python macos 2024
    5
    0 Votes
    5 Posts
    1k Views
    M
    Hi sorry for not answering this topic earlier, I finally found some time to investigate and sadly there is nothing you can do in your side, this memory leak is coming from the Illustrator Importer and can be big, since all the points and tangents of the file are leaking. A fix will be available in the next update. Thanks for the report ! Cheers, Maxime.
  • 0 Votes
    4 Posts
    1k Views
    S
    @ferdinand Just ran into the same problem. Thank you for the solution!
  • Populating a Bitmap Shader without a file

    c++
    10
    0 Votes
    10 Posts
    3k Views
    D
    Hey Ferdinand, thanks again for the quick reply. What we're going to do is basically have a "cache" location, as you said, where we will save the users' textures when they bake the stack. I would also prefer the approach you showed using the document's asset repository, but since the textures might be very heavy, it would probably lead to very large document sizes for a lot of users, especially if they use several textures/have several stacks with textures. I'm working on implementing solution 1.1, using the Message system to move things around. However, thank you very much for the code example, I will probably use something similar with other assets that are not as large as textures. Cheers, Daniel
  • 0 Votes
    5 Posts
    1k Views
    i_mazlovI
    Hi @mikeudin , To me it sounds pretty much like this issue here: issue with inserting fieldlayers in r2024, particularly after I couldn't reproduce this issue with the internally available next version of cinema. Cheers, Ilia
  • Tool Tabs and foldable groups

    python
    2
    0 Votes
    2 Posts
    669 Views
    ferdinandF
    Hello @BretBays, Thank you for reaching out to us. Please provide code and a clear problem description as statements like `How do you create the tabs ... I tried X but it only creates tabs' are a bit confusing for us. There are two ways to create tab interfaces, one is via groups and the method GeDialog.TabGroupBegin and the other one is via CUSTOMGUI_QUICKTAB. We have a code example for it in Python here. The "tab-look" of descriptions, i.e., what you usually see in the Attribute Manager, is achieved with CUSTOMGUI_QUICKTAB. There is no group folding in dialogs anymore, this feature has been deprecated (we probably should update the docs). There is a difference between dialogs and descriptions. They use similar UI elements but they are not the same. Folding in descriptions is still supported, in dialogs not (but you can implement it yourself when you really need it). You should also be aware that there are ToolData and DescriptionToolData plugins. The former tool type uses dialogs to display its UI in the Attribute Manager, and the latter uses descriptions. Most tools these days in Cinema 4D are implemented as DescriptionToolData which leads to a distinctive look and set of features which are not trivial to emulate with a plain ToolData. ToolData is exposed in Python and C++, DescriptionToolData is only exposed in C++. My colleague @m_adam likes to point out whenever this subject comes up that the type SculptBrushToolData is exposed in Python (which is derived from DescriptionToolData) and that you can (ab)use it to implement a DescriptionToolData in Python. I never tried doing that and what consequences that would have (and neither did Maxime AFAIK). For my taste that would be way too hacky, and I would rather just live with the minor restrictions of ToolData plugin and its dialog based UI. Cheers, Ferdinand
  • 0 Votes
    6 Posts
    1k Views
    O
    Thanks a LOT @ferdinand and @mikeudin , for sharing your insights and suggestions! They are definitely valuable and am sure will come in handy in the future!!!
  • How to check if document is rendering?

    python
    6
    0 Votes
    6 Posts
    2k Views
    P
    Hey sorry for gravedigging. i have the problem that my tag plugin recognises the difference between rendering and not rendering. unfortunately it also always changes the state in the doc itself and not only in the doc that is rendered [image: 1720870787719-6484d884-61c7-454c-a256-0f1167238772-grafik.png]
  • BitmapButton not work

    2024 python
    5
    1
    0 Votes
    5 Posts
    1k Views
    chuanzhenC
    @ferdinand Thanks
  • why my interface is sealed in maxon::Result?

    r25 c++
    4
    0 Votes
    4 Posts
    1k Views
    Y
    @ferdinand cool. this really helpful!