예제 #1
0
def create_pmx(ex, enable_bdef4=True):
    """
    PMX 出力
    """
    model = pmx.Model()

    o = ex.root.o
    model.name = o.get(bl.MMD_MB_NAME, 'Blenderエクスポート')
    model.english_name = o.get(bl.MMD_ENGLISH_NAME, 'blender export model')
    model.comment = o.get(bl.MMD_MB_COMMENT, 'Blnderエクスポート\n')
    model.english_comment = o.get(bl.MMD_ENGLISH_COMMENT,
                                  'blender export commen\n')

    class DeformBuilder:
        def __init__(self, skeleton):
            self.skeleton = skeleton
            self.bone_names = {b.name for b in skeleton.bones}
            self.count_bdef1 = 0
            self.count_bdef2 = 0
            self.count_bdef4 = 0
            self.count_error = 0

        def __filter(self, name, weight):
            return name in self.bone_names

        def __call__(self, ext_weight):
            weights=[ (self.skeleton.indexByName(w[0]), w[1]) \
                for w in ext_weight.get_normalized(4, self.__filter) ]
            if len(weights) == 0:
                self.count_error += 1
                return pmx.Bdef1(0)  # Recovery
            elif len(weights) == 1:
                self.count_bdef1 += 1
                return pmx.Bdef1(weights[0][0])
            elif len(weights) == 2:
                self.count_bdef2 += 1
                return pmx.Bdef2(weights[0][0], weights[1][0], weights[0][1])
            else:
                if len(weights) == 3:
                    weights.append((0, 0.0))  # Dummy Data
                self.count_bdef4 += 1
                return pmx.Bdef4(weights[0][0], weights[1][0], weights[2][0],
                                 weights[3][0], weights[0][1], weights[1][1],
                                 weights[2][1], weights[3][1])

        def show(self):
            print("BDEF Statistics >>>")
            print("\tBDEF1: %d BDEF2: %d BDEF4: %d ERROR: %d" % \
                (self.count_bdef1, self.count_bdef2, self.count_bdef4, self.count_error))

    deform_builder = DeformBuilder(ex.skeleton)

    def get_deform(b0, b1, weight):
        if b0 == -1:
            return pmx.Bdef1(b1, weight)
        elif b1 == -1:
            return pmx.Bdef1(b0, weight)
        else:
            return pmx.Bdef2(b0, b1, weight)

    model.vertices=[pmx.Vertex(
        # convert right-handed z-up to left-handed y-up
        common.Vector3(pos[0], pos[2], pos[1]),
        # convert right-handed z-up to left-handed y-up
        common.Vector3(attribute.nx, attribute.nz, attribute.ny),
        # reverse vertical
        common.Vector2(attribute.u, 1.0-attribute.v),
        deform_builder(ext_weight) if enable_bdef4 else \
        get_deform(ex.skeleton.indexByName(b0), ex.skeleton.indexByName(b1), weight),
        # edge flag, 0: enable edge, 1: not edge
        1.0
        )
        for pos, attribute, b0, b1, weight, ext_weight in ex.oneSkinMesh.vertexArray.zip2()]

    if enable_bdef4:
        deform_builder.show()

    boneMap = dict([(b.name, i) for i, b in enumerate(ex.skeleton.bones)])

    def getFixedAxis(b):
        if b.isFixedAxis():
            return common.Vector3(b.tail[0], b.tail[2], b.tail[1]).normalize()
        else:
            return common.Vector3(0, 0, 0)

    def create_bone(b):

        bone = pmx.Bone(
            name=b.name,
            english_name=b.english_name,
            # convert right-handed z-up to left-handed y-up
            position=common.Vector3(b.pos[0] if not near(b.pos[0], 0) else 0,
                                    b.pos[2] if not near(b.pos[2], 0) else 0,
                                    b.pos[1] if not near(b.pos[1], 0) else 0),
            parent_index=b.parent_index,
            layer=0,
            flag=0,
            tail_position=None,
            tail_index=b.tail_index,
            effect_index=-1,
            effect_factor=0.0,
            fixed_axis=getFixedAxis(b),
            local_x_vector=None,
            local_z_vector=None,
            external_key=-1,
            ik=None)

        if b.constraint == exporter.bonebuilder.CONSTRAINT_COPY_ROTATION:
            bone.layer = 2
            bone.effect_index = boneMap[b.constraintTarget]
            bone.effect_factor = b.constraintInfluence
            bone.setFlag(pmx.BONEFLAG_IS_EXTERNAL_ROTATION, True)

        if b.constraint == exporter.bonebuilder.CONSTRAINT_LIMIT_ROTATION:
            bone.setFlag(pmx.BONEFLAG_HAS_FIXED_AXIS, True)

        bone.setFlag(pmx.BONEFLAG_TAILPOS_IS_BONE, b.hasTail)
        bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
        bone.setFlag(pmx.BONEFLAG_CAN_TRANSLATE, b.canTranslate)
        bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, b.isVisible)
        bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, b.canManipulate())

        if b.ikSolver:
            bone.setFlag(pmx.BONEFLAG_IS_IK, True)
            bone.ik_target_index = b.ikSolver.effector_index
            bone.ik = pmx.Ik(b.ikSolver.effector_index, b.ikSolver.iterations,
                             b.ikSolver.weight, [
                                 pmx.IkLink(c.index, c.limitAngle,
                                            common.Vector3(*c.limitMin),
                                            common.Vector3(*c.limitMax))
                                 for c in b.ikSolver.chain
                             ])

        return bone

    model.bones = [create_bone(b) for b in ex.skeleton.bones]

    # textures
    textures = set()

    def get_texture_name(texture):
        pos = texture.replace("\\", "/").rfind("/")
        if pos == -1:
            return texture
        else:
            return texture[pos + 1:]

    try:
        for m in ex.oneSkinMesh.vertexArray.indexArrays.keys():
            for path in bl.material.eachEnalbeTexturePath(bl.material.get(m)):
                textures.add(get_texture_name(path))
    except KeyError as e:
        # no material
        pass
    model.textures = list(textures)

    # texture pathからtexture indexを逆引き
    texturePathMap = {}
    for i, texture_path in enumerate(model.textures):
        texturePathMap[texture_path] = i

    def get_flag(m):
        """
        return material flag
        """
        return (m.get(bl.MATERIALFLAG_BOTHFACE, 0) +
                (m.get(bl.MATERIALFLAG_GROUNDSHADOW, 0) << 1) +
                (m.get(bl.MATERIALFLAG_SELFSHADOWMAP, 0) << 2) +
                (m.get(bl.MATERIALFLAG_SELFSHADOW, 0) << 3) +
                (m.get(bl.MATERIALFLAG_EDGE, 0) << 4))

    def get_toon_shareing_flag(m):
        """
        return
        shared: 1
        not shared: 0
        """
        for t in bl.material.eachEnalbeTexturePath(m):
            if re.match("""toon\d\d.bmp"""):
                return 1
        return 0

    def get_texture_params(m, texturePathMap):
        texture_index = -1
        toon_texture_index = -1
        toon_sharing_flag = 0
        sphere_texture_index = -1
        sphere_mode = pmx.MATERIALSPHERE_NONE

        for t in bl.material.eachEnalbeTexture(m):
            texture_type = t.get(bl.TEXTURE_TYPE, 'NORMAL')
            texture_path = get_texture_name(bl.texture.getPath(t))
            if texture_type == 'NORMAL':
                texture_index = texturePathMap[texture_path]
            elif texture_type == 'TOON':
                toon_texture_index = texturePathMap[texture_path]
                toon_sharing_flag = 0
            elif texture_type == 'SPH':
                sphere_texture_index = texturePathMap[texture_path]
                sphere_mode = pmx.MATERIALSPHERE_SPH
            elif texture_type == 'SPA':
                sphere_texture_index = texturePathMap[texture_path]
                sphere_mode = pmx.MATERIALSPHERE_SPA

        if bl.MATERIAL_SHAREDTOON in m:
            toon_texture_index = m[bl.MATERIAL_SHAREDTOON]
            toon_sharing_flag = 1

        return (texture_index, toon_texture_index, toon_sharing_flag,
                sphere_texture_index, sphere_mode)

    # 面とマテリアル
    vertexCount = ex.oneSkinMesh.getVertexCount()
    model.materials = []
    for material_name, indices in ex.oneSkinMesh.vertexArray.each():
        #print('material:', material_name)
        try:
            m = bl.material.get(material_name)
        except KeyError as e:
            m = exporter.oneskinmesh.DefaultMaterial()
        (
            texture_index,
            toon_texture_index,
            toon_sharing_flag,
            sphere_texture_index,
            sphere_mode,
        ) = get_texture_params(m, texturePathMap)
        # マテリアル
        model.materials.append(
            pmx.Material(name=m.name,
                         english_name='',
                         diffuse_color=common.RGB(m.diffuse_color[0],
                                                  m.diffuse_color[1],
                                                  m.diffuse_color[2]),
                         alpha=m.use_transparency and m.alpha or 1.0,
                         specular_factor=(0 if m.specular_toon_size < 1e-5 else
                                          m.specular_toon_size * 10),
                         specular_color=common.RGB(m.specular_color[0],
                                                   m.specular_color[1],
                                                   m.specular_color[2]),
                         ambient_color=common.RGB(m.mirror_color[0],
                                                  m.mirror_color[1],
                                                  m.mirror_color[2]),
                         flag=get_flag(m),
                         edge_color=common.RGBA(0, 0, 0, 1),
                         edge_size=1.0,
                         texture_index=texture_index,
                         sphere_texture_index=sphere_texture_index,
                         sphere_mode=sphere_mode,
                         toon_sharing_flag=toon_sharing_flag,
                         toon_texture_index=toon_texture_index,
                         comment='',
                         vertex_count=len(indices)))
        # 面
        for i in indices:
            assert (i < vertexCount)
        for i in range(0, len(indices), 3):
            # reverse triangle
            model.indices.append(indices[i + 2])
            model.indices.append(indices[i + 1])
            model.indices.append(indices[i])

    def get_vertex_index(rel_index):
        return ex.oneSkinMesh.morphList[0].offsets[rel_index][0]

    # 表情
    from pymeshio import englishmap
    for i, m in enumerate(ex.oneSkinMesh.morphList[1:]):
        # name
        english_name = "morph: %d" % i
        panel = 4
        for en, n, p in englishmap.skinMap:
            if n == m.name:
                english_name = en
                panel = p
                break

        morph = pmx.Morph(
            name=m.name,
            english_name=english_name,
            panel=panel,
            morph_type=1,
        )
        morph.offsets = [
            pmx.VertexMorphOffset(
                get_vertex_index(index),
                common.Vector3(offset[0], offset[2], offset[1]))
            for index, offset in m.offsets
        ]
        model.morphs.append(morph)

    # ボーングループ
    model.display_slots = []
    for name, members in ex.skeleton.bone_groups:
        if name == "表情":
            slot = pmx.DisplaySlot(
                name=name,
                english_name=englishmap.getEnglishBoneGroupName(name),
                special_flag=1)
            slot.references = [(1, i) for i in range(len(model.morphs))]
            model.display_slots.append(slot)

        else:
            slot = pmx.DisplaySlot(
                name=name,
                english_name=englishmap.getEnglishBoneGroupName(name),
                special_flag=1 if name == "Root" else 0)
            slot.references = [(0, ex.skeleton.boneByName(m).index)
                               for m in members]
            model.display_slots.append(slot)

    # rigid body
    boneNameMap = {}
    for i, b in enumerate(ex.skeleton.bones):
        boneNameMap[b.name] = i
    rigidNameMap = {}
    for i, obj in enumerate(ex.oneSkinMesh.rigidbodies):
        name = obj[bl.RIGID_NAME] if bl.RIGID_NAME in obj else obj.name
        #print(name)
        rigidNameMap[name] = i
        boneIndex = boneNameMap[obj[bl.RIGID_BONE_NAME]]
        if boneIndex == 0:
            boneIndex = -1
        if obj[bl.RIGID_SHAPE_TYPE] == 0:
            shape_type = 0
            shape_size = common.Vector3(obj.scale[0], 0, 0)
        elif obj[bl.RIGID_SHAPE_TYPE] == 1:
            shape_type = 1
            shape_size = common.Vector3(obj.scale[0], obj.scale[2],
                                        obj.scale[1])
        elif obj[bl.RIGID_SHAPE_TYPE] == 2:
            shape_type = 2
            shape_size = common.Vector3(obj.scale[0], obj.scale[2], 0)
        rigidBody = pmx.RigidBody(
            name=name,
            english_name='',
            collision_group=obj[bl.RIGID_GROUP],
            no_collision_group=obj[bl.RIGID_INTERSECTION_GROUP],
            bone_index=boneIndex,
            shape_position=common.Vector3(obj.location.x, obj.location.z,
                                          obj.location.y),
            shape_rotation=common.Vector3(-obj.rotation_euler[0],
                                          -obj.rotation_euler[2],
                                          -obj.rotation_euler[1]),
            shape_type=shape_type,
            shape_size=shape_size,
            mass=obj[bl.RIGID_WEIGHT],
            linear_damping=obj[bl.RIGID_LINEAR_DAMPING],
            angular_damping=obj[bl.RIGID_ANGULAR_DAMPING],
            restitution=obj[bl.RIGID_RESTITUTION],
            friction=obj[bl.RIGID_FRICTION],
            mode=obj[bl.RIGID_PROCESS_TYPE])
        model.rigidbodies.append(rigidBody)

    # joint
    model.joints = [
        pmx.Joint(
            name=obj[bl.CONSTRAINT_NAME],
            english_name='',
            joint_type=0,
            rigidbody_index_a=rigidNameMap[obj[bl.CONSTRAINT_A]],
            rigidbody_index_b=rigidNameMap[obj[bl.CONSTRAINT_B]],
            position=common.Vector3(obj.location[0], obj.location[2],
                                    obj.location[1]),
            rotation=common.Vector3(-obj.rotation_euler[0],
                                    -obj.rotation_euler[2],
                                    -obj.rotation_euler[1]),
            translation_limit_min=common.Vector3(
                obj[bl.CONSTRAINT_POS_MIN][0], obj[bl.CONSTRAINT_POS_MIN][1],
                obj[bl.CONSTRAINT_POS_MIN][2]),
            translation_limit_max=common.Vector3(
                obj[bl.CONSTRAINT_POS_MAX][0], obj[bl.CONSTRAINT_POS_MAX][1],
                obj[bl.CONSTRAINT_POS_MAX][2]),
            rotation_limit_min=common.Vector3(obj[bl.CONSTRAINT_ROT_MIN][0],
                                              obj[bl.CONSTRAINT_ROT_MIN][1],
                                              obj[bl.CONSTRAINT_ROT_MIN][2]),
            rotation_limit_max=common.Vector3(obj[bl.CONSTRAINT_ROT_MAX][0],
                                              obj[bl.CONSTRAINT_ROT_MAX][1],
                                              obj[bl.CONSTRAINT_ROT_MAX][2]),
            spring_constant_translation=common.Vector3(
                obj[bl.CONSTRAINT_SPRING_POS][0],
                obj[bl.CONSTRAINT_SPRING_POS][1],
                obj[bl.CONSTRAINT_SPRING_POS][2]),
            spring_constant_rotation=common.Vector3(
                obj[bl.CONSTRAINT_SPRING_ROT][0],
                obj[bl.CONSTRAINT_SPRING_ROT][1],
                obj[bl.CONSTRAINT_SPRING_ROT][2]))
        for obj in ex.oneSkinMesh.constraints
    ]

    return model
