Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. John_Do
    • Profile
    • Following 0
    • Followers 0
    • Topics 9
    • Posts 33
    • Best 1
    • Controversial 0
    • Groups 0

    John_Do

    @John_Do

    1
    Reputation
    11
    Profile views
    33
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    John_Do Unfollow Follow

    Best posts made by John_Do

    • RE: Copy children to selection with GetClone()

      Hi @ferdinand, thanks for the feedback, I've got it working with your suggestion. The method B was correct but the undo part was wrong ( the undo step was applied on the original objects instead of the new ones, thus leading to a mess when performing an undo). I also added the bit part to keep new objects folded in the OM. Here is the code :

      # CopyDeformers
      
      import c4d
      
      doc = c4d.documents.GetActiveDocument()
      
      
      def main():
      
          doc.StartUndo()
      
          objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)
      
          if len(objs) >= 2:
              # Get the last selected object
              active = objs.pop(-1)
      
              # Get the deformers
              deformers = [i for i in active.GetChildren()]
      
              # Copy deformers to selection
              if deformers:
                  for o in objs:
                      for d in deformers[::-1]:
                          dcopy = d.GetClone(c4d.COPYFLAGS_NO_BITS)
                          doc.InsertObject(dcopy, parent=o)
                          doc.AddUndo(c4d.UNDOTYPE_NEW, dcopy)
                      o.SetBit(c4d.BIT_MFOLD)
      
          doc.EndUndo()
      
          c4d.EventAdd()
      
      
      if __name__ == '__main__':
          main()
      
      
      posted in Cinema 4D SDK
      John_DoJ
      John_Do

    Latest posts made by John_Do

    • RE: Finding duplicate materials - Octane Render

      Hi, sorry for bringing back up this topic but the Compare() method still gives weird results in 2024.5.1.

      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.

      posted in Cinema 4D SDK
      John_DoJ
      John_Do
    • CopyBitmapToClipboard gamma issue

      Hello,

      I'm writing a script to render objects in a specific document and copy the rendered image into the clipboard. Rendered image is fine, but
      the one pasted from the clipboard miss a gamma transform, it's darker.
      I've read about color profiles here and played a bit with it but it doesn't change the result. Any tip to fix that?

      abe57d25-112d-4f5d-adea-b7ff5c44320b-image.png

      Color Management is in Basic Mode with LWF enabled, and I'm rendering with Corona, no OCIO involved.

      Thanks !

      posted in Cinema 4D SDK python 2024 windows
      John_DoJ
      John_Do
    • RE: Copy info from one Object to other Object

      @Manuel Thanks ! Still here in 2024.5.1

      posted in Cinema 4D SDK
      John_DoJ
      John_Do
    • RE: CommandData.Message() implementation and Message concepts

      Hi @ferdinand,

      As always thank you very much for the detailed answer. Please mind that I'm not a seasoned programmer at all, not even a programmer. That doesn't excuse anything, but there are likely many mistakes in my messages.

      Thank you for reaching out to us. I must point out that your question is out of scope of support because you are using Corona. Thrid party libraries are out of scope of support as declared in our Forum Procedures. Please understand that we cannot run, debug, or help you with foreign APIs.

      I know that Corona is out of the scope of this forum since I've already posted some questions about it, and we already discussed about it. But the objects and data particular to Corona are based on the class and methods of the Cinema 4D API as far as I can tell. If it is still out of scope let me know. I've already mailed the Corona devs and had a bit of help few years ago but that's all. I made a diagram recently that shows how the Node Editor is integrated through the API.

      Messages
      Thanks for the explanation regarding messages, but I still don't get it. I think it doesn't make sense to me that I have to tell Cinema something has changed since something has really changed ( = through the interpreted Python code) from my point of view when executing the code. My lack of programming background maybe doesn't help me here.
      So in most cases, messages are used to trigger UI events / updates?
      How do I know if I have to send a message or not to an object to update it ( or it's representation in the current document )?
      How should I leverage CommandData.Message() and what is the difference with calling C4DAtom.Message / SendCoreMessage in Execute ? I'm really puzzled here.

      What is more likely going wrong here, is how you assemble your shader graph. For your first plugin, this little stretch of code is trying to do a lot all at once. And especially when I would run into problems, I would try to reduce that. In play comes here then how the Corona API works. It is probably best when you ask the Corona team for help with that.

      It's quite possible, but the thing is the code do exactly what I want (inserting a filter shader on top of any selected shader). But maybe I take too many shorcuts or that things are done in a unorthodox way. What would be the proper way to do this ? Split what's happening in Execute into multiple methods ?

      ¹ An added event will not be carried out right away but when the event queue is resolved. I.e., having one EventAdd at the end of your operation is equivalent to having multiple calls in one operation. EventAdd will only be carried out once you give control back to Cinema 4D.

      Is it a problem ? The command is really simple and linear, really it's just a script wrapped in a class' method.

      CommandData plugins also call EventAdd on their own after their Execute ran, so you do not have to do it yourself.

      I suspected that but I don't get the same result if I comment out EventAdd. Ui doesn't update and links are missing on the node widgets. So what's happening here ?

      alt text
      alt text
      alt text

      posted in Cinema 4D SDK
      John_DoJ
      John_Do
    • CommandData.Message() implementation and Message concepts

      Hi,

      I'm writing my first plugin and I have a hard time understanding how to implement the Message method of the CommandData class.

      The command is straightforward: it creates new shaders and the corresponding widgets for the Corona Node Material Editor. So in essence all the command is doing is modifying BaseList2D objects (shaders and node widgets) which are parented to another BaseList2D object (the Node Editor view).
      In this case, using EventAdd() refresh the Node Editor view instantly and populate it with new nodes, shaders, and links. On the other hand, using C4DAtom.Message() gives partial results = broken objects and links. And for the Message method, I just don't get it, even after looking at the docs and the example plugins extensively.

      class AddFilterShader(c4d.plugins.CommandData):
      
          def Execute(self, doc):
      
      
              context = CoronaNodeContext()
              nodes = context.active_nodes
              active_view = context.active_view
      
      
              if nodes:
      
                  parent_shader = set()
      
                  for node in nodes:
                      # Get the shader represented by the node widget
                      node_shader = node[2001]
      
                      # Skip if its a material
                      if isinstance(node_shader, c4d.BaseMaterial):
                          c4d.StatusSetText("Can't run on a material")
                          continue
      
                      # Filter shader
                      filter = c4d.BaseShader(c4d.Xfilter)
                      filter[c4d.SLA_FILTER_TEXTURE] = node_shader
      
                      # We check for a parent node, if not
                      # we parent to the Corona Node shaderhook
                      parent = node_shader.GetUp()
                      if parent is None:
                          parent = node_shader.GetMain()
                      # Add the parent for further operations
                      parent_shader.add(parent)
      
                      # Look for the link in the parent
                      if isinstance(parent,c4d.BaseMaterial) or isinstance(parent, c4d.BaseShader) :
                          parent_bc = parent.GetDataInstance()
                          index = bc_get_id(parent_bc, node_shader)
                          parent_bc.SetLink(index, filter)
      
                      # Create a new widget for the shader
                      cnode = create_node_widget(filter)
      
                      # Insert shaders
                      node_shader.InsertUnder(filter)
      
                      if isinstance(parent,c4d.BaseMaterial):
                          parent.InsertShader(filter)
                      else:
                          filter.InsertUnder(parent)
      
                      # Insert widget
                      cnode.InsertUnder(active_view)
      
                      # Selection state
                      node.DelBit(c4d.BIT_ACTIVE)
                      cnode.SetBit(c4d.BIT_ACTIVE)
      
                      # Update the node and the shaders
                      # Doesn't work ? 
                      node.Message(c4d.MSG_UPDATE)
                      parent.Message(c4d.MSG_UPDATE)
      
              # Update the view
              # Doesn't work ? 
              active_view.Message(c4d.MSG_UPDATE)
      
              c4d.EventAdd()
      
              return True
      

      As you can see I tried the C4DAtom.Message() command inside the Execute method but it didn't get any better.

      So how should I use the Message method to get the same result as with EventAdd()? Or should I not bother and use the function? But even so, I'd like to understand the Message concept.

      Thanks !

      posted in Cinema 4D SDK python 2023
      John_DoJ
      John_Do
    • RE: Copy children to selection with GetClone()

      Hi @ferdinand, thanks for the feedback, I've got it working with your suggestion. The method B was correct but the undo part was wrong ( the undo step was applied on the original objects instead of the new ones, thus leading to a mess when performing an undo). I also added the bit part to keep new objects folded in the OM. Here is the code :

      # CopyDeformers
      
      import c4d
      
      doc = c4d.documents.GetActiveDocument()
      
      
      def main():
      
          doc.StartUndo()
      
          objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)
      
          if len(objs) >= 2:
              # Get the last selected object
              active = objs.pop(-1)
      
              # Get the deformers
              deformers = [i for i in active.GetChildren()]
      
              # Copy deformers to selection
              if deformers:
                  for o in objs:
                      for d in deformers[::-1]:
                          dcopy = d.GetClone(c4d.COPYFLAGS_NO_BITS)
                          doc.InsertObject(dcopy, parent=o)
                          doc.AddUndo(c4d.UNDOTYPE_NEW, dcopy)
                      o.SetBit(c4d.BIT_MFOLD)
      
          doc.EndUndo()
      
          c4d.EventAdd()
      
      
      if __name__ == '__main__':
          main()
      
      
      posted in Cinema 4D SDK
      John_DoJ
      John_Do
    • Copy children to selection with GetClone()

      Hi all,

      I'm writing a script to copy the children objects of an "active" object to other selected objects using the GetClone() function, but I can't get it to work as intended, I feel I'm missing something obvious. The intent is to copy deformers from the active object to all others (but I don't want to limit the function to deformers).

      import c4d
      
      doc = c4d.documents.GetActiveDocument()
      
      
      def main():
      
          doc.StartUndo()
      
          objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)
      
          if len(objs) >= 2:
              # Get the last selected object
              active = objs.pop(-1)
      
              # --------------------------------- Method A --------------------------------- #
      
              # Get the deformers
              deformers = [i.GetClone(c4d.COPYFLAGS_NO_BITS) for i in active.GetChildren()]
      
              # Copy deformer to selection
              if deformers:
                  for o in objs:
                      for d in deformers[::-1]:
                          doc.InsertObject(d, parent=o)
                          doc.AddUndo(c4d.UNDOTYPE_NEW, d)
      
              # --------------------------------- Method B --------------------------------- #
      
              # # Get the deformers
              # deformers = [i for i in active.GetChildren()]
      
              # Copy deformer to selection
              # if deformers:
              #     for o in objs:
              #         for d in deformers[::-1]:
              #             doc.InsertObject(d.GetClone(c4d.COPYFLAGS_NO_BITS), parent=o)
              #             doc.AddUndo(c4d.UNDOTYPE_NEW, d)
      
          doc.EndUndo()
      
          c4d.EventAdd()
      
      
      if __name__ == '__main__':
          main()
      
      

      The method A kinda works but do only one copy and stop without error. I didn't see anything meaningful after printing the lists content in various steps of the script, everything seems ok from my understanding.
      The method B kinda works too and successfully copy deformers on all the selected objects but the undo is very buggy ( multiple steps rather than one as intended, delete deformers on the active object).

      Also the newly inserted objects open the hierarchies in the OM, is it because it's the default behavior of C4D when creating child objects ? Do I have to toggle BIT_OFOLD manually ?

      Thanks !

      posted in Cinema 4D SDK python 2024
      John_DoJ
      John_Do
    • RE: Undo method for LayerShaderLayer

      Oof, that's an unfortunate end for me but at least I have a clear explanation. Thanks @ferdinand

      posted in Bugs
      John_DoJ
      John_Do
    • RE: Undo method for LayerShaderLayer

      Hi @ferdinand , have you got a chance to look at the issue from the Cinema 4D side ?

      posted in Bugs
      John_DoJ
      John_Do
    • RE: Undo method for LayerShaderLayer

      Hi @ferdinand ,

      Thank you so much for taking the time to test all of this. Out of curiosity I tried your code on my side, and the same thing happen on native Cinema 4D materials.

      Please let me know if you find the root cause of the bug, in the meantime I'll publish the script with all necessary warnings.

      Have a nice day

      posted in Bugs
      John_DoJ
      John_Do