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
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!
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.
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 ?
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
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.