• Python - Set Take render state

    python
    4
    1
    0 Votes
    4 Posts
    641 Views
    J
    @ferdinand Okay I will do it in the future. Thanks for the code snippet, always helps to learn!
  • OpenUSD (pxr) library in c4d python

    python 2024
    17
    0 Votes
    17 Posts
    6k Views
    i_mazlovI
    Hi @llealloo, please excuse the delayed answers. To the best of my knowledge in the near future there're no plans for integrating usd python bindings into c4d python system. By the way, with the 2025.0 release internal usd library was properly updated to OpenUSD 24.08, so we expect the double loading usd issue to be solved under OSX. Cheers, Ilia
  • UserArea drag and drop example?

    windows 2024 python
    6
    0 Votes
    6 Posts
    2k Views
    K
    I tried using a timer to solve this problem, but I still want to know if there is a more direct way import c4d import threading from c4d.gui import GeUserArea, GeDialog GADGET_ID_GEUSERAREA = 10000 class DropArea(GeUserArea): def __init__(self): # Used to store all objects involved in the drag-and-drop operation self.currentDragObjects = [] # Flag to indicate whether a drag operation is in progress self.isDragging = False # Define a timer to delay the handling of the drag completion self.dragTimer = None def Message(self, msg, result): # Handle drag-and-drop messages if msg.GetId() == c4d.BFM_DRAGRECEIVE: # Check if the drag was lost or canceled if msg.GetInt32(c4d.BFM_DRAG_LOST) or msg.GetInt32(c4d.BFM_DRAG_ESC): self.isDragging = False return self.SetDragDestination(c4d.MOUSE_FORBIDDEN) # If the drag just started, clear the previous object list if not self.isDragging: self.currentDragObjects = [] # Initialize the storage list self.isDragging = True # Mark the beginning of the drag # Verify if it is a valid drop area if not self.CheckDropArea(msg, True, True): return self.SetDragDestination(c4d.MOUSE_FORBIDDEN) # Get the dragged file object dragInfo = self.GetDragObject(msg) if dragInfo is not None: dragObject = dragInfo['object'] # Check if the object already exists in the list to avoid duplicates if dragObject not in self.currentDragObjects: self.currentDragObjects.append(dragObject) # Reset the timer to delay the handling of drag completion if self.dragTimer is not None: self.dragTimer.cancel() # Set a short timer (e.g., 0.2 seconds) to determine if the drag operation is complete self.dragTimer = threading.Timer(0.2, self._finalize_drag) self.dragTimer.start() # Set the mouse cursor to a valid state return self.SetDragDestination(c4d.MOUSE_MOVE) # Call the base class Message() method to handle other messages return c4d.gui.GeUserArea.Message(self, msg, result) def _finalize_drag(self): # Delayed execution to ensure all dragged objects have been received self.isDragging = False if self.currentDragObjects: # Print all dropped files print(f"Dropped files: {self.currentDragObjects}") # Additional logic can be executed here, e.g., handling file paths or other content # Clear the object list for the next drag-and-drop operation self.currentDragObjects = [] # Redraw the user area (if UI update is needed) self.Redraw() class ExampleDialog(GeDialog): geUserArea = DropArea() def CreateLayout(self): self.SetTitle("Drag Area") if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=1, rows=0, title="", groupflags=0, initw=100, inith=100): self.GroupBorderSpace(8, 8, 8, 8) self.GroupSpace(2, 2) # Add the user area gadget self.AddUserArea(GADGET_ID_GEUSERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 200, 200) # Attach the user area to the gadget self.AttachUserArea(self.geUserArea, GADGET_ID_GEUSERAREA) self.GroupEnd() return True if __name__ == "__main__": global dlg dlg = ExampleDialog() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=200, defaulth=200)
  • How to set the active documents preview image

    windows python
    2
    0 Votes
    2 Posts
    412 Views
    ferdinandF
    Hey @MMayrh, Thank you for reaching out to us. This is not how this parameter works. The parameter DOCUMENT_PREVIEW_IMAGE is of data type BitmapButtonStruct, not of BaseBitmap. [image: 1731082043337-54c636b2-05c8-4e3a-af41-9edf7e80bd24-image.png] The documentation is a bit misleading here. This is not the document preview bitmap, but sort of the preview bitmap delegate. I.e., an entity that is used to retrieve a preview bitmap (for a document in this case). A BitmapButtonStruct wraps a node, an ID, and a dirty flag. [image: 1731082143508-3e4681a7-7db6-45b7-a1da-5279cc028cf2-image.png] This parameter does not make too much sense in the Python API, here is what the C++ API does when the parameter is access for a document: [image: 1731082401202-459e7ff6-a8fe-4abf-ae35-adc803c17170-image.png] I.e., it returns itself (the doc), the ID of the parameter (DOCUMENT_PREVIEW_IMAGE) and the dirty state of its internal current preview bitmap as the BitmapButtonStruct bbs. What you could technically try, is implement a node, e.g., an object, and then set that object as the preview provider for a document. Your node would for that have to implement MSG_DESCRIPTION_GETBITMAP, because that is what effectively will be called. But that is all very theoretical, DOCUMENT_PREVIEW_IMAGE is largely unused in our code base, and I do not see any implemnation for the SetParameter part. So, the document will likely just ignore you trying to overwrite its preview provider. There could be some base implemenation kicking in, but I doubt it. But what you definitely cannot do, is just set there a bitmap to overwrite the preview image of the document (assuming that was what you wanted to do). That would also not make too much sense since a document is constantly recalculating its preview image. So, on the next update that image would be gone (if it would work like that). Cheers, Ferdinand
  • How to Swap location in Object Manager

    c++ s26 windows
    3
    2
    0 Votes
    3 Posts
    713 Views
    P
    @ferdinand Thank you very much for your reply
  • TempUVHandle always None! Why?

    r21 python windows
    3
    0 Votes
    3 Posts
    703 Views
    ThomasBT
    @i_mazlov Thank you very much for the hint with the texture view and for the helpful links. The second thread I have already read, but was not able to find the solution so far. I study these examples. Thank you.
  • Finding duplicate materials - Octane Render

    python r19
    17
    0 Votes
    17 Posts
    3k Views
    John_DoJ
    Hi, sorry for bringing back up this topic but the Compare() method still gives weird results in 2024.5.1. [image: 1730828935913-cinema_4d_d5fwj9o4rq.gif] Comparing a material duplicated with Ctrl-Drag returns sometimes True, sometimes False Comparing a material against a copy-pasted version (in the same scene) always returns False Comparing two identical materials both copy-pasted together in one-go in another scene always returns False, even if True was returned in the original scene. Please note that I'm using Corona Materials here but results are the same with the Standard Material.
  • Monitoring object parameter changes

    c++
    8
    0 Votes
    8 Posts
    1k Views
    M
    Thanks you!
  • Change settings of XCode project generated by project tool

    c++ macos
    3
    0 Votes
    3 Posts
    722 Views
    B
    Thank you, @f8bet00net. Yeah, I remember I had gone though this with you before. But recently, we found there is a way to customize TreatSpecificWarningsAsErrors settings in projectdefinition.txt for MSVCBase.props for windows VS projects. So I asked this question again just to double confirm if we could do similar things for MacOS XCode settings. Thanks for confirming this is not possible on MacOS.
  • How to obtain the color of each ball in each frame

    s26 windows c++
    2
    3
    0 Votes
    2 Posts
    588 Views
    ferdinandF
    Hello @pchg, Thank you for reaching out to us. Please note that we normally expect question to be accompanied by code. It is also still unanswered in which context you want to do this: As an effector, as a Script Manager script, etc. Cheers, Ferdinand Result [image: 1730718564670-347fc2f0-a0cd-4583-816b-b3e38fda2280-image.png] Code """Reads out the particle data of a MoGraph Cloner object. Must be run as a Script Manager script in Cinema 4D with a MoGraph Cloner object selected. """ import c4d doc: c4d.documents.BaseDocument # The currently active document. op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. def main() -> None: """Called by Cinema 4D when the script is being executed. """ if not op or not op.CheckType(c4d.Omgcloner): raise ValueError("Please select a MoGraph Cloner object.") # Get the particle data from the cloner object. data: c4d.modules.mograph.MoData = c4d.modules.mograph.GeGetMoData(op) if data is None: return # Get the transform and color data for the particles. matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX) colors: list[c4d.Vector] = data.GetArray(c4d.MODATA_COLOR) # Iterate over all particle data and do something with it. If we were in an effector, we could # also write back data. Technically, we could also write back data here, but it would be volatile. for i in range(data.GetCount()): matrix: c4d.Matrix = matrices[i] color: c4d.Vector = colors[i] print(f"Particle {i} at {matrix.off} with color {color}") if __name__ == '__main__': main() And here is the 2024.0.0 effector full control mode default code which more or less is very similar but also writes data. """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 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 # The transform of both the generator and the effector, the transforms of all particles, and # finally the position of the effector as if it would live in the coordinate system of the # generator. mgGen: c4d.Matrix = gen.GetMg() mgEff: c4d.Matrix = op.GetMg() matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX) q: c4d.Vector = ~mgGen * mgEff.off # For each particle compute a weight `w` for how much the particle should be attracted to the # attraction point `q`, and then blend the particle position between the attraction point and # its own position `p`. for i in range(data.GetCount()) : p: c4d.Vector = matrices[i].off w: float = c4d.utils.RangeMap((mgGen * ~mgEff * p).GetLength(), 0., 100., 0., 1., True) ** 3. matrices[i].off = c4d.utils.MixVec(q, p, w) # Write the new data back. data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent()) return True
  • How to modify the index

    s26 c++ windows
    4
    1
    0 Votes
    4 Posts
    892 Views
    P
    @ferdinand Thank you for your reply
  • FontData BaseContainer IDs

    python r20
    4
    0 Votes
    4 Posts
    907 Views
    S
    @m_adam I still don't understand how to get the id of parameters? How do I know that this parameter has id 500?
  • Natvis settings not working?

    windows c++
    5
    0 Votes
    5 Posts
    907 Views
    ferdinandF
    Hey @bojidar, well, we do not write these object views (the natvis for MSVC and the Python scripts for Xcode) for public usage but for internal usage. That we hand them out to third parties is just a courtesy. When we are looking at maxon::GraphNode, <Type Name="maxon::GraphNode"> <DisplayString Condition="_mem[0] != 0">{((maxon::NodePath*)&amp;_mem[0]),na}</DisplayString> <!-- Root will have empty path and valid graph --> <DisplayString Condition="_mem[0] == 0 &amp;&amp; _graph._object != 0">Root</DisplayString> <DisplayString Condition="_mem[0] == 0">nullptr</DisplayString> <Expand> <Item Name="Path">(((maxon::NodePath*)&amp;_mem[0])),na</Item> <Item Name="Kind" Condition="_mem[0] != 0 &amp;&amp; _graph._object != 0">(maxon::NODE_KIND)((((nodes.module.xdl64!maxon::nodes::NodePathImpl::CountAndKind*) &amp; (*(nodes.module.xdl64!maxon::nodes::NodePathImpl**) &amp; _mem[0])->_path))->kind &amp; 0xFF)</Item> <Item Name="Kind" Condition="_mem[0] == 0 &amp;&amp; _graph._object != 0">maxon::NODE_KIND::NONE</Item> <Item Name="Info">((nodes.module.xdl64!maxon::nodes::NodesGraphModelImpl::Info*)this->_mem),na</Item> <Item Name="Graph">(this->_graph)</Item> <Item Name="Graph Storage">(this->_mem)</Item> </Expand> </Type> then there are indeed quite a few references to the implementation (which means that this cannot work in the public API). You could rip these out to make it work, but would then be left with only a small subset of the debug attributes. But that would be up to you. In general, you can expect the Cinema API to be more conservative and almost all object views working there, while the Maxon API is generally more internal in nature. Cheers, Ferdinand
  • Bake animation in the background

    python
    2
    0 Votes
    2 Posts
    536 Views
    i_mazlovI
    Hi @brian-michael, I've forked your posting in a dedicated thread. For your following postings please stick to our guidelines, which you can find in the Support Procedures, namely: Singular Subject: From all this follows that a topic must have a singular and sparse subject tied to a specific problem especially when it comes to N-years-old threads Regarding your question, please share more context on what specifically you're trying to do, because depending on that you can end up in a completely different ways of approaching your goal. For example, if you'd like to bake animation in a "read-only manner" (just take the object transformations and store/send them somewhere), then the suggested approach would be to clone document and process it in a separate C4DThread. You can check Ferdinand's code example on the exact same topic in application to rendering document: RenderDocument/PythonCallBack : how to display progress prints during the render. However, with such approach you're limited to not being able to modify original document (because you'd use the cloned document instead of the active one). Cheers, Ilia
  • Detect error-causing nodes in XPresso

    python
    4
    1
    0 Votes
    4 Posts
    746 Views
    K
    Hi @i_mazlov , Unfortunately, the python node approach is not effective for my use case, so I may have to emulate the error conditions on my own for each node. In any case, thank you for your answer.
  • Vertex Map Tag not in sync error

    python 2024 windows
    3
    1
    0 Votes
    3 Posts
    634 Views
    D
    Hi Ilia, Thank you very much, I was not aware of that! Cheers!
  • Global static classes?

    c++
    4
    0 Votes
    4 Posts
    629 Views
    ferdinandF
    As I said, you will run into access violations when you instantiate your fields on the class instead of the Init function. And as I also said, in your concrete case it would probably even be fine if you would directly do it in the class scope. But I would advise against breaking this rule. There is nothing to optimize here, either return a new instance when this is only called once in a blue moon and you do not want to bother with initializing a field. Or define a field and initialize it up in NodeData::Init. And no, scene elements (NodeData) should not share data on their class. We have types in the Maxon API to deal with this when you really want some heavy data structure which shall be initialized exactly once, but that is total overkill in this case. Cheers, Ferdinand
  • Refresh viewport after updating RenderData width and height

    windows python
    8
    0 Votes
    8 Posts
    1k Views
    S
    Hello @ferdinand ! Thanks for answer it is very clear, i will use virtual resolution from now on
  • Correct OCIO Color Value Conversion via Python?

    windows python 2024
    3
    0 Votes
    3 Posts
    596 Views
    B
    Hey Ferdinand, Thank you for the quick response! Ah ok I see. Thank you for the provided information, I will have a look at it. But I can also wait for the moment. My work arround for now would be to simply set everything up / import the parameters and colors with color management set to 'Basic' and manually doing the conversion via 'Convert to OCIO' in the Project settings. Thats giving me the correct result. But thanks again! Cheers, Ben
  • Programing a Tabulated BRDF Node / Shader - possible ?

    2024
    6
    1
    0 Votes
    6 Posts
    1k Views
    ferdinandF
    Hey, Out of curiosity, I did some poking in Redshift, and what I forgot, is that you are in principle unable to escape the current shading context of a sample in Redshift. I.e., you cannot just say, "screw the current UV coordinate, please sample my texture 'there'" due to the closure thing which Redshift has going. With the Standard Renderer, you can do the following, which is pretty close. I compute the v (i.e., view angle coordinate) as described above. Standard also does not give you directly light ray angles, but you can get the light contribution where I use the diffuse component of the light(s) as a faksimile: High diffuse = high angle of incident/light contribution. [image: 1730128355045-82ee51e1-15a9-487b-8cb0-91eec633352e-image-resized.png] Fig. I: A crude iridescence setup in Standard. test.png is your texture from above, I forgot to take the inverse of values as 1 - x. view_angle.zip In Redshift you cannot do the same light contribution hack, and I currently do not see how you could set the sampling coordinate of the texture in the first place. Maybe the Redshift pro's know more. Cheers, Ferdinand