def load(self, file_idx=0, is_check=True): if not self.is_set_path(): # パスが指定されてない場合、そのまま終了 self.data = None return True if not self.is_valid(): # 読み込み可能か self.data = None return False try: if self.set_no == 0: # CSVとかのファイルは番号出力なし display_set_no = "" else: display_set_no = "【No.{0}】 ".format(self.set_no) if self.is_aster and self.set_no == 1: base_file_path = self.file_ctrl.GetPath() if os.path.exists(base_file_path): file_path_list = [base_file_path] else: file_path_list = [p for p in glob.glob(base_file_path) if os.path.isfile(p)] if len(file_path_list) == 0: # 読み込み可能か self.data = None return False file_path = file_path_list[file_idx] else: file_path = self.file_ctrl.GetPath() file_name, input_ext = os.path.splitext(os.path.basename(file_path)) # 拡張子別にリーダー生成 if input_ext.lower() == ".vmd": reader = VmdReader(file_path) elif input_ext.lower() == ".vpd": reader = VpdReader(file_path) elif input_ext.lower() == ".pmx": reader = PmxReader(file_path, is_check=is_check) else: logger.error("%s%s 読み込み失敗(拡張子不正): %s", display_set_no, self.title, os.path.basename(file_path), decoration=MLogger.DECORATION_BOX) return False # ハッシュ値取得 new_data_digest = reader.hexdigest() # 新規データがあり、かつハッシュが違う場合、置き換え if new_data_digest and ((self.data and self.data.digest != new_data_digest) or not self.data): # ハッシュが取得できてて、過去データがないかハッシュが違う場合、読み込み self.data = reader.read_data() logger.info("%s%s 読み込み成功: %s", display_set_no, self.title, os.path.basename(file_path)) return True elif new_data_digest and self.data and self.data.digest == new_data_digest: # ハッシュが同じ場合、そのままスルー logger.info("%s%s 読み込み成功: %s", display_set_no, self.title, os.path.basename(file_path)) return True except MKilledException: logger.warning("読み込み処理を中断します。", decoration=MLogger.DECORATION_BOX) 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) finally: logging.shutdown() logger.error("%s%s 読み込み失敗: %s", display_set_no, self.title, os.path.basename(file_path), decoration=MLogger.DECORATION_BOX) return False
def execute(self): logging.basicConfig(level=self.options.logging_level, format="%(message)s [%(module_name)s]") try: service_data_txt = "VMDサイジング処理実行\n------------------------\nexeバージョン: {version_name}\n".format(version_name=self.options.version_name) for data_set_idx, data_set in enumerate(self.options.data_set_list): service_data_txt = "{service_data_txt}\n【No.{no}】 --------- \n".format(service_data_txt=service_data_txt, no=(data_set_idx+1)) # noqa service_data_txt = "{service_data_txt} モーション: {motion}\n".format(service_data_txt=service_data_txt, motion=os.path.basename(data_set.motion.path)) # noqa service_data_txt = "{service_data_txt} 作成元モデル: {trace_model} ({model_name})\n".format(service_data_txt=service_data_txt, trace_model=os.path.basename(data_set.org_model.path), model_name=data_set.org_model.name) # noqa service_data_txt = "{service_data_txt} 変換先モデル: {replace_model} ({model_name})\n".format(service_data_txt=service_data_txt, replace_model=os.path.basename(data_set.rep_model.path), model_name=data_set.rep_model.name) # noqa if data_set.camera_org_model: service_data_txt = "{service_data_txt} カメラ作成元モデル: {trace_model} ({model_name})\n".format(service_data_txt=service_data_txt, trace_model=os.path.basename(data_set.camera_org_model.path), model_name=data_set.camera_org_model.name) # noqa service_data_txt = "{service_data_txt} Yオフセット: {camera_offset_y}\n".format(service_data_txt=service_data_txt, camera_offset_y=data_set.camera_offset_y) # noqa service_data_txt = "{service_data_txt} スタンス追加補正有無: {detail_stance_flg}\n".format(service_data_txt=service_data_txt, detail_stance_flg=data_set.detail_stance_flg) # noqa if data_set.detail_stance_flg: # スタンス追加補正がある場合、そのリストを表示 service_data_txt = "{service_data_txt} {detail_stance_flg}\n".format(service_data_txt=service_data_txt, detail_stance_flg=", ".join(data_set.selected_stance_details)) # noqa service_data_txt = "{service_data_txt} 捩り分散有無: {twist_flg}\n".format(service_data_txt=service_data_txt, twist_flg=data_set.twist_flg) # noqa morph_list = [] for (org_morph_name, rep_morph_name, morph_ratio) in data_set.morph_list: morph_list.append(f"{org_morph_name} → {rep_morph_name} ({morph_ratio})") morph_txt = ", ".join(morph_list) service_data_txt = "{service_data_txt} モーフ置換: {morph_txt}\n".format(service_data_txt=service_data_txt, morph_txt=morph_txt) # noqa if data_set_idx in self.options.arm_options.avoidance_target_list: service_data_txt = "{service_data_txt} 対象剛体名: {avoidance_target}\n".format(service_data_txt=service_data_txt, avoidance_target=", ".join(self.options.arm_options.avoidance_target_list[data_set_idx])) # noqa service_data_txt = "{service_data_txt}\n--------- \n".format(service_data_txt=service_data_txt) # noqa if self.options.arm_options.avoidance: service_data_txt = "{service_data_txt}剛体接触回避: {avoidance}\n".format(service_data_txt=service_data_txt, avoidance=self.options.arm_options.avoidance) # noqa if self.options.arm_options.alignment: service_data_txt = "{service_data_txt}手首位置合わせ: {alignment} ({distance})\n".format(service_data_txt=service_data_txt, alignment=self.options.arm_options.alignment, distance=self.options.arm_options.alignment_distance_wrist) # noqa service_data_txt = "{service_data_txt}指位置合わせ: {alignment} ({distance})\n".format(service_data_txt=service_data_txt, alignment=self.options.arm_options.alignment_finger_flg, distance=self.options.arm_options.alignment_distance_finger) # noqa service_data_txt = "{service_data_txt}床位置合わせ: {alignment} ({distance})\n".format(service_data_txt=service_data_txt, alignment=self.options.arm_options.alignment_floor_flg, distance=self.options.arm_options.alignment_distance_floor) # noqa if self.options.arm_options.arm_check_skip_flg: service_data_txt = "{service_data_txt}腕チェックスキップ: {arm_check_skip}\n".format(service_data_txt=service_data_txt, arm_check_skip=self.options.arm_options.arm_check_skip_flg) # noqa if self.options.camera_motion: service_data_txt = "{service_data_txt}カメラ: {camera}({camera_length})\n".format(service_data_txt=service_data_txt, camera=os.path.basename(self.options.camera_motion.path), camera_length=self.options.camera_length) # noqa service_data_txt = "{service_data_txt} 距離制限: {camera_length}{camera_length_umlimit}\n".format(service_data_txt=service_data_txt, camera_length=self.options.camera_length, camera_length_umlimit=("" if self.options.camera_length < 5 else "(無制限)")) # noqa service_data_txt = "{service_data_txt}------------------------".format(service_data_txt=service_data_txt) # noqa if self.options.total_process_ctrl: self.options.total_process_ctrl.write(str(self.options.total_process)) self.options.now_process_ctrl.write("0") self.options.now_process_ctrl.write(str(self.options.now_process)) logger.info(service_data_txt, decoration=MLogger.DECORATION_BOX) if self.options.is_sizing_camera_only is True: # カメラサイジングのみ実行する場合、出力結果VMDを読み込む for data_set_idx, data_set in enumerate(self.options.data_set_list): reader = VmdReader(data_set.output_vmd_path) data_set.motion = reader.read_data() else: for data_set_idx, data_set in enumerate(self.options.data_set_list): # 足IKのXYZの比率 data_set.original_xz_ratio, data_set.original_y_ratio = MServiceUtils.calc_leg_ik_ratio(data_set) # 足IKの比率再計算 self.options.calc_leg_ratio() # 移動補正 if not MoveService(self.options).execute(): return False # スタンス補正 if not StanceService(self.options).execute(): return False # 剛体接触回避 if self.options.arm_options.avoidance: if not ArmAvoidanceService(self.options).execute(): return False # 手首位置合わせ if self.options.arm_options.alignment: if not ArmAlignmentService(self.options).execute(): return False # カメラ補正 if self.options.camera_motion: if not CameraService(self.options).execute(): return False if self.options.is_sizing_camera_only is False: # モーフ置換 if not MorphService(self.options).execute(): return False for data_set_idx, data_set in enumerate(self.options.data_set_list): # 実行後、出力ファイル存在チェック try: # 出力 VmdWriter(data_set).write() Path(data_set.output_vmd_path).resolve(True) logger.info("【No.%s】 出力終了: %s", (data_set_idx + 1), os.path.basename(data_set.output_vmd_path), decoration=MLogger.DECORATION_BOX, title="サイジング成功") except FileNotFoundError as fe: logger.error("【No.%s】出力VMDファイルが正常に作成されなかったようです。\nパスを確認してください。%s\n\n%s", (data_set_idx + 1), data_set.output_vmd_path, fe, decoration=MLogger.DECORATION_BOX) if self.options.camera_motion: try: camera_model = PmxModel() camera_model.name = "カメラ・照明" data_set = MOptionsDataSet(self.options.camera_motion, None, camera_model, self.options.camera_output_vmd_path, 0, 0, [], None, 0, []) # 出力 VmdWriter(data_set).write() Path(data_set.output_vmd_path).resolve(True) logger.info("カメラ出力終了: %s", os.path.basename(data_set.output_vmd_path), decoration=MLogger.DECORATION_BOX, title="サイジング成功") except FileNotFoundError as fe: logger.error("カメラ出力VMDファイルが正常に作成されなかったようです。\nパスを確認してください。%s\n\n%s", self.options.camera_output_vmd_path, fe, decoration=MLogger.DECORATION_BOX) if int(self.options.total_process) != int(self.options.now_process): logger.warning("一部処理がスキップされました。\n画面左下の進捗数をクリックすると、スキップされた処理がグレーで表示されています。", decoration=MLogger.DECORATION_BOX) return True except MKilledException: return False except SizingException as se: logger.error("サイジング処理が処理できないデータで終了しました。\n\n%s", se, decoration=MLogger.DECORATION_BOX) return False except Exception as e: logger.critical("サイジング処理が意図せぬエラーで終了しました。", e, decoration=MLogger.DECORATION_BOX) return False finally: logging.shutdown()
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)