Hi,
this is some work i did on an animation exporter for blender. I haven't made it into an addon yet but hopefully some of the script is helpful for learning. it basically uses pickle to write out the animation data because i tried to use objects to store the animation data instead of a dictionary. There may be better ways to implement this but hope its helpful.
Happy Sketching!
Nate
#some work in animation exporter from blender. testing in 2.79
#Usage:
#little error checking modify use at your own risk
"""
#for saving animation
#change this path for where to save animation
path = '/Users/Nathaniel/Documents/src_blender/python/snippets/tmp/anim.pickle'
obj_name = 'Cube' #change this to object name want to save animation for
exportAnimation(obj_name,path)
#for importing animation
#importAnimation(obj_name,path)
"""
import bpy
import pickle
import os
def exportAnimation(obj_name = None, out_path = ''):
"""write animation of a single object to disc
"""
#little error checking.
if obj_name not in bpy.data.objects:
print("expecting an object name in scene. doing nothing")
return
outDir = os.path.dirname(out_path)
if not os.path.exists(outDir):
print('Requires an out directory that exists to write animation file')
return
obj = bpy.data.objects[obj_name]
#read keyframe info into objects. no error checking. assumes object has keys
fc_obj_list = []
action_in_scene = obj.animation_data.action
if action_in_scene is None:
print("no animation action on object. skipping animation export")
return
fcurves_in_scene = action_in_scene.fcurves
if fcurves_in_scene is None:
print("no animation on object. skipping animation export")
return
for fc in fcurves_in_scene:
kf_obj_list = []
for kf in fc.keyframe_points:
#need to add additional keyframe info to dictionary here ex tangents
kf_obj = KeyframePoint(data = {'co':(kf.co.x,kf.co.y),
'handle_left':(kf.handle_left.x,kf.handle_left.y),
'handle_right':(kf.handle_right.x, kf.handle_right.y),
'handle_left_type':kf.handle_left_type,
'handle_right_type':kf.handle_right_type,
'interpolation':kf.interpolation
} )
kf_obj_list.append(kf_obj)
#make fcurve object
fc_obj = FCurve(points=kf_obj_list,
data_path = fc.data_path,
array_index = fc.array_index,
extrapolation = fc.extrapolation,
color_mode = fc.color_mode)
fc_obj_list.append(fc_obj)
#make action object from fcurves
action_obj = Action(fcurves = fc_obj_list)
#write action to disc
writeObject( obj = action_obj, path = out_path )
#importAnimation
def importAnimation(obj_name=None, path = ''):
anim_data = readObject(path = path)
#remove all animation on object
obj = bpy.data.objects[obj_name]
obj.animation_data_clear()
#create a new action on object. for now ignoring additional way
#to find action name to prevent trailing digits on action name.
obj.animation_data_create() #so we have .action attribute
obj.animation_data.action = bpy.data.actions.new(name= obj_name+'Action')
#create fcurves on action
for fc in anim_data.fcurves:
#create new fcurve
fc_scene = obj.animation_data.action.fcurves.new(fc.data_path,fc.array_index)
#add keyframe points for fcurve
for pt in fc.points:
print(pt.data['co'])
kp = fc_scene.keyframe_points.insert( pt.data['co'][0], pt.data['co'][1] )
#need to edit tangents here
kp.handle_left = pt.data['handle_left']
kp.handle_right = pt.data['handle_right']
kp.handle_left_type = pt.data['handle_left_type']
kp.handle_right_type = pt.data['handle_right_type']
kp.interpolation = pt.data['interpolation']
#handle addiditional fcurve attributes
fc_scene.extrapolation = fc.extrapolation
fc_scene.color_mode = fc.color_mode
#helper classes for storing animation from blender
#class Action has list of fcurves
class Action(object):
def __init__(self, **kwargs):
self.fcurves = kwargs.get('fcurves', None) #list of fcurves. using none for default
self.name = kwargs.get('name', None)
self.path = kwargs.get('path', None)
class FCurve(object):
def __init__(self, **kwargs):
self.points = kwargs.get('points', None) #list of keyframe points
self.data_path = kwargs.get('data_path', None) #str (ex: ‘location’ for positions)
self.array_index = kwargs.get('array_index', None) #int (0,1,2 for x,y,z)
self.extrapolation = kwargs.get('extrapolation', None) #str (ex: ‘CONSTANT’ flat at ends, linear would have linear bits at ends)
self.color_mode = kwargs.get('color_mode',None) #str for color ex: AUTO_RGB
class KeyframePoint(object):
def __init__(self, data = None):
self.data = data #dict of keyframe info example co, tangent info
#helper pickle functions no error checking
def writeObject(obj = None, path=''):
#no error checking.
#need to check output directory exists
if obj is None:
return
with open( path, "wb") as out_file:
pickle.dump(obj, out_file)
def readObject(path=''):
result = None
if not os.path.exists(path):
print("cannot find path to read")
return
with open( path, "rb") as in_file:
result = pickle.load(in_file)
return result
""" simple example:
p1 = KeyframePoint(data={'co':(3,2)})
p2 = KeyframePoint(data={'co':(4,3)})
f1 = FCurve(points=[p1,p2])
f2 = FCurve(points=[p1,p2])
a1 = Action(fcurves=[f1,f2])
outPath = '/Users/Nathaniel/Documents/src_blender/python/snippets/tmp/anim.pickle'
with open( outPath, "wb") as out_file:
pickle.dump(a1, out_file)
with open( outPath, "rb") as in_file:
anim_data = pickle.load(in_file)
for fc in anim_data.fcurves:
for pt in fc.points:
print(pt.data['co'])
"""
#Inspired by
#https://stackoverflow.com/questions/4530611/saving-and-loading-objects-and-using-pickle