Beispiel #1
0
    def test_split_bf_by_fno(self):
        motion = VmdReader(u"test/data/補間曲線テスト01.vmd").read_data()
        model = PmxReader(
            "D:/MMD/MikuMikuDance_v926x64/UserFile/Model/ダミーボーン頂点追加2.pmx"
        ).read_data()

        target_bone_name = "ボーン01"

        prev_bf = motion.bones[target_bone_name][0]
        next_bf = motion.bones[target_bone_name][15]

        motion.split_bf_by_fno(target_bone_name, prev_bf, next_bf, 8)

        for fno in motion.get_bone_fnos(target_bone_name):
            bf = motion.bones[target_bone_name][fno]
            print("fno: %s ------------" % bf.fno)
            print("position: %s" % bf.position)
            print("rotation: %s" % bf.rotation.toEulerAngles4MMD())
            print("int move x: %s, %s, %s, %s" % (bf.interpolation[MBezierUtils.MX_x1_idxs[3]], bf.interpolation[MBezierUtils.MX_y1_idxs[3]], \
                  bf.interpolation[MBezierUtils.MX_x2_idxs[3]], bf.interpolation[MBezierUtils.MX_y2_idxs[3]]))
            print("int move y: %s, %s, %s, %s" % (bf.interpolation[MBezierUtils.MY_x1_idxs[3]], bf.interpolation[MBezierUtils.MY_y1_idxs[3]], \
                  bf.interpolation[MBezierUtils.MY_x2_idxs[3]], bf.interpolation[MBezierUtils.MY_y2_idxs[3]]))
            print("int move z: %s, %s, %s, %s" % (bf.interpolation[MBezierUtils.MZ_x1_idxs[3]], bf.interpolation[MBezierUtils.MZ_y1_idxs[3]], \
                  bf.interpolation[MBezierUtils.MZ_x2_idxs[3]], bf.interpolation[MBezierUtils.MZ_y2_idxs[3]]))
            print("int rot: %s, %s, %s, %s" % (bf.interpolation[MBezierUtils.R_x1_idxs[3]], bf.interpolation[MBezierUtils.R_y1_idxs[3]], \
                  bf.interpolation[MBezierUtils.R_x2_idxs[3]], bf.interpolation[MBezierUtils.R_y2_idxs[3]]))

        data_set = MOptionsDataSet(
            motion, model, model,
            "E:/WebDownload/test_split_bf_by_fno_{0:%Y%m%d_%H%M%S}.vmd".format(
                datetime.now()), False, False)

        VmdWriter(data_set).write()
        print(data_set.output_vmd_path)
    def execute(self):
        logging.basicConfig(level=self.options.logging_level, format="%(message)s [%(module_name)s]")

        try:
            service_data_txt = "腕IK変換処理実行\n------------------------\nexeバージョン: {version_name}\n".format(version_name=self.options.version_name) \

            service_data_txt = "{service_data_txt} VMD: {vmd}\n".format(service_data_txt=service_data_txt,
                                    vmd=os.path.basename(self.options.motion.path)) # noqa
            service_data_txt = "{service_data_txt} モデル: {model}({model_name})\n".format(service_data_txt=service_data_txt,
                                    model=os.path.basename(self.options.motion.path), model_name=self.options.model.name) # noqa
            service_data_txt = "{service_data_txt} 不要キー削除: {center_rotation}\n".format(service_data_txt=service_data_txt,
                                    center_rotation=self.options.remove_unnecessary_flg) # noqa

            logger.info(service_data_txt, decoration=MLogger.DECORATION_BOX)

            # 処理に成功しているか
            result = self.convert_ik2fk()

            # 最後に出力
            VmdWriter(MOptionsDataSet(self.options.motion, None, self.options.model, self.options.output_path, False, False, [], None, 0, [])).write()

            logger.info("出力終了: %s", os.path.basename(self.options.output_path), decoration=MLogger.DECORATION_BOX, title="成功")

            return result
        except SizingException as se:
            logger.error("腕IK変換処理が処理できないデータで終了しました。\n\n%s", se.message, decoration=MLogger.DECORATION_BOX)
        except Exception:
            logger.critical("腕IK変換処理が意図せぬエラーで終了しました。\n\n%s", traceback.format_exc(), decoration=MLogger.DECORATION_BOX)
        finally:
            logging.shutdown()
    def execute(self):
        logging.basicConfig(level=self.options.logging_level,
                            format="%(message)s [%(module_name)s]")

        try:
            service_data_txt = "スムージング処理実行\n------------------------\nexeバージョン: {version_name}\n".format(version_name=self.options.version_name) \

            service_data_txt = "{service_data_txt} VMD: {vmd}\n".format(
                service_data_txt=service_data_txt,
                vmd=os.path.basename(self.options.motion.path))  # noqa
            service_data_txt = "{service_data_txt} モデル: {model}({model_name})\n".format(
                service_data_txt=service_data_txt,
                model=os.path.basename(self.options.motion.path),
                model_name=self.options.model.name)  # noqa
            service_data_txt = "{service_data_txt} 処理回数: {loop_cnt}回\n".format(
                service_data_txt=service_data_txt,
                loop_cnt=self.options.loop_cnt)  # noqa
            service_data_txt = "{service_data_txt} 補間方法: {interpolation}\n".format(
                service_data_txt=service_data_txt,
                interpolation=("補間曲線に従う" if self.options.interpolation == 0
                               else "補間曲線無視(円形)" if self.options.interpolation
                               == 1 else "補間曲線無視(曲線)"))  # noqa

            logger.info(service_data_txt, decoration=MLogger.DECORATION_BOX)

            # 処理に成功しているか
            result = self.convert_smooth()

            # 最後に出力
            VmdWriter(
                MOptionsDataSet(self.options.motion, None, self.options.model,
                                self.options.output_path, False, False, [],
                                None, 0, [])).write()

            logger.info("出力終了: %s",
                        os.path.basename(self.options.output_path),
                        decoration=MLogger.DECORATION_BOX,
                        title="成功")

            return result
        except SizingException as se:
            logger.error("スムージング処理が処理できないデータで終了しました。\n\n%s",
                         se.message,
                         decoration=MLogger.DECORATION_BOX)
        except Exception:
            logger.critical("スムージング処理が意図せぬエラーで終了しました。\n\n%s",
                            traceback.format_exc(),
                            decoration=MLogger.DECORATION_BOX)
        finally:
            logging.shutdown()
