原文地址 :https://blog.l0v0.com/posts/1b238b83.html
思路:用 unreal python 读取关键帧数据导出 json,Maya 再读取数据设置关键帧到控制器上。
# Import built-in modules
from collections import defaultdict
import json
import os
# Import local modules
import unreal
DIR = os.path.dirname(os.path.abspath(__file__))
def unreal_progress(tasks, label="进度", total=None):
total = total if total else len(tasks)
with unreal.ScopedSlowTask(total, label) as task:
task.make_dialog(True)
for i, item in enumerate(tasks):
if task.should_cancel():
break
task.enter_progress_frame(1, "%s %s/%s" % (label, i, total))
yield item
def main():
# NOTE: 读取 sequence
sequence = unreal.load_asset('/Game/Sequencer/MetaHumanSample_Sequence.MetaHumanSample_Sequence')
# NOTE: 收集 sequence 里面所有的 binding
binding_dict = defaultdict(list)
for binding in sequence.get_bindings():
binding_dict[binding.get_name()].append(binding)
# NOTE: 遍历命名为 Face 的 binding
for binding in unreal_progress(binding_dict.get("Face", []), "导出 Face 数据"):
# NOTE: 获取关键帧 channel 数据
keys_dict = {}
for track in binding.get_tracks():
for section in track.get_sections():
for channel in unreal_progress(section.get_channels(), "导出关键帧"):
if not channel.get_num_keys():
continue
keys = []
for key in channel.get_keys():
frame_time = key.get_time()
frame = frame_time.frame_number.value + frame_time.sub_frame
keys.append({"frame": frame, "value": key.get_value()})
keys_dict[channel.get_name()] = keys
# NOTE: 导出 json
name = binding.get_parent().get_name()
export_path = os.path.join(DIR, "{0}.json".format(name))
with open(export_path, "w") as wf:
json.dump(keys_dict, wf, indent=4)
上面的脚本会定位 MetaHuman 的 sequence 资源,然后导出关键帧的信息为 json
# Import built-in modules
import json
import os
import traceback
# Import third-party modules
import pymel.core as pm
DIR = os.path.dirname(os.path.abspath(__file__))
def progress(seq, status="", title=""):
pm.progressWindow(status=status, title=title, progress=0.0, isInterruptable=True)
total = len(seq)
for i, item in enumerate(seq):
try:
if pm.progressWindow(query=True, isCancelled=True):
break
pm.progressWindow(e=True, progress=float(i) / total * 100)
yield item # with body executes here
except:
traceback.print_exc()
pm.progressWindow(ep=1)
pm.progressWindow(ep=1)
def main():
# NOTE: 读取数据
with open(os.path.join(DIR, "BP_metahuman_001.json"), "r") as rf:
data = json.load(rf)
attr_map = {"location": "t", "rotation": "r"}
status = "Import Keyframe to metahuman controller"
# NOTE: undo 支持
pm.undoInfo(ock=1)
for channel, frame_list in progress(data.items(), status=status):
# NOTE: 解析 channel_name
has_attr = channel.count(".")
if not has_attr:
# NOTE: 处理 `CTRL_C_eye_parallelLook_4311` 格式
ctrl_name = channel.rsplit("_", 1)[0]
attr = "ty"
else:
parts = iter(channel.split("."))
ctrl_name = next(parts, "")
param = next(parts, "")
axis = next(parts, "")
if not axis:
# NOTE: 处理 `CTRL_C_teethD.Y_4330` 格式
attr = "t"
axis = param
else:
# NOTE: 处理 `CTRL_L_eyeAim.Rotation.Y_4387` 格式
attr = attr_map.get(param.lower())
attr += axis.split("_")[0].lower()
# NOTE: 解析出控制器属性设置关键帧
attribute = pm.PyNode(".".join([ctrl_name, attr]))
for frame_data in frame_list:
frame = frame_data.get("frame")
value = frame_data.get("value")
attribute.setKey(t=frame, v=value)
pm.undoInfo(cck=1)
maya中加载json数据