예제 #2
0
def savepmx(model, filename):
    pmx_model = pmx.Model()
    pmx_model.english_name = u'Empty model'
    pmx_model.comment = u'NeoX Model Converterで生成'
    pmx_model.english_comment = u'Created by NeoX Model Converter.'

    parent_child_dict = {}
    old2new = {}
    index_pool = [-1]
    bone_pool = []
    for i in range(len(model['bone_parent'])):
        p = model['bone_parent'][i]
        if p not in parent_child_dict:
            parent_child_dict[p] = []
        parent_child_dict[p].append(i)

    def build_joint(index, parent_index):
        matrix = model['bone_original_matrix'][index]
        x, y, z = tf.translation_from_matrix(matrix.T)
        bone_pool.append(
            pmx.Bone(name=model['bone_name'][index],
                     english_name=model['bone_name'][index],
                     position=common.Vector3(-x, y, -z),
                     parent_index=parent_index,
                     layer=0,
                     flag=0))
        bone_pool[-1].setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
        bone_pool[-1].setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
        bone_pool[-1].setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)

    def deep_first_search(index, index_pool, parent_index):
        index_pool[0] += 1
        current_node_index = index_pool[0]
        old2new[index] = current_node_index
        build_joint(index, parent_index)
        if index in parent_child_dict:
            for child in parent_child_dict[index]:
                deep_first_search(child, index_pool, current_node_index)

    deep_first_search(model['bone_parent'].index(-1), index_pool, -1)

    pmx_model.bones = bone_pool

    for i in range(len(model['position'])):
        x, y, z = model['position'][i]
        nx, ny, nz = model['normal'][i]
        u, v = model['uv'][i]
        if 65535 in model['vertex_joint'][i]:
            vertex_joint_index = list(
                map(lambda x: old2new[x]
                    if x != 65535 else 0, model['vertex_joint'][i]))
        else:
            vertex_joint_index = list(
                map(lambda x: old2new[x]
                    if x != 255 else 0, model['vertex_joint'][i]))

        vertex = pmx.Vertex(
            common.Vector3(-x, y, -z), common.Vector3(-nx, ny, -nz),
            common.Vector2(u, v),
            pmx.Bdef4(*vertex_joint_index, *(model['vertex_joint_weight'][i])),
            0.0)
        pmx_model.vertices.append(vertex)

    for i in range(len(model['face'])):
        pmx_model.indices += list(model['face'][i])

    pmx_model.materials[0].vertex_count = len(model['face']) * 3

    ###########
    pmx_model.materials = []
    for i in range(len(model['mesh'])):
        _, mesh_face_count, _, _ = model['mesh'][i]
        pmx_model.materials.append(
            pmx.Material(u'Mat{}'.format(i), u'material{}'.format(i),
                         common.RGB(0.5, 0.5, 1), 1.0, 1, common.RGB(1, 1, 1),
                         common.RGB(0, 0, 0), 0, common.RGBA(0, 0, 0, 1), 0,
                         -1, -1, pmx.MATERIALSPHERE_NONE, 1, 0, u"comment",
                         mesh_face_count * 3))

    filename = filename.replace('.mesh', '')
    pymeshio.pmx.writer.write_to_file(pmx_model, filename + '.pmx')
    for bone in pmx_model.bones:
        if bone.english_name in paj_middle_bone_name:
            bone.position.x = 0.0

    if 'bip001_l_finger13' in [bone.english_name for bone in pmx_model.bones]:
        paj_bone_name.update(paj_hand1_name)
    else:
        paj_bone_name.update(paj_hand0_name)

    for bone in pmx_model.bones:
        if bone.english_name in paj_bone_name:
            bone.name = paj_bone_name[bone.english_name][0]
            bone.english_name = paj_bone_name[bone.english_name][1]

    def add_bone(pmxm, bone, index):
        assert index <= len(pmxm.bones)
        pmxm.bones.insert(index, bone)
        for bone in pmxm.bones:
            if bone.parent_index >= index:
                bone.parent_index += 1

        for vertex in pmxm.vertices:
            if vertex.deform.index0 >= index:
                vertex.deform.index0 += 1
            if vertex.deform.index1 >= index:
                vertex.deform.index1 += 1
            if vertex.deform.index2 >= index:
                vertex.deform.index2 += 1
            if vertex.deform.index3 >= index:
                vertex.deform.index3 += 1

        return index

    def find_bone_index_by_name(pmxm, bone_english_name):
        ret = None
        for i in range(len(pmxm.bones)):
            if pmxm.bones[i].english_name == bone_english_name:
                ret = i
                break
        return ret

    #######################
    parent_node_index = find_bone_index_by_name(pmx_model, 'ParentNode')

    center_bone = pmx.Bone(name='センター',
                           english_name='Center',
                           position=common.Vector3(0, 8.0, 0),
                           parent_index=parent_node_index,
                           layer=0,
                           flag=0)
    center_bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
    center_bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
    center_bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)

    waist_index = find_bone_index_by_name(pmx_model, 'Waist')
    center_index = add_bone(pmx_model, center_bone, waist_index)

    groove_bone = pmx.Bone(name='グルーブ',
                           english_name='Groove',
                           position=common.Vector3(0, 8.2, 0),
                           parent_index=center_index,
                           layer=0,
                           flag=0)
    groove_bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
    groove_bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
    groove_bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)
    waist_index = find_bone_index_by_name(pmx_model, 'Waist')
    groove_index = add_bone(pmx_model, groove_bone, waist_index)

    waist_index = find_bone_index_by_name(pmx_model, 'Waist')
    pmx_model.bones[waist_index].parent_index = groove_index

    waist_index = find_bone_index_by_name(pmx_model, 'Waist')
    upper_body_index = find_bone_index_by_name(pmx_model, 'UpperBody')
    pmx_model.bones[upper_body_index].parent_index = waist_index

    ##########################
    for LR in ['Left', 'Right']:
        ankle_index = find_bone_index_by_name(pmx_model, '{}Ankle'.format(LR))
        ankle_x, ankle_y, ankle_z = pmx_model.bones[
            ankle_index].position.to_tuple()
        toe_index = find_bone_index_by_name(pmx_model, '{}Toe'.format(LR))
        toe_vec = pmx_model.bones[toe_index].position
        toe_vec.y = ankle_y - 1.0
        toe_vec.z = -1.65
        leg_ik_parent_bone = pmx.Bone(
            name='左足IK親' if LR == 'Left' else '右足IK親',
            english_name='{}LegIkParent'.format(LR),
            position=common.Vector3(ankle_x, 0, ankle_z),
            parent_index=parent_node_index,
            layer=0,
            flag=0)
        leg_ik_parent_bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
        leg_ik_parent_bone.setFlag(pmx.BONEFLAG_CAN_TRANSLATE, True)
        leg_ik_parent_bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
        leg_ik_parent_bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)
        leg_ik_parent_index = add_bone(pmx_model, leg_ik_parent_bone,
                                       len(pmx_model.bones))

        leg_ik_bone = pmx.Bone(name='左足IK' if LR == 'Left' else '右足IK',
                               english_name='{}LegIk'.format(LR),
                               position=common.Vector3(ankle_x, ankle_y,
                                                       ankle_z),
                               parent_index=leg_ik_parent_index,
                               layer=0,
                               flag=0)

        leg_ik_bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
        leg_ik_bone.setFlag(pmx.BONEFLAG_CAN_TRANSLATE, True)
        leg_ik_bone.setFlag(pmx.BONEFLAG_IS_IK, True)
        leg_ik_bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
        leg_ik_bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)

        knee_index = find_bone_index_by_name(pmx_model, '{}Knee'.format(LR))
        leg_index = find_bone_index_by_name(pmx_model, '{}Leg'.format(LR))
        leg_ik_link = [
            pmx.IkLink(knee_index, 1, common.Vector3(-180.0 / 57.325, 0, 0),
                       common.Vector3(-0.5 / 57.325, 0, 0)),
            pmx.IkLink(leg_index, 0)
        ]
        leg_ik_bone.ik = pmx.Ik(ankle_index, 40, 2, leg_ik_link)
        leg_ik_index = add_bone(pmx_model, leg_ik_bone, len(pmx_model.bones))

        toe_ik_bone = pmx.Bone(name='左つま先IK' if LR == 'Left' else '右つま先IK',
                               english_name='{}LegIk'.format(LR),
                               position=common.Vector3(toe_vec.x, toe_vec.y,
                                                       toe_vec.z),
                               parent_index=leg_ik_index,
                               layer=0,
                               flag=0)
        toe_ik_bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
        toe_ik_bone.setFlag(pmx.BONEFLAG_CAN_TRANSLATE, True)
        toe_ik_bone.setFlag(pmx.BONEFLAG_IS_IK, True)
        toe_ik_bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
        toe_ik_bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)
        toe_ik_bone.ik = pmx.Ik(toe_index, 3, 4, [pmx.IkLink(ankle_index, 0)])
        add_bone(pmx_model, toe_ik_bone, len(pmx_model.bones))
    '''
    # build local axis and get rotation
    left_arm_index = find_bone_index_by_name(pmx_model, 'LeftArm')
    left_elbow_index = find_bone_index_by_name(pmx_model, 'LeftElbow')
    left_wrist_index = find_bone_index_by_name(pmx_model, 'LeftWrist')
    larm_pos = np.array(list(pmx_model.bones[left_arm_index].position.to_tuple()))
    lelbow_pos = np.array(list(pmx_model.bones[left_elbow_index].position.to_tuple()))
    lwrist_pos = np.array(list(pmx_model.bones[left_wrist_index].position.to_tuple()))
    vec_ew = lwrist_pos - lelbow_pos
    vec_ea = larm_pos - lelbow_pos
    vec_ew = vec_ew / np.linalg.norm(vec_ew)
    vec_ea = vec_ea / np.linalg.norm(vec_ea)
    cos_ew_ea = np.dot(vec_ea, vec_ew)
    if -1 * math.cos(3/180 * 3.14) < cos_ew_ea and cos_ew_ea < 0:
        y_axis = np.cross(vec_ew, vec_ea)
        y_axis = y_axis / np.linalg.norm(y_axis)
        z_axis = np.cross(vec_ea, y_axis)
        z_axis = z_axis / np.linalg.norm(z_axis)
        x_axis = np.cross(z_axis, y_axis)
        x_axis = x_axis / np.linalg.norm(x_axis)
        # pmx_model.bones[left_elbow_index].setFlag(pmx.BONEFLAG_HAS_LOCAL_COORDINATE, True)
        pmx_model.bones[left_elbow_index].local_x_vector = common.Vector3(*x_axis.tolist())
        pmx_model.bones[left_elbow_index].local_z_vector = common.Vector3(*z_axis.tolist())
    '''
    head_index = find_bone_index_by_name(pmx_model, 'Head')
    eyes_bone = pmx.Bone(name='両目',
                         english_name='Eyes',
                         position=common.Vector3(0, 25, 0),
                         parent_index=head_index,
                         layer=0,
                         flag=0)
    eyes_bone.setFlag(pmx.BONEFLAG_CAN_ROTATE, True)
    eyes_bone.setFlag(pmx.BONEFLAG_IS_VISIBLE, True)
    eyes_bone.setFlag(pmx.BONEFLAG_CAN_MANIPULATE, True)

    pmx_model.bones.append(eyes_bone)
    eyes_index = find_bone_index_by_name(pmx_model, 'Eyes')
    for LR in 'lr':
        eyeball_index = find_bone_index_by_name(pmx_model,
                                                'bone_eyeball_{}'.format(LR))
        pmx_model.bones[eyeball_index].effect_index = eyes_index
        pmx_model.bones[eyeball_index].effect_factor = 2.2
        pmx_model.bones[eyeball_index].setFlag(
            pmx.BONEFLAG_IS_EXTERNAL_ROTATION, True)
    '''
    morph_ref_model = pymeshio.pmx.reader.read_from_file('morph_ref')
    pmx_model.morphs = morph_ref_model.morphs
    for morph in pmx_model.morphs:
        for offset in morph.offsets:
            bone_english_name = morph_ref_model.bones[offset.bone_index].english_name
            offset.bone_index = find_bone_index_by_name(pmx_model, bone_english_name)
    '''

    pymeshio.pmx.writer.write_to_file(pmx_model, filename + '_modified.pmx')
