[solved] Set inverse Child OF constraints via python

Hi there !
A few years ago I used to be using a little script found here in order to reset every “Stretch to” constraints of an armature, even on unselected/offlayered bones :

 import bpy
    for b in bpy.context.active_object.pose.bones:
        for c in b.constraints: 
            if c.type == "STRETCH_TO":
                c.rest_length = 0

It has been very useful, especially when you drastically edit the bones positions of an already finished rig (i.e. when you reuse the same rig for similar but different models).

I would like a very similar script, but with “set inverse” for CHILD_OF constraint.
But I barely know Blender’s API and every try haven’t got anything working nor going the right direction.

My last attempt looked like that:

import bpy

for b in bpy.context.active_object.pose.bones:
    for c in b.constraints: 
        if c.type == "CHILD_OF":
            context_py = bpy.context.copy()
            context_py["constraint"] = constraint
            bpy.ops.constraint.childof_set_inverse(context_py, constraint="Child Of")

And got this error:

Traceback (most recent call last):
  File "\Text", line 7, in <module>
NameError: name 'constraint' is not defined

If someone could help me, that would be kind.

I’m not a programmer, but I did something that kinda worked… using as reference the dynamic parent addon, which does set inverse sometimes.
On your script you had to first define the variable “constraint” before referencing it elsewhere…
Also, on the set_inverse line, apparently we need to say which is the “owner”… this is the script, which for now only works on the last selected bone which have a child_of constraint.

import bpy

for b in bpy.context.active_object.pose.bones:
    for c in b.constraints: 
        if c.type == "CHILD_OF":
            CO_constraint = c
            context_py = bpy.context.copy()
            context_py["constraint"] = CO_constraint
            bpy.ops.constraint.childof_set_inverse(context_py, constraint=CO_constraint.name, owner='BONE')

I don’t know why on the case of the Strech_to script it works on all unselected and selected bones, but in this case it doesn’t.
For now It’s not much different than clicking on the bone and clicking on set Inverse, but in code form. With the difference that it does all Set_Inverses on all child_of constraints of the bone at once.
But I think this is the start!

thank you, I’ll try to investigate on that.

I got this proposition from another guy:

import bpy

for b in bpy.context.active_object.pose.bones:
    for c in b.constraints: 
        if c.type == "CHILD_OF" and c.target is not None:
            c.inverse_matrix = c.target.matrix_world.inverted()

No errors returned, it executes propperly, but simply doesn’t affects the rig.

Thanks to this topic, now i have this :

import bpy

for b in bpy.context.active_object.pose.bones:
    for c in b.constraints: 
        if c.type == "CHILD_OF":
            context_py = bpy.context.copy()
            context_py["constraint"] = c
            bpy.ops.constraint.childof_set_inverse(context_py, constraint="Child Of", owner='BONE')

And it works, but only on the active bone. How can I make it work on the whole armature ? Even on offlayered bones ?

1 Like

Hello,
You could try this:

import bpy

ob = bpy.context.active_object

# Take a copy of current layers 
org_layers = ob.data.layers[:]

# Show all layers
for i in range(len(org_layers)):
    ob.data.layers[i] = True

for b in ob.pose.bones:
    for c in b.constraints: 
        if c.type == "CHILD_OF":
            context_py = bpy.context.copy()
            context_py["constraint"] = c
            ob.data.bones.active = b.bone
            bpy.ops.constraint.childof_set_inverse(context_py, constraint="Child Of", owner='BONE')
            
# Reset back to orginal layer state    
for i in range(len(org_layers)):
    ob.data.layers[i] = org_layers[i]

That should work for the entire armature and even those that are hidden in a layer. I’m not sure but based on this discussion it seems that you have to set each bone to active first before calling the childof_set_inverse

2 Likes

Damn, it worked like a charm :heart:
four days I’ve been struggling with that one! Thanks dude!

Just a little update:
Since then I started the making of an addon which will regroup every little script I made throughout my rigging experiences, with a nice little panel in the viewport’s sidebar for an easy usage.

It’s all right on my github:

It starts small with just two buttons but hopefully, it will get bigger.

2 Likes

Thanks for sharing @L0Lock!

1 Like