Python脚本批量解算Demo

发布于:2024-10-18


功能说明

适用于番剧文戏(非武打类的简单动作)的批量化解算,配置好服装好,通过脚本自动化解算

前期准备工作

UE编辑器中做好服装准备工作

  • 角色与服装准备:角色蓝图上挂载Style3D组件,配置好服装(碰撞分组、物理属性调节等)

  • Sequencer准备:配置好Style3D缓存录制轨道(设置镜头、动作等)

示例工程与脚本

下载地址

角色蓝图中配置了运行时自动Posefitting

示例Python脚本功能

  • 通过脚本录制服装缓存;

  • 通过脚本配置角色蓝图 、缓存录制参数;

操作步骤

在脚本目录中,用终端打开

  • 通过脚本配置蓝图 和 Sequence 中缓存录制参数: ue_command_style3d_config.py

  • 通过脚本控制缓存生成:ue_command_style3d_run.py

输入以下指令运行

(引擎中Python路径 脚本名)

ue_style3d_task.py

# -*-coding: utf-8 -*-
# ue ver 5.1.1
import os
import json
ue版本5.3.2配置 style3d 服装解算参数 和 Sequence 中生成缓存相关配置def config_style3d(enginePath, projLuncherPath, scriptPath, frame_start, frame_end, fps, ue_bp_path, ue_map_asset_path, ue_seq_path, save_package_name,
save_package_path, style3d_asset_path, style3d_clothconfig):ueLogCmds = ('LogSourceControl off,'
             'SourceControl off,'
             'LogEditorAssetSubsystem off,'
             'LogEditorScripting off,'
             'LogHttp off,'
             'LogUtils off,'
             'LogHttpListener off,'
             'LogAssetRegistry off,'
             'LogFileManager off,'
             'LogFeaturePack off,'
             'LogUnrealNames off,'
             'LogDirectoryWatcher off')

ueCmd = (
        "%s %s -LogCmds=\"%s\" -run=pythonscript -script=\"import sys;sys.path.append('%s');\
        import style3d_config_garment_cache;\
        style3d_config_garment_cache.do_cloth_solution('%d', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%f', '%d', '%f')\""
        % (
            enginePath,
            projLuncherPath,
            ueLogCmds,
            scriptPath,
            frame_start,
            frame_end,
            fps,
            ue_bp_path,
            ue_map_asset_path,
            ue_seq_path,
            save_package_name,
            save_package_path,
            style3d_asset_path,
            style3d_clothconfig["record_rate_scale"],
            style3d_clothconfig["iterations"],
            style3d_clothconfig["air_damping"]
        )
)