Beispiel #4
0
    def test_vmd_output(self):
        motion = VmdReader(u"test/data/補間曲線テスト01.vmd").read_data()
        model = PmxReader(
            "D:/MMD/MikuMikuDance_v926x64/UserFile/Model/ダミーボーン頂点追加2.pmx"
        ).read_data()

        for n in range(100):
            fill_fno = 8
            fill_bone_name = "右腕{0:03d}".format(n)
            fill_bf = motion.calc_bf(fill_bone_name, fill_fno)
            fill_bf.key = True

            motion.bones[fill_bone_name][fill_fno] = fill_bf

        data_set = MOptionsDataSet(
            motion, model, model,
            "E:/WebDownload/test_vmd_output_{0:%Y%m%d_%H%M%S}.vmd".format(
                datetime.now()), False, False)

        VmdWriter(data_set).write()
        print(data_set.output_vmd_path)
    def execute(self):
        logging.basicConfig(level=self.options.logging_level,
                            format="%(message)s [%(module_name)s]")

        try:
            service_data_txt = "多段分割処理実行\n------------------------\nexeバージョン: {version_name}\n".format(version_name=self.options.version_name) \

            service_data_txt = "{service_data_txt} VMD: {vmd}\n".format(
                service_data_txt=service_data_txt,
                vmd=os.path.basename(self.options.motion.path))  # noqa
            service_data_txt = "{service_data_txt} モデル: {model}({model_name})\n".format(
                service_data_txt=service_data_txt,
                model=os.path.basename(self.options.motion.path),
                model_name=self.options.model.name)  # noqa
            service_data_txt = "{service_data_txt} 不要キー削除: {center_rotation}\n".format(
                service_data_txt=service_data_txt,
                center_rotation=self.options.remove_unnecessary_flg)  # noqa

            selections = ["{0} → 回転(1): {1}, 回転(2): {2}, 回転(3): {3}, 移動(1): {4}, 移動(2): {5}, 移動(3): {6}" \
                          .format(bset[0], bset[1], bset[2], bset[3], bset[4], bset[5], bset[6]) for bset in self.options.target_bones]
            service_data_txt = "{service_data_txt} 対象ボーン: {target_bones}\n".format(
                service_data_txt=service_data_txt,
                target_bones='\n'.join(selections))  # noqa

            logger.info(service_data_txt, decoration=MLogger.DECORATION_BOX)

            motion = self.options.motion
            model = self.options.model

            futures = []

            with ThreadPoolExecutor(
                    thread_name_prefix="split",
                    max_workers=self.options.max_workers) as executor:
                center_mx = ""
                center_my = ""
                center_mz = ""
                for (bone_name, rrxbn, rrybn, rrzbn, rmxbn, rmybn,
                     rmzbn) in self.options.target_bones:
                    if bone_name not in model.bones or bone_name not in motion.bones:
                        continue

                    if bone_name == "センター":
                        center_mx = rmxbn
                        center_my = rmybn
                        center_mz = rmzbn

                    if bone_name == "グルーブ":
                        futures.append(
                            executor.submit(self.convert_multi_split,
                                            bone_name, rrxbn, rrybn, rrzbn,
                                            rmxbn, rmybn, rmzbn, center_mx,
                                            center_my, center_mz))
                    else:
                        futures.append(
                            executor.submit(self.convert_multi_split,
                                            bone_name, rrxbn, rrybn, rrzbn,
                                            rmxbn, rmybn, rmzbn, "", "", ""))

            concurrent.futures.wait(
                futures,
                timeout=None,
                return_when=concurrent.futures.FIRST_EXCEPTION)

            for f in futures:
                if not f.result():
                    return False

            if self.options.remove_unnecessary_flg:
                # 不要キー削除
                futures = []
                with ThreadPoolExecutor(
                        thread_name_prefix="remove",
                        max_workers=self.options.max_workers) as executor:
                    for (bone_name, rrxbn, rrybn, rrzbn, rmxbn, rmybn,
                         rmzbn) in self.options.target_bones:
                        if model.bones[bone_name].getRotatable():
                            if len(rrxbn) > 0:
                                futures.append(
                                    executor.submit(self.remove_unnecessary_bf,
                                                    rrxbn))
                            if len(rrybn) > 0:
                                futures.append(
                                    executor.submit(self.remove_unnecessary_bf,
                                                    rrybn))
                            if len(rrzbn) > 0:
                                futures.append(
                                    executor.submit(self.remove_unnecessary_bf,
                                                    rrzbn))

                        if model.bones[bone_name].getTranslatable():
                            if len(rmxbn) > 0:
                                futures.append(
                                    executor.submit(self.remove_unnecessary_bf,
                                                    rmxbn))
                            if len(rmybn) > 0:
                                futures.append(
                                    executor.submit(self.remove_unnecessary_bf,
                                                    rmybn))
                            if len(rmzbn) > 0:
                                futures.append(
                                    executor.submit(self.remove_unnecessary_bf,
                                                    rmzbn))

                concurrent.futures.wait(
                    futures,
                    timeout=None,
                    return_when=concurrent.futures.FIRST_EXCEPTION)

                for f in futures:
                    if not f.result():
                        return False

            # 最後に出力
            VmdWriter(
                MOptionsDataSet(self.options.motion, None, self.options.model,
                                self.options.output_path, False, False, [],
                                None, 0, [])).write()

            logger.info("出力終了: %s",
                        os.path.basename(self.options.output_path),
                        decoration=MLogger.DECORATION_BOX,
                        title="成功")

            return True
        except MKilledException:
            return False
        except SizingException as se:
            logger.error("多段分割処理が処理できないデータで終了しました。\n\n%s",
                         se.message,
                         decoration=MLogger.DECORATION_BOX)
        except Exception:
            logger.critical("多段分割処理が意図せぬエラーで終了しました。\n\n%s",
                            traceback.format_exc(),
                            decoration=MLogger.DECORATION_BOX)
        finally:
            logging.shutdown()
