I try to transfert a facial animation using shapekeys from one model to my target model using Rigify rig and drivers facial animation.
It works to do it by hand with this technique :
I copy as new driver the shapekey and go to paste this on the matching driver. Just add "+ value" on the expression. This allows me to keep the driver that connects the facial bones rig. I absolutely have to keep them.
But i have 52 shapekeys to link with a another model, and I risk having to make these exchanges on a lot of characters, that's why I started making a script.
I started by matching the names of the shape keys :
import bpy
import re
# get the selected object
depsgraph = bpy.context.evaluated_depsgraph_get()
obj_a = bpy.context.object
selected_object = depsgraph.objects[ obj_a.name ]
obj_b = [obj for obj in bpy.context.selected_objects if obj != obj_a][0]
# get its shapekeys
shape_keys_a = obj_a.data.shape_keys.key_blocks
shape_keys_b = obj_b.data.shape_keys.key_blocks
Lsuffix = 'Left'
# loop through shapekeys and replace the names
for index, key in enumerate(shape_keys_b):
if ('_L' in key.name) and not ('cor_' in key.name):
key.name = key.name.replace("_L",Lsuffix)
print (key.name)
Rsuffix = 'Right'
# loop through shapekeys and replace the names
for index, key in enumerate(shape_keys_b):
if ('_R' in key.name) and not ('cor_' in key.name):
key.name = key.name.replace("_R",Rsuffix)
print (key.name)
print (obj_a.name)
print (obj_b.name)
I chose the method where I select the 2 objects with an active, then I match the names of the shape keys.
For this part it's ok, but I get stuck when it comes to adding a variable to the already existing driver.
I saw on several topics on the website that we could not use python interface commands like :
bpy.ops.ui.copy_as_driver_button()
bpy.ops.graph.driver_variable_paste()
The 2 commands which correspond to Copy as a New Driver, and Paste Driver Variable.
I read that to edit a driver it was better to delete it and create a new one with the new information, but i can't do it because i will lose the first variable connected with rig.
So far I've tried something like this, but several things aren't working.
for index, key_a in enumerate(shape_keys_a):
for index, key_b in enumerate(shape_keys_b):
if (key_a.name == key_b.name) and (key_a.name != 'Basis'):
#print (key_a.name)
idx = obj_a.data.shape_keys.key_blocks.find(key_a.name)
#print (idx)
drvs = bpy.data.shape_keys['Key.004'].animation_data.drivers[idx]
var1 = drvs.driver.variables.new()
var1.name = "value" # add a name to this variable
var1.targets[0].id_type = 'KEY' # set ID type to a target object with the custom attribute
var1.targets[0].id = bpy.data.shape_keys['Key.008'] # set the object as ID
var1.targets[0].data_path = ' key_blocks["' + key_a.name + '"].value' # link the custom property
drvs.driver.expression = drvs.driver.expression + '+value' # set the variable with the custom attribute value as an expression
Edit : Now I manage to add the variables to the drivers but I have a discrepancy in the ID levels i think. The key_a.name on data_path dont't match with the good shapekey name. I don't understand why...
A good challenge ahead, thanks for any help!