Tutorial: ARewO - The Animation Replicator with Offset

Python scripts let you automate processes that would take forever if you had to do them by hand.

Have you ever done the same thing over and over again, thinking: There's got to be a better way. Well good news, there is. With a little basic understanding of Python you can make Blender do a lot of things for you. So whenever you find yourself doing the same thing over and over, consider just writing a script for it. Here's how:

Download the training Blendfile including the finished script here!

The script is also available as an addon with GUI-elements here... (Rightclick -> Save As)

The entire scripts with written explanation (be aware that you need to set the identation correctly if you copy it into Blender's text editor!):

import bpy

loops = 20
distanceX = 1.083
distanceY = 0
distanceZ = 0
offset = 10

for i in range(loops):
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate = {"linked":False})
	obj = bpy.context.active_object
	obj.delta_location[0] += distanceX
	obj.delta_location[1] += distanceY
	obj.delta_location[2] += distanceZ
	animData = obj.animation_data
	action = animData.action
	fcurves = action.fcurves
	for curve in fcurves:
		keyframePoints = curve.keyframe_points
		for keyframe in keyframePoints:
			keyframe.co[0] += offset
			keyframe.handle_left[0] += offset
			keyframe.handle_right[0] += offset

#The lines explained:

import bpy

#We need to import the Blender Python Library in order to make Python understand how to handle Blender objects.

loops = 20
distanceX = 1.083
distanceY = 0
distanceZ = 0
offset = 10

#Is a list of variables that you might want to alter when you are using the script for different tasks. 
#That is why I am storing them at the beginning instead of just putting the numbers in the according lines.
for i in range(loops): #calls a for loop, i is an arbitrary name of the ?counter? of this loop. #Range indicates that i is going to be an integer which in the first loop had the value 0 #and in the last loop it will have the value loops-1. bpy.ops.object.duplicate_move(OBJECT_OT_duplicate = {"linked":False}) #This is the viewport action for duplicating an object. #It is exactly what happens if you press SHIFT+D with the mouse over the viewport. obj = bpy.context.active_object #Defines a variable obj that stores the active object. #Note that the active object is the lastes duplicate, not the object that was active when we pressed ?run script?. obj.delta_location[0] += distanceX obj.delta_location[1] += distanceY obj.delta_location[2] += distanceZ #This alters the delta location of the latest object. #The delta location (or rotation) is added to the current location of the object. #This provides the great advantage that you can use location keyframes and the object will still be offset in space, #because the value is added to the values that the location keyframes hold. Not that the [0] indicates delta_location is an array, #and the [0] stands for its X-value, the [1] for its Y and of course the [2] for the Z-value of the location. animData = obj.animation_data action = animData.action fcurves = action.fcurves #This defines 3 new variables that make it easier to access properties of the animation of your object, #making the followinger a bit easier. for curve in fcurves: #This again calls a for loop, but this time it will not count up an integer, #but rather run this loop for every object stored in the fcurves of the object. #So in this case the variable curve will not simply hold a number, but all information the fcurve has. #Meaning, all its keyframes and bezier handles. for keyframe in keyframePoints: #For every loop of the curves loop this will call as many loops as there are keyframe points (points and handles) keyframe.co[0] += offset #This adds however many frames we defined in the variable offset above. #Again this is an array and the [0] indicates, we are altering the X value of the keyframe, ergo its time parameter. #[1] would alter its value. keyframe.handle_left[0] += offset keyframe.handle_right[0] += offset #Does the same thing to the bezier handles. #So in short: Thes script will duplicate the active object, transform the position of the copy #and move its keyframes in time by a number you specify.

#EDIT: if you want a random offset of your keyframes, rather than a static one, or want a random number of frames added or subtracted
#from the keyframe distance:

import random
#at the top of the script
rand = (0.5 -
random.random()) * 10 #creates a random number between -5 and +5, since random.random creates a random number between 0 and 1
newOffset = offset + rand #before animData = obj.animation_data
#and the replace the remaining "offsets" by "newOffset"


Thanks for the idea, Mitzkus.


Related Items: