Beispiel #1
0
    def read_float(self, format_size=4):
        if format_size == 4:
            format_type = "f"
        elif format_size == 8:
            format_type = "d"
        else:
            raise MParseException("read_float format_sizeエラー {0}".format(format_size))

        return self.unpack(format_size, format_type)
Beispiel #2
0
    def read_uint(self, format_size):
        if format_size == 1:
            format_type = "B"
        elif format_size == 2:
            format_type = "H"
        elif format_size == 4:
            format_type = "I"
        else:
            raise MParseException("read_uint format_sizeエラー {0}".format(format_size))

        return self.unpack(format_size, format_type)
Beispiel #3
0
    def get_file_encoding(self, file_path):
        try:
            f = open(file_path, "rb")
            fbytes = f.read()
            f.close()
        except Exception:
            raise MParseException("unknown encoding!")

        codelst = ('shift-jis', 'utf_8')

        for encoding in codelst:
            try:
                fstr = fbytes.decode(encoding)  # bytes文字列から指定文字コードの文字列に変換
                fstr = fstr.encode('utf-8')  # uft-8文字列に変換
                # 問題なく変換できたらエンコードを返す
                logger.test("%s: encoding: %s", file_path, encoding)
                return encoding
            except Exception:
                pass

        raise MParseException("unknown encoding!")
Beispiel #4
0
 def define_read_text(self, text_encoding):
     if text_encoding == 0:
         def read_text():
             format_size = self.read_int(4)
             bresult = self.unpack(format_size, "{0}s".format(format_size))
             return bresult.decode("utf-16-le")
         return read_text
     elif text_encoding == 1:
         def read_text():
             format_size = self.read_int(4)
             bresult = self.unpack(format_size, "{0}s".format(format_size))
             return bresult.decode("UTF8")
         return read_text
     else:
         raise MParseException("define_read_text 定義エラー {0}".format(text_encoding))
Beispiel #5
0
    def read_deform(self):
        deform_type = self.read_int(1)

        if deform_type == 0:
            # BDEF1
            return Bdef1(self.read_bone_index_size())
        elif deform_type == 1:
            # BDEF2
            return Bdef2(
                self.read_bone_index_size(),
                self.read_bone_index_size(),
                self.read_float()
            )
        elif deform_type == 2:
            # BDEF4
            return Bdef4(
                self.read_bone_index_size(),
                self.read_bone_index_size(),
                self.read_bone_index_size(),
                self.read_bone_index_size(),
                self.read_float(),
                self.read_float(),
                self.read_float(),
                self.read_float()
            )
        elif deform_type == 3:
            # SDEF
            return Sdef(
                self.read_bone_index_size(),
                self.read_bone_index_size(),
                self.read_float(),
                self.read_Vector3D(),
                self.read_Vector3D(),
                self.read_Vector3D()
            )
        elif deform_type == 4:
            # QDEF
            return Qdef(
                self.read_bone_index_size(),
                self.read_bone_index_size(),
                self.read_float(),
                self.read_Vector3D(),
                self.read_Vector3D(),
                self.read_Vector3D()
            )
        else:
            raise MParseException("unknown deform_type: {0}".format(deform_type))
Beispiel #6
0
    def read_data(self):
        # Pmxモデル生成
        pmx = PmxModel()
        pmx.path = self.file_path

        try:
            # PMXファイルをバイナリ読み込み
            with open(self.file_path, "rb") as f:
                self.buffer = f.read()
                # logger.test("hashlib.algorithms_available: %s", hashlib.algorithms_available)

                # pmx宣言
                signature = self.unpack(4, "4s")
                logger.test("signature: %s (%s)", signature, self.offset)

                # pmxバージョン
                version = self.read_float()
                logger.test("version: %s (%s)", version, self.offset)

                if signature[:3] != b"PMX" or (version != 2.0 and version != 2.1):
                    # 整合性チェック
                    raise MParseException("PMX2.0/2.1形式外のデータです。signature: {0}, version: {1} ".format(signature, version))

                # flag
                flag_bytes = self.read_int(1)
                logger.test("flag_bytes: %s (%s)", flag_bytes, self.offset)

                # エンコード方式
                text_encoding = self.read_int(1)
                logger.test("text_encoding: %s (%s)", text_encoding, self.offset)
                # エンコードに基づいて文字列解凍処理を定義
                self.read_text = self.define_read_text(text_encoding)

                # 追加UV数
                self.extended_uv = self.read_int(1)
                logger.test("extended_uv: %s (%s)", self.extended_uv, self.offset)

                # 頂点Indexサイズ
                self.vertex_index_size = self.read_int(1)
                logger.test("vertex_index_size: %s (%s)", self.vertex_index_size, self.offset)
                self.read_vertex_index_size = lambda: self.read_int(self.vertex_index_size)

                # テクスチャIndexサイズ
                self.texture_index_size = self.read_int(1)
                logger.test("texture_index_size: %s (%s)", self.texture_index_size, self.offset)
                self.read_texture_index_size = lambda: self.read_int(self.texture_index_size)

                # 材質Indexサイズ
                self.material_index_size = self.read_int(1)
                logger.test("material_index_size: %s (%s)", self.material_index_size, self.offset)
                self.read_material_index_size = lambda: self.read_int(self.material_index_size)

                # ボーンIndexサイズ
                self.bone_index_size = self.read_int(1)
                logger.test("bone_index_size: %s (%s)", self.bone_index_size, self.offset)
                self.read_bone_index_size = lambda: self.read_int(self.bone_index_size)

                # モーフIndexサイズ
                self.morph_index_size = self.read_int(1)
                logger.test("morph_index_size: %s (%s)", self.morph_index_size, self.offset)
                self.read_morph_index_size = lambda: self.read_int(self.morph_index_size)

                # 剛体Indexサイズ
                self.rigidbody_index_size = self.read_int(1)
                logger.test("rigidbody_index_size: %s (%s)", self.rigidbody_index_size, self.offset)
                self.read_rigidbody_index_size = lambda: self.read_int(self.rigidbody_index_size)

                # モデル名(日本語)
                pmx.name = self.read_text()
                logger.test("name: %s (%s)", pmx.name, self.offset)

                # モデル名(英語)
                pmx.english_name = self.read_text()
                logger.test("english_name: %s (%s)", pmx.english_name, self.offset)

                # コメント(日本語)
                pmx.comment = self.read_text()
                logger.test("comment: %s (%s)", pmx.comment, self.offset)

                # コメント(英語)
                pmx.english_comment = self.read_text()
                logger.test("english_comment: %s (%s)", pmx.english_comment, self.offset)

                # 頂点データリスト
                for vertex_idx in range(self.read_int(4)):
                    position = self.read_Vector3D()
                    normal = self.read_Vector3D()
                    uv = self.read_Vector2D()

                    extended_uvs = []
                    if self.extended_uv > 0:
                        # 追加UVがある場合
                        for _ in range(self.extended_uv):
                            extended_uvs.append(self.read_Vector4D())

                    deform = self.read_deform()
                    edge_factor = self.read_float()

                    # 頂点をウェイトボーンごとに分けて保持する
                    vertex = Vertex(vertex_idx, position, normal, uv, extended_uvs, deform, edge_factor)
                    for bone_idx in vertex.deform.get_idx_list():
                        if bone_idx not in pmx.vertices:
                            pmx.vertices[bone_idx] = []
                        pmx.vertices[bone_idx].append(vertex)

                logger.test("len(vertices): %s", len(pmx.vertices))
                logger.test("vertices.keys: %s", pmx.vertices.keys())
                logger.info("-- PMX 頂点読み込み完了")

                # 面データリスト
                for _ in range(self.read_int(4)):
                    if self.vertex_index_size <= 2:
                        # 頂点サイズが2以下の場合、符号なし
                        pmx.indices.append(self.read_uint(self.vertex_index_size))
                    else:
                        pmx.indices.append(self.read_int(self.vertex_index_size))
                logger.test("len(indices): %s", len(pmx.indices))
                
                logger.info("-- PMX 面読み込み完了")

                # テクスチャデータリスト
                for _ in range(self.read_int(4)):
                    pmx.textures.append(self.read_text())
                logger.test("len(textures): %s", len(pmx.textures))

                logger.info("-- PMX テクスチャ読み込み完了")

                # 材質データリスト
                for material_idx in range(self.read_int(4)):
                    material = Material(
                        name=self.read_text(),
                        english_name=self.read_text(),
                        diffuse_color=self.read_RGB(),
                        alpha=self.read_float(),
                        specular_color=self.read_RGB(),
                        specular_factor=self.read_float(),
                        ambient_color=self.read_RGB(),
                        flag=self.read_int(1),
                        edge_color=self.read_RGBA(),
                        edge_size=self.read_float(),
                        texture_index=self.read_texture_index_size(),
                        sphere_texture_index=self.read_texture_index_size(),
                        sphere_mode=self.read_int(1),
                        toon_sharing_flag=self.read_int(1)
                    )
                    material.index = material_idx

                    if material.toon_sharing_flag == 0:
                        material.toon_texture_index = self.read_texture_index_size()
                    elif material.toon_sharing_flag == 1:
                        material.toon_texture_index = self.read_int(1)
                    else:
                        raise MParseException("unknown toon_sharing_flag {0}".format(material.toon_sharing_flag))
                    material.comment = self.read_text()
                    material.vertex_count = self.read_int(4)

                    pmx.materials[material.name] = material
                    pmx.material_indexes[material.index] = material.name
                logger.test("len(materials): %s", len(pmx.materials))

                logger.info("-- PMX 材質読み込み完了")

                # サイジング用ルートボーン
                sizing_root_bone = Bone("SIZING_ROOT_BONE", "SIZING_ROOT_BONE", MVector3D(), -1, 0, 0)
                sizing_root_bone.index = -999

                pmx.bones[sizing_root_bone.name] = sizing_root_bone
                # インデックス逆引きも登録
                pmx.bone_indexes[sizing_root_bone.index] = sizing_root_bone.name

                # ボーンデータリスト
                for bone_idx in range(self.read_int(4)):
                    bone = Bone(
                        name=self.read_text(),
                        english_name=self.read_text(),
                        position=self.read_Vector3D(),
                        parent_index=self.read_bone_index_size(),
                        layer=self.read_int(4),
                        flag=self.read_int(2)
                    )

                    if not bone.getConnectionFlag():
                        bone.tail_position = self.read_Vector3D()
                    elif bone.getConnectionFlag():
                        bone.tail_index = self.read_bone_index_size()
                    else:
                        raise MParseException("unknown bone conenction flag: {0}".format(bone.getConnectionFlag()))

                    if bone.getExternalRotationFlag() or bone.getExternalTranslationFlag():
                        bone.effect_index = self.read_bone_index_size()
                        bone.effect_factor = self.read_float()

                    if bone.getFixedAxisFlag():
                        bone.fixed_axis = self.read_Vector3D()

                    if bone.getLocalCoordinateFlag():
                        bone.local_x_vector = self.read_Vector3D()
                        bone.local_z_vector = self.read_Vector3D()

                    if bone.getExternalParentDeformFlag():
                        bone.external_key = self.read_int(4)

                    if bone.getIkFlag():
                        bone.ik = Ik(
                            target_index=self.read_bone_index_size(),
                            loop=self.read_int(4),
                            limit_radian=self.read_float()
                        )

                        # IKリンク取得
                        for _ in range(self.read_int(4)):

                            link = IkLink(
                                self.read_bone_index_size(),
                                self.read_int(1)
                            )

                            if link.limit_angle == 0:
                                pass
                            elif link.limit_angle == 1:
                                link.limit_min = self.read_Vector3D()
                                link.limit_max = self.read_Vector3D()
                            else:
                                raise MParseException("invalid ik link limit_angle: {0}".format(link.limit_angle))

                            bone.ik.link.append(link)

                    # ボーンのINDEX
                    bone.index = bone_idx

                    if bone.name not in pmx.bones:
                        # まだ未登録の名前のボーンの場合のみ登録
                        pmx.bones[bone.name] = bone
                        # インデックス逆引きも登録
                        pmx.bone_indexes[bone.index] = bone.name
                
                # サイジング用ボーン ---------
                # 頭頂ボーン
                head_top_vertex = pmx.get_head_top_vertex()
                pmx.head_top_vertex = head_top_vertex
                head_top_bone = Bone("頭頂実体", "head_top", head_top_vertex.position.copy(), -1, 0, 0)
                head_top_bone.index = len(pmx.bones.keys())
                pmx.bones[head_top_bone.name] = head_top_bone
                pmx.bone_indexes[head_top_bone.index] = head_top_bone.name

                if "右足IK" in pmx.bones or "右つま先IK" in pmx.bones:
                    # 右つま先ボーン
                    right_toe_vertex = pmx.get_toe_vertex("右")
                    if right_toe_vertex:
                        pmx.right_toe_vertex = right_toe_vertex
                        right_toe_pos = right_toe_vertex.position.copy()
                        right_toe_pos.setY(0)
                        right_toe_bone = Bone("右つま先実体", "right toe entity", right_toe_pos, -1, 0, 0)
                        right_toe_bone.index = len(pmx.bones.keys())
                        pmx.bones[right_toe_bone.name] = right_toe_bone
                        pmx.bone_indexes[right_toe_bone.index] = right_toe_bone.name

                if "左足IK" in pmx.bones or "左つま先IK" in pmx.bones:
                    # 左つま先ボーン
                    left_toe_vertex = pmx.get_toe_vertex("左")
                    if left_toe_vertex:
                        pmx.left_toe_vertex = left_toe_vertex
                        left_toe_pos = left_toe_vertex.position.copy()
                        left_toe_pos.setY(0)
                        left_toe_bone = Bone("左つま先実体", "left toe entity", left_toe_pos, -1, 0, 0)
                        left_toe_bone.index = len(pmx.bones.keys())
                        pmx.bones[left_toe_bone.name] = left_toe_bone
                        pmx.bone_indexes[left_toe_bone.index] = left_toe_bone.name

                if "右足先EX" in pmx.bones or "右足IK" in pmx.bones:
                    # 右足底実体ボーン
                    right_sole_vertex = None
                    if "右足先EX" in pmx.bones:
                        right_sole_vertex = Vertex(-1, MVector3D(pmx.bones["右足先EX"].position.x(), 0, pmx.bones["右足先EX"].position.z()), MVector3D(), [], [], Bdef1(-1), -1)
                    elif "右足IK" in pmx.bones:
                        right_sole_vertex = pmx.get_sole_vertex("右")
                    
                    if right_sole_vertex:
                        pmx.right_sole_vertex = right_sole_vertex
                        right_sole_bone = Bone("右足底実体", "right sole entity", right_sole_vertex.position.copy(), -1, 0, 0)
                        right_sole_bone.index = len(pmx.bones.keys())
                        pmx.bones[right_sole_bone.name] = right_sole_bone
                        pmx.bone_indexes[right_sole_bone.index] = right_sole_bone.name

                if "左足先EX" in pmx.bones or "左足IK" in pmx.bones:
                    # 左足底実体ボーン
                    left_sole_vertex = None
                    if "左足先EX" in pmx.bones:
                        left_sole_vertex = Vertex(-1, MVector3D(pmx.bones["左足先EX"].position.x(), 0, pmx.bones["左足先EX"].position.z()), MVector3D(), [], [], Bdef1(-1), -1)
                    elif "左足IK" in pmx.bones:
                        left_sole_vertex = pmx.get_sole_vertex("左")
                    
                    if left_sole_vertex:
                        pmx.left_sole_vertex = left_sole_vertex
                        left_sole_bone = Bone("左足底実体", "left sole entity", left_sole_vertex.position.copy(), -1, 0, 0)
                        left_sole_bone.index = len(pmx.bones.keys())
                        pmx.bones[left_sole_bone.name] = left_sole_bone
                        pmx.bone_indexes[left_sole_bone.index] = left_sole_bone.name

                if "右足IK" in pmx.bones:
                    # 右足IK底実体ボーン
                    right_ik_sole_vertex = Vertex(-1, MVector3D(pmx.bones["右足IK"].position.x(), 0, pmx.bones["右足IK"].position.z()), MVector3D(), [], [], Bdef1(-1), -1)
                    pmx.right_ik_sole_vertex = right_ik_sole_vertex
                    right_ik_sole_bone = Bone("右足IK底実体", "right ik ik_sole entity", right_ik_sole_vertex.position.copy(), -1, 0, 0)
                    right_ik_sole_bone.index = len(pmx.bones.keys())
                    pmx.bones[right_ik_sole_bone.name] = right_ik_sole_bone
                    pmx.bone_indexes[right_ik_sole_bone.index] = right_ik_sole_bone.name

                if "左足IK" in pmx.bones:
                    # 左足IK底実体ボーン
                    left_ik_sole_vertex = Vertex(-1, MVector3D(pmx.bones["左足IK"].position.x(), 0, pmx.bones["左足IK"].position.z()), MVector3D(), [], [], Bdef1(-1), -1)
                    pmx.left_ik_sole_vertex = left_ik_sole_vertex
                    left_ik_sole_bone = Bone("左足IK底実体", "left ik ik_sole entity", left_ik_sole_vertex.position.copy(), -1, 0, 0)
                    left_ik_sole_bone.index = len(pmx.bones.keys())
                    pmx.bones[left_ik_sole_bone.name] = left_ik_sole_bone
                    pmx.bone_indexes[left_ik_sole_bone.index] = left_ik_sole_bone.name

                if "右足IK親" in pmx.bones:
                    # 右足IK親底実体ボーン
                    right_ik_sole_vertex = Vertex(-1, MVector3D(pmx.bones["右足IK親"].position.x(), 0, pmx.bones["右足IK親"].position.z()), MVector3D(), [], [], Bdef1(-1), -1)
                    pmx.right_ik_sole_vertex = right_ik_sole_vertex
                    right_ik_sole_bone = Bone("右足IK親底実体", "right ik ik_sole entity", right_ik_sole_vertex.position.copy(), -1, 0, 0)
                    right_ik_sole_bone.index = len(pmx.bones.keys())
                    pmx.bones[right_ik_sole_bone.name] = right_ik_sole_bone
                    pmx.bone_indexes[right_ik_sole_bone.index] = right_ik_sole_bone.name

                if "左足IK親" in pmx.bones:
                    # 左足IK親底実体ボーン
                    left_ik_sole_vertex = Vertex(-1, MVector3D(pmx.bones["左足IK親"].position.x(), 0, pmx.bones["左足IK親"].position.z()), MVector3D(), [], [], Bdef1(-1), -1)
                    pmx.left_ik_sole_vertex = left_ik_sole_vertex
                    left_ik_sole_bone = Bone("左足IK親底実体", "left ik ik_sole entity", left_ik_sole_vertex.position.copy(), -1, 0, 0)
                    left_ik_sole_bone.index = len(pmx.bones.keys())
                    pmx.bones[left_ik_sole_bone.name] = left_ik_sole_bone
                    pmx.bone_indexes[left_ik_sole_bone.index] = left_ik_sole_bone.name

                # 首根元ボーン
                if "左肩" in pmx.bones and "右肩" in pmx.bones:
                    neck_base_vertex = Vertex(-1, (pmx.bones["左肩"].position + pmx.bones["右肩"].position) / 2, MVector3D(), [], [], Bdef1(-1), -1)
                    neck_base_vertex.position.setX(0)
                    neck_base_bone = Bone("首根元", "base of neck", neck_base_vertex.position.copy(), -1, 0, 0)

                    if "上半身2" in pmx.bones:
                        # 上半身2がある場合、表示先は、上半身2
                        neck_base_bone.parent_index = pmx.bones["上半身2"].index
                        neck_base_bone.tail_index = pmx.bones["上半身2"].index
                    elif "上半身" in pmx.bones:
                        neck_base_bone.parent_index = pmx.bones["上半身"].index
                        neck_base_bone.tail_index = pmx.bones["上半身"].index

                    neck_base_bone.index = len(pmx.bones.keys())
                    pmx.bones[neck_base_bone.name] = neck_base_bone
                    pmx.bone_indexes[neck_base_bone.index] = neck_base_bone.name

                # 首根元2ボーン
                if "左腕" in pmx.bones and "右腕" in pmx.bones:
                    neck_base2_vertex = Vertex(-1, (pmx.bones["左腕"].position + pmx.bones["右腕"].position) / 2, MVector3D(), [], [], Bdef1(-1), -1)
                    neck_base2_vertex.position.setX(0)
                    neck_base2_bone = Bone("首根元2", "base of neck", neck_base2_vertex.position.copy(), -1, 0, 0)

                    if "首根元" in pmx.bones:
                        # 首根元が既にある場合は首根元
                        neck_base2_bone.parent_index = pmx.bones["首根元"].index
                        neck_base2_bone.tail_index = pmx.bones["首根元"].index
                    elif "上半身2" in pmx.bones:
                        # 上半身2がある場合、表示先は、上半身2
                        neck_base2_bone.parent_index = pmx.bones["上半身2"].index
                        neck_base2_bone.tail_index = pmx.bones["上半身2"].index
                    elif "上半身" in pmx.bones:
                        neck_base2_bone.parent_index = pmx.bones["上半身"].index
                        neck_base2_bone.tail_index = pmx.bones["上半身"].index

                    neck_base2_bone.index = len(pmx.bones.keys())
                    pmx.bones[neck_base2_bone.name] = neck_base2_bone
                    pmx.bone_indexes[neck_base2_bone.index] = neck_base2_bone.name

                if "右肩" in pmx.bones:
                    # 右肩下延長ボーン
                    right_shoulder_under_pos = pmx.bones["右肩"].position.copy()
                    right_shoulder_under_pos.setY(right_shoulder_under_pos.y() - 1)
                    right_shoulder_under_bone = Bone("右肩下延長", "", right_shoulder_under_pos, -1, 0, 0)
                    right_shoulder_under_bone.index = len(pmx.bones.keys())
                    pmx.bones[right_shoulder_under_bone.name] = right_shoulder_under_bone
                    pmx.bone_indexes[right_shoulder_under_bone.index] = right_shoulder_under_bone.name

                if "左肩" in pmx.bones:
                    # 左肩下延長ボーン
                    left_shoulder_under_pos = pmx.bones["左肩"].position.copy()
                    left_shoulder_under_pos.setY(left_shoulder_under_pos.y() - 1)
                    left_shoulder_under_bone = Bone("左肩下延長", "", left_shoulder_under_pos, -1, 0, 0)
                    left_shoulder_under_bone.index = len(pmx.bones.keys())
                    pmx.bones[left_shoulder_under_bone.name] = left_shoulder_under_bone
                    pmx.bone_indexes[left_shoulder_under_bone.index] = left_shoulder_under_bone.name

                if "右ひじ" in pmx.bones and "右手首" in pmx.bones:
                    # 右ひじ手首中間ボーン
                    right_elbow_middle_pos = (pmx.bones["右ひじ"].position + pmx.bones["右手首"].position) / 2
                    right_elbow_middle_bone = Bone("右ひじ手首中間", "", right_elbow_middle_pos, -1, 0, 0)
                    right_elbow_middle_bone.index = len(pmx.bones.keys())
                    pmx.bones[right_elbow_middle_bone.name] = right_elbow_middle_bone
                    pmx.bone_indexes[right_elbow_middle_bone.index] = right_elbow_middle_bone.name

                if "左ひじ" in pmx.bones and "左手首" in pmx.bones:
                    # 左ひじ手首中間ボーン
                    left_elbow_middle_pos = (pmx.bones["左ひじ"].position + pmx.bones["左手首"].position) / 2
                    left_elbow_middle_bone = Bone("左ひじ手首中間", "", left_elbow_middle_pos, -1, 0, 0)
                    left_elbow_middle_bone.index = len(pmx.bones.keys())
                    pmx.bones[left_elbow_middle_bone.name] = left_elbow_middle_bone
                    pmx.bone_indexes[left_elbow_middle_bone.index] = left_elbow_middle_bone.name

                if "右ひじ" in pmx.bones and "右腕" in pmx.bones:
                    # 右腕ひじ中間ボーン
                    right_arm_middle_pos = (pmx.bones["右ひじ"].position + pmx.bones["右腕"].position) / 2
                    right_arm_middle_bone = Bone("右腕ひじ中間", "", right_arm_middle_pos, -1, 0, 0)
                    right_arm_middle_bone.index = len(pmx.bones.keys())
                    pmx.bones[right_arm_middle_bone.name] = right_arm_middle_bone
                    pmx.bone_indexes[right_arm_middle_bone.index] = right_arm_middle_bone.name

                if "左ひじ" in pmx.bones and "左腕" in pmx.bones:
                    # 左腕ひじ中間ボーン
                    left_arm_middle_pos = (pmx.bones["左ひじ"].position + pmx.bones["左腕"].position) / 2
                    left_arm_middle_bone = Bone("左腕ひじ中間", "", left_arm_middle_pos, -1, 0, 0)
                    left_arm_middle_bone.index = len(pmx.bones.keys())
                    pmx.bones[left_arm_middle_bone.name] = left_arm_middle_bone
                    pmx.bone_indexes[left_arm_middle_bone.index] = left_arm_middle_bone.name

                # センター実体
                center_entity_bone = Bone("センター実体", "", MVector3D(), -1, 0, 0)
                center_entity_bone.index = len(pmx.bones.keys())
                pmx.bones[center_entity_bone.name] = center_entity_bone
                pmx.bone_indexes[center_entity_bone.index] = center_entity_bone.name

                # 指先ボーンがない場合、代替で挿入
                for direction in ["左", "右"]:
                    for (finger_name, end_joint_name) in [("親指", "2"), ("人指", "3"), ("中指", "3"), ("薬指", "3"), ("小指", "3")]:
                        end_joint_name = "{0}{1}{2}".format(direction, finger_name, end_joint_name)

                        if end_joint_name not in pmx.bones:
                            continue

                        to_joint_name = "{0}{1}{2}".format(direction, finger_name, "先実体")

                        finger_tail_vertex = pmx.get_finger_tail_vertex(end_joint_name, to_joint_name)
                        if finger_tail_vertex:
                            pmx.finger_tail_vertex = finger_tail_vertex
                            finger_tail_pos = finger_tail_vertex.position.copy()
                            finger_tail_bone = Bone(to_joint_name, "", finger_tail_pos, -1, 0, 0)
                            finger_tail_bone.index = len(pmx.bones.keys())
                            finger_tail_bone.parent_index = pmx.bones[end_joint_name].index
                            pmx.bones[finger_tail_bone.name] = finger_tail_bone
                            pmx.bone_indexes[finger_tail_bone.index] = finger_tail_bone.name

                # 足中間ボーン
                if "左足" in pmx.bones and "右足" in pmx.bones:
                    leg_center_vertex = Vertex(-1, (pmx.bones["左足"].position + pmx.bones["右足"].position) / 2, MVector3D(), [], [], Bdef1(-1), -1)
                    leg_center_vertex.position.setX(0)
                    leg_center_bone = Bone("足中間", "base of neck", leg_center_vertex.position.copy(), -1, 0, 0)

                    if "下半身" in pmx.bones:
                        leg_center_bone.parent_index = pmx.bones["下半身"].index
                        leg_center_bone.tail_index = pmx.bones["下半身"].index

                    leg_center_bone.index = len(pmx.bones.keys())
                    pmx.bones[leg_center_bone.name] = leg_center_bone
                    pmx.bone_indexes[leg_center_bone.index] = leg_center_bone.name

                logger.test("len(bones): %s", len(pmx.bones))

                logger.info("-- PMX ボーン読み込み完了")

                # ボーンの長さを計算する
                self.calc_bone_length(pmx.bones, pmx.bone_indexes)

                # 操作パネル (PMD:カテゴリ) 1:眉(左下) 2:目(左上) 3:口(右上) 4:その他(右下)
                morphs_by_panel = {}
                morphs_by_panel[2] = []  # 目
                morphs_by_panel[1] = []  # 眉
                morphs_by_panel[3] = []  # 口
                morphs_by_panel[4] = []  # 他
                morphs_by_panel[0] = []  # システム予約

                # モーフデータリスト
                for morph_idx in range(self.read_int(4)):
                    morph = Morph(
                        name=self.read_text(),
                        english_name=self.read_text(),
                        panel=self.read_int(1),
                        morph_type=self.read_int(1)
                    )

                    offset_size = self.read_int(4)

                    if morph.morph_type == 0:
                        # group
                        morph.offsets = [self.read_group_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 1:
                        # vertex
                        morph.offsets = [self.read_vertex_position_morph_offset() for _ in range(offset_size)]
                    elif morph.morph_type == 2:
                        # bone
                        morph.offsets = [self.read_bone_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 3:
                        # uv
                        morph.offsets = [self.read_uv_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 4:
                        # uv extended1
                        morph.offsets = [self.read_uv_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 5:
                        # uv extended2
                        morph.offsets = [self.read_uv_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 6:
                        # uv extended3
                        morph.offsets = [self.read_uv_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 7:
                        # uv extended4
                        morph.offsets = [self.read_uv_morph_data() for _ in range(offset_size)]
                    elif morph.morph_type == 8:
                        # material
                        morph.data = [self.read_material_morph_data() for _ in range(offset_size)]
                    else:
                        raise MParseException("unknown morph type: {0}".format(morph.morph_type))

                    # モーフのINDEXは、先頭から順番に設定
                    morph.index = morph_idx
                    # インデックス逆引きも登録
                    pmx.morph_indexes[morph.index] = morph.name

                    if morph.panel not in morphs_by_panel.keys():
                        # ないと思うが念のためパネル情報がなければ追加
                        morphs_by_panel[morph.panel] = 0

                    morphs_by_panel[morph.panel].append(morph)

                # モーフのパネル順に並び替えてモーフを登録していく
                for _, mlist in morphs_by_panel.items():
                    for m in mlist:
                        pmx.morphs[m.name] = m

                logger.test("len(morphs): %s", len(pmx.morphs))

                logger.info("-- PMX モーフ読み込み完了")

                # 表示枠データリスト
                for _ in range(self.read_int(4)):
                    display_slot = DisplaySlot(
                        name=self.read_text(),
                        english_name=self.read_text(),
                        special_flag=self.read_int(1)
                    )

                    display_count = self.read_int(4)

                    for _ in range(display_count):
                        display_type = self.read_int(1)
                        if display_type == 0:
                            born_idx = self.read_bone_index_size()
                            display_slot.references.append((display_type, born_idx))
                            # ボーン表示ON
                            for v in pmx.bones.values():
                                if v.index == born_idx:
                                    v.display = True
                        elif display_type == 1:
                            morph_idx = self.read_morph_index_size()
                            display_slot.references.append((display_type, morph_idx))
                            # モーフ表示ON
                            for v in pmx.morphs.values():
                                if v.index == morph_idx:
                                    v.display = True
                                # logger.test("v: %s, display: %s", v.name, v.display)
                        else:
                            raise MParseException("unknown display_type: {0}".format(display_type))

                    pmx.display_slots[display_slot.name] = display_slot

                logger.test("len(display_slots): %s", len(pmx.display_slots))

                logger.info("-- PMX 表示枠読み込み完了")

                # 剛体データリスト
                for rigidbody_idx in range(self.read_int(4)):
                    rigidbody = RigidBody(
                        name=self.read_text(),
                        english_name=self.read_text(),
                        bone_index=self.read_bone_index_size(),
                        collision_group=self.read_int(1),
                        no_collision_group=self.read_int(2),
                        shape_type=self.read_int(1),
                        shape_size=self.read_Vector3D(),
                        shape_position=self.read_Vector3D(),
                        shape_rotation=self.read_Vector3D(),
                        mass=self.read_float(),
                        linear_damping=self.read_float(),
                        angular_damping=self.read_float(),
                        restitution=self.read_float(),
                        friction=self.read_float(),
                        mode=self.read_int(1)
                    )

                    # ボーンのINDEX
                    rigidbody.index = rigidbody_idx

                    pmx.rigidbodies[rigidbody.name] = rigidbody
                    # インデックス逆引きも登録
                    pmx.rigidbody_indexes[rigidbody.index] = rigidbody.name

                logger.test("len(rigidbodies): %s", len(pmx.rigidbodies))

                logger.info("-- PMX 剛体読み込み完了")

                # ジョイントデータリスト
                for joint_idx in range(self.read_int(4)):
                    joint = Joint(
                        name=self.read_text(),
                        english_name=self.read_text(),
                        joint_type=self.read_int(1),
                        rigidbody_index_a=self.read_rigidbody_index_size(),
                        rigidbody_index_b=self.read_rigidbody_index_size(),
                        position=self.read_Vector3D(),
                        rotation=self.read_Vector3D(),
                        translation_limit_min=self.read_Vector3D(),
                        translation_limit_max=self.read_Vector3D(),
                        rotation_limit_min=self.read_Vector3D(),
                        rotation_limit_max=self.read_Vector3D(),
                        spring_constant_translation=self.read_Vector3D(),
                        spring_constant_rotation=self.read_Vector3D()
                    )

                    pmx.joints[joint.name] = joint

                logger.test("len(joints): %s", len(pmx.joints))

                logger.info("-- PMX ジョイント読み込み完了")

            # ハッシュを設定
            pmx.digest = self.hexdigest()
            logger.test("pmx: %s, hash: %s", pmx.name, pmx.digest)

            if self.is_check:
                # 腕がサイジング可能かチェック
                pmx.can_arm_sizing = pmx.check_arm_bone_can_sizing()
                logger.test("pmx: %s, can_arm_sizing: %s", pmx.name, pmx.can_arm_sizing)

            # # 上半身がサイジング可能かチェック
            # pmx.can_upper_sizing = pmx.check_upper_bone_can_sizing()
            # logger.test("pmx: %s, can_upper_sizing: %s", pmx.name, pmx.can_upper_sizing)

            return pmx
        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
Beispiel #7
0
    def read_model_name(self):
        model_name = ""
        with open(self.file_path, "rb") as f:
            # PMXファイルをバイナリ読み込み
            self.buffer = f.read()
            # logger.test("hashlib.algorithms_available: %s", hashlib.algorithms_available)

            # pmx宣言
            signature = self.unpack(4, "4s")
            logger.test("signature: %s (%s)", signature, self.offset)

            # pmxバージョン
            version = self.read_float()
            logger.test("version: %s (%s)", version, self.offset)

            if signature[:3] != b"PMX" or (version != 2.0 and version != 2.1):
                # 整合性チェック
                raise MParseException("PMX2.0/2.1形式外のデータです。signature: {0}, version: {1} ".format(signature, version))

            # flag
            flag_bytes = self.read_int(1)
            logger.test("flag_bytes: %s (%s)", flag_bytes, self.offset)

            # エンコード方式
            text_encoding = self.read_int(1)
            logger.test("text_encoding: %s (%s)", text_encoding, self.offset)
            # エンコードに基づいて文字列解凍処理を定義
            self.read_text = self.define_read_text(text_encoding)

            # 追加UV数
            self.extended_uv = self.read_int(1)
            logger.test("extended_uv: %s (%s)", self.extended_uv, self.offset)

            # 頂点Indexサイズ
            self.vertex_index_size = self.read_int(1)
            logger.test("vertex_index_size: %s (%s)", self.vertex_index_size, self.offset)
            self.read_vertex_index_size = lambda: self.read_int(self.vertex_index_size)

            # テクスチャIndexサイズ
            self.texture_index_size = self.read_int(1)
            logger.test("texture_index_size: %s (%s)", self.texture_index_size, self.offset)
            self.read_texture_index_size = lambda: self.read_int(self.texture_index_size)

            # 材質Indexサイズ
            self.material_index_size = self.read_int(1)
            logger.test("material_index_size: %s (%s)", self.material_index_size, self.offset)
            self.read_material_index_size = lambda: self.read_int(self.material_index_size)

            # ボーンIndexサイズ
            self.bone_index_size = self.read_int(1)
            logger.test("bone_index_size: %s (%s)", self.bone_index_size, self.offset)
            self.read_bone_index_size = lambda: self.read_int(self.bone_index_size)

            # モーフIndexサイズ
            self.morph_index_size = self.read_int(1)
            logger.test("morph_index_size: %s (%s)", self.morph_index_size, self.offset)
            self.read_morph_index_size = lambda: self.read_int(self.morph_index_size)

            # 剛体Indexサイズ
            self.rigidbody_index_size = self.read_int(1)
            logger.test("rigidbody_index_size: %s (%s)", self.rigidbody_index_size, self.offset)
            self.read_rigidbody_index_size = lambda: self.read_int(self.rigidbody_index_size)

            # モデル名(日本語)
            model_name = self.read_text()
            logger.test("name: %s (%s)", model_name, self.offset)

        return model_name