import unreal
import time
CONFIG_PATH = "/Game/DesertOsais"
def get_all_camera_actors_in_range(editor_actor_subs, start, end):
"""获取指定范围的相机"""
all_actors = editor_actor_subs.get_all_level_actors()
camera_list = []
for i in range(start, end + 1):
target_name = f"相机{i}"
found_actor = None
for actor in all_actors:
if actor.get_actor_label() == target_name:
found_actor = actor
break
if found_actor:
try:
video_index = found_actor.get_editor_property("视频序号")
camera_list.append({
'actor': found_actor,
'video_index': video_index,
'label': target_name
})
unreal.log(f"✅ 找到: {target_name} (视频序号: {video_index})")
except:
unreal.log_warning(f"⚠️ {target_name} 获取视频序号失败")
camera_list.sort(key=lambda x: x['video_index'])
return camera_list
def switch_camera_in_sequencer(level_sequence, camera_actor):
"""切换Sequencer相机剪切"""
try:
camera_cut_track = None
for track in level_sequence.get_tracks():
if isinstance(track, unreal.MovieSceneCameraCutTrack):
camera_cut_track = track
break
if not camera_cut_track:
unreal.log_error("❌ 未找到相机剪切轨道")
return False
bindings = level_sequence.get_bindings()
target_binding = None
for binding in bindings:
try:
bound_objects = unreal.SequencerTools.get_bound_objects(
level_sequence, [binding], level_sequence.get_time_range()
)
if bound_objects:
for obj in bound_objects:
if obj.bound_object == camera_actor:
target_binding = binding
break
except:
continue
if target_binding:
break
if not target_binding:
target_binding = level_sequence.add_possessable(camera_actor)
sections = camera_cut_track.get_sections()
section = sections[0] if sections else camera_cut_track.add_section()
section.set_range(level_sequence.get_playback_start(), level_sequence.get_playback_end())
binding_proxy = unreal.MovieSceneObjectBindingID()
binding_proxy.set_editor_property("Guid", target_binding.get_id())
section.set_editor_property("CameraBindingID", binding_proxy)
unreal.log(f" ✓ 相机剪切已切换到: {camera_actor.get_actor_label()}")
return True
except:
unreal.log_error("❌ 切换相机失败")
return False
def load_render_config():
"""加载渲染配置"""
try:
config = unreal.load_object(None, CONFIG_PATH)
if config:
unreal.log(f"✅ 成功加载渲染配置: {CONFIG_PATH}")
return config
else:
unreal.log_error(f"❌ 配置路径错误!")
return None
except Exception as e:
unreal.log_error(f"❌ 加载配置失败: {str(e)}")
return None
def render_job(video_index, level_sequence, config):
try:
# 获取渲染队列子系统
queue_sub = unreal.get_editor_subsystem(unreal.MoviePipelineQueueSubsystem)
queue = queue_sub.get_queue()
# 获取队列中已有的任务
jobs = queue.get_jobs()
if not jobs:
unreal.log_error(" ❌ 渲染队列为空,请先添加任务")
return False
# 使用第一个任务
job = jobs[0]
job.job_name = str(video_index) # 工作名称=视频序号
unreal.log(f" ✓ 获取已有任务: {job.job_name}")
# 更新任务配置
job.sequence = unreal.SoftObjectPath(level_sequence.get_path_name())
job.set_configuration(config)
unreal.log(f" ⏳ 开始渲染视频序号 {video_index},等待完成...")
# 使用标准的渲染队列执行方式
queue_sub.render_queue_with_executor_instance(unreal.MoviePipelinePIEExecutor())
# 等待渲染完全结束 - 多重检测确保渲染真正完成
max_wait_time = 300 # 最大等待时间(秒),防止无限等待
wait_count = 0
while queue_sub.is_rendering():
time.sleep(1)
wait_count += 1
if wait_count % 10 == 0: # 每10秒输出一次进度
unreal.log(f" ⏸ 渲染进行中... ({wait_count}秒)")
if wait_count > max_wait_time:
unreal.log_warning(f" ⚠️ 渲染超时,强制继续")
break
# 额外等待,确保预览窗口完全关闭和资源释放
unreal.log(f" ⏸ 等待资源释放...")
time.sleep(1)
unreal.log(f" ✓ 渲染完成: {video_index}")
return True
except Exception as e:
unreal.log_error(f" ❌ 渲染失败: {str(e)}")
return False
def batch_render_cameras(start=1, end=3):
"""主批量渲染函数"""
unreal.log(f"🎬 开始批量渲染任务,范围: {start}-{end}")
editor_actor_subs = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
# 获取当前关卡序列
try:
level_sequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()
except:
unreal.log_error("❌ 请先打开关卡序列!")
return
if not level_sequence:
unreal.log_error("❌ 未打开任何关卡序列!")
return
unreal.log(f"📋 当前关卡序列: {level_sequence.get_name()}")
# 加载配置
render_config = load_render_config()
if not render_config:
return
# 获取相机列表
camera_list = get_all_camera_actors_in_range(editor_actor_subs, start, end)
if not camera_list:
unreal.log_warning("⚠️ 未找到相机")
return
unreal.log(f"🎯 共找到 {len(camera_list)} 个相机需要渲染")
# 批量处理
for i, cam in enumerate(camera_list, 1):
actor = cam['actor']
idx = cam['video_index']
name = cam['label']
unreal.log(f"\n🔄 [{i}/{len(camera_list)}] 正在处理: {name} (视频序号: {idx})")
# 启用相机
actor.set_editor_property("是否使用?", True)
unreal.log(f" ✓ 设置 '是否使用?' = True")
# 切换相机
if not switch_camera_in_sequencer(level_sequence, actor):
actor.set_editor_property("是否使用?", False)
continue
time.sleep(0.5)
# 执行渲染(等待完成)
render_job(idx, level_sequence, render_config)
# 禁用相机
actor.set_editor_property("是否使用?", False)
unreal.log(f" ✓ 设置 '是否使用?' = False")
time.sleep(0.5)
unreal.log(f"\n🎉 批量渲染任务完成!共处理 {len(camera_list)} 个相机")
# ==================== 运行脚本 ====================
if __name__ == "__main__":
# 渲染 1-3 号相机,直接运行!
batch_render_cameras(start=1, end=2)
其中,queue_sub.render_queue_with_executor_instance(unreal. MoviePipelinePIEExecutor())开启渲染后,异步执行,我试了很多方法都没有用,python脚本怎么才能控制渲染当前视频完毕后再切换到下一个相机渲染视频啊
我原本的意图就是做一个镜头的批量渲染,去替代人为手动操作,我的版本是5.6.1