Beispiel #6
0
    def blend_morph(self):
        # モーションVMDディレクトリパス
        pmx_dir_path = MFileUtils.get_dir_path(self.options.model.path)
        # モーションVMDファイル名・拡張子
        pmx_file_name, pmx_ext = os.path.splitext(
            os.path.basename(self.options.model.path))

        dt_now = datetime.now()

        blend_fpath = "{0}\\{1}_blend_{2:%Y%m%d_%H%M%S}.vmd".format(
            pmx_dir_path, pmx_file_name, dt_now)

        bone_motion = VmdMotion()

        # 処理対象モーフ名(文字列)
        target_morphs = self.options.eye_list + self.options.eyebrow_list + self.options.lip_list + self.options.other_list

        # 処理対象モーフデータ
        all_morphs = []
        for mk, mv in self.options.model.morphs.items():
            if mv.display and mv.name in target_morphs:
                all_morphs.append(mv)
                bone_motion.morphs[mk] = {}

        # 変化量(少ない方のの割合を多くする)
        ratio_values = [self.options.inc_value * x for x in range(math.ceil(self.options.min_value / self.options.inc_value), \
                        math.ceil(self.options.max_value / self.options.inc_value) + 1) if self.options.min_value <= self.options.inc_value * x <= self.options.max_value]
        ratio_lower_values = [self.options.inc_value * x for x in range(math.ceil(self.options.min_value / self.options.inc_value), \
                              math.ceil(self.options.max_value / self.options.inc_value / 2) + 1) if self.options.min_value <= self.options.inc_value * x <= self.options.max_value]
        ratio_zero_values = [0 for x in range(len(all_morphs))]

        # 全体の比率増減量
        ratio_total_values = copy.deepcopy(ratio_values)
        ratio_total_values.extend(ratio_lower_values)
        ratio_total_values.extend(ratio_lower_values)
        ratio_total_values.extend(ratio_zero_values)

        # モーフの組合せ数
        morph_comb_cnt = 1
        # 変化量の組合せ数
        ratio_product_cnt = 1
        for n in range(len(all_morphs), 0, -1):
            morph_comb_cnt *= n
            ratio_product_cnt *= len(ratio_values)

        morph_total_cnt = 0

        if morph_comb_cnt * ratio_product_cnt <= 1000:
            # モーフの組合せ
            morph_comb = list(
                itertools.combinations(all_morphs, len(all_morphs)))
            logger.debug("morph_comb: %s", len(morph_comb))

            # 変化量の直積(同じ値を許容する)
            ratio_product = list(
                itertools.product(ratio_values, repeat=len(all_morphs)))
            logger.debug("ratio_product: %s", len(ratio_product))

            # 組合せが1000以下なら組合せをそのまま出力
            brend_mr_pairs_list = list(
                itertools.product(morph_comb, ratio_product))
            logger.debug("brend_mr_pairs_list: %s", len(brend_mr_pairs_list))

            for mframe, (morphs, ratios) in enumerate(brend_mr_pairs_list):
                # 上限までしか登録しない
                if morph_total_cnt > 19000:
                    break

                for morph, ratio in zip(morphs, ratios):
                    vmd_morph = VmdMorphFrame()
                    vmd_morph.fno = mframe
                    vmd_morph.set_name(morph.name)
                    vmd_morph.ratio = ratio
                    vmd_morph.key = True

                    bone_motion.morphs[morph.name][mframe] = vmd_morph
                    logger.test(vmd_morph)

                    morph_total_cnt += 1

        else:
            # 組合せが1000より多い場合、ランダム
            for mframe in range(1000):
                # 上限までしか登録しない
                if morph_total_cnt > 19000:
                    break

                for morph in all_morphs:
                    ratio = ratio_total_values[random.randint(
                        0,
                        len(ratio_values) - 1)]

                    vmd_morph = VmdMorphFrame()
                    vmd_morph.fno = mframe
                    vmd_morph.set_name(morph.name)
                    vmd_morph.ratio = ratio
                    vmd_morph.key = True

                    bone_motion.morphs[morph.name][mframe] = vmd_morph
                    logger.test(vmd_morph)

                    morph_total_cnt += 1

        data_set = MOptionsDataSet(bone_motion, self.options.model,
                                   self.options.model, blend_fpath, False,
                                   False, [], None, 0, [])

        VmdWriter(data_set).write()

        logger.info("モーフブレンドVMD: %s",
                    blend_fpath,
                    decoration=MLogger.DECORATION_BOX)

        return True
    def convert_noise(self, copy_no: int, seed: float):
        logger.info("ゆらぎ複製 【No.%s】", (copy_no + 1),
                    decoration=MLogger.DECORATION_LINE)

        # データをコピーしてそっちを弄る
        motion = self.options.motion.copy()

        for bone_name in motion.bones.keys():
            if not self.options.finger_noise_flg and "指" in bone_name:
                logger.info("-- 指スキップ【No.%s - %s】", copy_no + 1, bone_name)
                continue

            fnos = motion.get_bone_fnos(bone_name)
            prev_fno = 0
            prev_sep_fno = 0

            # 事前に細分化
            self.prepare_split_stance(motion, bone_name)
            logger.info("-- 準備完了【No.%s - %s】", copy_no + 1, bone_name)

            for fno in fnos:
                bf = motion.bones[bone_name][fno]
                org_bf = self.options.motion.calc_bf(bone_name, fno)

                # 移動
                if bf.position != MVector3D():
                    prev_org_bf = self.options.motion.calc_bf(
                        bone_name, prev_fno)

                    if org_bf.position == prev_org_bf.position and fno > 0:
                        bf.position = motion.calc_bf(bone_name,
                                                     prev_fno).position
                    else:
                        # 0だったら動かさない
                        if round(org_bf.position.x(), 1) != 0:
                            if self.options.motivation_flg:
                                bf.position.setX(
                                    bf.position.x() * seed +
                                    (0.5 - np.random.rand()) *
                                    (self.options.noise_size / 10))
                            else:
                                bf.position.setX(
                                    bf.position.x() +
                                    (0.5 - np.random.rand()) *
                                    (self.options.noise_size / 10))
                        if round(org_bf.position.y(),
                                 1) != 0 and "足IK" not in bone_name:
                            # 足IKのYは動かさない
                            if self.options.motivation_flg:
                                if org_bf.position.y() < 0:
                                    # Yはオリジナルがマイナスの場合は、マイナスのみに動かす
                                    bf.position.setY(
                                        bf.position.y() * seed +
                                        (0 - np.random.rand()) *
                                        (self.options.noise_size / 10))
                                elif org_bf.position.y() > 0:
                                    bf.position.setY(
                                        bf.position.y() * seed +
                                        (0.5 - np.random.rand()) *
                                        (self.options.noise_size / 10))
                            else:
                                bf.position.setY(
                                    bf.position.y() +
                                    (0.5 - np.random.rand()) *
                                    (self.options.noise_size / 10))
                        if round(org_bf.position.z(), 1) != 0:
                            if self.options.motivation_flg:
                                bf.position.setZ(
                                    bf.position.z() * seed +
                                    (0.5 - np.random.rand()) *
                                    (self.options.noise_size / 10))
                            else:
                                bf.position.setZ(
                                    bf.position.z() +
                                    (0.5 - np.random.rand()) *
                                    (self.options.noise_size / 10))

                        # 移動補間曲線
                        for (bz_idx1, bz_idx2, bz_idx3, bz_idx4) in [MBezierUtils.MX_x1_idxs, MBezierUtils.MX_y1_idxs, MBezierUtils.MX_x2_idxs, MBezierUtils.MX_y2_idxs, \
                                                                     MBezierUtils.MY_x1_idxs, MBezierUtils.MY_y1_idxs, MBezierUtils.MY_x2_idxs, MBezierUtils.MY_y2_idxs, \
                                                                     MBezierUtils.MZ_x1_idxs, MBezierUtils.MZ_y1_idxs, MBezierUtils.MZ_x2_idxs, MBezierUtils.MZ_y2_idxs]:
                            noise_interpolation = bf.interpolation[
                                bz_idx1] + math.ceil((0.5 - np.random.rand()) *
                                                     self.options.noise_size)
                            bf.interpolation[bz_idx1] = bf.interpolation[
                                bz_idx2] = bf.interpolation[
                                    bz_idx3] = bf.interpolation[bz_idx4] = int(
                                        noise_interpolation)

                # 回転
                euler = bf.rotation.toEulerAngles()
                # 回転は元が0であっても動かす(足は除く)
                if "足" not in bone_name and "ひざ" not in bone_name and "足首" not in bone_name:
                    if self.options.motivation_flg:
                        euler.setX(euler.x() * seed +
                                   (0.5 - np.random.rand()) *
                                   self.options.noise_size)
                        euler.setY(euler.y() * seed +
                                   (0.5 - np.random.rand()) *
                                   self.options.noise_size)
                        euler.setZ(euler.z() * seed +
                                   (0.5 - np.random.rand()) *
                                   self.options.noise_size)
                    else:
                        euler.setX(euler.x() + (0.5 - np.random.rand()) *
                                   self.options.noise_size)
                        euler.setY(euler.y() + (0.5 - np.random.rand()) *
                                   self.options.noise_size)
                        euler.setZ(euler.z() + (0.5 - np.random.rand()) *
                                   self.options.noise_size)
                bf.rotation = MQuaternion.fromEulerAngles(
                    euler.x(), euler.y(), euler.z())

                # 回転補間曲線
                for (bz_idx1, bz_idx2, bz_idx3, bz_idx4) in [
                        MBezierUtils.R_x1_idxs, MBezierUtils.R_y1_idxs,
                        MBezierUtils.R_x2_idxs, MBezierUtils.R_y2_idxs
                ]:
                    noise_interpolation = bf.interpolation[bz_idx1] + math.ceil(
                        (0.5 - np.random.rand()) * self.options.noise_size)

                    bf.interpolation[bz_idx1] = bf.interpolation[
                        bz_idx2] = bf.interpolation[
                            bz_idx3] = bf.interpolation[bz_idx4] = int(
                                noise_interpolation)

                # 前回fno保持
                prev_fno = fno

                if fno // 2000 > prev_sep_fno and fnos[-1] > 0:
                    logger.count(f"【No.{copy_no + 1} - {bone_name}】", fno,
                                 fnos)
                    prev_sep_fno = fno // 2000

        output_path = self.options.output_path.replace(
            "nxxx", "n{0:03d}".format(copy_no + 1))
        output_path = output_path.replace(
            "axxx", "a{0:+03d}".format(int(seed * 100) - 100))

        # 最後に出力
        VmdWriter(
            MOptionsDataSet(motion, None, self.options.model, output_path,
                            False, False, [], None, 0, [])).write()

        logger.info("出力成功: %s",
                    os.path.basename(output_path),
                    decoration=MLogger.DECORATION_BOX)

        return True
    def convert_vmd(self):
        dt_now = datetime.now()

        bone_fpath = None
        bone_motion = VmdMotion()

        if self.options.bone_csv_path and os.path.exists(self.options.bone_csv_path):
            # ボーンモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(self.options.bone_csv_path)
            # ボーンモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(os.path.basename(self.options.bone_csv_path))

            bone_fpath = "{0}\\{1}_bone_{2:%Y%m%d_%H%M%S}.vmd".format(motion_csv_dir_path, motion_csv_file_name, dt_now)

            # ボーンCSV読み込み
            with open(self.options.bone_csv_path, encoding='cp932', mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for row in reader:
                    bf = VmdBoneFrame()

                    # ボーン名
                    bf.set_name(row[0])

                    # フレーム
                    bf.fno = int(float(row[1]))

                    # 位置
                    bf.position = MVector3D(float(row[2]), float(row[3]), float(row[4]))

                    # 回転
                    bf.rotation = MQuaternion.fromEulerAngles(float(row[5]), float(row[6]) * -1, float(row[7]) * -1)

                    # 補間曲線
                    # 補間曲線(一旦floatで読み込んで指数等も読み込んだ後、intに変換)
                    bf.interpolation = [int(float(row[8])), int(float(row[9])), int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), \
                                        int(float(row[14])), int(float(row[15])), int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), \
                                        int(float(row[20])), int(float(row[21])), int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), \
                                        int(float(row[26])), int(float(row[27])), int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), \
                                        int(float(row[32])), int(float(row[33])), int(float(row[34])), int(float(row[35])), int(float(row[36])), int(float(row[37])), \
                                        int(float(row[38])), int(float(row[39])), int(float(row[40])), int(float(row[41])), int(float(row[42])), int(float(row[43])), \
                                        int(float(row[44])), int(float(row[45])), int(float(row[46])), int(float(row[47])), int(float(row[48])), int(float(row[49])), \
                                        int(float(row[50])), int(float(row[51])), int(float(row[52])), int(float(row[53])), int(float(row[54])), int(float(row[55])), \
                                        int(float(row[56])), int(float(row[57])), int(float(row[58])), int(float(row[59])), int(float(row[60])), int(float(row[61])), \
                                        int(float(row[62])), int(float(row[63])), int(float(row[64])), int(float(row[65])), int(float(row[66])), int(float(row[67])), \
                                        int(float(row[68])), int(float(row[69])), int(float(row[70])), int(float(row[71]))]
                    
                    bf.read = True
                    bf.key = True

                    if bf.name not in bone_motion.bones:
                        bone_motion.bones[bf.name] = {}

                    bone_motion.bones[bf.name][bf.fno] = bf

                    cnt += 1

                    if cnt % 10000 == 0:
                        logger.info("[ボーン] %sキー目:終了", cnt)

        if self.options.morph_csv_path and os.path.exists(self.options.morph_csv_path):
            # モーフモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(self.options.morph_csv_path)
            # モーフモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(os.path.basename(self.options.morph_csv_path))

            if not bone_fpath:
                bone_fpath = "{0}\\{1}_morph_{2:%Y%m%d_%H%M%S}.vmd".format(motion_csv_dir_path, motion_csv_file_name, dt_now)

            # モーフCSV読み込み
            with open(self.options.morph_csv_path, encoding='cp932', mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for row in reader:
                    mf = VmdMorphFrame()

                    # ボーン名
                    mf.set_name(row[0])

                    # フレーム
                    mf.fno = int(float(row[1]))

                    # 位置
                    mf.ratio = float(row[2])

                    if mf.name not in bone_motion.morphs:
                        bone_motion.morphs[mf.name] = {}

                    bone_motion.morphs[mf.name][mf.fno] = mf

                    cnt += 1

                    if cnt % 1000 == 0:
                        logger.info("[モーフ] %sキー目:終了", cnt)

        if len(bone_motion.bones.keys()) > 0 or len(bone_motion.morphs.keys()) > 0:
            # ボーンかモーフのキーがある場合、まとめて出力

            model = PmxModel()
            model.name = "CSV Convert Model"
            data_set = MOptionsDataSet(bone_motion, None, model, bone_fpath, False, False, [], None, None, [])

            VmdWriter(data_set).write()

            logger.info("ボーン・モーフモーションVMD: %s", bone_fpath, decoration=MLogger.DECORATION_BOX)

        if self.options.camera_csv_path and os.path.exists(self.options.camera_csv_path):
            # カメラモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(self.options.camera_csv_path)
            # カメラモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(os.path.basename(self.options.camera_csv_path))

            camera_fpath = "{0}\\{1}_camera_{2:%Y%m%d_%H%M%S}.vmd".format(motion_csv_dir_path, motion_csv_file_name, dt_now)
            camera_motion = VmdMotion()

            # カメラCSV読み込み
            with open(self.options.camera_csv_path, encoding='cp932', mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for row in reader:
                    cf = VmdCameraFrame()

                    # フレーム
                    cf.fno = int(row[0])

                    # 位置
                    cf.position = MVector3D(float(row[1]), float(row[2]), float(row[3]))

                    # 回転(オイラー角)
                    cf.euler = MVector3D(float(row[4]), float(row[5]), float(row[6]))

                    # 距離
                    cf.length = -(float(row[7]))

                    # 視野角
                    cf.angle = int(row[8])

                    # パース
                    cf.perspective = int(row[9])

                    # 補間曲線
                    cf.interpolation = [int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), int(float(row[14])), int(float(row[15])), \
                                        int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), int(float(row[20])), int(float(row[21])), \
                                        int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), int(float(row[26])), int(float(row[27])), \
                                        int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), int(float(row[32])), int(float(row[33]))]

                    camera_motion.cameras[cf.fno] = cf

                    cnt += 1

                    if cnt % 500 == 0:
                        logger.info("[カメラ] %sキー目:終了", cnt)

            if len(camera_motion.cameras) > 0:
                # ボーンかモーフのキーがある場合、まとめて出力

                model = PmxModel()
                model.name = "カメラ・照明"
                data_set = MOptionsDataSet(camera_motion, None, model, camera_fpath, False, False, [], None, None, [])

                VmdWriter(data_set).write()

                logger.info("カメラモーションVMD: %s", camera_fpath, decoration=MLogger.DECORATION_BOX)

        return True
