Keyframing custom properties - F-curve to action?

Hi folks.

Maybe someone can help a newbie with a keyframing question? (Blender 2.73a on Win-64.)

For the first time, I’m trying to keyframe a custom property driving a shape key.

The property is attached to the main armature, so lives under {Armature}.data.

But I notice that when I key-frame the property. No action is created in the action editor
(as happens when I key-frame a bone). I just get a new isolated F-curve with no
obvious way to create an action from it. If create a new action ‘up-front’, the F-curve
that gets created still isn’t added to it.

So how do I ‘convert’ the F-curve that gets created in this case into an action so that
I can include it in animations?

Thanks.

If your custom property is on a bone in the armature, it should be in the action of that armature.

Give me a screenshot of your custom property.

Thanks Danpro.

Not on a bone, no. On the Armature itself…


I can try moving them to a bone?

Yep. Move it to a bone. (Next icon over from the one you have selected.) Pick one that makes sense for your shapekey, or just use the rootbone if you have one. I’d put the custom prop for a wink on the head control bone.

OK. I’ve yet to work out how to link the sliders back to the properties when they are on the bone.
But if I keyframe the custom property that’s on the bone a new Action is created as I expected. So
that looks like the way to go, thanks.

So I guess Armature properties are treated in a different way. It made sense to me to expose the sliders
anytime the armature was selected, so that’s where I put the properties. Learned something new.

Copy the data path of the slider and paste it into your driver for the shapekey.

It’s the path to the bone property in the Python that has me. I’m guessing that if the property is
on the bone, then I have to test for that specific bone being selected in the current context.
At least this no longer works…

    if ob.type == 'ARMATURE':   # Original line
        layout.prop( ob.data, 'pose.bones["COG"]["Snarl"]' ) # Modified line - prop on COG

That has other implications. I really don’t want to have select specific bones to modify these properties.
Looks like I’ll have to lern me a lot more Python.

But thanks for your help. I’ll chase this some more tomorrow.

OK. I think I finally have it. Not yet fully tested, but it looks good as far as Action editing goes.
Documenting here in the hope that it helps another newbie…

As it does seem that properties on the armature itself are not easily animatable. I’ve done
what DanPro suggested and moved them to my root bone (thanks again DanPro).

The associated driver ‘RNA’ paths all had to be changed of course. E.G. from something like
‘data.[“SpineRecovery”]’ to ‘pose.bones[“Root”][“SpineRecovery”]’.

I really wanted to get my sliders all set up in the UI without selecting a specific bone,
so I had to try and work out the changes needed to the UI script I had. What took
the most time here, was working out that I couldn’t use Armature.bones,
but had to use Armature.pose.bones to fetch properties. Once I’d solved that
things came together.

The UI script I started with (using Armature prop’s):

import bpy

class SpineSlider( bpy.types.Panel ):
bl_label = “Animation”
bl_space_type = “VIEW_3D”
bl_region_type = “UI”

def draw(self,context):
    layout = self.layout
    ob = context.object
    if not ob:
        return
    if ob.type == 'ARMATURE':
        layout.prop( ob.data, '["SpineRecovery"]' )
        layout.prop( ob.data, '["LeftEyeWink"]' )
        layout.prop( ob.data, '["RightEyeWink"]' )
        layout.prop( ob.data, '["Snarl"]' )
          
@classmethod
def poll(cls, context):
    return context.active_object.type == 'ARMATURE'

def register():
bpy.utils.register_class(SpineSlider)

def unregister():
bpy.utils.unregister_class(SpineSlider)

register()


This finally ended up looking like this. Which should also be cleaner
in that it won’t get confused with multiple armatures:


import bpy

class AnimationSliders( bpy.types.Panel ):
bl_label = “Animation”
bl_space_type = “VIEW_3D”
bl_region_type = “UI”

def draw(self,context):
    layout = self.layout
    ob = context.object
    if not ob:
        return
    if (ob.type == 'ARMATURE') and (ob.name == 'FlorenceArmature'):
        bone = ob.pose.bones['Root']
        layout.prop( bone, '["SpineRecovery"]' )
        layout.prop( bone, '["LeftEyeWink"]' )
        layout.prop( bone, '["RightEyeWink"]' )
        layout.prop( bone, '["Snarl"]' )
          
@classmethod
def poll(cls, context):
    return (context.active_object.type == 'ARMATURE') and (context.active_object.name == 'FlorenceArmature')

def register():
bpy.utils.register_class(AnimationSliders)

def unregister():
bpy.utils.unregister_class(AnimationSliders)

register()