效果图
操作简析
工程与素材资源目录路径为
然后我们导入相应的资源,注意还需要开启以下插件
否则脚本会报 bpy.ops.import_image.to_plane 找不到的 错误。
接着我们复制以下脚本并运行,结果如下
- Outline 生成的各个对象
- Timeline 上相机的关键帧
小知识点
在 Timeline 上按
Ctrl+Tab可以切换为 Graph Edit 界面
然后按 空格键 启动动画,则我们可以看到相机在缓缓下滑的效果
完整代码与注释
# 我们需要它与 Blender Python API 一起工作
import bpy
# 我们需要它来处理目录和文件
import os
### 函数 ###
# 更改到一个目录,并获得当前的工作目录。另外,创建一个所有视频和所有图像的列表。为了实现后者,我们使用列表推导式。
def change_directory(directory):
# 这里我们使用了 global 语句,这样我们就可以访问函数外部的变量
global folder, videos, images
os.chdir(directory) # 改变当前工作目录
folder = os.getcwd() # 返回当前工作目录
# 视频
videos = [vid for vid in os.listdir(folder) if vid.endswith('.mp4')]
# 图像
images = [img for img in os.listdir(folder) if img.endswith('.jpg') or img.endswith('.png')]
# 重置 3D 光标回到世界原点。
def reset_cursor():
bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
# 添加文本
def add_text(text, scale, centered=False):
global pos
# 如果文本包含 jpg, png 或 mp4 扩展名,让我们删除它。我们可以通过切片来做。
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
# 记录文本的位置,这样你就知道最后一项在哪里。我们需要知道在动画中相机应该向下移动多少。
pos = ob.location
# 对文本进行变换
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
# 文本材质
mat = bpy.data.materials.get("Material")
if mat is None:
# 创建材质
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)
# 分配材质
if ob.data.materials:
# 分配到第一个材质槽
ob.data.materials[0] = mat
else:
# 无材质槽的话
ob.data.materials.append(mat)
# 显示条目 (视频或者图像).
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))
# 添加光源
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
# 添加文本
bpy.context.scene.cursor.location.x += 2
add_text(item, .25)
# 移动游标
bpy.context.scene.cursor.location.x -= 2
bpy.context.scene.cursor.location.z -= 2
### 主入口代码 ###
# 切换到图像和视频所在的目录。
change_directory(r'D:\Projects\BlenderProjects\PY\blend files\Animated Credits in Blender with Python\images and videos')
# 设置世界颜色为黑色。
bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[0].default_value = (0, 0, 0, 1)
# 重置 3D 游标
reset_cursor()
# 如果有任何视频,添加 'Videos' 文本。
if videos:
add_text('Videos', .5, centered=True)
# 游标下移
bpy.context.scene.cursor.location.z -= 2
# 显示所有视频
show_items(videos)
# 如果有任何图像,添加 'Images' 文本。
if images:
add_text('Images', .5, centered=True)
# 游标下移
bpy.context.scene.cursor.location.z -= 2
# 显示所有图像.
show_items(images)
# 重置游标
reset_cursor()
# 添加并设置相机
bpy.ops.object.camera_add(location=(4, -10, 0), rotation=(1.5708, -0, -0))
bpy.context.object.data.lens = 30
# 设置时间轴的结束帧为 480 (动画持续时间 - 20s)。
bpy.context.scene.frame_end = 480
# 转到第 1 帧
bpy.context.scene.frame_current = 1
# 关键帧相机(插入一个 ·位置· 关键帧)。
bpy.ops.anim.keyframe_insert_menu(type='Location')
# 转到第 480 帧.
bpy.context.scene.frame_current = 480
# 移动相机到最后一张图片的下方。这里我们使用了 pos 变量,它保存了最后一个文本元素的位置。
bpy.ops.transform.translate(value=(-0, -0, pos.z - 4), constraint_axis=(False, False, True))
# 再给相机(位置)设定关键帧。
bpy.ops.anim.keyframe_insert_menu(type='Location')
# 回转到第 1 帧
bpy.context.scene.frame_current = 1
注
bpy.ops.anim.keyframe_insert_menu 为指定的键控集 (Keying Set) 插入关键帧,如果未指定则提供可用的键控集菜单