1
$\begingroup$

I just want to print a log if the current frame contains keyframe

is there any method lile: IsKeyframe or something similar?

import bpy
import math
import random
import time


ctx = bpy.context
ops = bpy.ops
obj = ctx.object

ctx.scene.frame_start = 0
ctx.scene.frame_end = 112
ctx.scene.frame_current = 0

for i in range(112):
    ctx.scene.frame_set(i)
    print("Frame %i" % i)
$\endgroup$
1

1 Answer 1

1
$\begingroup$

Finding keyframes is a little bit trickier, since any object in the scene could have a keyframe at a given frame.

So this script will check all objects for keyframes at each of the frames between beginning and end, and print out any keyframe on any channel, for each of the objects. It will also print out the value of that channel at that keyframe, just in case.

import bpy

S = bpy.context.scene
O = bpy.context.scene.objects

def isKeyframe( f ):
    for o in O:
        for fc in o.animation_data.action.fcurves:
            kfs  = [ kf.co[0]     for kf in fc.keyframe_points ]
            if f in kfs:
                amp = fc.evaluate( f )
                print( 
                    "kf at %s for %s[%s] val: %s" % ( f, o.name, fc.data_path, amp ) 
                )

for i in range( S.frame_start, S.frame_end ):
    isKeyframe( i )

If you want this to apply only to the active object, use this code instead:

import bpy

S = bpy.context.scene
O = bpy.data.objects
o = bpy.context.object

def isKeyframe( f ):
    for fc in o.animation_data.action.fcurves:
        kfs  = [ kf.co[0]     for kf in fc.keyframe_points ]
        if f in kfs:
            amp = fc.evaluate( f )
            idx = fc.array_index
            print( 
                "kf at %s for %s[%s(%s)] val: %s" % ( f, o.name, fc.data_path, idx, amp ) 
            )

for i in range( S.frame_start, S.frame_end ):
    isKeyframe( i )

Sample output for a scene I just tested:

kf at 33 for Lamp[scale(0)] val: 1.0
kf at 33 for Lamp[scale(1)] val: 1.0
kf at 33 for Lamp[scale(2)] val: 1.0
kf at 70 for Lamp[rotation_euler(0)] val: 0.6503279805183411
kf at 70 for Lamp[rotation_euler(1)] val: 0.055217113345861435
kf at 70 for Lamp[rotation_euler(2)] val: 1.8663908243179321

EDIT: Must add a small disclaimer to this answer. This is will only print out keyframes on objects. This doesn't show keyframes on compositor nodes, scene settings and other non-object related properties. To get those, You need to alter the code a bit and read the fcurves from the specific keyframed element in question.

$\endgroup$
3
  • 1
    $\begingroup$ Suggest using for o in scene.objects to avoid false matching unlinked objects or objects from other scenes. $\endgroup$
    – batFINGER
    Commented Nov 7, 2015 at 15:00
  • $\begingroup$ Good idea, will update code later $\endgroup$
    – TLousky
    Commented Nov 7, 2015 at 15:29
  • $\begingroup$ if f in kfs is a bit risky with a float type. Consider importing a bvh (mocap) file with a high frame rate, most frames will not be at the integer part of the frame. I'd suggest using a kfs = [ kf for kf in fc.keyframe_points if abs(kf.co.x - f) < TOL] approach to select. $\endgroup$
    – batFINGER
    Commented Nov 8, 2015 at 5:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .