Sometimes when creating an animation it is necessary to perform some actions according to the timeline or, the same, to the current animation frame number. Binding animation to timeline frames in Blender is possible using the built-in Python API.
As an example, let’s make a simple animation which turns one of the letters of any text from lowercase to uppercase in series.
- First, add some text to the scene:
- shift+a – Text
- rename it to “toLower”
- replace default value “Text” to something more interesting, for example – “cartoon”. We’re creating a cartoon, isn’t it?
- add some volume:
- in the Properties window in the Object data tab in the Geometry panel set:
- Extrude = 5
- Depth = 1
- Resolution = 2
- in the Properties window in the Object data tab in the Geometry panel set:
- shift+a – Text
To associate the text changes with the current frame number, we must keep track of the frame switching event. Blender API provides the following events to listen:
- frame_change_pre – occurs before the next frame change
- frame_change_post – occurs after the next frame change
Using external IDE PyCharm to work with Blender API or simply with the built-in text editor let’s define a function that will perform the necessary actions when timeline frame is changing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import bpy import math def textChanger(scene): startFrame = bpy.data.scenes['Scene'].frame_start endFrame = bpy.data.scenes['Scene'].frame_end currentFrame = bpy.data.scenes['Scene'].frame_current textObject = bpy.data.objects['toLower'] text = list((textObject.data.body).lower()) upperLetterIndex = math.floor(currentFrame / ((endFrame - startFrame) / len(text))) text[upperLetterIndex] = text[upperLetterIndex].upper() textObject.data.body = ''.join(text) |
In the first four lines, this function defines three variables: startFrame – the number of the first frame, endFrame – the last frame number, and currentFrame – the current frame number, and the reference to the previously created text object “toLower”.
In the last four lines of this function we split the text from the text object “toLower” letter by letter, calculate the number of the letter, which should be uppercase according to the current animation frame based on the total number of letters in the text and the total number of frames in animation, convert it to uppercase, and update the text in the “toLower” object.
It remains only to set the created function as an event handler of changing the animation frames.
To do this, let’s add this function to the event handlers list of the frame_change_pre event:
1 2 |
if textChanger not in bpy.app.handlers.frame_change_pre: bpy.app.handlers.frame_change_pre.append(textChanger) |
This code first checks was this function already has been added to event handlers list of frame_change_pre event, and if not – adds it to the list.
Full code of the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import bpy import math def textChanger(scene): startFrame = bpy.data.scenes['Scene'].frame_start endFrame = bpy.data.scenes['Scene'].frame_end currentFrame = bpy.data.scenes['Scene'].frame_current textObject = bpy.data.objects['toLower'] text = list((textObject.data.body).lower()) upperLetterIndex = math.floor(currentFrame / ((endFrame - startFrame) / len(text))) text[upperLetterIndex] = text[upperLetterIndex].upper() textObject.data.body = ''.join(text) if textChanger not in bpy.app.handlers.frame_change_pre: bpy.app.handlers.frame_change_pre.append(textChanger) |
After running the script, if starting the animation, or manually moving the cursor in the Timeline window, one of the text letters is changing to uppercase according to the current frame position.
Choose a bit funny font, customize the background and materials and start render the animation.