CmdRet = os.popen(ueCmd).read()
print(CmdRet)启动 MRQ 来渲染生成服装缓存渲染好的序列存放在Saved\MovieRender中def render_MRQ_seq(enginPath, projPath, map, seq, configPath):
rendercmd = '{0} {1} {2} -game -LevelSequence="{3}" ' 
'-MoviePipelineConfig="{4}" -windowed -resx=2880 -resy=1620 -log -notexturestreaming'.format(enginPath, projPath, map, seq, configPath)
print(rendercmd)
os.system(rendercmd)引擎目录enginePath = 'E:/UnrealEngine/UE5.3/UE_5.3/Engine/Binaries/Win64/UnrealEditor-Cmd.exe'工程目录projLuncherPath = 'E:/AutoPatch/UEProject/Style3D_Automation/Demo_zdhgx/Demo_zdhgx.uproject'脚本目录scriptPath = 'E:/AutoPatch/UEProject/Style3D_Automation/scripts'阶段一 配置 Style3Dframe_start = 0
frame_end = 300
fps = 30
ue_bp_path = 'MetaHumans/Char1/BP_Char1'
ue_map_asset_path = '/Game/DemoProject/Map/Map_2'
save_cache_path = ''
style3d_clothconfig = {"record_rate_scale": 0.2,"iterations": 300,"air_damping": 0.01}task_configs = [
{
"ue_seq_path": '/Game/DemoProject/Sequence/Seq_01/Sequence01_Dance03',
"save_cache_name": 'Cache_Seq1',
"style3d_asset_path": '/Game/Style3D/Cloth_02',
"enable": True
},
{
"ue_seq_path": '/Game/DemoProject/Sequence/Seq_02/Sequence02_Dance12',
"save_cache_name": 'Cache_Seq2',
"style3d_asset_path": '/Game/Style3D/Cloth_02',
"enable": True
},
{
"ue_seq_path": '/Game/DemoProject/Sequence/Seq_03/Sequence03_Fitting01',
"save_cache_name": 'Cache_Seq3',
"style3d_asset_path": '/Game/Style3D/Cloth_02',
"enable": True
}
]enable用True、False控制task是否执行for task_config in task_configs:
if task_config["enable"]:
# 阶段一 配置Style3D服装资产、解算参数、Sequence配置
config_style3d(enginePath, projLuncherPath, scriptPath, frame_start, frame_end, fps, ue_bp_path, ue_map_asset_path, task_config["ue_seq_path"], task_config["save_cache_name"], save_cache_path, task_config["style3d_asset_path"], style3d_clothconfig)    # 阶段二 渲染生成服装缓存
    configPath = '/Game/Template/Blueprints/Render/Pending_MoviePipelinePrimaryConfig.Pending_MoviePipelinePrimaryConfig'
    render_MRQ_seq(enginePath, projLuncherPath, ue_map_asset_path, task_config["ue_seq_path"], configPath)

#break</code></pre><p></p><h3><span style="font-size: 15px; line-height: 22.5px;">ue_command_style3d_</span><a target="_blank" rel="noopener noreferrer nofollow" href="http://config.py" data-link-id="" data-link-title="" data-link-description="" data-link-sync-mode="master" data-link-display-mode="title" data-link-type=""><span style="font-size: 15px; line-height: 22.5px;">config.py</span></a></h3><pre><code># -*-coding: utf-8 -*-ue ver 5.1.1import os
import unreal as ue
import jsondef track_to_dict(track):
t = {
'name' : str(track.get_display_name()),
'type' : track.get_class().get_name(),
'sections' : []
}for section in track.get_sections():
	section_range = section.get_range()
	t['sections'].append({
		'range' : {
			'has_start' : section_range.has_start,
			'start' : section_range.inclusive_start,
			'has_end' : section_range.has_end,
			'end' : section_range.exclusive_end,
		},
		'type': section.get_class().get_name()
	})

return tdef do_cloth_solution(frame_start, frame_end, fps, ue_bp_path, ue_map_asset_path, ue_seq_path, save_package_name,
save_package_path, style3d_asset_path, record_rate_scale, iterations, air_damping):
"""
Args:
frame_start: shot start frame num, int32, eg: 950     frame_end: shot end frame num, int32, eg: 1058

     fps: shot fps, int32, eg: 25

     ue_bp_path: solution used bp asset ue path, string, eg: "/Game/character/hanli_default/BP/bp_hanli_default"

     ue_map_asset_path: map asset ue path

     ue_seq_path: sequence asset ue path
     
     save_package_name: solution file name for save in ue, string

     save_package_path: solution file ue path for save in ue, string

     style3d_asset_path: style3d cloth asset path

     style3d_clothconfig: { 'record_rate_scale': 0.3,
                            'iterations': 50,
                            'air_damping': 0.1,
                            }

Returns:
    solution_finish_path: file ue path of solution finished in ue, string
"""

"""
ue.log_warning("style3d_clothconfigfile_path:" + style3d_clothconfigfile_path)
if ue.EditorAssetLibrary.does_asset_exist(style3d_clothconfigfile_path):
    ue.log_warning("have style3d_clothconfigfile_path!")

    blueprint_clothconfig_asset = ue.EditorAssetLibrary.load_asset(style3d_clothconfigfile_path)
    bp_class = ue.load_object(None, blueprint_clothconfig_asset.generated_class().get_path_name()) 
    bp_cdo = ue.get_default_object(bp_class)
    
    bp_cdo.set_editor_property('new_cache_name', 'hahahaaha')
    
    ue.EditorAssetLibrary.save_asset(style3d_clothconfigfile_path)
"""

