Today we’ll be making animated scrolling credits in Blender that you can use at the end of a video with all the images and video clips that were used in it. I’ll be using the 2.93 version of Blender. You will find the blend file and the images and video clips that I’m using here on Github.
Here’s what it’s supposed to look like:
So, let’s do it. Here are the steps for you to follow:
Table of Contents
Step 1 – Create a New File
Create a new blend file, delete everything, so the default cube, the light and the camera, so that you can start with an empty scene. We’ll add all elements we need in code. You can just select all the elements in the Outliner, right-click and select Delete:
Step 2 – Add a Script
Next, go to the Scripting workspace (A) and hit the New button (B) to create a new script:
Step 3 – Type In the Python Script
Script Description
Type in the following script. You will find all the explanations in comments, but to be brief, here’s what the code in the script does:
– First we import the bpy and os modules that we’ll need to use the Blender Python API and to work with files and directories respectively.
– Then we define some functions. In particular we define the following functions:
1) change_directory (It will change to the directory where the videos and images are that we want to show in the credits animation. It will also create a list of all videos and a list of all images. To keep things simple, we’ll only be using files with the ‘.jpg’ and ‘.png’ extensions for images and files with the ‘.mp4’ extension for videos.)
2) reset_cursor (It will move the 3D cursor to the World origin, so to the location at x=0, y=0, z=0.)
3) add_text (It will create text and add a material to it.)
4) show_items (It will display each video or image and add text to it. Again, to keep things simple, the text will be just the name of the file without its extension.)
– Next, the main part of our code begins. We’ll change to a sample directory. The names of the files in that directory are at the same time the credits that I want to display. Here you can see them in the folder:
As you can see, they all have either the ‘.jpg’ or the ‘.mp4’ extension. The ‘.png’ extension would work too.
– Next we’ll change the World color to black and reset the 3D cursor.
– If there are any videos in our folder, we’ll create the text ‘Videos’ and display all the videos one after another below it.
– Next, if there are any images in the folder, we’ll create the text ‘Images’ and show all the images below it.
– Next, we’ll add and set a camera.
– We’ll set the End Frame to 480 so that the animation takes 20 seconds to complete (the frame rate is by default 24 FPS).
– At frame 1 we’ll insert a Location keyframe for the camera. Then the camera will move all the way down, below where the last image is, and we’ll insert another Location keyframe at the last frame. After that we’ll go back to frame 1.
The Script Itself
OK, so here’s the script that you can use to create the animated credits in Blender:
# We need this to work with the Blender Python API.
import bpy
# We need this to work with directories and files.
import os
### Functions ###
# Change to a directory and get the current working directory. Also, create
# a list of all the videos and a list of all the images. To do the latter, we're using
# list comprehensions. If you want to learn more about these, you will find
# the links below the code section. You will also find a link to my article about
# string boolean methods like endswith, which is the one I'm using inside the
# list comprehensions.
def change_directory(directory):
# Here we're using the global statement so that we have access to the variables
# outside the function. I have an article about the global statement, so if you want
# to read it, you will find the link below.
global folder, videos, images
os.chdir(directory)
folder = os.getcwd()
# videos
videos = [vid for vid in os.listdir(folder) if vid.endswith('.mp4')]
# images
images = [img for img in os.listdir(folder) if img.endswith('.jpg') or img.endswith('.png')]
# Reset 3D cursor back to World origin.
def reset_cursor():
bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
# Add text.
def add_text(text, scale, centered=False):
global pos
# If the text contains the jpg, png or mp4 extension, let's remove it. We can do it by slicing.
# If you want to learn more about slicing, you'll find a link below.
if text.endswith('.jpg') or text.endswith('.png') or text.endswith('.mp4'):
text = text[:-4]
bpy.ops.object.text_add()
ob=bpy.context.object
ob.data.body = text
# Remember text position so that you know where the last item is. We'll need
# this to know how much the camera should move down in the animation.
pos = ob.location
# Here we have some transformations. I have a separate article about transformations
# in Blender Python, so feel free to check it out (link below).
bpy.ops.transform.rotate(value=1.5708, constraint_axis=(True, False, False))
bpy.ops.transform.resize(value=(scale, scale, scale))
if centered:
bpy.context.object.data.align_x = 'CENTER'
bpy.context.object.data.extrude = 0.05
# create text material
mat = bpy.data.materials.get("Material")
if mat is None:
# create material
mat = bpy.data.materials.new(name="Material")
bpy.data.materials["Material"].node_tree.nodes["Principled BSDF"].inputs[17].default_value = (0.0469195, 1, 0.971278, 1)
# assign material
if ob.data.materials:
# assign to 1st material slot
ob.data.materials[0] = mat
else:
# no slots
ob.data.materials.append(mat)
# Show items (videos or images).
def show_items(item_list):
for item in item_list:
bpy.ops.import_image.to_plane(files=[{"name":item}], directory=folder)
bpy.ops.transform.rotate(value=1.5708, constraint_axis=(True, False, False))
# add light
bpy.ops.object.light_add(type='POINT', align='WORLD', scale=(1, 1, 1))
bpy.context.object.data.shadow_soft_size = 1
bpy.context.object.data.energy = 100
# add text
bpy.context.scene.cursor.location.x += 2
add_text(item, .25)
# move cursor
bpy.context.scene.cursor.location.x -= 2
bpy.context.scene.cursor.location.z -= 2
### Main Code ###
# Change to the directory where the images and videos are.
change_directory(r'D:\Blender\YT\Projects\42 - Credits in Blender with Python\images and videos')
# Set World color to black.
bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[0].default_value = (0, 0, 0, 1)
# Reset the 3D cursor.
reset_cursor()
# Add the 'Videos' text if there are any videos.
if videos:
add_text('Videos', .5, centered=True)
# Move cursor down.
bpy.context.scene.cursor.location.z -= 2
# Show all the videos.
show_items(videos)
# Add the 'Images' text if there are any images.
if images:
add_text('Images', .5, centered=True)
# Move cursor down.
bpy.context.scene.cursor.location.z -= 2
# Show all the images.
show_items(images)
# Reset cursor.
reset_cursor()
# Add and set camera.
bpy.ops.object.camera_add(location=(4, -10, 0), rotation=(1.5708, -0, -0))
bpy.context.object.data.lens = 30
# Set the end frame in the timeline to 480 (animation duration - 20s).
bpy.context.scene.frame_end = 480
# Go to frame 1.
bpy.context.scene.frame_current = 1
# Keyframe the camera (insert a Location keyframe).
bpy.ops.anim.keyframe_insert_menu(type='Location')
# Go to frame 480.
bpy.context.scene.frame_current = 480
# Move the camera below the last image. We're using the pos variable here
# which holds the location of the last text element.
bpy.ops.transform.translate(value=(-0, -0, pos.z - 4), constraint_axis=(False, False, True))
# Keyframe the camera again.
bpy.ops.anim.keyframe_insert_menu(type='Location')
# Go back to frame 1.
bpy.context.scene.frame_current = 1
Here you can see the script in the Text editor (A). As you can see, the 3D Viewport is empty (B):
Some Useful Links
In the script above I mentioned some links to my other videos where topics related to what I used in the code are covered. Here they are:
- If you want to learn more about list comprehensions, check out this article. There’s also a drill on list comprehensions, so if you want to test your knowledge, go ahead.
- Do you remember how to use the endswith method? If you need a refresher, make sure to read this article on string boolean methods.
- Here’s my article on the global statement.
- You may also want to read about slicing. You can do it here.
- In the code above there are lots of transformations. Here’s my article about how to code transformations in Blender with Python.
Step 4 – Run the Script
Hit the Run Script button (A). If there are no errors (there shouldn’t be if you copied and pasted the code as well as used a path to an existing folder with JPG, PNG and MP4 files. Naturally, your results will be different. Anyway, you will see all the new elements that we added in the Outliner (B) and in the 3D Viewport (C). Go to front view (Num 1) and switch to Rendered shading (D):
Step 5 – Play the Animation and Watch the Credits in Blender Scroll
Now you can go back to the Layout workspace and test the animation. Switch to Rendered shading and go to camera view (Num 0):
Step 6 – Render the Credits in Blender Animation
In the Output Properties tab (A) select a location for your animation file (B). Set File Format to FFmpeg Video (C) and under Encoding set the Container to MPEG-4 (D). Then go to the Render menu (E) and select Render Animation. It will take a while to render.
Naturally, this was just a very basic example. You can tweak it to your heart’s content. For example you can choose to allow other file formats or get the texts from other sources. Feel free to experiment.