第10章 角色动画与表演
2024/1/1大约 12 分钟
第10章 角色动画与表演
学习目标
- 掌握角色动画的基本原理和制作流程
- 学会创建自然的角色行走、跑步动画
- 掌握面部表情和口型同步技术
- 理解角色表演和情感传达
- 学会使用约束系统优化动画制作
- 掌握动画分层和混合技术
知识点详解
10.1 角色动画基础原理
10.1.1 动画十二法则
迪士尼动画师总结的经典动画原理,适用于所有角色动画:
法则 | 描述 | Blender应用 |
---|---|---|
挤压和拉伸 | 物体受力变形 | 使用形态键和骨骼变形 |
预备动作 | 动作前的准备 | 关键帧设置反向动作 |
演出布局 | 清晰的动作表达 | 摄像机角度和构图 |
连续运动与关键动作 | 两种动画制作方法 | Graph Editor精确控制 |
跟随和重叠动作 | 次要动作延迟 | 骨骼层级和约束 |
缓入缓出 | 速度变化 | 缓动曲线设置 |
弧线运动 | 自然的运动轨迹 | Motion Path可视化 |
次要动作 | 支撑主要动作 | 附加骨骼动画 |
时间节奏 | 控制动作速度 | 帧速率和关键帧间隔 |
夸张 | 突出重点 | 幅度和时间的夸张 |
扎实的绘画功底 | 基础造型能力 | 3D造型和解剖知识 |
吸引力 | 角色魅力 | 个性化动作设计 |
10.1.2 角色动画工作流程
# 角色动画制作流程
import bpy
def character_animation_workflow():
"""角色动画标准工作流程"""
# 1. 角色准备
def prepare_character():
# 检查绑定完整性
armature = bpy.data.objects['Character_Armature']
if not armature:
print("错误:未找到角色绑定")
return False
# 验证约束设置
for bone in armature.pose.bones:
if bone.constraints:
print(f"骨骼 {bone.name} 包含约束")
return True
# 2. 动画规划
def plan_animation():
scene = bpy.context.scene
# 设置帧范围
scene.frame_start = 1
scene.frame_end = 120 # 5秒动画(24fps)
# 创建动作计划
animation_plan = {
'blocking': (1, 30), # 阻挡阶段
'spline': (31, 80), # 样条曲线调整
'polish': (81, 120) # 抛光阶段
}
return animation_plan
# 3. 关键帧设置
def set_key_poses():
armature = bpy.context.object
# 主要姿势关键帧
key_frames = [1, 12, 24, 36, 48]
for frame in key_frames:
bpy.context.scene.frame_set(frame)
# 设置所有骨骼关键帧
bpy.ops.anim.keyframe_insert_menu(type='WholeCharacter')
print("关键帧设置完成")
return prepare_character(), plan_animation()
# 执行工作流程
character_animation_workflow()
10.2 基础角色动画
10.2.1 行走循环动画
创建标准的角色行走动画:
import bpy
import bmesh
from mathutils import Vector
def create_walk_cycle():
"""创建角色行走循环动画"""
armature = bpy.context.object
if not armature or armature.type != 'ARMATURE':
print("请选择绑定对象")
return
# 切换到姿势模式
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
# 行走循环关键帧(24帧循环)
walk_keyframes = {
1: 'contact_right', # 右脚接触地面
7: 'recoil_right', # 右脚缓冲
13: 'passing_right', # 右脚通过
19: 'high_point_right', # 右脚最高点
25: 'contact_left' # 左脚接触地面(循环开始)
}
# 骨骼映射
bone_map = {
'root': 'Root',
'pelvis': 'Pelvis',
'spine': 'Spine',
'head': 'Head',
'upper_arm_l': 'UpperArm.L',
'forearm_l': 'ForeArm.L',
'upper_arm_r': 'UpperArm.R',
'forearm_r': 'ForeArm.R',
'thigh_l': 'Thigh.L',
'shin_l': 'Shin.L',
'foot_l': 'Foot.L',
'thigh_r': 'Thigh.R',
'shin_r': 'Shin.R',
'foot_r': 'Foot.R'
}
def set_walk_pose(frame, pose_name):
"""设置特定帧的行走姿势"""
bpy.context.scene.frame_set(frame)
# 根据姿势名称设置骨骼变换
if pose_name == 'contact_right':
# 右脚接触地面姿势
set_bone_rotation('thigh_r', (0, 0, -20))
set_bone_rotation('shin_r', (0, 0, 40))
set_bone_rotation('foot_r', (0, 0, -10))
set_bone_rotation('thigh_l', (0, 0, 30))
set_bone_rotation('shin_l', (0, 0, -10))
# 手臂摆动
set_bone_rotation('upper_arm_l', (0, 0, 20))
set_bone_rotation('upper_arm_r', (0, 0, -20))
elif pose_name == 'passing_right':
# 右脚通过姿势
set_bone_rotation('thigh_r', (0, 0, 0))
set_bone_rotation('shin_r', (0, 0, 0))
set_bone_rotation('thigh_l', (0, 0, -20))
set_bone_rotation('shin_l', (0, 0, 40))
# 躯干轻微倾斜
set_bone_rotation('pelvis', (0, 0, 2))
# 为所有姿势骨骼设置关键帧
for bone_name in bone_map.values():
if bone_name in armature.pose.bones:
bone = armature.pose.bones[bone_name]
bone.keyframe_insert(data_path="rotation_euler", frame=frame)
bone.keyframe_insert(data_path="location", frame=frame)
def set_bone_rotation(bone_key, rotation):
"""设置骨骼旋转"""
bone_name = bone_map.get(bone_key)
if bone_name and bone_name in armature.pose.bones:
bone = armature.pose.bones[bone_name]
bone.rotation_euler = rotation
# 创建所有关键帧姿势
for frame, pose_name in walk_keyframes.items():
set_walk_pose(frame, pose_name)
print("行走循环动画创建完成")
# 创建行走动画
create_walk_cycle()
10.2.2 跑步动画
def create_run_cycle():
"""创建角色跑步循环动画"""
armature = bpy.context.object
bpy.ops.object.mode_set(mode='POSE')
# 跑步循环更快,更夸张的动作
run_keyframes = {
1: 'flight_phase_1', # 腾空阶段1
6: 'contact_right', # 右脚着地
9: 'recoil_right', # 右脚缓冲
12: 'flight_phase_2', # 腾空阶段2
18: 'contact_left', # 左脚着地
21: 'recoil_left' # 左脚缓冲
}
def set_run_pose(frame, pose_name):
bpy.context.scene.frame_set(frame)
if pose_name == 'flight_phase_1':
# 腾空姿势 - 身体前倾
set_bone_rotation('pelvis', (-10, 0, 0))
set_bone_rotation('spine', (-5, 0, 0))
# 腿部大幅摆动
set_bone_rotation('thigh_r', (0, 0, 45))
set_bone_rotation('shin_r', (0, 0, -90))
set_bone_rotation('thigh_l', (0, 0, -30))
set_bone_rotation('shin_l', (0, 0, 10))
# 手臂大幅摆动
set_bone_rotation('upper_arm_l', (0, 0, 45))
set_bone_rotation('upper_arm_r', (0, 0, -45))
set_bone_rotation('forearm_l', (0, 0, -30))
set_bone_rotation('forearm_r', (0, 0, 30))
elif pose_name == 'contact_right':
# 右脚着地 - 身体垂直
set_bone_rotation('pelvis', (0, 0, 0))
set_bone_rotation('spine', (0, 0, 0))
# 支撑腿垂直
set_bone_rotation('thigh_r', (0, 0, 0))
set_bone_rotation('shin_r', (0, 0, 0))
# 为骨骼设置关键帧
for bone_name in ['pelvis', 'spine', 'thigh_r', 'shin_r', 'thigh_l', 'shin_l',
'upper_arm_l', 'upper_arm_r', 'forearm_l', 'forearm_r']:
real_name = bone_map.get(bone_name, bone_name)
if real_name in armature.pose.bones:
bone = armature.pose.bones[real_name]
bone.keyframe_insert(data_path="rotation_euler", frame=frame)
# 创建跑步关键帧
for frame, pose_name in run_keyframes.items():
set_run_pose(frame, pose_name)
print("跑步循环动画创建完成")
10.3 面部动画和表情
10.3.1 面部表情系统
def setup_facial_animation():
"""设置面部动画系统"""
# 选择角色头部网格
head_mesh = bpy.data.objects.get('Character_Head')
if not head_mesh:
print("未找到头部网格")
return
bpy.context.view_layer.objects.active = head_mesh
bpy.ops.object.mode_set(mode='EDIT')
# 创建基础面部表情形态键
facial_expressions = {
'Basis': 'base_expression',
'Happy': 'smile_expression',
'Sad': 'frown_expression',
'Angry': 'angry_expression',
'Surprised': 'surprise_expression',
'Fear': 'fear_expression',
'Disgust': 'disgust_expression'
}
# 口型同步形态键
visemes = {
'A': 'ah_sound', # "ah", "father"
'E': 'eh_sound', # "bet", "said"
'I': 'ih_sound', # "bit", "tip"
'O': 'oh_sound', # "bought", "fall"
'U': 'oo_sound', # "boot", "you"
'M': 'mbp_sound', # "mat", "bat", "pat"
'L': 'l_sound', # "lot", "hello"
'S': 's_sound', # "sit", "kiss"
'T': 't_sound', # "tip", "butter"
'F': 'fv_sound', # "far", "very"
'TH': 'th_sound', # "think", "that"
'R': 'r_sound' # "red", "error"
}
def create_shape_key(name, description):
"""创建形态键"""
bpy.ops.object.mode_set(mode='OBJECT')
# 确保有基础形态键
if not head_mesh.data.shape_keys:
bpy.ops.object.shape_key_add(from_mix=False)
# 添加新形态键
bpy.ops.object.shape_key_add(from_mix=False)
shape_key = head_mesh.data.shape_keys.key_blocks[-1]
shape_key.name = name
print(f"创建形态键: {name}")
return shape_key
# 创建表情形态键
for name, desc in facial_expressions.items():
if name != 'Basis': # 基础形态键自动存在
create_shape_key(name, desc)
# 创建口型形态键
for viseme, desc in visemes.items():
create_shape_key(f"Viseme_{viseme}", desc)
return True
# 面部动画控制器
def animate_facial_expression():
"""创建面部表情动画"""
head_mesh = bpy.data.objects.get('Character_Head')
if not head_mesh or not head_mesh.data.shape_keys:
print("未找到面部形态键")
return
shape_keys = head_mesh.data.shape_keys.key_blocks
# 创建复杂表情动画
def create_expression_sequence():
"""创建表情序列"""
# 表情时间轴
expression_timeline = [
(1, {'Happy': 0.0, 'Sad': 0.0}), # 中性表情
(24, {'Happy': 1.0, 'Sad': 0.0}), # 开心
(48, {'Happy': 0.5, 'Sad': 0.3}), # 混合表情
(72, {'Happy': 0.0, 'Sad': 1.0}), # 悲伤
(96, {'Happy': 0.0, 'Sad': 0.0}) # 回到中性
]
for frame, expressions in expression_timeline:
bpy.context.scene.frame_set(frame)
for expr_name, value in expressions.items():
if expr_name in shape_keys:
shape_key = shape_keys[expr_name]
shape_key.value = value
shape_key.keyframe_insert(data_path="value", frame=frame)
print("表情序列动画创建完成")
create_expression_sequence()
# 执行面部动画设置
setup_facial_animation()
animate_facial_expression()
10.3.2 口型同步
def create_lip_sync_animation(audio_file=None):
"""创建口型同步动画"""
head_mesh = bpy.data.objects.get('Character_Head')
if not head_mesh:
return
# 口型同步数据(手动或从音频分析获得)
lip_sync_data = [
(1, 'A', 0.8), # 帧,音素,强度
(5, 'M', 1.0),
(8, 'A', 0.6),
(12, 'S', 0.9),
(15, 'I', 0.7),
(18, 'T', 0.8),
(22, 'I', 0.6),
(25, 'N', 0.7),
(28, 'G', 0.8)
]
shape_keys = head_mesh.data.shape_keys.key_blocks
def apply_lip_sync():
"""应用口型同步数据"""
# 重置所有口型形态键
viseme_keys = [key for key in shape_keys.keys() if key.startswith('Viseme_')]
for frame, phoneme, intensity in lip_sync_data:
bpy.context.scene.frame_set(frame)
# 重置所有口型
for viseme_key in viseme_keys:
shape_keys[viseme_key].value = 0.0
shape_keys[viseme_key].keyframe_insert(data_path="value", frame=frame)
# 设置当前音素
target_key = f"Viseme_{phoneme}"
if target_key in shape_keys:
shape_keys[target_key].value = intensity
shape_keys[target_key].keyframe_insert(data_path="value", frame=frame)
print("口型同步动画创建完成")
apply_lip_sync()
# 高级口型同步(基于音频分析)
def advanced_lip_sync_from_audio(audio_path):
"""从音频文件生成口型同步"""
try:
import librosa
import numpy as np
except ImportError:
print("需要安装librosa库进行音频分析")
return
# 加载音频文件
y, sr = librosa.load(audio_path)
# 提取音频特征
mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
# 简化的音素识别(实际应用中需要更复杂的算法)
def audio_to_visemes(mfccs):
"""音频特征转换为口型"""
viseme_sequence = []
frame_count = mfccs.shape[1]
hop_length = 512
for i in range(frame_count):
# 基于MFCC特征简单分类
mfcc_frame = mfccs[:, i]
# 这里使用简化的规则,实际需要训练的分类器
if mfcc_frame[1] > 0.5:
viseme = 'A'
elif mfcc_frame[2] > 0.3:
viseme = 'E'
elif mfcc_frame[3] > 0.2:
viseme = 'O'
else:
viseme = 'M'
frame_time = librosa.frames_to_time(i, sr=sr, hop_length=hop_length)
blender_frame = int(frame_time * 24) # 24fps
viseme_sequence.append((blender_frame, viseme, 0.8))
return viseme_sequence
# 应用生成的口型序列
lip_sync_data = audio_to_visemes(mfccs)
head_mesh = bpy.data.objects.get('Character_Head')
shape_keys = head_mesh.data.shape_keys.key_blocks
for frame, phoneme, intensity in lip_sync_data:
bpy.context.scene.frame_set(frame)
# 应用口型
target_key = f"Viseme_{phoneme}"
if target_key in shape_keys:
shape_keys[target_key].value = intensity
shape_keys[target_key].keyframe_insert(data_path="value", frame=frame)
print(f"从音频生成 {len(lip_sync_data)} 个口型关键帧")
10.4 高级动画技术
10.4.1 动画分层系统
def setup_animation_layers():
"""设置动画分层系统"""
armature = bpy.context.object
if not armature or armature.type != 'ARMATURE':
return
# 创建动画分层
animation_layers = {
'Base': 'base_animation', # 基础动画层
'Additive': 'additive_layer', # 叠加动画层
'Override': 'override_layer' # 覆盖动画层
}
def create_nla_strips():
"""创建NLA条带进行分层管理"""
# 确保在姿势模式
bpy.ops.object.mode_set(mode='POSE')
# 创建基础动作
base_action = bpy.data.actions.new(name="BaseWalk")
armature.animation_data.action = base_action
# 创建基础行走动画
create_walk_cycle()
# 推送到NLA
bpy.ops.nla.actionclip_add()
# 创建叠加动作(如呼吸、闲置动作)
additive_action = bpy.data.actions.new(name="BreathingIdle")
armature.animation_data.action = additive_action
# 创建呼吸动画
create_breathing_animation()
# 推送到新的NLA轨道
bpy.ops.nla.tracks_add()
bpy.ops.nla.actionclip_add()
# 设置混合模式
nla_tracks = armature.animation_data.nla_tracks
if len(nla_tracks) > 1:
additive_track = nla_tracks[1]
additive_track.name = "Additive_Layer"
for strip in additive_track.strips:
strip.blend_type = 'ADD' # 叠加模式
strip.influence = 0.5 # 影响强度
def create_breathing_animation():
"""创建呼吸动画"""
spine_bones = ['Spine', 'Spine.001', 'Spine.002']
for frame in range(1, 121, 30): # 每30帧一个呼吸循环
bpy.context.scene.frame_set(frame)
for bone_name in spine_bones:
if bone_name in armature.pose.bones:
bone = armature.pose.bones[bone_name]
# 呼吸时脊椎轻微扩展
if frame % 60 == 1: # 吸气
bone.scale = (1.0, 1.02, 1.0)
else: # 呼气
bone.scale = (1.0, 0.98, 1.0)
bone.keyframe_insert(data_path="scale", frame=frame)
print("呼吸动画创建完成")
create_nla_strips()
# 动画混合控制
def setup_animation_blending():
"""设置动画混合系统"""
armature = bpy.context.object
# 创建自定义属性用于混合控制
def add_blend_controls():
"""添加混合控制属性"""
# 走路强度
armature["walk_influence"] = 1.0
armature.id_properties_ui("walk_influence").update(
min=0.0, max=1.0, description="Walking animation influence"
)
# 跑步强度
armature["run_influence"] = 0.0
armature.id_properties_ui("run_influence").update(
min=0.0, max=1.0, description="Running animation influence"
)
# 情绪强度
armature["emotion_intensity"] = 0.5
armature.id_properties_ui("emotion_intensity").update(
min=0.0, max=1.0, description="Emotional animation intensity"
)
def setup_drivers():
"""设置驱动器进行程序化混合"""
if not armature.animation_data:
armature.animation_data_create()
nla_tracks = armature.animation_data.nla_tracks
for track in nla_tracks:
for strip in track.strips:
# 为条带影响强度添加驱动器
driver = strip.driver_add("influence").driver
driver.type = 'AVERAGE'
# 添加变量
var = driver.variables.new()
var.name = "control"
var.type = 'SINGLE_PROP'
# 连接到自定义属性
target = var.targets[0]
target.id = armature
if "walk" in strip.name.lower():
target.data_path = '["walk_influence"]'
elif "run" in strip.name.lower():
target.data_path = '["run_influence"]'
print(f"为 {strip.name} 添加驱动器")
add_blend_controls()
setup_drivers()
# 执行分层设置
setup_animation_layers()
setup_animation_blending()
实践案例
案例1:角色情绪表演
def create_emotional_performance():
"""创建角色情绪表演动画"""
# 情绪表演时间轴
emotional_sequence = [
(1, 'neutral', 0.0), # 中性
(48, 'happy', 1.0), # 高兴
(96, 'contemplative', 0.5), # 沉思
(144, 'determined', 0.8), # 坚决
(192, 'triumphant', 1.0) # 胜利
]
armature = bpy.context.object
head_mesh = bpy.data.objects.get('Character_Head')
def animate_emotion(frame, emotion, intensity):
"""为特定帧设置情绪动画"""
bpy.context.scene.frame_set(frame)
# 面部表情
if head_mesh and head_mesh.data.shape_keys:
shape_keys = head_mesh.data.shape_keys.key_blocks
if emotion == 'happy':
shape_keys['Happy'].value = intensity
shape_keys['Happy'].keyframe_insert(data_path="value", frame=frame)
elif emotion == 'contemplative':
shape_keys['Sad'].value = intensity * 0.3
shape_keys['Sad'].keyframe_insert(data_path="value", frame=frame)
# 身体姿态
if armature:
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
if emotion == 'triumphant':
# 胜利姿势 - 举起双臂
armature.pose.bones['UpperArm.L'].rotation_euler = (0, 0, 1.57)
armature.pose.bones['UpperArm.R'].rotation_euler = (0, 0, -1.57)
armature.pose.bones['UpperArm.L'].keyframe_insert(data_path="rotation_euler", frame=frame)
armature.pose.bones['UpperArm.R'].keyframe_insert(data_path="rotation_euler", frame=frame)
elif emotion == 'contemplative':
# 沉思姿势 - 手托下巴
armature.pose.bones['Head'].rotation_euler = (0.3, 0, 0)
armature.pose.bones['Head'].keyframe_insert(data_path="rotation_euler", frame=frame)
# 应用情绪序列
for frame, emotion, intensity in emotional_sequence:
animate_emotion(frame, emotion, intensity)
print("情绪表演动画创建完成")
create_emotional_performance()
案例2:角色对话场景
def create_dialogue_scene():
"""创建角色对话场景动画"""
# 对话脚本和时间轴
dialogue_script = [
(1, 30, "Hello there!", 'friendly'),
(35, 65, "How are you doing?", 'curious'),
(70, 100, "That's great to hear!", 'happy'),
(105, 135, "See you later!", 'farewell')
]
def animate_dialogue_line(start_frame, end_frame, text, emotion):
"""为对话行创建动画"""
# 设置基础身体动画
mid_frame = (start_frame + end_frame) // 2
# 说话时的微妙身体动作
bpy.context.scene.frame_set(start_frame)
# 开始姿势
bpy.context.scene.frame_set(mid_frame)
# 强调姿势
bpy.context.scene.frame_set(end_frame)
# 结束姿势
# 设置面部表情
head_mesh = bpy.data.objects.get('Character_Head')
if head_mesh and head_mesh.data.shape_keys:
shape_keys = head_mesh.data.shape_keys.key_blocks
expression_map = {
'friendly': 'Happy',
'curious': 'Surprised',
'happy': 'Happy',
'farewell': 'Happy'
}
target_expression = expression_map.get(emotion, 'Happy')
if target_expression in shape_keys:
# 淡入表情
bpy.context.scene.frame_set(start_frame)
shape_keys[target_expression].value = 0.0
shape_keys[target_expression].keyframe_insert(data_path="value")
# 表情高峰
bpy.context.scene.frame_set(mid_frame)
shape_keys[target_expression].value = 0.8
shape_keys[target_expression].keyframe_insert(data_path="value")
# 淡出表情
bpy.context.scene.frame_set(end_frame)
shape_keys[target_expression].value = 0.0
shape_keys[target_expression].keyframe_insert(data_path="value")
print(f"对话行动画: {text}")
# 创建所有对话动画
for start, end, text, emotion in dialogue_script:
animate_dialogue_line(start, end, text, emotion)
print("对话场景动画创建完成")
create_dialogue_scene()
快捷键汇总
动画制作快捷键
功能 | 快捷键 | 说明 |
---|---|---|
插入关键帧 | I | 弹出关键帧菜单 |
删除关键帧 | Alt + I | 删除所选属性关键帧 |
复制姿势 | Ctrl + C | 复制当前姿势 |
粘贴姿势 | Ctrl + V | 粘贴姿势到当前帧 |
镜像姿势 | Ctrl + Shift + V | 镜像粘贴姿势 |
播放动画 | Space | 播放/暂停动画 |
跳到下一帧 | → | 前进一帧 |
跳到上一帧 | ← | 后退一帧 |
跳到下个关键帧 | Page Down | 跳到下个关键帧 |
跳到上个关键帧 | Page Up | 跳到上个关键帧 |
骨骼操作快捷键
功能 | 快捷键 | 说明 |
---|---|---|
选择骨骼链 | Shift + G → Parent | 选择父子骨骼链 |
选择连接骨骼 | Ctrl + L | 选择连接的骨骼 |
切换骨骼层 | M | 移动骨骼到层 |
显示/隐藏骨骼层 | Shift + 数字 | 切换骨骼层显示 |
IK约束开关 | Shift + I | 切换IK约束 |
Graph Editor快捷键
功能 | 快捷键 | 说明 |
---|---|---|
平滑曲线 | Alt + O | 平滑选中关键帧 |
线性插值 | T → Linear | 设置线性插值 |
贝塞尔插值 | T → Bezier | 设置贝塞尔插值 |
自动手柄 | V → Auto | 自动调整手柄 |
对齐手柄 | V → Aligned | 对齐贝塞尔手柄 |
注意事项
- 角色动画需要良好的绑定基础,确保绑定无误后再开始动画
- 遵循动画十二法则,创建更自然的角色动作
- 使用参考视频研究真实的人体运动
- 分层制作动画,便于后期调整和修改
- 定期保存工作文件,避免数据丢失
进阶建议
- 学习动作捕捉技术,提高动画制作效率
- 研究不同角色的个性化动作特征
- 掌握群体动画和角色交互技术
- 了解游戏引擎中的角色动画管线
- 关注最新的AI辅助动画制作工具
本章小结
本章深入学习了 Blender 中的角色动画和表演技术。通过学习动画基础原理、角色动画制作、面部表情系统和高级动画技术,你应该能够:
- 掌握动画基础:理解迪士尼动画十二法则,应用到3D角色动画中
- 创建角色动画:制作行走、跑步等基础角色动作循环
- 面部动画:设置面部表情系统和口型同步技术
- 高级技术:使用动画分层、混合和程序化控制
- 表演技巧:创建有情感深度的角色表演动画
角色动画是3D创作中最具挑战性但也最有回报的技能之一。通过持续练习和观察真实世界的运动,你将能够创造出生动、有说服力的角色表演。