# 此处假设 Style3D 组件已经在蓝图 Actor 上挂载,服装资产也已经挂载到 Style3D 组件, 只是需要配置缓存名称和部分解算参数
if ue.EditorAssetLibrary.does_asset_exist(ue_bp_path):
    ue.log_warning("have ue_bp_path: " + ue_bp_path)

    bp_asset = ue.load_asset(ue_bp_path)

    #style3d_clothconfig_obj = json.loads(style3d_clothconfig)
    #style3d_clothconfig_obj = {"record_rate_scale": 0.4,"simulate_time_scale": 1.2,"iterations": 60,"air_damping": 0.2}

    subsystem: ue.SubobjectDataSubsystem = ue.get_engine_subsystem(ue.SubobjectDataSubsystem)
    root_data_handle: ue.SubobjectDataHandle = subsystem.k2_gather_subobject_data_for_blueprint(context=bp_asset)

    objects = []
    #get components in blueprint
    for handle in root_data_handle:
        subobject = subsystem.k2_find_subobject_data_from_handle( handle )
        objects.append( ue.SubobjectDataBlueprintFunctionLibrary.get_object( subobject ) )

    #remove duplicates
    objects = list(dict.fromkeys(objects))

    #check if Style3DComponent and update the parameters
    for object in objects:
        if "Style3DComponent" in str(object):
            ue.log_warning("have style3d_component!")

            style3d_component = object
            #style3d_component.set_editor_property('new_cache_name', save_package_name)
            style3d_component.get_editor_property('cache_record_setting').set_editor_property('record_rate_scale', float(record_rate_scale))
            style3d_component.get_editor_property('solver_property').set_editor_property('iterations', int(iterations))
            style3d_component.get_editor_property('solver_property').set_editor_property('air_damping', float(air_damping))

            if ue.EditorAssetLibrary.does_asset_exist(style3d_asset_path):
                style3d_asset = ue.load_asset(style3d_asset_path)
                style3d_component.set_editor_property('meta_data_asset', style3d_asset)
            
              
            
    ue.EditorAssetLibrary.save_asset(ue_bp_path)

else:
    ue.log_warning("have not find ue_bp_path!")
        


# 此处假设 Style3D 缓存录制轨道已经在 Sequence 中配置完成, 只是需要配置缓存名称,起始帧和结束帧
ue.log_warning("ue_seq_path: " + ue_seq_path)
if ue.EditorAssetLibrary.does_asset_exist(ue_seq_path):
    
    ue.log_warning("have ue_seq_path!")
    world = ue.EditorLoadingAndSavingUtils.load_map(ue_map_asset_path)

    sequence = ue.load_asset(ue_seq_path, ue.LevelSequence)

    bindings = sequence.get_bindings()
    #ue.log_warning(bindings)

    for binding in bindings:
        tracks = binding.get_tracks()
        for track in tracks:
            for section in track.get_sections():
                section_class_str = str(section.get_class())
                ue.log_warning(section_class_str)

                if section_class_str.find("Style3DMovieSceneGarmentCacheSection") != -1:    
                    #section.set_start_frame_seconds(0)
	                #section.set_end_frame_seconds(100)
                    section.get_editor_property('params').set_editor_property('garment_cache_name', save_package_name)
                    
                    #integrate_info = section.get_editor_property('params').get_editor_property('garment_integrate_info')
                    #style3d_asset_name = integrate_info.get_editor_property('garment_asset_map')['default'].get_editor_property('garment_asset').get_name()

                    style3d_asset_name = 'test'
                    


    ue.LevelSequenceEditorBlueprintLibrary.refresh_current_level_sequence()
    ue.EditorAssetLibrary.save_asset(ue_seq_path)



solution_finish_path = '/Game/Style3D/GarmentCache/'# + style3d_asset_name + '/' + save_package_name
return solution_finish_path

附录

  • Unreal Python 脚本文档学习


提交反馈