Not everything can be keyframed, but almost everything can. There are benefits to keyframing, but it isn't always necessary. This short example shows how to use frame_change_pre handler, it is called on every frame change. This means if you have something you want to change as a function of
Search blender API docs for more information about frame_change_pre. You could even combine the frame_change_pre with setting and adding keyframes, but unless you want to export the animation - that might be overkill.
While debugging, you might find that you are calling successive versions of a function from the event handler. There might be more efficient ways of fixing this, but i've found this method removes 'old' code from the event handler list just fine.
time
or frame number
, that you can do this very easily. This works on text body too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import math | |
# for demo it creates a cube if it doesn't exist, | |
# but this can be any existing named object. | |
if not 'Cube' in bpy.data.objects: | |
bpy.ops.mesh.primitive_cube_add() | |
frames_per_revolution = 120.0 | |
step_size = 2*math.pi / frames_per_revolution | |
def set_object_location(n): | |
x = math.sin(n) * 5 | |
y = math.cos(n) * 5 | |
z = 0.0 | |
ob = bpy.data.objects.get("Cube") | |
ob.location = (x, y, z) | |
# every frame change, this function is called. | |
def my_handler(scene): | |
frame = scene.frame_current | |
n = frame % frames_per_revolution | |
if n == 0: | |
set_object_location(n) | |
else: | |
set_object_location(n*step_size) | |
bpy.app.handlers.frame_change_pre.append(my_handler) |
While debugging, you might find that you are calling successive versions of a function from the event handler. There might be more efficient ways of fixing this, but i've found this method removes 'old' code from the event handler list just fine.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# if i ran the script twice, the functions are daisy-chained | |
>> bpy.app.handlers.frame_change_pre | |
[<function my_handler at 0x48a7d10>, <function my_handler at 0x5406490>] | |
# this will removal all 'frame_change_pre' handlers, | |
bpy.app.handlers.frame_change_pre.clear() | |
# there are scenarios when you might want this, but sometimes it will be too broad. | |
# one way to remove them is by doing a pop() on those items that match | |
# the name of the function you want to remove, this needs to happen in reverse | |
my_handler_list = bpy.app.handlers.frame_change_pre # alias | |
fin = len(my_handler_list) | |
for idx, func in enumerate(reversed(my_handler_list)): | |
if func.__name__ == 'my_handler': | |
my_handler_list.pop(fin-1-idx) |