def parse(cls, version_name: str): parser = argparse.ArgumentParser() parser.add_argument('--motion_path', dest='motion_path', help='input vmd', type=str) parser.add_argument('--model_path', dest='model_path', help='model_path', type=str) parser.add_argument('--loop_cnt', dest='loop_cnt', help='loop_cnt', type=int) parser.add_argument('--interpolation', dest='interpolation', help='interpolation', type=int) parser.add_argument("--verbose", type=int, default=20) args = parser.parse_args() # ログディレクトリ作成 os.makedirs("log", exist_ok=True) MLogger.initialize(level=args.verbose, is_file=True) try: motion = VmdReader(args.motion_path).read_data() model = PmxReader(args.model_path).read_data() # 出力ファイルパス output_vmd_path = MFileUtils.get_output_smooth_vmd_path( motion.path, model.path, "", args.interpolation, args.loop_cnt, True) options = MSmoothOptions(\ version_name=version_name, \ logging_level=args.verbose, \ motion=motion, \ model=model, \ output_path=output_vmd_path, \ loop_cnt=args.loop_cnt, \ interpolation=args.interpolation, \ monitor=sys.stdout, \ is_file=True, \ outout_datetime=logger.outout_datetime, \ max_workers=1) return options except SizingException as se: logger.error("スムージング処理が処理できないデータで終了しました。\n\n%s", se.message, decoration=MLogger.DECORATION_BOX) except Exception as e: logger.critical("スムージング処理が意図せぬエラーで終了しました。", e, decoration=MLogger.DECORATION_BOX)
def test_separate(self): MLogger.initialize(level=MLogger.TEST, is_file=True) logger = MLogger(__name__, level=MLogger.TEST) # motion = VmdReader("D:\\MMD\\MikuMikuDance_v926x64\\UserFile\\Motion\\ダンス_1人\\桃源恋歌配布用motion moka\\ノーマルTda式用0-2000.vmd").read_data() model = PmxReader( "D:\\MMD\\MikuMikuDance_v926x64\\UserFile\\Model\\VOCALOID\\初音ミク\\Tda式初音ミク・アペンドVer1.10\\Tda式初音ミク・アペンド_Ver1.10.pmx", is_check=False).read_data() bone_axis_dict = {} for bone_name in ["左ひじ", "右ひじ"]: local_x_axis = model.get_local_x_axis("左ひじ") local_z_axis = MVector3D(0, 0, -1) local_y_axis = MVector3D.crossProduct(local_x_axis, local_z_axis).normalized() bone_axis_dict[bone_name] = { "x": local_x_axis, "y": local_y_axis, "z": local_z_axis } new_ik_qq = MQuaternion.fromEulerAngles(24.58152072747821, 135.9182003500461, 56.36785502950723) ik_bone = model.bones["左ひじ"] fno = 394 x_qq, y_qq, z_qq, yz_qq = MServiceUtils.separate_local_qq( fno, ik_bone.name, new_ik_qq, bone_axis_dict[ik_bone.name]["x"]) logger.debug( f"now: {new_ik_qq.toEulerAngles()} -> {(y_qq * x_qq * z_qq).toEulerAngles()}" ) logger.debug( f"now: x: {x_qq.toDegree()}, y: {y_qq.toDegree()}, z: {z_qq.toDegree()}" ) for (x_sign, y_sign, z_sign) in list(itertools.product((1, -1), (1, -1), (1, -1))): new_x_qq = MQuaternion.fromAxisAndAngle(x_qq.vector(), x_qq.toDegree() * x_sign) new_y_qq = MQuaternion.fromAxisAndAngle(y_qq.vector(), y_qq.toDegree() * y_sign) new_z_qq = MQuaternion.fromAxisAndAngle(z_qq.vector(), z_qq.toDegree() * z_sign) logger.debug( f"x: {x_sign}, y: {y_sign}, z: {z_sign} -> {(new_y_qq * new_x_qq * new_z_qq).toEulerAngles()}" ) self.assertTrue(True)
import wx import argparse import numpy as np import multiprocessing from form.MainFrame import MainFrame from utils.MLogger import MLogger VERSION_NAME = "ver1.00" # 指数表記なし、有効小数点桁数6、30を超えると省略あり、一行の文字数200 np.set_printoptions(suppress=True, precision=6, threshold=30, linewidth=200) # Windowsマルチプロセス対策 multiprocessing.freeze_support() if __name__ == '__main__': # 引数解釈 parser = argparse.ArgumentParser() parser.add_argument("--verbose", default=20, type=int) args = parser.parse_args() # ロガー初期化 MLogger.initialize(level=args.verbose, is_file=False) # GUI起動 app = wx.App(False) frame = MainFrame(None, VERSION_NAME, args.verbose) frame.Show(True) app.MainLoop()
# import os import wx import wx.lib.newevent import sys from form.panel.BasePanel import BasePanel from form.parts.BaseFilePickerCtrl import BaseFilePickerCtrl from form.parts.HistoryFilePickerCtrl import HistoryFilePickerCtrl from form.parts.ConsoleCtrl import ConsoleCtrl from form.parts.TargetBoneDialog import TargetBoneDialog from form.worker.MultiJoinWorkerThread import MultiJoinWorkerThread from utils import MFormUtils, MFileUtils from utils.MLogger import MLogger # noqa logger = MLogger(__name__) TIMER_ID = wx.NewId() # イベント定義 (MultiJoinThreadEvent, EVT_SMOOTH_THREAD) = wx.lib.newevent.NewEvent() class MultiJoinPanel(BasePanel): def __init__(self, frame: wx.Frame, multi_join: wx.Notebook, tab_idx: int): super().__init__(frame, multi_join, tab_idx) self.timer = wx.Timer(self, TIMER_ID) self.convert_multi_join_worker = None self.header_sizer = wx.BoxSizer(wx.VERTICAL) self.description_txt = wx.StaticText(self, wx.ID_ANY, u"モーションの指定ボーンの移動量XYZと回転量XYZを統合します。\n" \
# -*- coding: utf-8 -*- # import copy import numpy as np # noqa import math # noqa from collections import OrderedDict from mmd.PmxData import PmxModel, Vertex, Material, Bone, Morph, DisplaySlot, RigidBody, Joint # noqa from mmd.VmdData import VmdMotion, VmdBoneFrame, VmdCameraFrame, VmdInfoIk, VmdLightFrame, VmdMorphFrame, VmdShadowFrame, VmdShowIkFrame # noqa from module.MMath import MRect, MVector2D, MVector3D, MVector4D, MQuaternion, MMatrix4x4 # noqa from module.MOptions import MOptions, MOptionsDataSet # noqa from module.MParams import BoneLinks # noqa from utils import MBezierUtils # noqa from utils.MLogger import MLogger # noqa logger = MLogger(__name__, level=1) # IK計算 # target_pos: IKリンクの目的位置 # ik_links: IKリンク def calc_IK(model: PmxModel, links: BoneLinks, motion: VmdMotion, fno: int, target_pos: MVector3D, ik_links: BoneLinks, max_count=10): for bone_name in list(ik_links.all().keys())[1:]: # bfをモーションに登録 bf = motion.calc_bf(bone_name, fno)
def parse(cls, version_name: str): parser = argparse.ArgumentParser() parser.add_argument("--motion_path", required=True, type=(lambda x: list(map(str, x.split(';'))))) parser.add_argument("--org_model_path", required=True, type=(lambda x: list(map(str, x.split(';'))))) parser.add_argument("--rep_model_path", required=True, type=(lambda x: list(map(str, x.split(';'))))) parser.add_argument("--detail_stance_flg", required=True, type=(lambda x: list(map(int, x.split(';'))))) parser.add_argument("--twist_flg", required=True, type=(lambda x: list(map(int, x.split(';'))))) parser.add_argument("--arm_process_flg_avoidance", type=int, default=0) parser.add_argument("--avoidance_target_list", default=[], type=(lambda x: list(map(str, x.split(';'))))) parser.add_argument("--arm_process_flg_alignment", type=int, default=0) parser.add_argument("--alignment_finger_flg", type=int, default=0) parser.add_argument("--alignment_floor_flg", type=int, default=0) parser.add_argument("--alignment_distance_wrist", type=float, default=1.7) parser.add_argument("--alignment_distance_finger", type=float, default=1.4) parser.add_argument("--alignment_distance_floor", type=float, default=1.8) parser.add_argument("--arm_check_skip_flg", type=int, default=0) parser.add_argument("--camera_motion_path", type=str, default="") parser.add_argument("--camera_org_model_path", default=[], type=(lambda x: list(map(str, x.split(';'))))) parser.add_argument("--camera_offset_y", default=[], type=(lambda x: list(map(str, x.split(';'))))) parser.add_argument("--verbose", type=int, default=20) args = parser.parse_args() # ログディレクトリ作成 os.makedirs("log", exist_ok=True) MLogger.initialize(level=args.verbose, is_file=True) try: arm_process_flg_avoidance = True if args.arm_process_flg_avoidance == 1 else False arm_process_flg_alignment = True if args.arm_process_flg_alignment == 1 else False alignment_finger_flg = True if args.alignment_finger_flg == 1 else False alignment_floor_flg = True if args.alignment_floor_flg == 1 else False arm_check_skip_flg = True if args.arm_check_skip_flg == 1 else False arm_options = MArmProcessOptions( arm_process_flg_avoidance, \ {0: [(a.strip() if len(a.strip()) > 0 else "") for a in args.avoidance_target_list]}, \ arm_process_flg_alignment, \ alignment_finger_flg, \ alignment_floor_flg, \ args.alignment_distance_wrist, \ args.alignment_distance_finger, \ args.alignment_distance_floor, \ arm_check_skip_flg ) # 元モデルが未指定の場合、空で処理する if not args.camera_org_model_path or ( len(args.camera_org_model_path) == 1 and len(args.camera_org_model_path[0]) == 0): args.camera_org_model_path = [] for org_path in args.org_model_path: args.camera_org_model_path.append("") # オフセットYが未指定の場合、0で処理する if not args.camera_offset_y or (len(args.camera_offset_y) == 1 and len(args.camera_offset_y[0]) == 0): args.camera_offset_y = [] for org_path in args.org_model_path: args.camera_offset_y.append(0) data_set_list = [] for set_no, (motion_path, org_model_path, rep_model_path, detail_stance_flg_val, twist_flg_val, camera_org_model_path, camera_offset_y) in enumerate( \ zip(args.motion_path, args.org_model_path, args.rep_model_path, args.detail_stance_flg, args.twist_flg, args.camera_org_model_path, \ args.camera_offset_y)): # noqa display_set_no = "【No.{0}】".format(set_no + 1) # モーションパス -------- logger.info("%s 調整対象モーションVMD/VPDファイル 読み込み開始", display_set_no) file_name, input_ext = os.path.splitext( os.path.basename(motion_path)) if input_ext.lower() == ".vmd": motion_reader = VmdReader(motion_path) elif input_ext.lower() == ".vpd": motion_reader = VpdReader(motion_path) else: raise SizingException( "{0}.motion_path 読み込み失敗(拡張子不正): {1}".format( display_set_no, os.path.basename(motion_path))) motion = motion_reader.read_data() logger.info("%s 調整対象モーションVMD/VPDファイル 読み込み成功 %s", display_set_no, os.path.basename(motion_path)) # 元モデル ---------- logger.info("%s モーション作成元モデルPMXファイル 読み込み開始", display_set_no) file_name, input_ext = os.path.splitext( os.path.basename(org_model_path)) if input_ext.lower() == ".pmx": org_model_reader = PmxReader(org_model_path) else: raise SizingException( "{0}.org_model_path 読み込み失敗(拡張子不正): {1}".format( display_set_no, os.path.basename(org_model_path))) org_model = org_model_reader.read_data() logger.info("%s モーション作成元モデルPMXファイル 読み込み成功 %s", display_set_no, os.path.basename(org_model_path)) # 先モデル ---------- logger.info("%s モーション変換先モデルPMXファイル 読み込み開始", display_set_no) file_name, input_ext = os.path.splitext( os.path.basename(rep_model_path)) if input_ext.lower() == ".pmx": rep_model_reader = PmxReader(rep_model_path) else: raise SizingException( "{0}.rep_model_path 読み込み失敗(拡張子不正): {1}".format( display_set_no, os.path.basename(rep_model_path))) rep_model = rep_model_reader.read_data() logger.info("%s モーション変換先モデルPMXファイル 読み込み成功 %s", display_set_no, os.path.basename(rep_model_path)) # 元モデル ---------- if len(camera_org_model_path) > 0: logger.info("%s カメラ作成元モデルPMXファイル 読み込み開始", display_set_no) file_name, input_ext = os.path.splitext( os.path.basename(camera_org_model_path)) if input_ext.lower() == ".pmx": camera_org_model_reader = PmxReader( camera_org_model_path) else: raise SizingException( "{0}.camera_org_model_path 読み込み失敗(拡張子不正): {1}". format(display_set_no, os.path.basename(camera_org_model_path))) camera_org_model = camera_org_model_reader.read_data() logger.info("%s カメラ作成元モデルPMXファイル 読み込み成功 %s", display_set_no, os.path.basename(camera_org_model_path)) else: # カメラ元モデルが未指定の場合、作成元モデルをそのまま流用 camera_org_model = org_model detail_stance_flg = True if detail_stance_flg_val == 1 else False twist_flg = True if twist_flg_val == 1 else False # 出力ファイルパス output_vmd_path = MFileUtils.get_output_vmd_path( motion_path, rep_model_path, detail_stance_flg, twist_flg, arm_process_flg_avoidance, arm_process_flg_alignment, False, "", True) data_set = MOptionsDataSet( motion, org_model, rep_model, output_vmd_path, detail_stance_flg, twist_flg, [], camera_org_model, camera_offset_y, [ "センターXZ補正", "上半身補正", "下半身補正", "足IK補正", "つま先IK補正", "つま先補正", "肩補正", "センターY補正" ]) data_set_list.append(data_set) if len(args.camera_motion_path) != 0: # カメラパス -------- logger.info("調整対象カメラVMDファイル 読み込み開始") file_name, input_ext = os.path.splitext( os.path.basename(args.camera_motion_path)) if input_ext.lower() == ".vmd": camera_motion_reader = VmdReader(args.camera_motion_path) else: raise SizingException( "camera_motion_path 読み込み失敗(拡張子不正): %s", os.path.basename(args.camera_motion_path)) camera_motion = camera_motion_reader.read_data() camera_output_vmd_path = MFileUtils.get_output_camera_vmd_path( args.camera_motion_path, data_set_list[0].rep_model.path, "") logger.info("調整対象カメラVMD/VPDファイル 読み込み成功 %s", os.path.basename(args.camera_motion_path)) else: camera_motion = None camera_output_vmd_path = None options = MOptions(\ version_name=version_name, \ logging_level=args.verbose, \ data_set_list=data_set_list, \ arm_options=arm_options, \ camera_motion=camera_motion, \ camera_output_vmd_path=camera_output_vmd_path, \ monitor=sys.stdout, \ is_file=True, \ outout_datetime=logger.outout_datetime, \ max_workers=1) return options except SizingException as se: logger.error("サイジング処理が処理できないデータで終了しました。\n\n%s", se.message, decoration=MLogger.DECORATION_BOX) except Exception as e: logger.critical("サイジング処理が意図せぬエラーで終了しました。", e, decoration=MLogger.DECORATION_BOX)