0
$\begingroup$

I am writing a simple script using the blender api (2.8) that essentially translates keyframed animation info from a rigged model to another model using shapekeys. It attempts to do this by the following;

  1. Moves through a scene frame by frame, applying an armature modifier to a mesh and then setting that modifier as a shapekey

  2. Moves through the same scene frame by frame setting the above created shapekeys as keyframes one by one setting their value to 1 in their corresponding frame.

Part 1 works fine, and I think I understand how to write part 2 as the keyframes are added. The problem I have is that the value of 1 is only applied to the last shapekey and does not change per frame.

Please see below my code. Please note I am a python novice:

    import bpy
    #save the total number of frames as var
    frames = bpy.context.scene.frame_end + 1

    #loop through frames, jump to each frame, add the armature, set as shapekey
    for frame in range(frames):
        bpy.context.scene.frame_set(frame)
        bpy.ops.object.modifier_add(type='ARMATURE')
        bpy.context.object.modifiers["Armature"].object = bpy.data.objects["rig"]
        bpy.ops.object.modifier_apply(apply_as='SHAPE', modifier="Armature")
        #loop through shapekeys and add as keyframe per frame
        for shapekey in bpy.data.shape_keys:
            for i, keyblock in enumerate(shapekey.key_blocks):
                if keyblock.name != 'Basis':
                    curr = i - 1
                    if curr != frame:
                        keyblock.value = 0
                        keyblock.keyframe_insert("value",frame=curr)
                    else:
                        keyblock.value = 1
                        keyblock.keyframe_insert("value",frame=curr)

And here is screenshot of the results you can see the shapekeys are applied, that they are all keyframed, but the value of 1 is only applied to the last shapekey and does not change per frame. (Hard to see that here but please see attached file).

enter image description here

What I expect to happen is that for each frame, the corresponding shapekey will have a keyframed value of 1 and all the others have 0.

So;

  • for frame 0, 'Armature' shapekey has value 1, all others have 0

  • for frame 1, 'Armature.001' shapekey has value 1, all others have 0

  • for frame 2, 'Armature.002' shapekey has value 1, all others have 0

etc. and so on, the result being the equivalent of the original animation but using shapekeys instead of a rig.

It is probably easier to understand the intent and the issue by looking at an example file so if you are willing, I attach the file here. Please open and select the 2nd model ('Cube.001') then go into the scripting layout and run the 'Test' script. You will see the shapekeys are successfully created and the keyframes are applied but the values are not correct.

Downloadable file here

My feeling is that there is an issue with my loop, that is does actually work but it keeps overwriting it each time which is why only the last one shows. No tweaking can get it working though so any advice would be much appreciated. Any more info needed please ask.

Thanks

$\endgroup$
0
$\begingroup$

Answering my own question as I figured it out. Just in case anyone else has a need for it, the below script works as expected.

import bpy

#save the total number of frames as var
frames = bpy.context.scene.frame_end + 1

#loop through frames, jump to each frame, add the armature, set as shapekey
for frame in range(frames):
    bpy.context.scene.frame_set(frame)
    bpy.ops.object.modifier_add(type='ARMATURE')
    bpy.context.object.modifiers["Armature"].object = bpy.data.objects["rig"]
    bpy.ops.object.modifier_apply(apply_as='SHAPE', modifier="Armature")

#for each frame, loop through shapekeys and add as keyframe per frame, set value to 1 if current frame = corresponding shapekey
for frame in range(frames):
    for shapekey in bpy.data.shape_keys:
        for i, keyblock in enumerate(shapekey.key_blocks):
            if keyblock.name != 'Basis':
               curr = i - 1
               if curr != frame:
                   keyblock.value = 0
                   keyblock.keyframe_insert("value", frame=frame)
               else:
                   keyblock.value = 1
                   keyblock.keyframe_insert("value", frame=frame)
$\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.