From BlenderWiki
Actions and drivers
Object action
#-------------------------------------------------- # File ob_action.py #-------------------------------------------------- import bpy import math def run(origin): # Set animation start and stop scn = bpy.context.scene scn.frame_start = 11 scn.frame_end = 200 # Create ico sphere bpy.ops.mesh.primitive_ico_sphere_add(location=origin) ob = bpy.context.object # Insert keyframes with operator code # Object should be automatically selected z = 10 t = 1 for n in range(5): t += 10 bpy.ops.anim.change_frame(frame = t) bpy.ops.transform.translate(value=(2, 0, z)) bpy.ops.anim.keyframe_insert_menu(type='Location') t += 10 bpy.ops.anim.change_frame(frame = t) bpy.ops.transform.translate(value=(2, 0, -z)) bpy.ops.anim.keyframe_insert_menu(type='Location') z *= 0.67 action = ob.animation_data.action # Create dict with location FCurves fcus = {} for fcu in action.fcurves: if fcu.data_path == 'location': fcus[fcu.array_index] = fcu print(fcus.items()) # Add new keypoints to x and z kpts_x = fcus[0].keyframe_points kpts_z = fcus[2].keyframe_points (x0,y0,z0) = origin omega = 2*math.pi/20 z *= 0.67 for t in range(101, 201): xt = 20 + 0.2*(t-101) zt = z*(1-math.cos(omega*(t - 101))) z *= 0.98 kpts_z.insert(t, zt+z0, options={'FAST'}) kpts_x.insert(t, xt+x0) # Change extrapolation and interpolation for # X curve to linear fcus[0].extrapolation = 'LINEAR' for kp in kpts_x: kp.interpolation = 'LINEAR' # Y location constant and can be removed action.fcurves.remove(fcus[1]) bpy.ops.object.paths_calculate() return if __name__ == "__main__": run((0,0,10)) bpy.ops.screen.animation_play(reverse=False, sync=False)
Posebone action
This program creates an armature with two bones, which rotate in some complicated curves.
#-------------------------------------------------- # File pose_action.py #-------------------------------------------------- import bpy import math def run(origin): # Set animation start and stop scn = bpy.context.scene scn.frame_start = 1 scn.frame_end = 250 # Create armature and object bpy.ops.object.armature_add() ob = bpy.context.object amt = ob.data # Rename first bone and create second bone bpy.ops.object.mode_set(mode='EDIT') base = amt.edit_bones['Bone'] base.name = 'Base' tip = amt.edit_bones.new('Tip') tip.head = (0,0,1) tip.tail = (0,0,2) tip.parent = base tip.use_connect = True # Set object location in object mode bpy.ops.object.mode_set(mode='OBJECT') ob.location=origin # Set rotation mode to Euler ZYX bpy.ops.object.mode_set(mode='POSE') pbase = ob.pose.bones['Base'] pbase.rotation_mode = 'ZYX' ptip = ob.pose.bones['Tip'] ptip.rotation_mode = 'ZYX' # Insert 26 keyframes for two rotation FCurves # Last keyframe will be outside animation range for n in range(26): pbase.keyframe_insert( 'rotation_euler', index=0, frame=n, group='Base') ptip.keyframe_insert( 'rotation_euler', index=2, frame=n, group='Tip') # Get FCurves from newly created action action = ob.animation_data.action fcus = {} for fcu in action.fcurves: bone = fcu.data_path.split('"')[1] fcus[(bone, fcu.array_index)] = fcu # Modify the keypoints baseKptsRotX = fcus[('Base', 0)].keyframe_points tipKptsRotZ = fcus[('Tip', 2)].keyframe_points omega = 2*math.pi/250 for n in range(26): t = 10*n phi = omega*t kp = baseKptsRotX[n] kp.co = (t+1,phi+0.7*math.sin(phi)) kp.interpolation = 'LINEAR' kp = tipKptsRotZ[n] kp.co = (t+1, -3*phi+2.7*math.cos(2*phi)) kp.interpolation = 'LINEAR' # Calculate paths for posebones bpy.ops.pose.select_all(action='SELECT') bpy.ops.pose.paths_calculate() return if __name__ == "__main__": run((10,0,0)) bpy.ops.screen.animation_play(reverse=False, sync=False)
Parenting
This program creates a complicated motion by consecutively parenting a few empties to each other, and assigning a simple rotation to each of them.
#---------------------------------------------------------- # File epicycle.py #---------------------------------------------------------- import bpy import math from math import pi def createEpiCycle(origin): periods = [1, 5, 8, 17] radii = [1.0, 0.3, 0.5, 0.1] axes = [0, 2, 1, 0] phases = [0, pi/4, pi/2, 0] # Add empties scn = bpy.context.scene empties = [] nEmpties = len(periods) for n in range(nEmpties): empty = bpy.data.objects.new('Empty_%d' % n, None) scn.objects.link(empty) empties.append(empty) # Make each empty the parent of the consecutive one for n in range(1, nEmpties): empties[n].parent = empties[n-1] empties[n].location = (0, radii[n-1], 0) # Insert two keyframes for each empty for n in range(nEmpties): empty = empties[n] empty.keyframe_insert( 'rotation_euler', index=axes[n], frame=0, group=empty.name) empty.keyframe_insert( 'rotation_euler', index=axes[n], frame=periods[n], group=empty.name) fcu = empty.animation_data.action.fcurves[0] print(empty, fcu.data_path, fcu.array_index) kp0 = fcu.keyframe_points[0] kp0.co = (0, phases[n]) kp0.interpolation = 'LINEAR' kp1 = fcu.keyframe_points[1] kp1.co = (250.0/periods[n], 2*pi + phases[n]) kp1.interpolation = 'LINEAR' fcu.extrapolation = 'LINEAR' last = empties[nEmpties-1] bpy.ops.mesh.primitive_ico_sphere_add( size = 0.2, location=last.location) ob = bpy.context.object ob.parent = last empties[0].location = origin return def run(origin): createEpiCycle(origin) bpy.ops.object.paths_calculate() return if __name__ == "__main__": run((0,0,0)) bpy.ops.screen.animation_play(reverse=False, sync=False)
Drivers
This program adds an armature with one driver bones and two driven bones. The tip's Z rotation is driven by the driver's x location. The base's Z rotation is driven both by the driver's Y location and its Z rotation.
#---------------------------------------------------------- # File driver.py #---------------------------------------------------------- import bpy def run(origin): # Create armature and object amt = bpy.data.armatures.new('MyRigData') rig = bpy.data.objects.new('MyRig', amt) rig.location = origin amt.show_names = True # Link object to scene scn = bpy.context.scene scn.objects.link(rig) scn.objects.active = rig scn.update() # Create bones bpy.ops.object.mode_set(mode='EDIT') base = amt.edit_bones.new('Base') base.head = (0,0,0) base.tail = (0,0,1) tip = amt.edit_bones.new('Tip') tip.head = (0,0,1) tip.tail = (0,0,2) tip.parent = base tip.use_connect = True driver = amt.edit_bones.new('Driver') driver.head = (2,0,0) driver.tail = (2,0,1) bpy.ops.object.mode_set(mode='POSE') # Add driver for Tip's Z rotation # Tip.rotz = 1.0 - 1.0*x, where x = Driver.locx fcurve = rig.pose.bones["Tip"].driver_add('rotation_quaternion', 3) drv = fcurve.driver drv.type = 'AVERAGE' drv.show_debug_info = True var = drv.variables.new() var.name = 'x' var.type = 'TRANSFORMS' targ = var.targets[0] targ.id = rig targ.transform_type = 'LOC_X' targ.bone_target = 'Driver' targ.use_local_space_transform = True fmod = fcurve.modifiers[0] fmod.mode = 'POLYNOMIAL' fmod.poly_order = 1 fmod.coefficients = (1.0, -1.0) # Add driver for Base's Z rotation # Base.rotz = z*z - 3*y, where y = Driver.locy and z = Driver.rotz fcurve = rig.pose.bones["Base"].driver_add('rotation_quaternion', 3) drv = fcurve.driver drv.type = 'SCRIPTED' drv.expression = 'z*z - 3*y' drv.show_debug_info = True var1 = drv.variables.new() var1.name = 'y' var1.type = 'TRANSFORMS' targ1 = var1.targets[0] targ1.id = rig targ1.transform_type = 'LOC_Y' targ1.bone_target = 'Driver' targ1.use_local_space_transform = True var2 = drv.variables.new() var2.name = 'z' var2.type = 'TRANSFORMS' targ2 = var2.targets[0] targ2.id = rig targ2.transform_type = 'ROT_Z' targ2.bone_target = 'Driver' targ2.use_local_space_transform = True return if __name__ == "__main__": run((0,0,0))
