Copying Objects from inside Character Object



  • On 01/07/2018 at 08:08, xxxxxxxx wrote:

    I'm trying to use the Character Object to create a rig that uses deformers other than skin (Squash and Stretch, Spline Wrap, etc.) But since objects inside the Character's hierarchy can't be dragged around, my plan was to write a command that copies of the deformers and pastes them outside of the Character Object, which means I can drag them under mesh objects. (The deformer has an XPresso tag on it to drive the parameters. This makes it react to the rig even when it's copied.)

    The problem is, I can't find any way to copy the deformer and its tags. I've tried CallCommand() with copy-paste, but it's not allowed. I tried CopyTo(), GetClone(), CopyTagsTo(), but they don't work either; they can only duplicate the objects within the Character Object.

    The only way that kinda works is to manually create new objects and tags, and individually copy the parameters of the original deformers. But I couldn't copy the contents of the XPresso tag this way...

    Is there a solution that doesn't require me to use Current State to Object? Very worst case scenario is I create a command that calls CStO, and deletes all objects except for the deformers. But I want to avoid that if possible...



  • On 02/07/2018 at 06:23, xxxxxxxx wrote:

    Hello,

    I'm not an expert on the "Character" object, so maybe I'm missing something. What deformers/modifiers exactly are you talking about? The "Skin" deformer is typically a child object of the deformed mesh and not part of the object hierarchy created by the "Character" object.

    best wishes,
    Sebastian



  • On 02/07/2018 at 07:22, xxxxxxxx wrote:

    Yes, the Skin deformers are generated outside of the hierarchy. From what I know, the Bind command is internally called to do that.

    But that means the only deformer you could get out of the Character Object is Skin.

    What I want to do is to create a 'template' of a deformer inside the Character Object (Jiggle, Splinewrap, Null that's PSR-constrained to a controller/spline, etc.), then copy-paste that deformer outside of the Character Object that can be used on my character's mesh.

    The deformers I want to copy-paste have XPresso tags, so I can't just create new objects. But I can't copy because the deformers are protected by the Character Object.

    EDIT:
    Here's an example character template I made to show what I'm trying to do:
    https://drive.google.com/open?id=1VLgspLNhZs301d3LWtGtVvzrcPcroI-F
    In my animation scene, I want to create a copy of the "bind" hierarchy from the Character Object so that I can attach them to objects.



  • On 03/07/2018 at 01:36, xxxxxxxx wrote:

    Hello,

    so you want to create a custom "Character Object" template and then copy object that were created using these custom templates?

    The issue of course is that the objects created by the "Character Objects" must not be moved or modified by the user. So the "Character Object" protects these child objects. If you want to copy elements from the "Character Object" hierarchy, you must remove this protection.

    The objects are "protected" by setting various NBits. You would have to clear these NBits to get objects that behave like a normal object.

      
      # array of clones  
      clones = []  
      
      element = op  
      
      # check child objects  
      # real code should of course also check GetNext()  
      while element is not None:  
      
          print(element)  
            
          # clone object  
          clone = element.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)  
            
          # store clone in array  
          if clone is not None:  
              print("cloned" + str(clone))  
              clones.append(clone)  
            
            
          element = element.GetDown()  
            
      # insert clonse  
      for clone in clones:  
          print("insert " + str(clone))  
            
          # clear bits  
          clone.ChangeNBit(c4d.NBIT_OHIDE, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_SUBOBJECT, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_SUBOBJECT_AM, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_LINK_ACTIVE, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_THIDE, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_NOANIM, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_NOSELECT, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_EHIDE, c4d.NBITCONTROL_CLEAR)  
          clone.ChangeNBit(c4d.NBIT_PROTECTION, c4d.NBITCONTROL_CLEAR)  
            
          # insert object  
          doc.InsertObject(clone, None, None)  
            
            
      c4d.EventAdd()  
    

    best wishes,
    Sebastian



  • On 03/07/2018 at 05:35, xxxxxxxx wrote:

    Awesome! That's exactly what I was looking for.

    Here's the code I now have on my python tag (UserData button to trigger the script is on the object, works R17+)

      
    import c4d  
      
    def Unlock( clone ) :  
      clone.ChangeNBit( c4d.NBIT_OHIDE,        c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_SUBOBJECT,    c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_SUBOBJECT_AM, c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_LINK_ACTIVE,  c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_THIDE,        c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_NOANIM,       c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_NOSELECT,     c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_EHIDE,        c4d.NBITCONTROL_CLEAR )  
      clone.ChangeNBit( c4d.NBIT_PROTECTION,   c4d.NBITCONTROL_CLEAR )  
      
    def message( msg_type, data ) :  
      if msg_type == c4d.MSG_NOTIFY_EVENT:  
      event_data = data['event_data']  
      if event_data['msg_id'] == c4d.MSG_DESCRIPTION_COMMAND:  
        desc_id = event_data['msg_data']['id']  
        desc_id_id = desc_id[1].id  
        did = -1  
        if desc_id_id == 1:# user id of button  
      
          obj = op[c4d.ID_USERDATA,2]# bind hierarchy's root  
          clone = obj.GetClone( c4d.COPYFLAGS_0 )  
          if clone is not None:  
            doc.StartUndo()  
            Unlock( clone )  
            goal = doc.GetFirstObject()  
            clone.InsertBefore( goal )  
            doc.AddUndo( c4d.UNDOTYPE_NEW, clone )  
            clone.KillTag( 1022113 )# kill character component tag, unneeded  
      
            clone = clone.GetDown()  
            while clone is not None:  
              Unlock( clone )  
              clone.KillTag( 1022113 )# kill character component tag, unneeded  
              clone = clone.GetNext()  
      
            doc.EndUndo()  
            c4d.EventAdd()  
      
    def main() :  
      obj = op.GetObject()  
      bc  = c4d.BaseContainer()  
      #script reacts to userdata button  
      obj.AddEventNotification( op, c4d.NOTIFY_EVENT_MESSAGE, 0, bc )  
    

    Objects are now properly cloned into the scene, and keep all their links to the Character Object's contents.

    Thank you so much!


Log in to reply