Solved WeightManager/Autoweight > set the amount of Joints in Python?

For a particular setup in R23/24, I’m trying to restrict the auto weighting to 1 joint - to avoid blending between weights (which will save me trouble down the line..).

Since R21 the “ID_CA_WEIGHT_MGR_AUTOWEIGHT_JOINTS” is removed so I can’t set it directly (see the simplified code below).

I tried to figure out a workaround, with no luck. My thought was that if I could read the autoweightDictonary, I could also set it.
The function “GetAutoWeightDictionary” needs a stringId (which is a maxon.Id, but that didn’t help me any further..)

So, the main question: How can I set the amount of Joints (to 1) when autoweighting?
And of course I don’t mean mannualy :} tia, Jochem

import c4d, maxon

def message(id, data):
    if id == c4d.MSG_DESCRIPTION_COMMAND:
        id2 = data['id'][0].id
        if id2 == c4d.ID_USERDATA:
            userDataId = data['id'][1].id
            if userDataId == 1:
                accessWM()
                c4d.EventAdd()


def accessWM():
    doc = op.GetDocument()
    for tag in op.GetObject().GetTags():
        if tag.GetType() == 1019365: wTag = tag
    doc.SetActiveTag(wTag, c4d.SELECTION_NEW)
    wmgr = c4d.modules.character.CAWeightMgr
    wmgr.SetParameter(doc,c4d.ID_CA_WEIGHT_MGR_AUTOWEIGHT_MODE,1) # heatmap
    wmgr.SetParameter(doc,c4d.ID_CA_WEIGHT_MGR_AUTOWEIGHT_IN_BIND_POSE,True)
    # ID_CA_WEIGHT_MGR_AUTOWEIGHT_JOINTS // removed since R21 :{
    wmgr.AutoWeight(doc)
    wmgr.Update(doc)
    
    """
    hmmm1 = wmgr.GetAutoWeightDictionary(doc, maxon.Id("AutoWeight"))
    hmmm2 = wmgr.GetAutoWeightDictionary(doc, maxon.Id)
    print (hmmm1, type(hmmm1))
    print (hmmm2, type(hmmm2))
    # both print: <class 'maxon.reference.DataDictionary'>
    """

def main():
    pass

Hi @jochemdk, weight has been rewritten to make use of the new MAXON API and ease the new implementation of weight algorithms. Theoretically, a C++ 3rd party developer may create a new weight algorithm and have it incorporated into the Weight Manager.

But this Maxon API is slightly different than the classic API, so here some basics information.

MAXON API does not use any more integer value (e.g. Ocube to describe the ID corresponding to a cube) to represent things instead they use reverse domain approach (e.g. "net.maxon.animation.autoweight.base.jointcount" represent the joint count parameter).
These reverse domains are strings but the type to represent them is maxon.Id.

Then come the DataDictionarry part, this is almost similar to a BaseContainer, except that it acts like a Python dict where a key can be anything, and the value can be any maxon.Data.

So finally find an example of how to do it

import c4d
import maxon
from maxon.frameworks import animation


# Main function
def main():
    wmgr = c4d.modules.character.CAWeightMgr
    # Retrieve the maxon id corresponding to the current weight algorithm used
    # 1 == the second entry, in our case the heatmap
    heatmap_id = wmgr.GetAutoWeightAlgoId(doc, 1)
    
    # Retrieve the current settings (only changed values will appear here)
    settings = wmgr.GetAutoWeightDictionary(doc, heatmap_id)

    # Change the value for the joint count
    settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.JOINTCOUNT, 2)
    wmgr.SetAutoWeightDictionary(doc, settings, heatmap_id)
    
    # Update the Weight Manager
    c4d.EventAdd()
    

# Execute main()
if __name__=='__main__':
    main()

Regarding how I find the ID, I just looked at the python file located within '{c4d_install_dir}/resource/modules/python/libs/python39/maxon/frameworks/animation.py'.

Unfortunately, this is not documented in the Python online documentation I will add a note to do it.
Cheers,
Maxime.

Super, thx a lot! Will check first thing in the morning :}

Hi @m_adam, thx for your input, it does reset the WeightManager, but doesn’t do the autoWeighting accordingly..

_First thing I noticed: a difference between int 64 & 32. Not sure if this might be a problem..
Reading the GET> AutoWeight…base.jointcount : <int64> “number of joints”
Reading the SET> AutoWeight…base.jointcount : <int32> “number of joints”

_After the WeightManager is being set (to 1 joint in my case), I can’t click on the “Calculate button” manually.
Nothing happens, unless I change the joint count manually to another number. So something in the update hasn’t been applied..
Note that reading the dict says <int32>, until manually changed, than is says <int64> again..

_I also tried wmgr.SetDirty(doc) / wmgr.Update(doc) / followed by another c4d.EventAdd().. Perhaps these need a different approach as well?
I tried to find something in the “maxon/frameworks” folders you linked to, but couldn’t find any info on how to tackle this issue.

So the current status is still that “default weighting” is applied.
If you can please help in the right direction, it would be greatly appreciated, tia, Jochem

import c4d, maxon
from maxon.frameworks import animation


def main():
    doc = c4d.documents.GetActiveDocument()
    wmgr = c4d.modules.character.CAWeightMgr
    #wmgr.SetDirty(doc)
    
    heatmap_id = wmgr.GetAutoWeightAlgoId(doc, 1) # heatmap
    settings = wmgr.GetAutoWeightDictionary(doc, heatmap_id)
    settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.JOINTCOUNT, 1)
    settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.SELECTEDPOINTS, False)
    settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.ALLOWZEROLENGTH, False)
    wmgr.SetAutoWeightDictionary(doc, settings, heatmap_id)
    #doc.ExecutePasses(None,True,True,True,flags=c4d.BUILDFLAGS_NONE)
    c4d.EventAdd()
    
    # getWeightTag - setActive
    firstJoint = doc.GetFirstObject().GetDown().GetDown() # just in my testDoc..
    weightTag = (firstJoint.GetWeightTag())["op"]
    doc.SetActiveTag(weightTag, c4d.SELECTION_NEW)
    #weightTag.GetObject().SetBit(c4d.BIT_ACTIVE)
        
    # update weightManager / doesn't make any difference..
    #wmgr.SetDirty(doc)
    #wmgr.Update(doc)
    #c4d.EventAdd()
    
    # autoWeight func
    wmgr.SelectAllJoints(doc)
    bla = wmgr.AutoWeight(doc)
    print(bla) # prints True, but not in the right way :{
    c4d.EventAdd()

if __name__=='__main__':
    main()

Hi @jochemdk, sorry for the delay, looks like the autoconversion from Python to C++ fail,
so you will need to pass settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.JOINTCOUNT, maxon.Int(1))

For bool the autoconversion should work out of the box otherwise use maxon.Bool(False).
Since there is only 1 boolean type in C++ the bool conversion is ok, while there is maxon.Int, maxon.Int32, maxon.Int64 for integer value, so the Python system has to do some guesswork.

How could you know that? For the moment the only way is looking where this parameter is declared in 'sdk.zip/frameworks/animation.framework/source/maxon/autoweight_attributes.h' with line MAXON_ATTRIBUTE(Int, JOINTCOUNT, "net.maxon.animation.autoweight.base.jointcount");
So this attribute accepts a maxon.Int.

This is indeed something that we are aware of and will need to address sooner or later in our documentation.

Cheers,
Maxime.

So, now we have a maxon.Int :}
Yes, the system is working - thx @m_adam
Consider it solved // more info in general on the maxon framework - especially on the python side - would we be welcome..