Transfering weights



  • On 19/09/2014 at 23:58, xxxxxxxx wrote:

    I'm attempting to write a script that would transfer weights from one weght tag to another. The rigs are somewhat different and have different naming conventions, but the point count of the object is the same. I've cobbled up together a little script but I'm not getting a weight transfer of a test joint.

    import c4d
    from c4d import gui, documents
    #This script copies weights from a figure to the
    #custom c4d rig
      
      
    class transferW(gui.GeDialog) :
       
        def CreateLayout(self) :
            #create the layout of the dialog
            self.SetTitle("Weight Transfer")
            self.GroupBegin(1001, c4d.BFH_SCALEFIT, 2, 3)
            self.AddStaticText(1002, flags=c4d.BFH_LEFT, initw=100, name="Source")
            self.sourceLink = self.AddCustomGui(1003, c4d.CUSTOMGUI_LINKBOX, "",
             c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 400, 0)
            self.AddStaticText(1003, flags=c4d.BFH_LEFT, initw=100, name="Target")
            self.targetLink = self.AddCustomGui(1004, c4d.CUSTOMGUI_LINKBOX, "",
             c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 400, 0)
             
            self.AddButton(1005, c4d.BFH_SCALE, name="Execute")
            self.GroupEnd()
            
            return True
       
        def InitValues(self) :
            #initiate the gadgets with values
            return True
       
        def Command(self, id, msg) :
            #handle user input
            if id==1005:
                self.TranferWeight()
            return True

    def TranferWeight(self) :
            #Do the weight transfer
            sourceWeights = self.sourceLink.GetLink() #Gets the link to the source weight tag
            targetWeights = self.targetLink.GetLink() #Get the link to the target weight tag
            
            jntCount = sourceWeights.GetJointCount()
            sIndex = 0; #Setup the source joint index
            dIndex = 0; #Setup the destination joint index
            
            #quick loop to find neck joint in the source genesis rig
            for i in range(0, jntCount) : 
                jnt = sourceWeights.GetJoint(i, doc)
                if jnt.GetName() == "neck":
                    sIndex = i
                    break
            #quick loop to find neck joint in the destination genesis rig
            jntCount = targetWeights.GetJointCount() 
            for i in range(0, jntCount) :
                jnt = targetWeights.GetJoint(i, doc)
                if jnt.GetName() == "neck":
                    dIndex = i
                    break
            
            print "Source Index: ",sIndex, "Dest Index: ", dIndex
            
            #Transfer weight
            sourceWeights.TransferWeightMap(doc, targetWeights, sIndex, dIndex, 0, c4d.NOTOK)
            
            c4d.EventAdd()
            
            return True
       
    dlg = transferW()
    dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=300, defaulth=50)



  • On 21/09/2014 at 10:16, xxxxxxxx wrote:

    Welcome,

    Two things that I'm seeing:
    1- You're sIndex & dIndex variables will always return zero the way they are used.
    They should probably be either global, or class member variables, so they don't reset themselves to zero

    2- The Python version of TransferWeightMap() seems to be broken.
    It sets the weight values to zero instead of the weight values from the source tag. OUCH!😠

    Here's an example for both C++ and Python that I used to test it:

    //C++ version works  
      
      BaseObject *sourceObj = doc->SearchObject("mesh1");  
      BaseTag *sourceWeights = sourceObj->GetTag(Tweights);  
      BaseObject *targetObj = doc->SearchObject("mesh2");  
      BaseTag *targetWeights = targetObj->GetTag(Tweights);  
      CAWeightTag *sw = (CAWeightTag* )sourceWeights;  
      CAWeightTag *tw = (CAWeightTag* )targetWeights;  
      
      String sname = sw->GetJoint(1,doc)->GetName();  
      String tname = tw->GetJoint(1,doc)->GetName();  
      GePrint(sname + "  " + tname);  
      
      Real s = sw->GetWeight(1,1);  
      Real t = tw->GetWeight(1,1);  
      GePrint(RealToString(s) + "  " + RealToString(t));  
      
      
      PolygonObject *sobj = (PolygonObject* )sourceObj;  
      LONG pntcount = sobj->GetPointCount();  
      //The WM lists joints in alphabetical order  
      //Copy the second WM joint from the source to the second WM joint in the target  
      sw->TransferWeightMap(doc, tw, 1, 1, NOTOK, pntcount, NULL);   
        
      EventAdd();  
      
    /////////////////////////////////////////////////////////////////////////////////////////////////////////  
      
      
    #Python version seems to be broken...It sets the weight values on the target to zero!!!  
      
    import c4d  
    def main() :  
        
      jointID = 1  
        
      sourceObj = doc.SearchObject("mesh1")  
      sourceWeights = sourceObj.GetTag(c4d.Tweights)  
      targetObj = doc.SearchObject("mesh2")  
      targetWeights = targetObj.GetTag(c4d.Tweights)  
      
      sname = sourceWeights.GetJoint(jointID,doc).GetName()  
      tname = targetWeights.GetJoint(jointID,doc).GetName()  
      print sname, "  " ,tname  
      
      s = sourceWeights.GetWeight(jointID,0)  
      t = targetWeights.GetWeight(jointID,0)  
      print s, "  " , t  
      
      pntcount = sourceObj.GetPointCount()  
      #The WM lists joints in alphabetical order  
      #Copy the second WM joint from the source to the second WM joint in the target  
      sourceWeights.TransferWeightMap(doc, targetWeights, jointID, jointID, c4d.NOTOK, pntcount)   
        
      c4d.EventAdd()  
      
    if __name__=='__main__':  
      main()
    

    Even if it did work properly. The TransferWeightMap() function is not the best choice for transferring weight values between two different rigs. Because this function will make your target mesh be deformed by the source rig's joints.
    This is also the same thing that happens when using the VAMP tool. And why so many people have problems with it. It's not a good choice for copying and pasting the weight values between the weight tags in two different rigs.

    I do know how to transfer the weights using different code though.
    If you want it I'll post it.

    -ScottA



  • On 22/09/2014 at 11:27, xxxxxxxx wrote:

    Yeah, I came up with a slightly different technique that brute forces it after finding the the Transfer Maps just would not work. My code worked initially, but when I created the JointTransfer function to simplify code it fails at the GetName() for the target joint. Since I'm targeting this at a very specific rig I made some very specific assumptions about the script: The point count between the object will and should match, and the only thing that different is where the joint are placed and their names. Since the point counts are the same my thinking was to get the source point count and then based on the joint specified iterate through all the mesh points only applying weight where applicable to a specific joint. If there is a more optimized less error prone way I'd really appreciate it. That's for the help.

    import c4d
    from c4d import gui, documents
    # this script copies weights from a figure to the
    # custom c4d rig, point counts of both rigs need to
    # match
      
    global sourceWeights
    global targetWeights
    global meshPntCnt
      
    class transferW(gui.GeDialog) :
       
        def CreateLayout(self) :
            #create the layout of the dialog
            self.SetTitle("Weight Transfer")
            self.GroupBegin(1001, c4d.BFH_SCALEFIT, 2, 3)
            self.AddStaticText(1002, flags=c4d.BFH_LEFT, initw=100, name="Source")
            self.sourceLink = self.AddCustomGui(1003, c4d.CUSTOMGUI_LINKBOX, "",
             c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 400, 0)
            self.AddStaticText(1003, flags=c4d.BFH_LEFT, initw=100, name="Target")
            self.targetLink = self.AddCustomGui(1004, c4d.CUSTOMGUI_LINKBOX, "",
             c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 400, 0)
             
            self.AddButton(1005, c4d.BFH_SCALE, name="Execute")
            self.GroupEnd()
            
            return True
       
        def InitValues(self) :
            #initiate the gadgets with values
            return True
       
        def Command(self, id, msg) :
            #handle user input
            if id==1005:
                self.TranferWeight()
            return True
        
        # transfer weights between source and target joint, takes the names
        # as args
        def JointTransfer(self, sJntName, tJntName) :
            global sourceWeights
            global targetWeights
            
            sJntIndex = 0; #Setup the source joint index
            dJntIndex = 0; #Setup the destination joint index
            
            # we need the joint count so we can do a name match search
            # through all the joints in the weight tags
            jntCount = sourceWeights.GetJointCount()
            
            #quick loop to find source joint in the source genesis rig
            for i in range(0, jntCount) : 
                jnt = sourceWeights.GetJoint(i, doc)
                if jnt.GetName() == sJntName:
                    sJntIndex = i
                    break
                
            #quick loop to find target joint in the destination genesis rig
            jntCount = targetWeights.GetJointCount() 
            print jntCount
            for i in range(0, jntCount) :
                jnt = targetWeights.GetJoint(i, doc)
                print jnt.GetName()
                if jnt.GetName() == tJntName:
                    dJntIndex = i
                    break
            
            # we are going to brute force this. we'll go through every vertex
            # on the mesh and check if this joint is weighted. if it is we'll
            # set the weight on our new mesh 
            for i in range(0, meshPntCnt) :
                #Get the weight of the current vertex
                weight = sourceWeights.GetWeight(sJntIndex, i)
                
                # if the weight is greater than 0 lets set it on the new joint
                if weight > 0:    
                    targetWeights.SetWeight(dJntIndex, i, weight)
                    #print "Index ", i,": ", weight #debug
                    
            return
        
        #Do the weight transfer
        def TranferWeight(self) :
            global sourceWeights
            global targetWeights
            
            #Gets the link to the source weight tag
            sourceWeights = self.sourceLink.GetLink().GetTag(c4d.Tweights)
            
            #Get the link to the target weight tag
            targetWeights = self.targetLink.GetLink().GetTag(c4d.Tweights)
            
            #The mesh point count
            meshPntCnt = self.sourceLink.GetLink().GetPointCount()
            
            # use a custom function to transfer joints
            self.JointTransfer("abdomen", "abdomen")
            self.JointTransfer("abdomen2", "abdomen2")
            self.JointTransfer("chest", "chest")
            self.JointTransfer("lPectoral", "l_Pectoral")
            self.JointTransfer("rPectoral", "r_Pectoral")
            self.JointTransfer("neck", "neck")
            self.JointTransfer("head", "head")
            self.JointTransfer("lEye", "l_Eye")
            #self.JointTransfer("rEye", "r_Eye")
            self.JointTransfer("pelvis", "pelvis")
            self.JointTransfer("lThigh", "l_Thigh")
            self.JointTransfer("lShin", "l_Shin")
            self.JointTransfer("lFoot", "l_Foot")
            self.JointTransfer("lToe", "l_Toe")
            self.JointTransfer("lBigToe", "l_BigToe")
            self.JointTransfer("rThigh", "r_Thigh_1")
            self.JointTransfer("rShin", "r_Shin_1")
            self.JointTransfer("rFoot", "r_Foot_1")
            self.JointTransfer("rToe", "r_Toe_1")
            self.JointTransfer("rBigToe", "r_BigToe_1")
            self.JointTransfer("lCollar", "l_Collar")
            self.JointTransfer("lShldr", "l_Shldr")
            self.JointTransfer("lForeArm", "l_ForeArm")
            self.JointTransfer("lHand", "l_Hand")
            self.JointTransfer("lThumb1", "l_Thumb1")
            self.JointTransfer("lThumb1", "l_Thumb2")
            self.JointTransfer("lThumb1", "l_Thumb3")
            self.JointTransfer("lCarpal1", "l_Carpal1")
            self.JointTransfer("lCarpal2", "l_Carpal2")
            self.JointTransfer("lIndex1", "l_Index1")
            self.JointTransfer("lIndex2", "l_Index2")
            self.JointTransfer("lIndex3", "l_Index3")
            self.JointTransfer("lMid1", "l_Mid1")
            self.JointTransfer("lMid2", "l_Mid2")
            self.JointTransfer("lMid3", "l_Mid3")
            self.JointTransfer("lRing1", "l_Ring1")
            self.JointTransfer("lRing2", "l_Ring2")
            self.JointTransfer("lRing3", "l_Ring3")
            self.JointTransfer("rCollar", "r_Collar")
            self.JointTransfer("rShldr", "r_Shldr_1")
            self.JointTransfer("rForeArm", "r_ForeArm_1")
            self.JointTransfer("rHand", "r_Hand_1")
            self.JointTransfer("rThumb1", "r_Thumb1_1")
            self.JointTransfer("rThumb1", "r_Thumb2_1")
            self.JointTransfer("rThumb1", "r_Thumb3_1")
            self.JointTransfer("rCarpal1", "r_Carpal1_1")
            self.JointTransfer("rCarpal2", "r_Carpal2_1")
            self.JointTransfer("rIndex1", "r_Index1_1")
            self.JointTransfer("rIndex2", "r_Index2_1")
            self.JointTransfer("rIndex3", "r_Index3_1")
            self.JointTransfer("rMid1", "r_Mid1_1")
            self.JointTransfer("rMid2", "r_Mid2_1")
            self.JointTransfer("rMid3", "r_Mid3_1")
            self.JointTransfer("rRing1", "r_Ring1_1")
            self.JointTransfer("rRing2", "r_Ring2_1")
            self.JointTransfer("rRing3", "r_Ring3_1")
              
            c4d.EventAdd()
            
            return True
       
    dlg = transferW()
    dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=300, defaulth=50)
    


  • On 23/09/2014 at 07:40, xxxxxxxx wrote:

    Here's the final working script in case anyone needs to do something similar in the future. It's very specific and works with one type of rig but it could be adapted.

    import c4d
    from c4d import gui, documents
    from types import *
    # this script copies weights from a figure to the a
    # custom c4d rig, point counts of both rigs need to
    # match
      
    global sourceWeights
    global targetWeights
    global meshPntCnt
      
    class transferW(gui.GeDialog) :
       
        def CreateLayout(self) :
            #create the layout of the dialog
            self.SetTitle("Weight Transfer")
            self.GroupBegin(1001, c4d.BFH_SCALEFIT, 2, 3)
            self.AddStaticText(1002, flags=c4d.BFH_LEFT, initw=100, name="Source")
            self.sourceLink = self.AddCustomGui(1003, c4d.CUSTOMGUI_LINKBOX, "",
             c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 400, 0)
            self.AddStaticText(1003, flags=c4d.BFH_LEFT, initw=100, name="Target")
            self.targetLink = self.AddCustomGui(1004, c4d.CUSTOMGUI_LINKBOX, "",
             c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 400, 0)
             
            self.AddButton(1005, c4d.BFH_SCALE, name="Execute")
            self.GroupEnd()
            
            return True
       
        def InitValues(self) :
            #initiate the gadgets with values
            return True
       
        def Command(self, id, msg) :
            #handle user input
            if id==1005:
                self.TranferWeight()
            return True
        
        # transfer weights between source and target joint, takes the names
        # as args
        def JointTransfer(self, sJntName, tJntName) :
            global sourceWeights
            global targetWeights
            global meshPntCnt
            
            sJntIndex = 0; #Setup the source joint index
            dJntIndex = 0; #Setup the destination joint index
            
            # we need the joint count so we can do a name match search
            # through all the joints in the weight tags
            jntCount = sourceWeights.GetJointCount()
            
            #quick loop to find source joint in the source genesis rig
            for i in range(0, jntCount) : 
                jnt = sourceWeights.GetJoint(i, doc)
                if(type(jnt) != NoneType) :
                    if jnt.GetName() == sJntName:
                        sJntIndex = i
                        break
                
            #quick loop to find target joint in the destination genesis rig
            jntCount = targetWeights.GetJointCount()
            for i in range(0, jntCount) :
                jnt = targetWeights.GetJoint(i, doc)
                if(type(jnt) != NoneType) :
                    if jnt.GetName() == tJntName:
                        dJntIndex = i
                        break
            
            # we are going to brute force this. we'll go through every vertex
            # on the mesh and check if this joint is weighted. if it is we'll
            # set the weight on our new mesh 
            for i in range(0, meshPntCnt) :
                #Get the weight of the current vertex
                weight = sourceWeights.GetWeight(sJntIndex, i)
                
                #Set the weight to target mesh and joint
                targetWeights.SetWeight(dJntIndex, i, weight)
                    
            return
        
        #Do the weight transfer
        def TranferWeight(self) :
            global sourceWeights
            global targetWeights
            global meshPntCnt
            
            #Gets the link to the source weight tag
            sourceWeights = self.sourceLink.GetLink().GetTag(c4d.Tweights)
            
            #Get the link to the target weight tag
            targetWeights = self.targetLink.GetLink().GetTag(c4d.Tweights)
            
            #The mesh point count
            meshPntCnt = self.sourceLink.GetLink().GetPointCount()
            
            # use a custom function to transfer joints
            self.JointTransfer("abdomen", "abdomen")
            self.JointTransfer("abdomen2", "abdomen2")
            self.JointTransfer("chest", "chest")
            self.JointTransfer("lPectoral", "l_Pectoral")
            self.JointTransfer("rPectoral", "r_Pectoral")
            self.JointTransfer("neck", "neck")
            self.JointTransfer("head", "head")
            self.JointTransfer("lEye", "l_Eye")
            #self.JointTransfer("rEye", "r_Eye")
            self.JointTransfer("pelvis", "pelvis")
            self.JointTransfer("lThigh", "l_Thigh")
            self.JointTransfer("lShin", "l_Shin")
            self.JointTransfer("lFoot", "l_Foot")
            self.JointTransfer("lToe", "l_Toe")
            self.JointTransfer("lBigToe", "l_BigToe")
            self.JointTransfer("rThigh", "r_Thigh_1")
            self.JointTransfer("rShin", "r_Shin_1")
            self.JointTransfer("rFoot", "r_Foot_1")
            self.JointTransfer("rToe", "r_Toe_1")
            self.JointTransfer("rBigToe", "r_BigToe_1")
            self.JointTransfer("lCollar", "l_Collar")
            self.JointTransfer("lShldr", "l_Shldr")
            self.JointTransfer("lForeArm", "l_ForeArm")
            self.JointTransfer("lHand", "l_Hand")
            self.JointTransfer("lThumb1", "l_Thumb1")
            self.JointTransfer("lThumb2", "l_Thumb2")
            self.JointTransfer("lThumb3", "l_Thumb3")
            self.JointTransfer("lCarpal1", "l_Carpal1")
            self.JointTransfer("lCarpal2", "l_Carpal2")
            self.JointTransfer("lIndex1", "l_Index1")
            self.JointTransfer("lIndex2", "l_Index2")
            self.JointTransfer("lIndex3", "l_Index3")
            self.JointTransfer("lMid1", "l_Mid1")
            self.JointTransfer("lMid2", "l_Mid2")
            self.JointTransfer("lMid3", "l_Mid3")
            self.JointTransfer("lRing1", "l_Ring1")
            self.JointTransfer("lRing2", "l_Ring2")
            self.JointTransfer("lRing3", "l_Ring3")
            self.JointTransfer("lPinky1", "l_Pinky1")
            self.JointTransfer("lPinky2", "l_Pinky2")
            self.JointTransfer("lPinky3", "l_Pinky3")
            self.JointTransfer("rCollar", "r_Collar")
            self.JointTransfer("rShldr", "r_Shldr_1")
            self.JointTransfer("rForeArm", "r_ForeArm_1")
            self.JointTransfer("rHand", "r_Hand_1")
            self.JointTransfer("rThumb1", "r_Thumb1_1")
            self.JointTransfer("rThumb2", "r_Thumb2_1")
            self.JointTransfer("rThumb3", "r_Thumb3_1")
            self.JointTransfer("rCarpal1", "r_Carpal1_1")
            self.JointTransfer("rCarpal2", "r_Carpal2_1")
            self.JointTransfer("rIndex1", "r_Index1_1")
            self.JointTransfer("rIndex2", "r_Index2_1")
            self.JointTransfer("rIndex3", "r_Index3_1")
            self.JointTransfer("rMid1", "r_Mid1_1")
            self.JointTransfer("rMid2", "r_Mid2_1")
            self.JointTransfer("rMid3", "r_Mid3_1")
            self.JointTransfer("rRing1", "r_Ring1_1")
            self.JointTransfer("rRing2", "r_Ring2_1")
            self.JointTransfer("rRing3", "r_Ring3_1")
            self.JointTransfer("rPinky1", "r_Pinky1_1")
            self.JointTransfer("rPinky2", "r_Pinky2_1")
            self.JointTransfer("rPinky3", "r_Pinky3_1")
                    
            # update scene and object  
            self.targetLink.GetLink().Message(c4d.MSG_UPDATE)
            c4d.EventAdd()
           
            
            return True
       
    dlg = transferW()
    dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=300, defaulth=50)
    

Log in to reply