脚本篇
安装额外的python库需要 mobupy.exe -m pip install
执行脚本的窗口在window->Python Editor
常用的记录整理
正规化动捕数据
def normalize_trans_rots(trans,rots,refid=0):
r = sciR.from_euler("xyz", rots, degrees=True).as_matrix()
r1 = r[refid]
b1 = r1[0]
b2 = np.array([0,1,0])
b1 = b1 - (b1*b2).sum(-1) * b2
b1 = b1 / np.linalg.norm(b1)
b3 = np.cross(b1, b2)
rref = np.vstack((b1, b2, b3)).T # inv
r = np.einsum('cd,bda->bca', rref, r)
trans = np.einsum('cd,bd->bc', rref, trans)
rots = sciR.from_matrix(r).as_euler("xyz", degrees=True)
basetrans = trans[refid:refid+1].copy()
#print( basetrans, trans[:5] )
basetrans[:, 1] = 0
trans = trans - basetrans
#print( basetrans, trans[:5] )
print( r[refid] )
return trans,rots
bvh2fbx
@ECHO off
set exe="D:\soft\progm\mb2022\MotionBuilder 2022/bin/x64/motionbuilder.exe"
%exe% -batch -console -verbosePython scripts/bvh2fbx.py
python 脚本,需要创建 tmp 文件夹,并把 bvh 文件夹放进去
import sys, os, logging
import pyfbsdk
#import numpy as np
logging.basicConfig(
filename="tmp/compile_results.log",
filemode="w",
format="%(asctime)s %(levelname)-8s %(message)s",
level=logging.DEBUG,
)
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console.setFormatter(logging.Formatter("%(asctime)s %(levelname)-8s %(message)s"))
logging.getLogger("").addHandler(console)
def bvh2fbx(animation_file, output_file, template_file, sound_file=None):
pyfbsdk.FBApplication().FileNew()
if template_file:
logging.info("Loading %s..." % str(template_file))
if not pyfbsdk.FBApplication().FileOpen(str(template_file)):
raise IOError("Could not open file: {}".format(str(template_file)))
if sound_file is not None:
# Load Audio
logging.info("Loading %s..." % str(sound_file))
audio = pyfbsdk.FBAudioClip(sound_file)
if audio is None:
raise IOError("Could not open file: {}".format(str(sound_file)))
# Rescale Timespan
pyfbsdk.FBSystem().CurrentTake.LocalTimeSpan = pyfbsdk.FBTimeSpan(
pyfbsdk.FBTime(0), audio.Duration
)
# Set FPS
#pyfbsdk.FBPlayerControl().SetTransportFps(pyfbsdk.FBTimeMode.kFBTimeModeCustom, 60) #
pyfbsdk.FBPlayerControl().SetTransportFps(pyfbsdk.FBTimeMode.kFBTimeMode30Frames)
pyfbsdk.FBPlayerControl().SnapMode = (
pyfbsdk.FBTransportSnapMode.kFBTransportSnapModeSnapOnFrames
)
# Load BVH
if not pyfbsdk.FBApplication().FileImport(animation_file, True):
raise IOError("Could not open file: {}".format(str(animation_file)))
# Save FBX
pyfbsdk.FBApplication().FileSave(output_file)
def main(input_file, output_file=None):
try:
logging.info("======")
logging.info("BVH2FBX")
logging.info("======")
template_file = None
if not output_file:
output_file = input_file.replace(".bvh", ".fbx")
#else:
# output_file = os.path.join(output_file, os.path.basename(input_file)).replace(".bvh", ".fbx")
print(input_file, output_file)
bvh2fbx(
input_file,
output_file,
template_file,
sound_file=None
)
pyfbsdk.FBApplication().FileExit()
except Exception as e:
logging.exception("FAILED:")
raise e
import sys
logging.info(os.getcwd())
import os
import glob
#din, dout = sys.argv[1:3]
din, dout="tmp/bvh", "tmp/fbx"
logging.info("======")
for fin in glob.glob(f"{din}/*.bvh"):
fin = os.path.abspath(fin)
nm = os.path.relpath(fin, din)
fout = os.path.abspath(dout+"/"+nm.replace(".bvh", ".fbx"))
_dout = os.path.dirname(fout)
if not os.path.exists(_dout):
os.makedirs(_dout)
logging.info(fin +" --- " + fout + " --- " + _dout)
main(fin, fout)