找回密码
 立即注册
查看: 736|回复: 0

Unreal Python Sequencer 批量渲染总结

[复制链接]
发表于 2020-11-27 12:52 | 显示全部楼层 |阅读模式
本文章转载自 智伤帝的个人博客 - 原文链接

前言

  最近我的学弟找我咨询关于 Unreal Sequencer 渲染输出的问题。
  之前没有折腾过这个一块,于是就跟进了一下,顺便学习 Sequencer 的序列输出。
  另外最近另一个师弟也研究了差不多的问题,发了一篇 B站专栏 , 在这里推荐一下 链接
手动操作

  在自动化操作渲染之前,需要先搞清楚怎么手动操作 Sequencer 进行渲染。
  其实操作起来不难,打开 Unreal 的定序器,点击上面的 Render 图标打开 Render Movie Setting
  然后配置好渲染设置就可以点击渲染,就可以将影片批量渲染出来。
自动化操作

  下面就是将手动操作转为 Python 的自动操作。
  具体的操作脚本其实可以参考官方的脚本,在官方 SequencerScripting 插件里面有渲染相关的 Python 脚本。
  安装了 Unreal 引擎之后可以根据地址查找 \Engine\Plugins\MovieScene\SequencerScripting\Content\Python
sequencer_examples 就有输出的 Python 代码,不需要自己查文档研究怎么搭建代码。
  参照 render_sequence_to_movie 的代码即可输出。
  其中比较坑的点在于 OnRenderMovieStopped 的 delegate
  接入 Python 回调需要一个 global 函数才可以,否则执行完成的回调函数不会触发。
  官方的案例是放到最外层执行的,如果不凑巧回调函数写在函数里面,就需要利用 global 关键字解决这个问题。
  官方案例还没能实现一个需求,就是批量将不同 Sequence 同时渲染出来。
  然而 render_movie 这个函数是不阻塞的,如果使用 for 循环会一直把所有的 render_movie 持续执行。
  所以这里进行渲染需要通过回调来实现逐个渲染的调用。
Python 代码