예제 #3
0
def khiankhuen(chue_tem_file='',khanat_ok=0.125,chai_kraduk=1,chai_bs=1,chai_watsadu=1,lok_tex=1,mod_sph=1,tex_sph=''):
    t0 = time.time()
    chue_path_file = os.path.dirname(chue_tem_file)
    shoki = os.path.join(os.path.dirname(__file__),u'shoki.pmx')
    model = pmxread(shoki) # สร้างโมเดล pmx ตั้งต้น
    # เพื่อความรวดเร็ว ดึง append มาเก็บไว้ก่อน
    model_vert_ap = model.vertices.append
    model_ind_ap = model.indices.append
    model_bon_ap = model.bones.append
    model_mat_ap = model.materials.append
    model_mor_ap = model.morphs.append
    model_slot_ap1 = model.display_slots[1].references.append
    model_slot_ap2 = model.display_slots[2].references.append
    
    # โหนดโพลิกอนทั้งหมดที่เลือกอยู่
    list_chue_nod_poly = mc.filterExpand(mc.ls(tr=1,sl=1),sm=12)
    list_chue_nod_shep = []
    list_chue_nod_skin = []
    list_matrix_mun = [0]
    if(list_chue_nod_poly==None): # กรณีที่ไม่ได้เลือกโพลิกอนไว้เลย
        print(u'ポリゴンは選択せれていません')
        return
    
    for chue_nod_poly in list_chue_nod_poly:
        # โหนดรูปร่างของโพลิกอนนั้นๆ
        chue_nod_shep = mc.listRelatives(chue_nod_poly,s=1)[0]
        list_chue_nod_shep.append(chue_nod_shep)
        # หาโหนด skin ที่ใช้กับโพลิกอนนั้นๆ
        if(chai_kraduk):
            for chue_nod_skin in mc.ls(typ='skinCluster'):
                if(chue_nod_shep in mc.skinCluster(chue_nod_skin,q=1,g=1)):
                    list_chue_nod_skin.append(chue_nod_skin)
                    break
            # ถ้าหาไม่เจอก็คือไม่มี
            else:
                list_chue_nod_skin.append(0)
    
    if(chai_kraduk):
        dic_chue_nod_kho = {u'全ての親':0}
        i_kho = 1
        for k in mc.ls(typ='joint',l=1):
            # ถ้ามีอยู่แล้วก็ข้ามไปได้เลย
            if(k in dic_chue_nod_kho):
                continue
            # หาว่าตรึงอยู่กับสกินที่ใช้หรือเปล่า
            for chue_nod_skin in list_chue_nod_skin:
                if(chue_nod_skin and k in (pm.PyNode(x).fullPath() for x in mc.skinCluster(chue_nod_skin,q=1,inf=1))):
                    break
            # ถ้าไม่มีเลยก็ข้ามไป
            else:
                continue
            # หาตัวรากฐาน
            parent = mc.listRelatives(k,p=1,f=1)
            if(parent):
                pp = ['']
                for p in parent[0].split('|')[1:]:
                    pp.append(p)
                    pj = '|'.join(pp)
                    if(mc.nodeType(pj)=='joint'):
                        parent = pj
                        break
                else:
                    parent = k
            else:
                parent = k # ถ้าไม่มีก็คือตัวมันเองเป็น
            # ถ้าตัวรากฐานมีอยู่แล้วก็ข้ามไปได้เลย
            if(parent in dic_chue_nod_kho):
                continue
            # ถ้ายังไม่มีก็ใส่ข้อมูลเข้าไปทั้งตัวรากฐานและลูกทั้งหมด
            list_child = mc.listRelatives(parent,ad=1,f=1)
            list_cp = [parent]
            if(list_child):
                list_cp += list(reversed(list_child))
            for j,chue_nod_kho in enumerate(list_cp):
                dic_chue_nod_kho[chue_nod_kho] = i_kho+j
            for chue_nod_kho in list_cp:
                if(mc.objExists(chue_nod_kho+'.namae')):
                    namae = mc.getAttr(chue_nod_kho+'.namae')
                else:
                    namae = u'骨%d'%i_kho
                kw = {'name':namae,'english_name':chue_nod_kho,'layer':0,'flag':2074}
                kho = pm.PyNode(chue_nod_kho)
                p = kho.getTranslation(space='world')
                kw['position'] = common.Vector3(p.x*khanat_ok,p.y*khanat_ok,-1*p.z*khanat_ok)
                try:
                    chue_parent = kho.getParent().fullPath()
                    parent_index = dic_chue_nod_kho[chue_parent]
                    kw['parent_index'] = parent_index
                except:
                    parent_index = 0
                    kw['parent_index'] = 0
                    kw['flag'] += 4 # ให้ขยับได้อิสระ
                child = kho.getChildren()
                if(len(child)==1):
                    kw['tail_index'] = dic_chue_nod_kho[child[0].fullPath()]
                    kw['flag'] += 1
                else:
                    kw['tail_index'] = -1
                
                
                jo = mc.getAttr(chue_nod_kho+'.jo')[0]
                mm = list_matrix_mun[parent_index]
                if(jo==(0,0,0)):
                    if(not mm):
                        kw['flag'] -= 2048
                    list_matrix_mun.append(mm)
                else:
                    mm *= 1
                    if(mm):
                        mm *= om.MEulerRotation(math.radians(jo[0]),math.radians(jo[1]),math.radians(jo[2])).asMatrix()
                    else:
                        mm = om.MEulerRotation(math.radians(jo[0]),math.radians(jo[1]),math.radians(jo[2])).asMatrix()
                    list_matrix_mun.append(mm)
                
                if(mm):
                    kw['local_x_vector'] = common.Vector3(mm(0,0),mm(0,1),-mm(0,2))
                    kw['local_z_vector'] = common.Vector3(mm(2,0),mm(2,1),-mm(2,2))
                    
                model_bon_ap(pmx.Bone(**kw))
                
                # ใส่ข้อต่อลงในแผงควบคุม ถ้าไม่ใช่ท่อนปลายสุด
                if(child):
                    model_slot_ap2((0,i_kho))
                i_kho += 1
    
    
    
    list_tamnaeng = []
    list_norm = []
    list_u = []
    list_v = []
    
    list_lek_tamnaeng_nai_na = []
    list_na_to_poly = []
    list_chut_to_poly = []
    
    lai_lek_tamnaeng = 0
    lai_lek_norm = 0
    lai_lek_uv = 0
    
    list_lek_chut_mai = []
    dic_str_chut = {}
    lai_lek = 0
    
    list_chue_nod_bs = mc.ls(typ='blendShape')
    
    i_poly = 0 # โพลิกอนอันที่เท่าไหร่
    for chue_nod_poly in list_chue_nod_poly:
        chue_nod_shep = list_chue_nod_shep[i_poly]
        try:
            nod_shep = pm.PyNode(chue_nod_shep)
        except pm.MayaNodeError:
            print(u'特殊なポリゴンが含まれる可能性があります。ポリゴンを結合しておいてください')
            raise # กรณีที่เป็นโพลิกอนที่สร้างมาจากวิธีที่เหนือความคาดหมายอาจมีข้อผิดพลาด แก้ได้โดยรวมโพลิกอนที่มีปัญหา
        
        if(chai_kraduk):
            chue_nod_skin = list_chue_nod_skin[i_poly]
            if(chue_nod_skin):
                dic_kho = {} # ดิกเชื่อมโยงเลขข้อสำหรับสกินนี้ กับเลขดัชนีของข้อต่อที่ลำดับตามดิกที่สร้างตอนแรก
                for i,chue_nod_kho in enumerate(mc.skinCluster(chue_nod_skin,q=1,inf=1)):
                    dic_kho[i] = dic_chue_nod_kho[pm.PyNode(chue_nod_kho).fullPath()]
                
                # โค้ดยาวๆก้อนนี้มีไว้เพื่อดึงข้อมูลน้ำหนักที่เชื่อมข้อต่อกับโพลิกอน
                nod_skin = pm.PyNode(chue_nod_skin)
                obj_skin = om.MObject()
                sl = om.MSelectionList()
                sl.add(nod_skin.name())
                sl.getDependNode(0,obj_skin)
                fn_skin = oma.MFnSkinCluster(obj_skin)
                path_mesh = om.MDagPath()
                sl = om.MSelectionList()
                sl.add(nod_shep.fullPath())
                sl.getDagPath(0,path_mesh)
                nod_shep.fullPath()
                path_inf = om.MDagPathArray()
                n_inf = fn_skin.influenceObjects(path_inf)
                util = om.MScriptUtil()
                util.createFromList(range(n_inf),n_inf)
                id_inf = om.MIntArray(util.asIntPtr(),n_inf)
                n_vert = nod_shep.numVertices()
                fn_comp = om.MFnSingleIndexedComponent()
                components = fn_comp.create(om.MFn.kMeshVertComponent)
                util = om.MScriptUtil()
                util.createFromList(range(n_vert),n_vert)
                id_vert = om.MIntArray(util.asIntPtr(),n_vert)
                fn_comp.addElements(id_vert)
                list_namnak = om.MDoubleArray() # ได้ข้อมูลน้ำหนักเป็นลิสต์ ยาว = จำนวนข้อ x จำนวนจุดยอด
                fn_skin.getWeights(path_mesh,components,id_inf,list_namnak)
                n_kho = len(dic_kho) # จำนวนข้อ
        
        if(chai_bs):
            w = [] # ลิสต์เก็บค่าน้ำหนักเดิมของเบลนด์เชปทั้งหมด
            # หาเบลนด์เชปคัดเอาเฉพาะที่เชื่อมกับโพลิกอนตัวนี้อยู่
            list_chue_nod_bs_ni = []
            for chue_nod_bs in list_chue_nod_bs:
                # ดูว่านี่เป็นโพลิกอนที่เชื่อมอยู่กับเบลนด์เชปอันนี้หรือเปล่า
                if(chue_nod_shep not in mc.blendShape(chue_nod_bs,q=1,g=1)):
                    continue
                try: # try เพื่อกันกรณีที่มีโหนดเบลนด์เชปอยู่แต่ไม่มีเบลนด์เชปอยู่เลย
                    ww = mc.getAttr(chue_nod_bs+'.w[*]') # เก็บค่าน้ำหนักปัจจุบันไว้
                except:
                    continue
                if(type(ww)==float):
                    ww = [ww] # เพื่อกันกรณีที่มีอยู่แค่ตัวเดียว จะได้ค่าไม่เป็นลิสต์ ต้องทำให้เป็นลิสต์เหมือนกันหมด
                w.append(ww)
                mc.setAttr(chue_nod_bs+'.w[*]',*[0]*len(ww)) # ตั้งน้ำหนักให้เป็น 0 ไว้ก่อน
                list_chue_nod_bs_ni.append(chue_nod_bs)
        
        # เก็บค่าตำแหน่งจุด
        tamnaeng = nod_shep.getPoints(space='world')
        list_tamnaeng.extend(tamnaeng)
        list_chut_to_na,vertid = nod_shep.getVertices()
        chut_to_poly = len(vertid)
        
        # เก็บค่าเส้นตั้งฉาก
        norm = nod_shep.getNormals(space='world')
        list_norm.extend(norm)
        normid = nod_shep.getNormalIds()[1]
        
        # เก็บค่า uv
        u,v = nod_shep.getUVs()
        list_u.extend(u)
        list_v.extend(v)
        uvid = nod_shep.getAssignedUVs()[1]
        
        list_samliam_to_na,list_lek_chut = nod_shep.getTriangles()
        list_lek_tamnaeng_nai_na_to_poly = []
        lai_samliam = 0
        
        # ดึงข้อมูลเบลนด์เชป
        list_chue_bs = []
        if(chai_bs):
            list_tamnaeng_bs = []
            list_luean_bs = []
            list_luean_bs_ap = []
            for i,chue_nod_bs in enumerate(list_chue_nod_bs_ni):
                # ถ้ามีข้อมูลชื่อญี่ปุ่นหรือช่องให้ดึงมา
                if(mc.objExists(chue_nod_bs+'.namae')):
                    try:
                        dic_namae = dict(namae.split(u'๑',1) for namae in mc.getAttr(chue_nod_bs+'.namae').split(u'๐'))
                    except:
                        dic_namae = {}
                else:
                    dic_namae = {}
                    
                lenw = len(w[i]) # จำนวนเบลนด์เชปในโหนดนั้นๆ
                for i,bs in enumerate(mc.listAttr(chue_nod_bs+'.w',m=1)):
                    # ตั้งให้น้ำหนักเป็น 1 แค่แบบเดียวทีละแบบ ที่เหลือเป็น 0 ไปก่อน
                    ww = [0]*lenw
                    ww[i] = 1
                    mc.setAttr(chue_nod_bs+'.w[*]',*ww)
                    # ดึงข้อมูลตำแหน่งที่เลื่อนแล่้ว
                    tamnaeng_bs = nod_shep.getPoints(space='world')
                    list_tamnaeng_bs.append(tamnaeng_bs)
                    if(bs in dic_namae):
                        namae = dic_namae[bs].split(u'๑')
                        try:
                            list_chue_bs.append((namae[0],bs,int(namae[1])))
                        except:
                            list_chue_bs.append((namae[0],bs,4))
                    # ถ้าไม่ได้มีชื่อที่ตั้งเก็บไว้ในโหนดแต่แรกก็ให้ใช้ทั้งชื่อญี่ปุ่นและชื่ออังกฤษเป็นชื่อเดียวกัน
                    else:
                        list_chue_bs.append((bs,bs,4))
                    luean_bs = []
                    list_luean_bs.append(luean_bs)
                    list_luean_bs_ap.append(luean_bs.append)
            # เปลี่ยนรูปร่างกลับคืนเดิมด้วย
            for i,chue_nod_bs in enumerate(list_chue_nod_bs_ni):
                mc.setAttr(chue_nod_bs+'.w[*]',*w[i])
        
        n_bs = len(list_chue_bs)
        list_lek_chut_mai_to_poly = []
        i = 0
        for samliam_to_na,chut_to_na in zip(list_samliam_to_na,list_chut_to_na):
            dic_lai_lek = {}
            
            for j in range(chut_to_na):
                lek_tamnaeng = vertid[i]
                lek_norm = normid[i]
                lek_uv = uvid[i]
                str_chut = '%d:%d:%d'%(lek_tamnaeng+lai_lek_tamnaeng,lek_norm+lai_lek_norm,lek_uv+lai_lek_uv)
                if(str_chut in dic_str_chut):
                    lek_chut_mai = dic_str_chut[str_chut]
                else:
                    lek_chut_mai = lai_lek
                    dic_str_chut[str_chut] = lek_chut_mai
                    
                    #ถ้ามีเชื่อมสกินอยู่ก็ดึงน้ำหนักมาใช้
                    if(chai_kraduk and chue_nod_skin):
                        w = [] # ลิสต์เก็บทูเพิลของ (ดัชนีข้อ,ค่าน้ำหนัก)
                        # ดึงข้อมูลน้ำหนักจากลิสต์น้ำหนัก ความยาวเท่ากับจำนวนข้อ
                        for i_namnak,namnak in enumerate(list_namnak[lek_tamnaeng*n_kho:(lek_tamnaeng+1)*n_kho]):
                            # คัดเฉพาะที่ไม่น้อยจนเกือบ 0 เท่านั้น
                            if(namnak>0.001):
                                w.append((dic_kho[i_namnak],namnak))
                        if(len(w)>3):
                            # ถ้ามากเกิน 4 ให้เรียงเอาอันที่มากก็พอ
                            if(len(w)>4):
                                w.sort(key=f_riang_namnak,reverse=1)
                                w = w[:4]
                            w_ruam = w[0][1]+w[1][1]+w[2][1]+w[3][1]
                            ww0 = w[0][1]/w_ruam
                            ww1 = w[1][1]/w_ruam
                            ww2 = w[2][1]/w_ruam
                            ww3 = w[3][1]/w_ruam
                            deform = pmx.Bdef4(w[0][0],w[1][0],w[2][0],w[3][0],ww0,ww1,ww2,ww3)
                        elif(len(w)==3):
                            w_ruam = w[0][1]+w[1][1]+w[2][1]
                            ww0 = w[0][1]/w_ruam
                            ww1 = w[1][1]/w_ruam
                            ww2 = w[2][1]/w_ruam
                            deform = pmx.Bdef4(w[0][0],w[1][0],w[2][0],-1,ww0,ww1,ww2,0.)
                        elif(len(w)==2):
                            ww0 = w[0][1]/(w[0][1]+w[1][1])
                            deform = pmx.Bdef2(w[0][0],w[1][0],ww0)
                        elif(len(w)==1):
                            deform = pmx.Bdef1(w[0][0])
                        else:
                            deform = pmx.Bdef1(0)
                    # ถ้าไม่ได้เชื่อมกับสกินก็ให้ตรึงกับข้อรากฐานให้หมด
                    else:
                        deform = pmx.Bdef1(0)
                    
                    p = list_tamnaeng[lek_tamnaeng+lai_lek_tamnaeng]
                    position = common.Vector3(p[0]*khanat_ok,p[1]*khanat_ok,-p[2]*khanat_ok)
                    nm = list_norm[lek_norm+lai_lek_norm]
                    normal = common.Vector3(nm[0],nm[1],-nm[2])
                    uv = common.Vector2(list_u[lek_uv+lai_lek_uv],1.-list_v[lek_uv+lai_lek_uv])
                    
                    # สร้างจุดจากข้อมูลที่ดึงมาได้ แล้วเพื่มเข้าไปในลิสต์ของจุด
                    vertex = pmx.Vertex(position,normal,uv,deform,edge_factor=1.)
                    model_vert_ap(vertex)
                    
                    for i_bs in range(n_bs):
                        p1 = list_tamnaeng_bs[i_bs][lek_tamnaeng]
                        po = common.Vector3((p1[0]-p[0])*khanat_ok,(p1[1]-p[1])*khanat_ok,(p[2]-p1[2])*khanat_ok)
                        # เอาข้อมูลเฉพาะจุดที่มีการเปลี่ยนตำแหน่ง
                        if(po.getNorm()>0):
                            list_luean_bs_ap[i_bs](pmx.VertexMorphOffset(lai_lek,po))
                    lai_lek += 1
                
                dic_lai_lek[lek_tamnaeng+lai_lek_tamnaeng] = lek_chut_mai
                i += 1
                
            
            ll = []
            for j in range(lai_samliam*3,(lai_samliam+samliam_to_na)*3,3):
                for jj in range(3):
                    lek_tamnaeng = list_lek_chut[j+2-jj]
                    lek_chut_mai = dic_lai_lek[lek_tamnaeng+lai_lek_tamnaeng]
                    ll.append(lek_chut_mai)
            lai_samliam += samliam_to_na
            list_lek_chut_mai_to_poly.append(ll)
        
        # สร้างมอร์ฟทั้งหมดจากข้อมูลเบลนด์เชปที่เตรียมไว้
        if(chai_bs):
            for i_mor,(chue_bs,luean_bs) in enumerate(zip(list_chue_bs,list_luean_bs)):
                model_mor_ap(pmx.Morph(name=chue_bs[0],english_name=chue_bs[1],panel=chue_bs[2],morph_type=1,offsets=luean_bs))
                model_slot_ap1((1,i_mor))
            
        list_na_to_poly.append(vertid)
        list_chut_to_poly.append(chut_to_poly)
        lai_lek_tamnaeng += len(tamnaeng)
        lai_lek_norm += len(norm)
        lai_lek_uv += len(u)
        list_lek_tamnaeng_nai_na.append(list_lek_tamnaeng_nai_na_to_poly)
        list_lek_chut_mai.append(list_lek_chut_mai_to_poly)
        i_poly += 1
        
    
    
    # ถ้าเลือกจะสร้างวัสดุด้วยก็สร้างแล้วเรียงจุดในหน้าตามวัสดุ
    if(chai_watsadu):
        list_chue_nod_mat = [] # ลิสต์เก็บโหนดวัสดุ
        list_chue_nod_sg = [] # ลิสต์เก็บโหนด sg
        i_tex = 0 # ดัชนีเท็กซ์เจอร์
        i_mat = 0 # ดัชนีวัสดุ
        for mat in mc.ls(mat=1):
            # เอาเฉพาะวัสดุที่มี sg เท่านั้น
            try:
                liscon = mc.listConnections(mat+'.outColor')
                sg = liscon[0]
                list_na = mc.sets(sg,q=1) # ดูว่ามีหน้าไหนที่ใช้วัสดุนี้
                if(not list_na):
                    if(len(liscon)>1):
                        sg = liscon[1]
                        list_na = mc.sets(sg,q=1)
                    # หากไม่ถูกใช้อยู่ก็ข้าม
                    if(not list_na):
                        continue
            except:
                continue
            
            n_chut_to_mat = 0 # จำนวนจุดของหน้านี้ (= 3 เท่าของจำนวนหน้า)
            for na in list_na:
                if('[' in na):
                    chue_nod_poly,na0,na1 = re.findall(r'(\w+).f\[(\d+):?(\d+)?]',na)[0]
                    na0 = int(na0)
                    if(na1==''):
                        na1 = na0
                    else:
                        na1 = int(na1)
                else:
                    chue_nod_poly = mc.listRelatives(na,p=1)[0]
                    na0 = 0
                    na1 = mc.polyEvaluate(chue_nod_poly,f=1)-1
                
                # ถ้าอยู่ในลิสต์ของโพลิกอนที่เลือกอยู่ให้หาเลขดัชนีของโพลิกอนนั้นในลิสต์
                if(chue_nod_poly in list_chue_nod_poly):
                    lek_nod_poly = list_chue_nod_poly.index(chue_nod_poly)
                # ถ้าไม่อยู่ในลิสต์ก็ข้ามไปเลย
                else:
                    continue
                
                for lai_na in range(na0,na1+1):
                    for lek in list_lek_chut_mai[lek_nod_poly][lai_na]:
                        model_ind_ap(lek)
                        n_chut_to_mat += 1
            
            # ถ้าวัสดุนี้ไม่ถูกใช้ในโพลิกอนที่เลือกอยู่เลยก็ข้าม
            if(n_chut_to_mat==0):
                continue
            if(mc.objExists(mat+'.namae')):
                namae = mc.getAttr(mat+'.namae')
            else:
                namae = u'材質%d'%(i_mat+1)
            # ค่าองค์ประกอบต่างๆของวัสดุ เก็บไว้ในดิกก่อน
            
            kw = {'name':namae,'english_name':mat,
                'diffuse_color':common.RGB(1,1,1),'alpha':1,
                'specular_factor':0.5,'specular_color':common.RGB(0.,0.,0.),
                'ambient_color':common.RGB(0.5,0.5,0.5),
                'flag':1,'edge_color':common.RGBA(0.,0.,0.,1.),'edge_size':1,
                'texture_index':-1,'sphere_texture_index':-1,'sphere_mode':0,
                'toon_sharing_flag':0,'toon_texture_index':-1,'vertex_count':n_chut_to_mat}
            # ใส่ try กันกรณีที่เป็นวัสดุชนิดแปลกๆที่ไม่สามารถอ่านค่าได้ปกติ
            try:
                nodetype = mc.nodeType(mat) # ชนิดของวัสดุ
                # หาดูว่าวัสดุนี้ใช้เท็กซ์เจอร์หรือไม่
                if(nodetype!='aiStandardSurface'):
                    chue_nod_tex = mc.listConnections(mat+'.color')
                else:
                    chue_nod_tex = mc.listConnections(mat+'.baseColor')
                # ถ้ามีเท็กซ์เจอร์ และเป็นไฟล์
                if(chue_nod_tex):
                    if(mc.nodeType(chue_nod_tex[0])=='file'):
                        chue_tem_file_tex = mc.getAttr(chue_nod_tex[0]+'.ftn') # ชื่อไฟล์
                        # ถ้ามีชื่อไฟล์นี้อยู่แล้ว
                        if(chue_tem_file_tex in model.textures):
                            kw['texture_index'] = model.textures.index(chue_tem_file_tex)
                        # ถ้ายังไม่มีก็เพิ่มเข้าไป
                        else:
                            chue_tex = os.path.basename(chue_tem_file_tex)
                            model.textures.append(chue_tex)
                            # ถ้าเลือกว่าจะคัดลอกไฟล์เท็กซ์เจอร์ก็ทำการคัดลอก
                            if(lok_tex):
                                shutil.copyfile(chue_tem_file_tex,os.path.join(chue_path_file,chue_tex))
                            kw['texture_index'] = i_tex
                            i_tex += 1 # นับไล่ดัชนีเท็กซ์เจอร์ต่อ
                    else:
                        print(u'テクスチャ%sはファイルではないため使えません'%chue_nod_tex[0])
                    dc = [1.,1.,1.]
                # ถ้าไม่ใช้เท็กซ์เจอร์ไฟล์จึงกำหนดสีผิว
                else:
                    if(nodetype!='aiStandardSurface'):
                        dc = mc.getAttr(mat+'.color')[0]
                    else:
                        dc = mc.getAttr(mat+'.baseColor')[0]
                    dc = [min(max(s,0.),1.) for s in dc]
                    kw['diffuse_color'] = common.RGB(*dc)
                
                if(nodetype not in ['aiStandard','aiStandardSurface']):
                    tran = sum(mc.getAttr(mat+'.transparency')[0])/3 # ความโปร่งใสใช้เป็นค่าเฉลี่ย
                    kw['alpha'] = min(max(1-tran,0),1.)
                    # ค่าสีแอมเบียนต์ให้คูณสีผิวไปด้วย
                    ac = [min(max(s,0.),1.)*d for s,d in zip(mc.getAttr(mat+'.ambientColor')[0],dc)]
                    kw['ambient_color'] = common.RGB(*ac)
                    # เฉพาะ blinn เท่านั้นจึงเก็บค่าสเป็กคิวลาร์ นอกนั้นใช้ค่าตั้งต้น
                    if(nodetype=='blinn'):
                        sr = min(max(mc.getAttr(mat+'.specularRollOff'),0.1),1.)
                        kw['specular_factor'] = round(math.pow(2,math.log(sr,0.75)-1))
                        kw['specular_color'] = common.RGB(*[min(max(s,0.),1.) for s in mc.getAttr(mat+'.specularColor')[0]])
                # กรณี aiStandard
                else:
                    opa = sum(mc.getAttr(mat+'.opacity')[0])/3 # ความทึบแสงใช้เป็นค่าเฉลี่ย
                    kw['alpha'] = min(max(opa,0.),1.)
                    if(nodetype!='aiStandardSurface'):
                        kw['specular_color'] = common.RGB(*[min(max(s,0.),1.) for s in mc.getAttr(mat+'.KsColor')[0]])
                    else:
                        kw['specular_color'] = common.RGB(*[min(max(s,0.),1.) for s in mc.getAttr(mat+'.specularColor')[0]])
                    sr = max(mc.getAttr(mat+'.specularRoughness'),0.1)
                    kw['specular_factor'] = round(math.pow(2,math.log(sr,0.75)-1))
                    kw['ambient_color'] = common.RGB(0,0,0)
            except:
                print(u'材質%sに問題が見つかりました'%mat)
            
            model_mat_ap(pmx.Material(**kw)) # เพิ่มวัสดุเข้าไปในโมเดล
            
            list_chue_nod_mat.append(mat)
            list_chue_nod_sg.append(sg)
            i_mat += 1
        
        if(mod_sph):
            i = len(model.textures)
            model.textures.append(tex_sph)
            for mat in model.materials:
                mat.sphere_mode = mod_sph
                mat.sphere_texture_index = i
            
    # ถ้าเลือกไม่เอาวัสดุก็ให้ใช้เป็นวัสดุตั้งต้นแบบเดียวกันหมด
    else:
        n_chut_to_mat = 0
        for list_lek_chut_nai_poly in list_lek_chut_mai:
            for list_lek_chut_nai_na in list_lek_chut_nai_poly:
                n_chut_to_mat += len(list_lek_chut_nai_na)
                for lek_chut in list_lek_chut_nai_na:
                    model_ind_ap(lek_chut)
        
        model_mat_ap(pmx.Material(name=u'材質1',english_name='',
                diffuse_color=common.RGB(0.5,0.5,0.5),alpha=1,
                specular_factor=0.5,specular_color=common.RGB(0.5,0.5,0.5),
                ambient_color=common.RGB(0.25,0.25,0.25),
                flag=1,edge_color=common.RGBA(0.,0.,0.,1.),edge_size=1,
                texture_index=-1,sphere_texture_index=-1,sphere_mode=0,
                toon_sharing_flag=0,toon_texture_index=-1,vertex_count=n_chut_to_mat))
    
    chue_model = os.path.basename(chue_tem_file).split('.')[0]
    model.name = chue_model
    model.english_name = chue_model
    if(not model.display_slots[2].references):
        model.display_slots.pop()
    
    with io.open(chue_tem_file,'wb') as s:
        pmxwri(s,model)
    mc.select(list_chue_nod_poly)
    
    print(u'ファイル%s作成完了。%.2f秒かかりました'%(chue_tem_file,time.time()-t0))