Batch Solver Demo Using Python Scripts
发布于:2024-11-21
Function Description
Batch solving for slice-of-life anime scenes (non-combat simple actions), automating the setup and solving process once clothing is prepared using scripts.
Preparatory Work
Prepare clothing in the UE editor.
● Character and Clothing Setup: Attach the Style3D component to the character blueprint and configure clothing (collision groups, physical property adjustments, etc.).
● Sequencer Setup: Configure the Style3D cache recording track (set up shots, actions, etc.)
The character blueprint is configured to automatically perform Posefitting at runtime.
Example Python Script Features
● Record clothing cache via script.
● Configure character blueprints and cache recording parameters via script.
Operating Steps
In the script directory, open a terminal.
■ Configure blueprint and sequence cache recording parameters using the script: ue_command_style3d_config.py
■ Control cache generation through scripting: ue_command_style3d_run.py
Run the following command to execute.
(Engine Python path, script name)
ue_style3d_task.py
# -*-coding: utf-8 -*-
# ue ver 5.1.1
import os
import json
# ue Version 5.3.2
# Configuring style3d clothing simulation parameters and cache generation settings in 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)
# Start MRQ to render and generate clothing cache.
# The rendered sequence is stored in 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)
# Engine Directory
enginePath = 'E:/UnrealEngine/UE5.3/UE_5.3/Engine/Binaries/Win64/UnrealEditor-Cmd.exe'
# Project Directory
projLuncherPath = 'E:/AutoPatch/UEProject/Style3D_Automation/Demo_zdhgx/Demo_zdhgx.uproject'
# Script Directory
scriptPath = 'E:/AutoPatch/UEProject/Style3D_Automation/scripts'
# Phase1 Setting Style3D
frame_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 controls whether the task is executed, with True or False.
for task_config in task_configs:
if task_config["enable"]:
# Phase One: Configure Style3D garment assets, solver parameters, and sequence settings.
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)
# Phase Two: Render and Generate Clothing Cache
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
ue_command_style3d_config.py
# -*-coding: utf-8 -*-
# ue ver 5.1.1
import os
import unreal as ue
import json
def 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 t
def 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)
"""
# Assuming the Style3D component has been mounted on the Blueprint Actor and the clothing asset has also been attached to the Style3D component, only the cache name and some solver parameters need to be configured here.
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!")
# Here, assuming the Style3D cache recording track has already been configured in the Sequence, you just need to set the cache name, start frame, and end frame.
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
Appendix
Unreal Python Study
(Engine Python path, script name)