Beispiel #9
0
    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
                service_data_txt = "{service_data_txt}  カメラ作成元モデル: {trace_model} ({model_name})({offset_y})\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, 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

                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}\n".format(service_data_txt=service_data_txt,
                                        camera=os.path.basename(self.options.camera_motion.path)) # noqa

            service_data_txt = "{service_data_txt}------------------------".format(service_data_txt=service_data_txt) # noqa

            logger.info(service_data_txt, decoration=MLogger.DECORATION_BOX)

            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 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.message, 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.message, decoration=MLogger.DECORATION_BOX)

            return True
        except MKilledException:
            return False
        except SizingException as se:
            logger.error("サイジング処理が処理できないデータで終了しました。\n\n%s", se.message, decoration=MLogger.DECORATION_BOX)
            return False
        except Exception as e:
            logger.critical("サイジング処理が意図せぬエラーで終了しました。", e, decoration=MLogger.DECORATION_BOX)
            return False
        finally:
            logging.shutdown()
Beispiel #10
0
    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()
Beispiel #11
0
    def execute(self):
        logging.basicConfig(level=self.options.logging_level,
                            format="%(message)s [%(module_name)s]")

        try:
            service_data_txt = "足IK変換処理実行\n------------------------\nexeバージョン: {version_name}\n".format(version_name=self.options.version_name) \

            service_data_txt = "{service_data_txt} VMD: {vmd}\n".format(
                service_data_txt=service_data_txt,
                vmd=os.path.basename(self.options.motion.path))  # noqa
            service_data_txt = "{service_data_txt} モデル: {model}({model_name})\n".format(
                service_data_txt=service_data_txt,
                model=os.path.basename(self.options.motion.path),
                model_name=self.options.model.name)  # noqa
            service_data_txt = "{service_data_txt} 不要キー削除: {center_rotation}\n".format(
                service_data_txt=service_data_txt,
                center_rotation=self.options.remove_unnecessary_flg)  # noqa

            logger.info(service_data_txt, decoration=MLogger.DECORATION_BOX)

            futures = []

            with ThreadPoolExecutor(
                    thread_name_prefix="leffk",
                    max_workers=self.options.max_workers) as executor:
                futures.append(executor.submit(self.convert_leg_fk2ik, "右"))
                futures.append(executor.submit(self.convert_leg_fk2ik, "左"))

            concurrent.futures.wait(
                futures,
                timeout=None,
                return_when=concurrent.futures.FIRST_EXCEPTION)

            for f in futures:
                if not f.result():
                    return False

            # 最後に出力
            VmdWriter(
                MOptionsDataSet(self.options.motion, None, self.options.model,
                                self.options.output_path, False, False, [],
                                None, 0, [])).write()

            logger.info("出力終了: %s",
                        os.path.basename(self.options.output_path),
                        decoration=MLogger.DECORATION_BOX,
                        title="成功")

            return True
        except MKilledException:
            return False
        except SizingException as se:
            logger.error("足IK変換処理が処理できないデータで終了しました。\n\n%s",
                         se.message,
                         decoration=MLogger.DECORATION_BOX)
        except Exception:
            logger.critical("足IK変換処理が意図せぬエラーで終了しました。\n\n%s",
                            traceback.format_exc(),
                            decoration=MLogger.DECORATION_BOX)
        finally:
            logging.shutdown()
Beispiel #12
0
    def a_test_split_bf_by_fno02(self):
        original_motion = VmdReader(u"test/data/補間曲線テスト01.vmd").read_data()
        model = PmxReader(
            "D:/MMD/MikuMikuDance_v926x64/UserFile/Model/ダミーボーン頂点追加2.pmx"
        ).read_data()

        target_bone_name = "ボーン01"
        links = BoneLinks()
        links.append(model.bones["SIZING_ROOT_BONE"])
        links.append(model.bones["ボーン01"])

        base_params = [0, 16, 32, 127]

        # https://qiita.com/wakame1367/items/0744268e928a28810c20
        for xparams, yparams, zparams, rparams in zip(np.array(np.meshgrid(base_params, base_params, base_params, base_params)).T.reshape(-1, 4), \
                                                      np.array(np.meshgrid(base_params, base_params, base_params, base_params)).T.reshape(-1, 4), \
                                                      np.array(np.meshgrid(base_params, base_params, base_params, base_params)).T.reshape(-1, 4), \
                                                      np.array(np.meshgrid(base_params, base_params, base_params, base_params)).T.reshape(-1, 4)):
            try:
                for fill_fno in range(
                        original_motion.get_bone_fnos(target_bone_name)[0] + 1,
                        original_motion.get_bone_fnos(target_bone_name)[-1]):

                    motion = cPickle.loads(cPickle.dumps(original_motion, -1))

                    # bfの補間曲線を再設定する
                    next_bf = motion.bones[target_bone_name][
                        motion.get_bone_fnos(target_bone_name)[-1]]
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(xparams[0], xparams[1]), MVector2D(xparams[2], xparams[3]), None], \
                                                     MBezierUtils.MX_x1_idxs, MBezierUtils.MX_y1_idxs, MBezierUtils.MX_x2_idxs, MBezierUtils.MX_y2_idxs)
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(yparams[0], yparams[1]), MVector2D(yparams[2], yparams[3]), None], \
                                                     MBezierUtils.MY_x1_idxs, MBezierUtils.MY_y1_idxs, MBezierUtils.MY_x2_idxs, MBezierUtils.MY_y2_idxs)
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(zparams[0], zparams[1]), MVector2D(zparams[2], zparams[3]), None], \
                                                     MBezierUtils.MZ_x1_idxs, MBezierUtils.MZ_y1_idxs, MBezierUtils.MZ_x2_idxs, MBezierUtils.MZ_y2_idxs)
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(rparams[0], rparams[1]), MVector2D(rparams[2], rparams[3]), None], \
                                                     MBezierUtils.R_x1_idxs, MBezierUtils.R_y1_idxs, MBezierUtils.R_x2_idxs, MBezierUtils.R_y2_idxs)

                    # 補間曲線を再設定したモーションを再保持
                    org_motion = cPickle.loads(cPickle.dumps(motion, -1))

                    # 間のキーフレをテスト
                    prev_bf = motion.bones[target_bone_name][
                        motion.get_bone_fnos(target_bone_name)[0]]
                    next_bf = motion.bones[target_bone_name][
                        motion.get_bone_fnos(target_bone_name)[-1]]

                    result = motion.split_bf_by_fno(target_bone_name, prev_bf,
                                                    next_bf, fill_fno)
                    # 分割に成功した場合、誤差小。失敗してる場合は誤差大
                    delta = 0.3 if result else 1

                    # print("-----------------------------")

                    # for now_fno in motion.get_bone_fnos(target_bone_name):
                    #     # 有効なキーフレをテスト
                    #     now_bf = motion.calc_bf(target_bone_name, now_fno)

                    #     org_pos_dic = MServiceUtils.calc_global_pos(model, links, org_motion, now_fno)
                    #     now_pos_dic = MServiceUtils.calc_global_pos(model, links, motion, now_fno)

                    #     print("fill_fno: %s, now_fno: %s key: %s ------------" % (fill_fno, now_bf.fno, now_bf.key))
                    #     print("xparams: %s" % xparams)
                    #     print("yparams: %s" % yparams)
                    #     print("zparams: %s" % zparams)
                    #     print("rparams: %s" % rparams)
                    #     print("position: %s" % now_bf.position)
                    #     print("rotation: %s" % now_bf.rotation.toEulerAngles4MMD())
                    #     print("int move x: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MX_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y1_idxs[3]], \
                    #           now_bf.interpolation[MBezierUtils.MX_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y2_idxs[3]]))
                    #     print("int move y: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MY_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y1_idxs[3]], \
                    #           now_bf.interpolation[MBezierUtils.MY_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y2_idxs[3]]))
                    #     print("int move z: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MZ_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y1_idxs[3]], \
                    #           now_bf.interpolation[MBezierUtils.MZ_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y2_idxs[3]]))
                    #     print("int rot: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.R_x1_idxs[3]], now_bf.interpolation[MBezierUtils.R_y1_idxs[3]], \
                    #           now_bf.interpolation[MBezierUtils.R_x2_idxs[3]], now_bf.interpolation[MBezierUtils.R_y2_idxs[3]]))

                    #     self.assertAlmostEqual(org_pos_dic[target_bone_name].x(), now_pos_dic[target_bone_name].x(), delta=(delta * 2))
                    #     self.assertAlmostEqual(org_pos_dic[target_bone_name].y(), now_pos_dic[target_bone_name].y(), delta=(delta * 3))
                    #     self.assertAlmostEqual(org_pos_dic[target_bone_name].z(), now_pos_dic[target_bone_name].z(), delta=(delta * 4))

                    print("-----------------------------")

                    for fno in range(
                            motion.get_bone_fnos(target_bone_name)[-1]):
                        # org_bf = org_motion.calc_bf(target_bone_name, fno)
                        now_bf = motion.calc_bf(target_bone_name, fno)

                        org_pos_dic = MServiceUtils.calc_global_pos(
                            model, links, org_motion, fno)
                        now_pos_dic = MServiceUtils.calc_global_pos(
                            model, links, motion, fno)

                        print("** fill_fno: %s, fno: %s key: %s ------------" %
                              (fill_fno, now_bf.fno, now_bf.key))
                        print("xparams: %s" % xparams)
                        print("yparams: %s" % yparams)
                        print("zparams: %s" % zparams)
                        print("rparams: %s" % rparams)
                        print("** position: %s" % now_bf.position)
                        print("** rotation: %s" %
                              now_bf.rotation.toEulerAngles4MMD())
                        print("** int move x: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MX_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MX_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y2_idxs[3]]))
                        print("** int move y: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MY_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MY_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y2_idxs[3]]))
                        print("** int move z: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MZ_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MZ_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y2_idxs[3]]))
                        print("** int rot: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.R_x1_idxs[3]], now_bf.interpolation[MBezierUtils.R_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.R_x2_idxs[3]], now_bf.interpolation[MBezierUtils.R_y2_idxs[3]]))

                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].x(),
                            now_pos_dic[target_bone_name].x(),
                            delta=(delta * 2))
                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].y(),
                            now_pos_dic[target_bone_name].y(),
                            delta=(delta * 3))
                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].z(),
                            now_pos_dic[target_bone_name].z(),
                            delta=(delta * 4))

                    # now = datetime.now()

                    # data_set = MOptionsDataSet(motion, model, model, "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}.vmd".format(now), False, False)
                    # VmdWriter(data_set).write()
                    # print(data_set.output_vmd_path)

                    # data_set = MOptionsDataSet(org_motion, model, model, "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}_orignal.vmd".format(now), False, False)
                    # VmdWriter(data_set).write()
                    # print(data_set.output_vmd_path)

            except Exception as e:
                # エラーになったらデータを出力する
                now = datetime.now()

                data_set = MOptionsDataSet(
                    motion, model, model,
                    "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}.vmd"
                    .format(now), False, False)
                VmdWriter(data_set).write()
                print(data_set.output_vmd_path)

                data_set = MOptionsDataSet(
                    org_motion, model, model,
                    "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}_orignal.vmd"
                    .format(now), False, False)
                VmdWriter(data_set).write()
                print(data_set.output_vmd_path)

                raise e
