1

I have two objects with identical topology and shape keys. Copying over the static shape key values is simple enough.

def copy_shape_keys(source_obj_name, target_obj_name):
source_obj = bpy.data.objects.get(source_obj_name)
target_obj = bpy.data.objects.get(target_obj_name)    
source_shape_keys = source_obj.data.shape_keys
target_shape_keys = target_obj.data.shape_keys

for source_key_block in source_shape_keys.key_blocks: target_key_block = target_shape_keys.key_blocks.get(source_key_block.name) target_key_block.value = source_key_block.value

How could this be extended to include copying over the keyframes of animated shape keys? Blenders API does not seem to provide the necessary access to shape key animation data for this to be feasible.

None of the answers from this thread directly address this question.

Harry McKenzie
  • 10,995
  • 8
  • 23
  • 51
  • Hello and welcome. by "animated shape keys" do you just mean the keyframes as well? – Harry McKenzie Aug 06 '23 at 16:09
  • @HarryMcKenzie Hello, thank you. Yes, I would like to copy the keyframes of one shape key to another. Doing the animation copying through keyframes is the most straight forward approach, though I am open to other methods of copying over animation data, such as through actions for example. – Jonas Görke Aug 06 '23 at 16:22

1 Answers1

1

Here's the script that will copy the shape keys and the keyframe animation as well:

import bpy

def copy_shape_keys(src, tgt): if len(src.data.vertices) != len(tgt.data.vertices): raise RuntimeError('Objects have different vertex count!')

if tgt.data.shape_keys:
    for key in tgt.data.shape_keys.key_blocks:
        tgt.shape_key_remove(key)

keys = src.data.shape_keys

for key in keys.key_blocks:
    k = tgt.shape_key_add(name=key.name, from_mix=False)
    for i, v in enumerate(src.data.vertices):
        k.data[i].co = key.data[i].co
    k.value = key.value

    data = tgt.data.shape_keys.animation_data_create()
    data.action = bpy.data.actions.new(name=key.name+"_action")

    for fc in keys.animation_data.action.fcurves:
        tgt_fc = data.action.fcurves.new(data_path=fc.data_path)
        for kf in fc.keyframe_points:
            tgt_fc.keyframe_points.insert(kf.co.x, kf.co.y)


source_obj = bpy.data.objects.get("Cube 1") target_obj = bpy.data.objects.get("Cube 2")

copy_shape_keys(source_obj, target_obj)

Harry McKenzie
  • 10,995
  • 8
  • 23
  • 51
  • This script works in the example file, thank you! I am aware that this is technically outside of the scope of my clarification; but could you adjust this script so that it can handle copying over the animation data for all animated shape keys? Say if "Key 2" on "Cube 1" had keyframes as well. – Jonas Görke Aug 08 '23 at 20:06
  • 1
    whoops made a mistake. now its fixed. – Harry McKenzie Aug 08 '23 at 23:18
  • Thank you very much.

    In my use case, I sometimes have models that don't have exactly matching vertex counts or even topology. They only have matching shape key names (for facial expressions). Is there a way to copy animated shape keys, that doesn't rely on matching vertex count and topology?

    I am aware that this is a flaw of how my question was formulated. I did not expect the solution to involve deleting and rebuilding of shape keys using exact vertex data.

    – Jonas Görke Aug 08 '23 at 23:59
  • you can remove the check and see if it still works. but take note that you cannot have a basis shape key with 10 vertices and then a key 1 shape key with 11 vertices. – Harry McKenzie Aug 09 '23 at 00:33
  • Removing the check and running it on meshes with different vertex counts results in all shape keys being deleted and turns the base shape into a mangled mess. If the target mesh has less vertices than the source it raises an index out of range IndexError in line 16. If it has more, it's a 'NoneType' object has no attribute 'action' AttributeError in line 22. Is there really not a more straight forward method to access shape key animation data? – Jonas Görke Aug 09 '23 at 01:11
  • yes you cannot have different amount of vertices, try to see https://blender.stackexchange.com/questions/298676/shape-key-depending-on-another. or open/ask a new question and i will look at it :) – Harry McKenzie Aug 09 '23 at 01:27
  • I opened a new question. link – Jonas Görke Aug 10 '23 at 00:37
  • I have been trying to get a variant on this script to work with chat gpt because I don't know what the heck I'm doing. My variant is that I have two different objects with the same shape key names already, but they are in a different order. How could you modify the script to copy the animation data from a source object to a target based on the same names – Tyson Paris-Hansen Dec 12 '23 at 21:50