# -*- coding: utf-8 -*-
"""
渲染 sequencer 的画面
选择 LevelSequence 批量进行渲染
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

__author__ = 'timmyliang'
__email__ = '820472580@qq.com'
__date__ = '2020-07-14 21:57:32'

import unreal

import os
import subprocess
from functools import partial

def alert(msg):
    unreal.SystemLibrary.print_string(None,msg,text_color=[255,255,255,255])

def render(sequence_list,i,output_directory="C:/render",output_format="{sequence}"):
   
    # NOTE 如果超出数组则退出执行
    if i >= len(sequence_list):
   
        # NOTE 输出完成 打开输出文件夹的路径
        subprocess.call(["start","",output_directory], creationflags=0x08000000,shell=True)
        return

    # NOTE 获取当前渲染序号下的 LevelSequence
    sequence = sequence_list

    # NOTE 配置渲染参数
    settings = unreal.MovieSceneCaptureSettings()
    path = unreal.DirectoryPath(output_directory)
    settings.set_editor_property("output_directory",path)
    settings.set_editor_property("output_format",output_format)
    settings.set_editor_property("overwrite_existing",True)
    settings.set_editor_property("game_mode_override",None)
    settings.set_editor_property("use_relative_frame_numbers",False)
    settings.set_editor_property("handle_frames",0)
    settings.set_editor_property("zero_pad_frame_numbers",4)
    settings.set_editor_property("use_custom_frame_rate",True)
    settings.set_editor_property("custom_frame_rate",unreal.FrameRate(24, 1))

    # NOTE 渲染大小
    w,h = 1280,720
    settings.set_editor_property("resolution",unreal.CaptureResolution(w,h))
   
    settings.set_editor_property("enable_texture_streaming",False)
    settings.set_editor_property("cinematic_engine_scalability",True)
    settings.set_editor_property("cinematic_mode",True)
    settings.set_editor_property("allow_movement",False)
    settings.set_editor_property("allow_turning",False)
    settings.set_editor_property("show_player",False)
    settings.set_editor_property("show_hud",False)

    # NOTE 设置默认的自动渲染参数
    option = unreal.AutomatedLevelSequenceCapture()
    option.set_editor_property("use_separate_process",False)
    option.set_editor_property("close_editor_when_capture_starts",False)
    option.set_editor_property("additional_command_line_arguments","-NOSCREENMESSAGES")
    option.set_editor_property("inherited_command_line_arguments","")
    option.set_editor_property("use_custom_start_frame",False)
    option.set_editor_property("use_custom_end_frame",False)
    option.set_editor_property("warm_up_frame_count",0.0)
    option.set_editor_property("delay_before_warm_up",0)
    option.set_editor_property("delay_before_shot_warm_up",0.0)
    option.set_editor_property("write_edit_decision_list",True)
    # option.set_editor_property("custom_start_frame",unreal.FrameNumber(0))
    # option.set_editor_property("custom_end_frame",unreal.FrameNumber(0))
        
    option.set_editor_property("settings",settings)
    option.set_editor_property("level_sequence_asset",unreal.SoftObjectPath(sequence.get_path_name()))

    # NOTE 设置自定义渲染参数
    option.set_image_capture_protocol_type(unreal.CompositionGraphCaptureProtocol)
    protocol = option.get_image_capture_protocol()
    # NOTE 这里设置 Base Color 渲染 Base Color 通道,可以根据输出的 UI 设置数组名称
    passes = unreal.CompositionGraphCapturePasses(["Base Color"])
    protocol.set_editor_property("include_render_passes",passes)
    # protocol.set_editor_property("compression_quality",100)

    # NOTE 设置全局变量才起作用!
    global on_finished_callback
    on_finished_callback = unreal.OnRenderMovieStopped(
        lambda s:render(sequence_list,i+1,output_directory,output_format))
    unreal.SequencerTools.render_movie(option,on_finished_callback)
   

def main(output_directory="C:/render",output_format="{sequence}"):
    # NOTE 获取当前选择的 LevelSequence
    sequence_list = [asset for asset in unreal.EditorUtilityLibrary.get_selected_assets() if isinstance(asset,unreal.LevelSequence)]

    if not sequence_list:
        alert(u"请选择一个 LevelSequence")
        return

    if not os.access(output_directory, os.W_OK):
        alert(u"当前输出路径非法")
        return
    elif not os.path.exists(output_directory):
        # NOTE 路径不存在则创建文件夹
        os.makedirs(output_directory)
    elif os.path.isfile(output_directory):
        # NOTE 如果传入文件路径则获取目录
        output_directory = os.path.dirname(output_directory)

    render(sequence_list,0,output_directory,output_format)


if __name__ == "__main__":
    main()
  选择 Sequencer 执行上面的脚本,就可以自动批量输出 Sequencer 了。


总结

  理论上 Python 调用蓝图方法做到的功能, 蓝图应该也可以做到的。
  但是经过我的测试,我发现 蓝图 的 get_image_capture_protocol 返回值是 基类。
  导致无法获取 CompositionGraphCaptureProtocol 这个类
  也就无法设置  include_render_passes 的值了,这样导致蓝图输出会将所有通道输出,而不能实现单一通道的输出。
  另外这一次没有制作 GUI ,我还在纠结使用 Qt 还是 Unreal 原生的界面。
  Unreal使用 Editor Utility 创建的 UI 是二进制 uasset ,无法向前兼容 Unreal 版本。
  UI的功能响应上也没有 Qt 成熟。
  但是无论如何,Unreal 的 UMG 是原生体验,嵌入样式各方面都比较舒服的。
  虽然 Qt 可以写一套 Qss 来解决样式问题,但是在 Unreal 中实现 Dock 目前还是无解。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-12-25 14:59 , Processed in 0.105066 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表