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$

2 Answers 2

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$
1
  • $\begingroup$ I hate to revive solved questions, however I've been earching everywhere for a proper in code solution ( aka not just mimicking the user pressing UI elements ) and this has so far been the only one I could find ( sans the c.inverse_matrix = c.target.matrix_world.inverted() from the linked question ). However I can't seem to get it to work. There's no errors but it doesn't seem to affect anything. I tried a few update() functions but they don't seem to help. Does this code, by itself, work currently in blender ( or 2.79 ) $\endgroup$
    – KaydemonLP
    Commented Mar 4, 2021 at 17:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .