def read_data(self): # モーションパス motion = VmdMotion() motion.path = self.file_path try: with open(self.file_path, "rb") as f: # VMDファイルをバイナリ読み込み self.buffer = f.read() # vmdバージョン signature = self.unpack(30, "30s") logger.test("signature %s", signature) # モデル名 model_bname, model_name = self.read_text(20) logger.test("model_bname %s, model_name: %s", model_bname, model_name) motion.model_name = model_name # モーション数 motion.motion_cnt = self.read_uint(4) logger.test("motion.motion_cnt %s", motion.motion_cnt) # 1F分のモーション情報 prev_n = 0 for n in range(motion.motion_cnt): frame = VmdBoneFrame(0) frame.key = True frame.read = True # ボーン ---------------------- # ボーン名 bone_bname, bone_name = self.read_text(15) frame.name = bone_name frame.bname = bone_bname logger.test("name: %s, bname %s", bone_name, bone_bname) # フレームIDX frame.fno = self.read_uint(4) logger.test("frame.fno %s", frame.fno) # 位置X,Y,Z frame.position = self.read_Vector3D() logger.test("frame.position %s", frame.position) # 回転X,Y,Z,scalar frame.rotation = self.read_Quaternion() logger.test("frame.rotation %s", frame.rotation) logger.test("frame.rotation.euler %s", frame.rotation.toEulerAngles()) # オリジナルを保持 frame.org_rotation = frame.rotation.copy() # 補間曲線 frame.interpolation = list(self.unpack(64, "64B", True)) logger.test("interpolation %s", frame.interpolation) if bone_name not in motion.bones: # まだ辞書にない場合、配列追加 motion.bones[bone_name] = {} # 辞書の該当部分にボーンフレームを追加 if frame.fno not in motion.bones[bone_name]: motion.bones[bone_name][frame.fno] = frame if frame.fno > motion.last_motion_frame: # 最終フレームを記録 motion.last_motion_frame = frame.fno if n // 10000 > prev_n: prev_n = n // 10000 logger.info("-- VMDモーション読み込み キー: %s" % n) try: # モーフ数 motion.morph_cnt = self.read_uint(4) logger.test("motion.morph_cnt %s", motion.morph_cnt) # 1F分のモーフ情報 prev_n = 0 for n in range(motion.morph_cnt): morph = VmdMorphFrame() morph.key = True morph.read = True # モーフ ---------------------- # モーフ名 morph_bname, morph_name = self.read_text(15) morph.name = morph_name morph.bname = morph_bname logger.test("name: %s, bname %s", morph_name, morph_bname) # フレームIDX morph.fno = self.read_uint(4) logger.test("morph.fno %s", morph.fno) # 度数 morph.ratio = self.read_float(4) logger.test("morph.ratio %s", morph.ratio) if morph_name not in motion.morphs: # まだ辞書にない場合、配列追加 motion.morphs[morph_name] = {} if morph.fno not in motion.morphs[morph_name]: # まだなければ辞書の該当部分にモーフフレームを追加 motion.morphs[morph_name][morph.fno] = morph if n // 1000 > prev_n: prev_n = n // 1000 logger.info("-- VMDモーション読み込み モーフ: %s" % n) except Exception: # 情報がない場合、catchして握りつぶす motion.morph_cnt = 0 try: # カメラ数 motion.camera_cnt = self.read_uint(4) logger.test("motion.camera_cnt %s", motion.camera_cnt) # 1F分のカメラ情報 prev_n = 0 for n in range(motion.camera_cnt): camera = VmdCameraFrame() # フレームIDX camera.fno = self.read_uint(4) logger.test("camera.fno %s", camera.fno) # 距離 camera.length = self.read_float(4) logger.test("camera.length %s", camera.length) # 0距離の場合、念のため少しだけ距離を入れておく if camera.length == 0: camera.length = -0.00001 # 位置X,Y,Z camera.position = self.read_Vector3D() logger.test("camera.position %s", camera.position) # 角度(オイラー角) camera.euler = self.read_Vector3D() logger.test("camera.euler %s", camera.euler) # 補間曲線 camera.interpolation = self.unpack(24, "24B", True) logger.test("camera.interpolation %s", camera.interpolation) # 視野角 camera.angle = self.read_uint(4) logger.test("camera.angle %s", camera.angle) # パース有無 camera.perspective = self.unpack(1, "B") logger.test("camera.perspective %s", camera.perspective) # オリジナルを保持 camera.org_length = camera.org_length camera.org_position = camera.org_position.copy() # カメラを追加 motion.cameras[camera.fno] = camera if n // 10000 > prev_n: prev_n = n // 10000 logger.info("VMDカメラ読み込み キー: %s" % n) except Exception: # 情報がない場合、catchして握りつぶす motion.camera_cnt = 0 # 照明数 try: motion.light_cnt = self.read_uint(4) logger.test("motion.light_cnt %s", motion.light_cnt) # 1F分の照明情報 for _ in range(motion.light_cnt): light = VmdLightFrame() # フレームIDX light.fno = self.read_uint(4) logger.test("light.fno %s", light.fno) # 照明色(RGBだが、下手に数値が変わるのも怖いのでV3D) light.color = self.read_Vector3D() logger.test("light.color %s", light.color) # 照明位置 light.position = self.read_Vector3D() logger.test("light.position %s", light.position) # 追加 motion.lights.append(light) except Exception: # 情報がない場合、catchして握りつぶす motion.light_cnt = 0 # セルフシャドウ数 try: motion.shadow_cnt = self.read_uint(4) logger.test("motion.shadow_cnt %s", motion.shadow_cnt) # 1F分のシャドウ情報 for _ in range(motion.shadow_cnt): shadow = VmdShadowFrame() # フレームIDX shadow.fno = self.read_uint(4) logger.test("shadow.fno %s", shadow.fno) # シャドウ種別 shadow.type = self.read_uint(1) logger.test("shadow.type %s", shadow.type) # 距離 shadow.distance = self.read_float() logger.test("shadow.distance %s", shadow.distance) # 追加 motion.shadows.append(shadow) except Exception: # 情報がない場合、catchして握りつぶす motion.shadow_cnt = 0 # IK数 try: motion.ik_cnt = self.read_uint(4) logger.test("motion.ik_cnt %s", motion.ik_cnt) # 1F分のIK情報 for _ in range(motion.ik_cnt): show_ik = VmdShowIkFrame() # フレームIDX show_ik.fno = self.read_uint(4) logger.test("ik.fno %s", show_ik.fno) # モデル表示, 0:OFF, 1:ON show_ik.show = self.read_uint(1) logger.test("ik.show %s", show_ik.show) # 記録するIKの数 show_ik.ik_count = self.read_uint(4) logger.test("ik.ik_count %s", show_ik.ik_count) for _ in range(show_ik.ik_count): ik_info = VmdInfoIk() # IK名 ik_bname, ik_name = self.read_text(20) ik_info.name = ik_name ik_info.bname = ik_bname logger.test("ik_info.name %s", ik_name) # モデル表示, 0:OFF, 1:ON ik_info.onoff = self.read_uint(1) logger.test("ik_info.onoff %s", ik_info.onoff) show_ik.ik.append(ik_info) # 追加 motion.showiks.append(show_ik) except Exception: # 昔のMMD(MMDv7.39.x64以前)はIK情報がないため、catchして握りつぶす motion.ik_cnt = 0 # ハッシュを設定 motion.digest = self.hexdigest() logger.test("motion: %s, hash: %s", motion.path, motion.digest) return motion except MKilledException as ke: # 終了命令 raise ke except SizingException as se: logger.error("サイジング処理が処理できないデータで終了しました。\n\n%s", se.message) return se except Exception as e: import traceback logger.error("サイジング処理が意図せぬエラーで終了しました。\n\n%s", traceback.format_exc()) raise e
def read_data(self): # VPDファイルを通常読み込み lines = [] try: with open(self.file_path, "r", encoding=self.get_file_encoding(self.file_path)) as f: lines = f.readlines() if len(lines) > 0: # vpdバージョン signature = lines[0] logger.test("signature %s", signature) motion = VmdMotion() # モーション数(常に1) motion.motion_cnt = 1 motion.last_motion_frame = 0 # 各パターン(括弧はひとつのみ実体として取得する) model_name_pattern = re.compile(r'(.*)(?:\.osm;)(?:.*// 親ファイル名.*)', flags=re.IGNORECASE) bone_start_pattern = re.compile(r'(?:.*)(?:{)(.*)', flags=re.IGNORECASE) bone_pos_pattern = re.compile( r'([+-]?\d+(?:\.\d+))(?:,)([+-]?\d+(?:\.\d+))(?:,)([+-]?\d+(?:\.\d+))(?:;)(?:.*trans.*)', flags=re.IGNORECASE) bone_rot_pattern = re.compile( r'([+-]?\d+(?:\.\d+))(?:,)([+-]?\d+(?:\.\d+))(?:,)([+-]?\d+(?:\.\d+))(?:,)([+-]?\d+(?:\.\d+))(?:;)(?:.*Quaternion.*)', flags=re.IGNORECASE) bone_end_pattern = re.compile(r'(?:.*)(})(?:.*)', flags=re.IGNORECASE) frame = None for n in range(len(lines)): # モデル名 result_values = self.read_line(lines[n], model_name_pattern, n) if result_values: motion.model_name = result_values[0] continue # 括弧開始 result_values = self.read_line(lines[n], bone_start_pattern, n) if result_values: bone_name = result_values[0] # キーフレ生成 frame = VmdBoneFrame(0) frame.set_name(bone_name) frame.key = True frame.read = True continue if frame: # 括弧内のチェック # 位置 result_values = self.read_line(lines[n], bone_pos_pattern, n) if result_values: # 位置X,Y,Z frame.position = MVector3D(float(result_values[0]), float(result_values[1]), float(result_values[2])) continue # 角度 result_values = self.read_line(lines[n], bone_rot_pattern, n) if result_values: # 回転scalar,X,Y,Z frame.rotation = MQuaternion(float(result_values[3]), float(result_values[0]), float(result_values[1]), float(result_values[2])) continue # 括弧終了 result_values = self.read_line(lines[n], bone_end_pattern, n) if result_values: motion.bones[bone_name] = {0: frame} frame = None continue # ハッシュを設定 motion.digest = self.hexdigest() logger.test("motion: %s, hash: %s", motion.path, motion.digest) return motion except MKilledException as ke: # 終了命令 raise ke except SizingException as se: logger.error("サイジング処理が処理できないデータで終了しました。\n\n%s", se.message) return se except Exception as e: import traceback logger.error("サイジング処理が意図せぬエラーで終了しました。\n\n%s", traceback.print_exc()) raise e