Building a Character Object [SOLVED]



  • On 30/05/2016 at 16:43, xxxxxxxx wrote:

    Trying to figure out a way to build a character template with python. First, create the character object, then select the character type, then build the components.  An example would be to create an Advanced Biped, then build the root, spine, then arms. Can't seem to figure out how to mimic pushing the button to create the components.

    obj = c4d.BaseObject(c4d.Ocharacter) # Create Character Object 
    doc.InsertObject(obj)                # Insert object in document
    obj[c4d.ID_CA_CHARACTER_TEMPLATE] = 1# Select Advanced Biped

    Create Root some how ...

    Create Spine some how...

    Related question, does anyone know how I can make sure I am creating the right character template with [c4d.ID_CA_CHARACTER_TEMPLATE]? I guess I am asking how do I know the integer that corresponds to a template will be the same on other computers? If I have a bunch of different templates the integer corresponding to my template maybe be different on someone else(I think), I believe it is based upon how many you have saved? I want to figure out a way to make sure I build the correct template.

    Thank you to anyone reading this I appreciate all the help.



  • On 01/06/2016 at 01:44, xxxxxxxx wrote:

    Hello,

    since the Character object does not provide a dedicated API one must access its internal data to utilize it. This is not documented and not further supported.

    You would have to read the object's parameter description to search for the IDs of the templates and identify them by their name. Also you would have to access an internal container to get the settings of the long buttons that are used to create the components. You can identify the buttons by their names and "press" them by sending a specific message to the Character object.

      
    # get object description  
    description = op.GetDescription(c4d.DESCFLAGS_DESC_0)  
    if description is None:  
      return  
      
      
    # check parameter description  
    for bc, paramid, groupid in description:      
       
      # check "Template" parameter description  
      if paramid[0].id == c4d.ID_CA_CHARACTER_TEMPLATE:  
            
          # get cycle content  
          cycle = bc.GetContainer(c4d.DESC_CYCLE)  
          for id, data in cycle:  
              print(str(id) + " " + data)  
                
      # check for character components  
      if paramid[0].id == c4d.ID_CA_CHARACTER_TEMPLATE_CONTAINER:  
      
          print("Full Parameter ID: " + str(paramid))         
            
          # check cycle content  
          cycle = bc.GetContainer(c4d.DESC_CYCLE)  
          for id, data in cycle:  
              print(str(id) + " " + data)  
                
          # press the "button" by sending a message  
          message = {}  
          message['id'] = paramid  
            
          op.Message(c4d.MSG_DESCRIPTION_COMMAND, message)  
    

    Best wishes,
    Sebastian



  • On 01/06/2016 at 09:27, xxxxxxxx wrote:

    Woohoo this is super helpful thank you so much! I would have never been able to figure this all out on my own. I do have one more question, I can't seem to figure out how to find the IDs of the next components after I build the first one. Example: create the Advanced Biped Character, using your technique to create the "Root", now to build the "Spine" you need to be selected on the Root, but then I can not find the paramid for "Spine". I tried looking for the paramid for the "Spine" but can't seem to find it. Do you know how I can access the buttons that only show up after you build the parent components? Thank you so much. Bummer that the Character object does not have a documented API, I guess it is not used enough :(



  • On 02/06/2016 at 00:18, xxxxxxxx wrote:

    Hello,

    to get the Description showing the buttons for the sub-components you must select the component object but access the Description of the actual Character object.

    Best wishes,
    Sebastian



  • On 02/06/2016 at 08:08, xxxxxxxx wrote:

    Waaaa! Got it right a way! Why did I not to think of trying it thay way. Thank you very much Sebastian this is very helpful. I appreceate all of your help.



  • On 27/11/2016 at 00:08, xxxxxxxx wrote:

    I just stumbled upon this. I don't quite understand how to build subsequent components. The code Sebastian posted successfully builds the Root component. The issue I'm seeing is that regardless, the first paramid is the same. So even though Root was created, event if I select root but run GetDescription still on the character object, it will print the right component name, but it will not build the spine, even thought it worked just fine for the root. Am I missing something?



  • On 28/11/2016 at 00:39, xxxxxxxx wrote:

    Hello,

    could you please post some code showing what you are doing?

    best wishes,
    Sebastian



  • On 28/11/2016 at 09:22, xxxxxxxx wrote:

    Hey Sebastian,

    The code I was using was pretty much the same as the code you had posted. The only difference was instead of"
    description = op.GetDescription(c4d.DESCFLAGS_DESC_0), I had replaced op with charObj, which is a variable i got via a doc.SearchObject("Character"). I did that because one of the things here mentioned running the code on the char object whilest a component was selected. This creates the root component and selects it but it doesn't create any others, despite the fact that it will print the next component(Spine FK/IK).



  • On 29/11/2016 at 00:32, xxxxxxxx wrote:

    Hello,

    the posted script only does one thing. It loops through the description and "presses" the buttons. The script is only intended to show how to obtain the needed parameter IDs and how to "press" the button, nothing else.

    So when you execute the script once, it only presses one button ("Root"). If the script should create something else it must run again (or you have to code the "pressing" of the next button yourself).

    The script does not print "the next component".

    best wishes,
    Sebastian



  • On 29/11/2016 at 23:49, xxxxxxxx wrote:

    Hey Sebastian,

    So here's my script. It's very much like the one you posted but changed as I mentioned and a couple things commented out.

    import c4d
    from c4d import gui
    #Welcome to the world of Python

    def main() :
        # get object description
        charObj=doc.SearchObject("Character")
        description = charObj.GetDescription(c4d.DESCFLAGS_DESC_0)
        if description is None:
            return
        
        
        # check parameter description
        for bc, paramid, groupid in description:    
            
            # check "Template" parameter description
            if paramid[0].id == c4d.ID_CA_CHARACTER_TEMPLATE:
                
                # get cycle content
                cycle = bc.GetContainer(c4d.DESC_CYCLE)
                #for id, data in cycle:
                #    print(str(id) + " " + data)
                    
            # check for character components
            if paramid[0].id == c4d.ID_CA_CHARACTER_TEMPLATE_CONTAINER:
        
                print("Full Parameter ID: " + str(paramid))       
                
                # check cycle content
                cycle = bc.GetContainer(c4d.DESC_CYCLE)
                for id, data in cycle:
                    print(str(id) + " " + data)
                    
                # press the "button" by sending a message
                message = {}
                message['id'] = paramid
                
                op.Message(c4d.MSG_DESCRIPTION_COMMAND, message)
                
    if __name__=='__main__':
        main()

    Now, if you create a character object and select it and then run the script, it will print the following:

    "Full Parameter ID: ((2113,5,0), (1000, 150))
    1000 Root"

    And it will create and then select the Root. So this gets the Description of the Character Object, and presses a button based on the selected object(op.Message).

    Now, with the Root still selected, run the script again. This time it will print:

    "Full Parameter ID: ((2113, 5,0),(1000,15,0))
    1000 Spine (IK/FK Blend)"

    yet it won't create that button. Even though op, is now our Root component object, and it displays the right component name, but when it tries to click the button like you did for Root, it doesn't do it. Why is that? That's the part I don't quite understand. It also seems to generate the same paramid, I assume that the first one always is that number(1000), and it goes up from there.

    But why doesn't it keep creating components as I keep running the script?



  • On 30/11/2016 at 08:04, xxxxxxxx wrote:

    Hello,

    you have to send the message to the character object, not the "Root" object. Just like in the original script.

    best wishes,
    Sebastian



  • On 01/12/2016 at 23:14, xxxxxxxx wrote:

    Thanks for that Sebastian. It  works. But now I'm running into an issue. I want to run through a loop and build components whos names I specify. Here's what I have:

    import c4d
    from c4d import gui
    #Welcome to the world of Python

    def main() :
        # get object description
        parents=['Character', 'Root', 'Spine', 'Spine', 'Spine', 'Spine']
        buttonNames=['Root', 'Spine (IK/FK Blend)', 'Arm (IK/FK Bendy)', 'Jaw', 'Eye', 'Leg (IK/FK Bendy)']
        charObj=doc.SearchObject('Character')
        for id2, buttonName in enumerate(buttonNames) :
            description = charObj.GetDescription(c4d.DESCFLAGS_DESC_0)
            if description is None:
                return
            
            
            # check parameter description
            for bc, paramid, groupid in description:    
                
                        
                # check for character components
                if paramid[0].id == c4d.ID_CA_CHARACTER_TEMPLATE_CONTAINER:
              
                    
                    # check cycle content
                    cycle = bc.GetContainer(c4d.DESC_CYCLE)

    for id, data in cycle:
                        print(str(id) + " " + data)
                        
                        if data==buttonName:
                            # press the "button" by sending a message
                            message = {}
                            message['id'] = paramid
                            
                            charObj.Message(c4d.MSG_DESCRIPTION_COMMAND, message)
            c4d.DrawViews(c4d.DRAWFLAGS_FORCEFULLREDRAW)

    if __name__=='__main__':
        main()

    However, it just is always saying Root first. The data from cycle is not updating? Is that the issue or am I doing something stupid?

    The other question I have: There are different behaviors for clicking the button based on keyboard modifiers(ie different things happen if I SHIFT+Click on the button, CTRL+Click, or CTRL+SHIFT click). Is it possible to pass these modifiers into the message so that when i simulates the button click it can simulate the button click with CTRL+SHIFT pressed?



  • On 02/12/2016 at 07:55, xxxxxxxx wrote:

    Hello,

    it seems that the Character object only works properly when used manually. The Description returned is always the same, the Character object (and the whole Character System in the background) seems to update internal data at several stages of the event system and scene execution. I'm afraid it is not possible to properly update the Character object from within a script.

    If a key is pressed is detected with functions like GetInputState(). This has nothing to do with the MSG_DESCRIPTION_COMMAND and cannot be emulated.

    best wishes,
    Sebastian


Log in to reply