Scripting: Shape Keys
-
Key: animation_data, key_blocks (prop_collection), reference_key
Shape Keys are not directly stored in a Key data block. This is a monolithic data block containing the shape keys. The actual shape keys are stored in the key_blocks attribute as Shape Key types.
# Get the list of shape keys
shapekeylist = bpy.context.active_object.data.shape_keys.key_blocks
for shapekey in shapekeylist:
print(f"Key '{shapekey.name}' value is {shapekey.value}")
The active shape key can be acquired directly from the object (not the object data!):
currKey = obj.active_shape_key
currIndex = obj.active_shape_key_index
Single shape keys can be addressed by ID or by name:
sk=bpy.context.active_object.data.shape_keys.key_blocks[22]
print(sk.name)
sk=bpy.context.active_object.data.shape_keys.key_blocks["Male 002"]
print(sk.name)
#getting the id from name
myObj=bpy.context.scene.objects[0]
first_shape_id = myObj.data.shape_keys.key_blocks.find("Male 001")
A new shape key is created via the bpy.ops.object.shape_key_add operator and you remove them with bpy.ops.object.shape_key_remove.
bpy.ops.object.shape_key_add(from_mix=False)
bpy.ops.object.shape_key_remove(all=False)
The positions of the shape keys is stored in the data block of the shape key
for i, d in enumerate(sk.data):
print(f"Vertex {i} Pos: {d.co}")
Shape Key Meshes
Meshes are stored in the data part of a Shape Key. It's a list of ShapeKeyPoint, which has the coordinates as a Vector.
sk=bpy.context.active_object.data.shape_keys.key_blocks[22]
print(f"Shapekey {sk.name} first vertex: {sk.data[0].co}")
# <Vector (-0.8453, -0.8453, -0.8453)>
Animation
Shape key derives from bpy_struct, hence keyframes are set via the keyframe_insert method:
sk.value=1
sk.keyframe_insert("value")
sk.value=0
next_frame_number=bpy.context.scene.frame_current+1
sk.keyframe_insert("value", frame=next_frame_number)
Same way it's possible to delete a keyframe:
sk.keyframe_delete("value")
next_frame_number=bpy.context.scene.frame_current+1
sk.keyframe_delete("value", frame=next_frame_number)
Get keyframes and the values via the animation_data:
ad=bpy.context.active_object.data.shape_keys.animation_data
action=ad.action
print("Keyframes:")
for fcu in action.fcurves:
print()
print(fcu.data_path, fcu.array_index)
for kp in fcu.keyframe_points:
print(f" Frame {kp.co[0]}: {kp.co[1]}")
print("Frames:")
for fcu in action.fcurves:
print()
print(fcu.data_path, fcu.array_index)
for i in range(1, 6):
print(f" Frame {i}: {fcu.evaluate(i):6f}")
Various Examples
# Delete all shapekeys starting with a keystring
import bpy
shapekey_keystring = "frame"
obj = bpy.context.active_object
# Get the list of shape keys
shapekeylist = obj.data.shape_keys.key_blocks
keys = dict(enumerate(shapekeylist))
for sid, shapekey in reversed(keys.items()):
if shapekey.name.starts_with(shapekey_key):
obj.active_shape_key_index = sid
bpy.ops.object.shape_key_remove(all=False)