Beispiel #13
0
    def test_split_bf_by_fno01(self):
        original_motion = VmdReader(u"test/data/補間曲線テスト01.vmd").read_data()
        model = PmxReader(
            "D:/MMD/MikuMikuDance_v926x64/UserFile/Model/ダミーボーン頂点追加2.pmx"
        ).read_data()

        target_bone_name = "ボーン01"
        links = BoneLinks()
        links.append(model.bones["SIZING_ROOT_BONE"])
        links.append(model.bones["ボーン01"])

        for pidx in range(10):
            try:
                params = np.random.randint(0, 127, (1, 4))
                # params = [[116, 24, 22, 82]]

                for fill_fno in range(
                        original_motion.get_bone_fnos(target_bone_name)[0] + 1,
                        original_motion.get_bone_fnos(target_bone_name)[-1]):

                    motion = original_motion.copy()

                    # bfの補間曲線を再設定する
                    next_bf = motion.bones[target_bone_name][
                        motion.get_bone_fnos(target_bone_name)[-1]]
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(20, 20), MVector2D(107, 107), None], \
                                                     MBezierUtils.R_x1_idxs, MBezierUtils.R_y1_idxs, MBezierUtils.R_x2_idxs, MBezierUtils.R_y2_idxs)
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(params[0][0], params[0][1]), MVector2D(params[0][2], params[0][3]), None], \
                                                     MBezierUtils.MX_x1_idxs, MBezierUtils.MX_y1_idxs, MBezierUtils.MX_x2_idxs, MBezierUtils.MX_y2_idxs)
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(20, 20), MVector2D(107, 107), None], \
                                                     MBezierUtils.MY_x1_idxs, MBezierUtils.MY_y1_idxs, MBezierUtils.MY_x2_idxs, MBezierUtils.MY_y2_idxs)
                    motion.reset_interpolation_parts(target_bone_name, next_bf, [None, MVector2D(20, 20), MVector2D(107, 107), None], \
                                                     MBezierUtils.MZ_x1_idxs, MBezierUtils.MZ_y1_idxs, MBezierUtils.MZ_x2_idxs, MBezierUtils.MZ_y2_idxs)

                    # 補間曲線を再設定したモーションを再保持
                    org_motion = motion.copy()

                    # 間のキーフレをテスト
                    prev_bf = motion.bones[target_bone_name][
                        motion.get_bone_fnos(target_bone_name)[0]]
                    next_bf = motion.bones[target_bone_name][
                        motion.get_bone_fnos(target_bone_name)[-1]]

                    result = motion.split_bf_by_fno(target_bone_name, prev_bf,
                                                    next_bf, fill_fno)
                    # 分割に成功した場合、誤差小。失敗してる場合は誤差大
                    delta = 0.3 if result else 1

                    print("-----------------------------")

                    for now_fno in motion.get_bone_fnos(target_bone_name):
                        # 有効なキーフレをテスト
                        now_bf = motion.calc_bf(target_bone_name, now_fno)

                        org_pos_dic = MServiceUtils.calc_global_pos(
                            model, links, org_motion, now_fno)
                        now_pos_dic = MServiceUtils.calc_global_pos(
                            model, links, motion, now_fno)

                        print(
                            "fill_fno: %s, now_fno: %s key: %s (%s) ------------"
                            % (fill_fno, now_bf.fno, now_bf.key, pidx))
                        print("params: %s" % params)
                        print("position: %s" % now_bf.position)
                        print("rotation: %s" %
                              now_bf.rotation.toEulerAngles4MMD())
                        print("int move x: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MX_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MX_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y2_idxs[3]]))
                        print("int move y: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MY_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MY_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y2_idxs[3]]))
                        print("int move z: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MZ_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MZ_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y2_idxs[3]]))
                        print("int rot: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.R_x1_idxs[3]], now_bf.interpolation[MBezierUtils.R_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.R_x2_idxs[3]], now_bf.interpolation[MBezierUtils.R_y2_idxs[3]]))

                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].x(),
                            now_pos_dic[target_bone_name].x(),
                            delta=0.2)
                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].y(),
                            now_pos_dic[target_bone_name].y(),
                            delta=0.2)
                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].z(),
                            now_pos_dic[target_bone_name].z(),
                            delta=0.2)

                    print("-----------------------------")

                    for fno in range(
                            motion.get_bone_fnos(target_bone_name)[-1]):
                        # org_bf = org_motion.calc_bf(target_bone_name, fno)
                        now_bf = motion.calc_bf(target_bone_name, fno)

                        org_pos_dic = MServiceUtils.calc_global_pos(
                            model, links, org_motion, fno)
                        now_pos_dic = MServiceUtils.calc_global_pos(
                            model, links, motion, fno)

                        print(
                            "** fill_fno: %s, fno: %s key: %s (%s) ------------"
                            % (fill_fno, now_bf.fno, now_bf.key, pidx))
                        print("** params: %s" % params)
                        print("** position: %s" % now_bf.position)
                        print("** rotation: %s" %
                              now_bf.rotation.toEulerAngles4MMD())
                        print("** int move x: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MX_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MX_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MX_y2_idxs[3]]))
                        print("** int move y: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MY_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MY_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MY_y2_idxs[3]]))
                        print("** int move z: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.MZ_x1_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.MZ_x2_idxs[3]], now_bf.interpolation[MBezierUtils.MZ_y2_idxs[3]]))
                        print("** int rot: %s, %s, %s, %s" % (now_bf.interpolation[MBezierUtils.R_x1_idxs[3]], now_bf.interpolation[MBezierUtils.R_y1_idxs[3]], \
                              now_bf.interpolation[MBezierUtils.R_x2_idxs[3]], now_bf.interpolation[MBezierUtils.R_y2_idxs[3]]))

                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].x(),
                            now_pos_dic[target_bone_name].x(),
                            delta=(delta * 2))
                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].y(),
                            now_pos_dic[target_bone_name].y(),
                            delta=(delta * 3))
                        self.assertAlmostEqual(
                            org_pos_dic[target_bone_name].z(),
                            now_pos_dic[target_bone_name].z(),
                            delta=(delta * 4))

                    now = datetime.now()

                    data_set = MOptionsDataSet(
                        motion, model, model,
                        "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}.vmd"
                        .format(now), False, False)
                    VmdWriter(data_set).write()
                    print(data_set.output_vmd_path)

                    data_set = MOptionsDataSet(
                        org_motion, model, model,
                        "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}_orignal.vmd"
                        .format(now), False, False)
                    VmdWriter(data_set).write()
                    print(data_set.output_vmd_path)

            except Exception as e:
                # エラーになったらデータを出力する
                now = datetime.now()

                data_set = MOptionsDataSet(
                    motion, model, model,
                    "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}.vmd"
                    .format(now), False, False)
                VmdWriter(data_set).write()
                print(data_set.output_vmd_path)

                data_set = MOptionsDataSet(
                    org_motion, model, model,
                    "E:/WebDownload/test_split_bf_by_fno01_{0:%Y%m%d_%H%M%S%f}_orignal.vmd"
                    .format(now), False, False)
                VmdWriter(data_set).write()
                print(data_set.output_vmd_path)

                raise e
    def convert_vmd(self):
        dt_now = datetime.now()

        bone_fpath = None
        bone_motion = VmdMotion()

        if self.options.bone_csv_path and os.path.exists(
                self.options.bone_csv_path):
            # ボーンモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(
                self.options.bone_csv_path)
            # ボーンモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(
                os.path.basename(self.options.bone_csv_path))

            bone_fpath = "{0}\\{1}_bone_{2:%Y%m%d_%H%M%S}.vmd".format(
                motion_csv_dir_path, motion_csv_file_name, dt_now)

            # ボーンCSV読み込み
            with open(self.options.bone_csv_path, encoding='cp932',
                      mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for ridx, row in enumerate(reader):
                    bf = VmdBoneFrame()
                    rno = ridx + 1

                    try:
                        if len(row) < 0 or not row[0]:
                            logger.error("[ボーン] %s行目のボーン名(1列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # ボーン名
                        bf.set_name(row[0])
                    except Exception as e:
                        logger.error("[ボーン] %s行目のボーン名の読み取りに失敗しました\n%s",
                                     rno,
                                     e,
                                     decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 1 or not row[1]:
                            logger.error("[ボーン] %s行目のフレーム番号(2列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # フレーム
                        bf.fno = int(float(row[1]))

                        if bf.fno < 0:
                            logger.error("[ボーン] %s行目のフレーム番号(2列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目のフレーム番号の読み取りに失敗しました\nフレーム番号は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 4 or not row[2] or not row[3] or not row[4]:
                            logger.error("[ボーン] %s行目の位置(3-5列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 位置
                        bf.position = MVector3D(float(row[2]), float(row[3]),
                                                float(row[4]))
                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目の位置の読み取りに失敗しました\n位置は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 7 or not row[5] or not row[6] or not row[7]:
                            logger.error("[ボーン] %s行目の回転(6-8列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 回転
                        bf.rotation = MQuaternion.fromEulerAngles(
                            float(row[5]),
                            float(row[6]) * -1,
                            float(row[7]) * -1)
                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目の回転の読み取りに失敗しました\n位置は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 71:
                            logger.error(
                                "[ボーン] %s行目の補間曲線(9-72列目)のいずれかが設定されていません",
                                rno,
                                decoration=MLogger.DECORATION_BOX)
                            return False

                        for cidx in range(8, 72):
                            if not row[cidx]:
                                logger.error("[ボーン] %s行目の補間曲線の%s番目が設定されていません",
                                             rno,
                                             cidx - 7,
                                             decoration=MLogger.DECORATION_BOX)
                                return False

                        # 補間曲線(一旦floatで読み込んで指数等も読み込んだ後、intに変換)
                        bf.interpolation = [int(float(row[8])), int(float(row[9])), int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), \
                                            int(float(row[14])), int(float(row[15])), int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), \
                                            int(float(row[20])), int(float(row[21])), int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), \
                                            int(float(row[26])), int(float(row[27])), int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), \
                                            int(float(row[32])), int(float(row[33])), int(float(row[34])), int(float(row[35])), int(float(row[36])), int(float(row[37])), \
                                            int(float(row[38])), int(float(row[39])), int(float(row[40])), int(float(row[41])), int(float(row[42])), int(float(row[43])), \
                                            int(float(row[44])), int(float(row[45])), int(float(row[46])), int(float(row[47])), int(float(row[48])), int(float(row[49])), \
                                            int(float(row[50])), int(float(row[51])), int(float(row[52])), int(float(row[53])), int(float(row[54])), int(float(row[55])), \
                                            int(float(row[56])), int(float(row[57])), int(float(row[58])), int(float(row[59])), int(float(row[60])), int(float(row[61])), \
                                            int(float(row[62])), int(float(row[63])), int(float(row[64])), int(float(row[65])), int(float(row[66])), int(float(row[67])), \
                                            int(float(row[68])), int(float(row[69])), int(float(row[70])), int(float(row[71]))]

                        for bidx, bi in enumerate(bf.interpolation):
                            if 0 > bi:
                                logger.error(
                                    "[ボーン] %s行目の補間曲線(%s列目)に負数が設定されています",
                                    rno,
                                    bidx + 9,
                                    decoration=MLogger.DECORATION_BOX)
                                return False

                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目の補間曲線の読み取りに失敗しました\n位置は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    bf.read = True
                    bf.key = True

                    if bf.name not in bone_motion.bones:
                        bone_motion.bones[bf.name] = {}

                    bone_motion.bones[bf.name][bf.fno] = bf

                    cnt += 1

                    if cnt % 10000 == 0:
                        logger.info("[ボーン] %sキー目:終了", cnt)

        if self.options.morph_csv_path and os.path.exists(
                self.options.morph_csv_path):
            # モーフモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(
                self.options.morph_csv_path)
            # モーフモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(
                os.path.basename(self.options.morph_csv_path))

            if not bone_fpath:
                bone_fpath = "{0}\\{1}_morph_{2:%Y%m%d_%H%M%S}.vmd".format(
                    motion_csv_dir_path, motion_csv_file_name, dt_now)

            # モーフCSV読み込み
            with open(self.options.morph_csv_path, encoding='cp932',
                      mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for ridx, row in enumerate(reader):
                    mf = VmdMorphFrame()
                    rno = ridx + 1

                    try:
                        if len(row) < 0 or not row[0]:
                            logger.error("[モーフ] %s行目のモーフ名(1列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # ボーン名
                        mf.set_name(row[0])
                    except Exception as e:
                        logger.error("[モーフ] %s行目のモーフ名の読み取りに失敗しました\n%s",
                                     rno,
                                     e,
                                     decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 1 or not row[1]:
                            logger.error("[モーフ] %s行目のフレーム番号(2列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # フレーム
                        mf.fno = int(float(row[1]))

                        if mf.fno < 0:
                            logger.error("[モーフ] %s行目のフレーム番号(2列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False
                    except Exception as e:
                        logger.error(
                            "[モーフ] %s行目のフレーム番号の読み取りに失敗しました\nフレーム番号は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 2 or not row[2]:
                            logger.error("[モーフ] %s行目の大きさ(3列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 値
                        mf.ratio = float(row[2])
                    except Exception as e:
                        logger.error(
                            "[モーフ] %s行目の大きさの読み取りに失敗しました\n大きさは半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    if mf.name not in bone_motion.morphs:
                        bone_motion.morphs[mf.name] = {}

                    bone_motion.morphs[mf.name][mf.fno] = mf

                    cnt += 1

                    if cnt % 1000 == 0:
                        logger.info("[モーフ] %sキー目:終了", cnt)

        if len(bone_motion.bones.keys()) > 0 or len(
                bone_motion.morphs.keys()) > 0:
            # ボーンかモーフのキーがある場合、まとめて出力

            model = PmxModel()
            model.name = "CSV Convert Model"
            data_set = MOptionsDataSet(bone_motion, model, model, bone_fpath,
                                       False, False, [], None, 0, [])

            VmdWriter(data_set).write()

            logger.info("ボーン・モーフモーションVMD: %s",
                        bone_fpath,
                        decoration=MLogger.DECORATION_BOX)

        if self.options.camera_csv_path and os.path.exists(
                self.options.camera_csv_path):
            # カメラモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(
                self.options.camera_csv_path)
            # カメラモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(
                os.path.basename(self.options.camera_csv_path))

            camera_fpath = "{0}\\{1}_camera_{2:%Y%m%d_%H%M%S}.vmd".format(
                motion_csv_dir_path, motion_csv_file_name, dt_now)
            camera_motion = VmdMotion()

            # カメラCSV読み込み
            with open(self.options.camera_csv_path, encoding='cp932',
                      mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for ridx, row in enumerate(reader):
                    cf = VmdCameraFrame()
                    rno = ridx + 1

                    try:
                        if len(row) < 1 or not row[0]:
                            logger.error("[カメラ] %s行目のフレーム番号(1列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # フレーム
                        cf.fno = int(row[0])

                        if cf.fno < 0:
                            logger.error("[カメラ] %s行目のフレーム番号(1列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目のフレーム番号の読み取りに失敗しました\nフレーム番号は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 3 or not row[1] or not row[2] or not row[3]:
                            logger.error("[カメラ] %s行目の位置(2-4列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 位置
                        cf.position = MVector3D(float(row[1]), float(row[2]),
                                                float(row[3]))
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の位置の読み取りに失敗しました\n位置は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 6 or not row[4] or not row[5] or not row[6]:
                            logger.error("[カメラ] %s行目の回転(5-7列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 回転(オイラー角)
                        cf.euler = MVector3D(float(row[4]), float(row[5]),
                                             float(row[6]))
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の回転の読み取りに失敗しました\n回転は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 7 or not row[7]:
                            logger.error("[カメラ] %s行目の距離(8列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 距離
                        cf.length = -(float(row[7]))
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の距離の読み取りに失敗しました\n距離は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 8 or not row[8]:
                            logger.error("[カメラ] %s行目の視野角(9列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 視野角
                        cf.angle = int(row[8])

                        if cf.angle < 0:
                            logger.error("[カメラ] %s行目の視野角(9列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の視野角の読み取りに失敗しました\n視野角は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 8 or not row[9]:
                            logger.error("[カメラ] %s行目のパース(10列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # パース
                        cf.perspective = int(row[9])

                        if cf.perspective not in [0, 1]:
                            logger.error(
                                "[カメラ] %s行目のパース(10列目)に0, 1以外の値が設定されています",
                                rno,
                                decoration=MLogger.DECORATION_BOX)
                            return False
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目のパースの読み取りに失敗しました\nパースは0, 1のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 33:
                            logger.error(
                                "[カメラ] %s行目の補間曲線(11-34列目)のいずれかが設定されていません",
                                rno,
                                decoration=MLogger.DECORATION_BOX)
                            return False

                        for cidx in range(10, 34):
                            if not row[cidx]:
                                logger.error("[カメラ] %s行目の補間曲線の%s番目が設定されていません",
                                             rno,
                                             cidx - 9,
                                             decoration=MLogger.DECORATION_BOX)
                                return False

                        # 補間曲線(一旦floatで読み込んで指数等も読み込んだ後、intに変換)
                        cf.interpolation = [int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), int(float(row[14])), int(float(row[15])), \
                                            int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), int(float(row[20])), int(float(row[21])), \
                                            int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), int(float(row[26])), int(float(row[27])), \
                                            int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), int(float(row[32])), int(float(row[33]))]

                        for cidx, ci in enumerate(cf.interpolation):
                            if 0 > ci:
                                logger.error(
                                    "[カメラ] %s行目の補間曲線(%s列目)に負数が設定されています",
                                    rno,
                                    cidx + 11,
                                    decoration=MLogger.DECORATION_BOX)
                                return False

                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の補間曲線の読み取りに失敗しました\n位置は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    camera_motion.cameras[cf.fno] = cf

                    cnt += 1

                    if cnt % 500 == 0:
                        logger.info("[カメラ] %sキー目:終了", cnt)

            if len(camera_motion.cameras) > 0:
                # ボーンかモーフのキーがある場合、まとめて出力

                model = PmxModel()
                model.name = "カメラ・照明"
                data_set = MOptionsDataSet(camera_motion, model, model,
                                           camera_fpath, False, False, [],
                                           None, 0, [])

                VmdWriter(data_set).write()

                logger.info("カメラモーションVMD: %s",
                            camera_fpath,
                            decoration=MLogger.DECORATION_BOX)

        return True