3
$\begingroup$

When I try to use the "set inverse" operator in python there comes an error that it missed a context called "constraint". But I did it exactly like in the Info Panel.

bpy.ops.constraint.childof_set_inverse(constraint="Child Of", owner='BONE')

The Name of the constraint is correct and the also the owner

$\endgroup$
4
$\begingroup$

You need to specify the context and also make sure the bone is active:

import bpy

pbone = bpy.context.active_object.pose.bones["Bone_name"]

context_copy = bpy.context.copy()
context_copy["constraint"] = pbone.constraints["Child Of"]
bpy.context.active_object.data.bones.active = pbone.bone
bpy.ops.constraint.childof_set_inverse(context_copy, constraint="Child Of", owner='BONE')

If the constraint is targeting object + vertex_group instead of armature + bone, make sure the data of the object is updated before setting the inverse. This is for example needed if the target vertex group was also generated by code:

mesh_ob.update_tag({'DATA'})

If not updated entering edit-mode of the mesh or armature will reset the set-inverse.

$\endgroup$
2
$\begingroup$

Toggle a constraint property

As mentioned in this (possible duplicate) question Set inverse Child OF constraints via python , simply changing the inverse_matrix property of a constraint does nought. However, if another property of the constraint is toggled, for example the target it appears to work as expected, using the new value assigned to inverse_matrix

Test script, tested on simple example of single bone and default cube parent. Set cmd to 'CLEAR' for clear and 'SET' for set. For all child of constraints on all pose bones of the context object. AFAICT it doesn't need context.

import bpy
from mathutils import Matrix

context = bpy.context

ob = context.object
constraints = [(pb, c) for pb in ob.pose.bones
        for c in pb.constraints if c.type == 'CHILD_OF']

cmd = 'CLEAR' # or 'SET'       
for pb, c in constraints:

    if cmd == 'CLEAR':
        c.inverse_matrix = Matrix.Identity(4)    

    elif cmd == 'SET': 
        if c.target:
            mw = c.target.matrix_world
            c.inverse_matrix = mw.inverted()
    # toggle a property
    target = c.target
    c.target = None
    c.target = target
    #pb.constraints.update()

Notes: takes into no account the owner_space and target_space, nor the influence value when the script is run, which changes the calculated value for set, (have a feeling influence zero is clear)... An interpolated target matrix could be found by decomposing, lerping and slerping from identity to target.matrix_world.

why is this so? Constraint properties that are set by a user (esp via UI) update the data appropriately on change.

An operator for each has been chosen to crunch the numbers , and handle the necessary updating. Perhaps a patch to make the python attribute update on change, not sure..

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.