def _set_subdivision_levels(prop, value):
        cloth_mesh_object: bpy.types.Object = prop.id_data
        cloth_modifier: bpy.types.ClothModifier = MeshEditor(
            prop.id_data).find_subsurface_modifier(
                name='mmd_uuunyaa_physics_cloth_subsurface')
        cloth_modifier.levels = value
        cloth_modifier.render_levels = value

        for obj in bpy.data.objects:
            if obj.type != 'MESH':
                continue

            for modifier in obj.modifiers:
                if modifier.type != 'SURFACE_DEFORM':
                    continue

                if modifier.target != cloth_mesh_object:
                    continue

                # bind/unbind -> unbind/bind
                # pylint: disable=redundant-keyword-arg
                bpy.ops.object.surfacedeform_bind({'object': obj},
                                                  modifier=modifier.name)
                bpy.ops.object.surfacedeform_bind({'object': obj},
                                                  modifier=modifier.name)
                return
 def mmd_model_cloths_method(self):
     for obj in self.allObjects(self.clothGroupObject()):
         if obj.type != 'MESH':
             continue
         if MeshEditor(obj).find_cloth_modifier() is None:
             continue
         yield obj
    def poll(cls, context: bpy.types.Context):
        if context.mode != 'OBJECT':
            return False

        active_object = context.active_object
        if active_object is None:
            return False

        if active_object.type != 'MESH':
            return False

        return MeshEditor(active_object).find_cloth_modifier() is not None
    def execute(self, context: bpy.types.Context):
        try:
            for obj in context.selected_objects:
                if obj.type != 'MESH':
                    continue

                MeshEditor(obj).remove_cloth_modifier()

        except MessageException as ex:
            self.report(type={'ERROR'}, message=str(ex))
            return {'CANCELLED'}

        return {'FINISHED'}
Exemple #5
0
    def execute(self, context: bpy.types.Context):
        from_object = context.active_object
        from_settings = from_object.mmd_uuunyaa_tools_collision_settings
        from_modifier = MeshEditor(from_object).get_collision_modifier()

        for to_object in context.selected_objects:
            if to_object.type != 'MESH':
                continue

            if from_object == to_object:
                continue

            MeshEditor(to_object).get_collision_modifier(from_modifier.name)

            to_settings = to_object.mmd_uuunyaa_tools_collision_settings
            to_settings.presets = from_settings.presets
            to_settings.damping = from_settings.damping
            to_settings.thickness_outer = from_settings.thickness_outer
            to_settings.thickness_inner = from_settings.thickness_inner
            to_settings.cloth_friction = from_settings.cloth_friction

        return {'FINISHED'}
    def execute(self, context: bpy.types.Context):
        from_object = context.active_object
        from_settings = from_object.mmd_uuunyaa_tools_cloth_settings
        from_modifier = MeshEditor(from_object).get_cloth_modifier()

        for to_object in context.selected_objects:
            if to_object.type != 'MESH':
                continue

            if from_object == to_object:
                continue

            MeshEditor(to_object).get_cloth_modifier(from_modifier.name)

            to_settings = to_object.mmd_uuunyaa_tools_cloth_settings
            to_settings.presets = from_settings.presets
            to_settings.mass = from_settings.mass
            to_settings.stiffness = from_settings.stiffness
            to_settings.damping = from_settings.damping
            to_settings.collision_quality = from_settings.collision_quality
            to_settings.distance_min = from_settings.distance_min
            to_settings.impulse_clamp = from_settings.impulse_clamp

        return {'FINISHED'}
Exemple #7
0
    def execute(self, context: bpy.types.Context):
        key_object = context.active_object
        key_settings = key_object.mmd_uuunyaa_tools_collision_settings

        obj: bpy.types.Object
        for obj in self.filter_only_in_mmd_model(
                key_object) if self.same_mmd_model else bpy.data.objects:
            if obj.type != 'MESH':
                continue

            if MeshEditor(obj).find_collision_modifier() is None:
                continue

            if self.same_physics_settings and not key_settings.physics_equals(
                    obj.mmd_uuunyaa_tools_collision_settings):
                continue

            obj.select_set(True)

        return {'FINISHED'}
    def execute(self, context: bpy.types.Context):
        key_object = context.active_object
        key_rigid_body_object = key_object.find_rigid_body_object()

        obj: bpy.types.Object
        for obj in self.filter_only_in_mmd_model(
                key_object) if self.only_in_mmd_model else bpy.data.objects:
            if obj.type != 'MESH':
                continue

            rigid_body_object = MeshEditor(obj).find_rigid_body_object()
            if rigid_body_object is None:
                continue

            if self.only_same_settings and rigid_body_object != key_rigid_body_object:
                continue

            obj.select_set(True)

        return {'FINISHED'}
    def draw(self, context: bpy.types.Context):
        layout = self.layout
        mesh_object: bpy.types.Object = context.active_object
        cloth_settings = mesh_object.mmd_uuunyaa_tools_cloth_settings

        box = layout.box()
        col = box.column()
        col.prop(cloth_settings, 'presets')
        col.prop(cloth_settings, 'mass')
        col.prop(cloth_settings, 'stiffness')
        col.prop(cloth_settings, 'damping')

        col = box.column()
        col.label(text=_('Collision:'))
        col.prop(cloth_settings, 'collision_quality')
        col.prop(cloth_settings, 'distance_min', slider=True)
        col.prop(cloth_settings, 'impulse_clamp')

        col = box.column()
        col.label(text=_('Batch Operation:'))
        col.operator(CopyClothAdjusterSettings.bl_idname,
                     text=_('Copy to Selected'),
                     icon='DUPLICATE')

        col = layout.column(align=True)
        col.label(text=_('Cache:'))
        row = col.row(align=True)
        row.prop(cloth_settings, 'frame_start', text=_('Simulation Start'))
        row.prop(cloth_settings, 'frame_end', text=_('Simulation End'))

        if MeshEditor(mesh_object).find_subsurface_modifier(
                'mmd_uuunyaa_physics_cloth_subsurface') is None:
            return

        col = layout.column(align=True)
        col.label(text=_('Subdivision:'))
        col.prop(cloth_settings,
                 'subdivision_levels',
                 text=_('Subdivision Levels'))
 def _set_damping(prop, value):
     cloth_settings: bpy.types.ClothSettings = MeshEditor(
         prop.id_data).find_cloth_settings()
     cloth_settings.tension_damping = value
     cloth_settings.compression_damping = value
     cloth_settings.shear_damping = value
class ClothAdjusterSettingsPropertyGroup(bpy.types.PropertyGroup):
    @staticmethod
    def _update_presets(prop, _):
        TUNERS[prop.presets](prop.id_data).execute()

    presets: bpy.props.EnumProperty(name=_('Presets'),
                                    items=TUNERS.to_enum_property_items(),
                                    update=_update_presets.__func__,
                                    default=None)

    mass: bpy.props.FloatProperty(
        name=_('Vertex Mass'),
        min=0,
        soft_max=10,
        step=10,
        unit='MASS',
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_cloth_settings(), 'mass', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_cloth_settings(), 'mass', v),
    )

    @staticmethod
    def _set_stiffness(prop, value):
        cloth_settings: bpy.types.ClothSettings = MeshEditor(
            prop.id_data).find_cloth_settings()
        cloth_settings.tension_stiffness = value
        cloth_settings.compression_stiffness = value
        cloth_settings.shear_stiffness = value

    stiffness: bpy.props.FloatProperty(
        name=_('Stiffness'),
        min=0,
        soft_max=50,
        max=10000,
        precision=3,
        step=10,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_cloth_settings(), 'tension_stiffness', 0
        ),
        set=_set_stiffness.__func__,
    )

    @staticmethod
    def _set_damping(prop, value):
        cloth_settings: bpy.types.ClothSettings = MeshEditor(
            prop.id_data).find_cloth_settings()
        cloth_settings.tension_damping = value
        cloth_settings.compression_damping = value
        cloth_settings.shear_damping = value

    damping: bpy.props.FloatProperty(
        name=_('Damping'),
        min=0,
        max=50,
        precision=3,
        step=10,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_cloth_settings(), 'tension_damping', 0),
        set=_set_damping.__func__,
    )

    collision_quality: bpy.props.IntProperty(
        name=_('Collision Quality'),
        min=1,
        max=20,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_cloth_collision_settings(),
            'collision_quality', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_cloth_collision_settings(),
            'collision_quality', v),
    )

    distance_min: bpy.props.FloatProperty(
        name=_('Minimum Distance'),
        min=0.001,
        max=1.000,
        step=10,
        unit='LENGTH',
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_cloth_collision_settings(),
            'distance_min', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_cloth_collision_settings(),
            'distance_min', v),
    )

    impulse_clamp: bpy.props.FloatProperty(
        name=_('Impulse Clamping'),
        min=0,
        max=100,
        precision=3,
        step=10,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_cloth_collision_settings(),
            'impulse_clamp', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_cloth_collision_settings(),
            'impulse_clamp', v),
    )

    frame_start: bpy.props.IntProperty(
        name=_('Simulation Start'),
        min=0,
        max=1048574,
        get=lambda p: getattr(
            getattr(
                MeshEditor(p.id_data).find_cloth_modifier(), 'point_cache',
                None), 'frame_start', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_cloth_modifier().point_cache,
            'frame_start', v),
    )

    frame_end: bpy.props.IntProperty(
        name=_('Simulation End'),
        min=1,
        max=1048574,
        get=lambda p: getattr(
            getattr(
                MeshEditor(p.id_data).find_cloth_modifier(), 'point_cache',
                None), 'frame_end', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_cloth_modifier().point_cache,
            'frame_end', v),
    )

    @staticmethod
    def _set_subdivision_levels(prop, value):
        cloth_mesh_object: bpy.types.Object = prop.id_data
        cloth_modifier: bpy.types.ClothModifier = MeshEditor(
            prop.id_data).find_subsurface_modifier(
                name='mmd_uuunyaa_physics_cloth_subsurface')
        cloth_modifier.levels = value
        cloth_modifier.render_levels = value

        for obj in bpy.data.objects:
            if obj.type != 'MESH':
                continue

            for modifier in obj.modifiers:
                if modifier.type != 'SURFACE_DEFORM':
                    continue

                if modifier.target != cloth_mesh_object:
                    continue

                # bind/unbind -> unbind/bind
                # pylint: disable=redundant-keyword-arg
                bpy.ops.object.surfacedeform_bind({'object': obj},
                                                  modifier=modifier.name)
                bpy.ops.object.surfacedeform_bind({'object': obj},
                                                  modifier=modifier.name)
                return

    subdivision_levels: bpy.props.IntProperty(
        name=_('Subdivision Levels'),
        min=0,
        soft_max=2,
        max=6,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_subsurface_modifier(
                name='mmd_uuunyaa_physics_cloth_subsurface'), 'levels', 0),
        set=_set_subdivision_levels.__func__,
    )

    def physics_equals(self, obj):
        return (isinstance(obj, ClothAdjusterSettingsPropertyGroup)
                and self.presets == obj.presets and self.mass == obj.mass
                and self.stiffness == obj.stiffness
                and self.damping == obj.damping
                and self.collision_quality == obj.collision_quality
                and self.distance_min == obj.distance_min
                and self.impulse_clamp == obj.impulse_clamp)

    def cache_equals(self, obj):
        return (isinstance(obj, ClothAdjusterSettingsPropertyGroup)
                and self.frame_start == obj.frame_start
                and self.frame_end == obj.frame_end)

    @staticmethod
    def register():
        # pylint: disable=assignment-from-no-return
        bpy.types.Object.mmd_uuunyaa_tools_cloth_settings = bpy.props.PointerProperty(
            type=ClothAdjusterSettingsPropertyGroup)

    @staticmethod
    def unregister():
        del bpy.types.Object.mmd_uuunyaa_tools_cloth_settings
 def poll(cls, context: bpy.types.Context):
     return MeshEditor(
         context.active_object).find_cloth_modifier() is not None
Exemple #13
0
class CollisionAdjusterSettingsPropertyGroup(bpy.types.PropertyGroup):
    @staticmethod
    def _update_presets(prop, _):
        TUNERS[prop.presets](prop.id_data).execute()

    presets: bpy.props.EnumProperty(name=_('Presets'),
                                    items=TUNERS.to_enum_property_items(),
                                    update=_update_presets.__func__,
                                    default=None)

    damping: bpy.props.FloatProperty(
        name=_('Damping'),
        min=0.000,
        max=1.000,
        precision=3,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_collision_settings(), 'damping', 0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_collision_settings(), 'damping', v),
    )

    thickness_outer: bpy.props.FloatProperty(
        name=_('Thickness Outer'),
        min=0.001,
        max=1.000,
        precision=3,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_collision_settings(), 'thickness_outer',
            0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_collision_settings(), 'thickness_outer',
            v),
    )

    thickness_inner: bpy.props.FloatProperty(
        name=_('Thickness Inner'),
        min=0.001,
        max=1.000,
        precision=3,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_collision_settings(), 'thickness_inner',
            0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_collision_settings(), 'thickness_inner',
            v),
    )

    cloth_friction: bpy.props.FloatProperty(
        name=_('Cloth Friction'),
        min=0.000,
        max=80.000,
        step=10,
        precision=3,
        get=lambda p: getattr(
            MeshEditor(p.id_data).find_collision_settings(), 'cloth_friction',
            0),
        set=lambda p, v: setattr(
            MeshEditor(p.id_data).find_collision_settings(), 'cloth_friction',
            v),
    )

    def physics_equals(self, obj):
        return (isinstance(obj, CollisionAdjusterSettingsPropertyGroup)
                and self.presets == obj.presets and self.damping == obj.damping
                and self.thickness_outer == obj.thickness_outer
                and self.thickness_inner == obj.thickness_inner
                and self.cloth_friction == obj.cloth_friction)

    @staticmethod
    def register():
        # pylint: disable=assignment-from-no-return
        bpy.types.Object.mmd_uuunyaa_tools_collision_settings = bpy.props.PointerProperty(
            type=CollisionAdjusterSettingsPropertyGroup)

    @staticmethod
    def unregister():
        del bpy.types.Object.mmd_uuunyaa_tools_collision_settings
Exemple #14
0
def assign_deform_weights(pyramid_armature_object: bpy.types.Object, deform_mesh_object: bpy.types.Object, target_bone_name: str, boundary_expansion_hop_count: int):
    mesh_editor = MeshEditor(deform_mesh_object)
    deform_bmesh: bmesh.types.BMesh = bmesh.new()

    start_time = datetime.datetime.now()

    print(f'assign deform weights:begin: {target_bone_name}')

    # pylint: disable=no-member
    depsgraph: bpy.types.Depsgraph = bpy.context.evaluated_depsgraph_get()
    deform_bmesh.from_object(mesh_editor.mesh_object, depsgraph)
    deform_bmesh.transform(deform_mesh_object.matrix_world)

    vid2weight = expand_boundary(
        to_vid2weight(deform_bmesh, mesh_editor.get_vertex_group(target_bone_name).index),
        deform_bmesh, boundary_expansion_hop_count
    )
    deform_bmesh_verts = deform_bmesh.verts

    print(f'assign deform weights:build_adjacencies: vid_count={len(vid2weight)}, {datetime.datetime.now() - start_time}')

    adjacencies, vid2uid = build_adjacencies(deform_bmesh_verts, vid2weight)

    # unified vertex id to numpy id
    uid2nid: Dict[int, int] = {uid: nid for nid, uid in enumerate(set(vid2uid.values()))}
    uid2vids: Dict[int, List[int]] = {uid: [vid for vid in vid2uid if vid2uid[vid] == uid] for uid in vid2uid.values()}
    nid2uid: Dict[int, int] = {v: k for k, v in uid2nid.items()}

    sink_nids: Set[int] = set()

    for index, weight in vid2weight.items():
        if weight > 0:
            continue
        sink_nids.add(uid2nid[vid2uid[index]])

    nid_count = len(uid2nid)

    adjacency_matrix = np.zeros((nid_count, nid_count))
    for (from_uid, to_uid), span in adjacencies.items():
        magnitude = math.exp(-span)
        adjacency_matrix[uid2nid[from_uid], uid2nid[to_uid]] = magnitude
        adjacency_matrix[uid2nid[to_uid], uid2nid[from_uid]] = magnitude

    deform_bmesh_verts.ensure_lookup_table()
    vertex_kdtree = mathutils.kdtree.KDTree(nid_count)
    for uid in uid2nid:
        if vid2weight[uid] == 0:
            continue
        vertex_kdtree.insert(deform_bmesh_verts[uid].co, uid)
    vertex_kdtree.balance()

    def collect_nid2weight(position: Vector, scale: float):
        max_weight: Union[float, None] = None
        nid2weight: Dict[int, float] = {}
        for _co, near_uid, near_span in vertex_kdtree.find_n(position, 16):
            weight = math.exp(-near_span/scale)

            if max_weight is None:
                max_weight = weight
                weight = 1
            else:
                weight = weight / max_weight

            nid2weight[uid2nid[near_uid]] = weight

            if weight < 0.4:
                break

        return nid2weight

    bone_names = PyramidBoneNames(target_bone_name)

    pyramid_armature: bpy.types.Armature = pyramid_armature_object.data
    pyramid_origin = pyramid_armature_object.location
    bone_length = pyramid_armature.bones[bone_names.apex].length

    bone_name2nid2weight: Dict[str, Dict[int, float]] = {
        bone_names.apex: collect_nid2weight(pyramid_armature.bones[bone_names.apex].tail_local + pyramid_origin, bone_length),
        bone_names.base_a: collect_nid2weight(pyramid_armature.bones[bone_names.base_a].head_local + pyramid_origin, bone_length),
        bone_names.base_b: collect_nid2weight(pyramid_armature.bones[bone_names.base_b].head_local + pyramid_origin, bone_length),
        bone_names.base_c: collect_nid2weight(pyramid_armature.bones[bone_names.base_c].head_local + pyramid_origin, bone_length),
        bone_names.base_d: collect_nid2weight(pyramid_armature.bones[bone_names.base_d].head_local + pyramid_origin, bone_length),
    }

    print(f'assign deform weights:auto_weight: nid_count={nid_count}, {datetime.datetime.now() - start_time}')

    laplacian_matrix = np.diag(np.sum(adjacency_matrix, axis=1))
    laplacian_matrix -= adjacency_matrix
    eigen_values, eigen_vector = np.linalg.eigh(laplacian_matrix)
    diffusion = np.exp(-eigen_values*2)

    for bone_name in bone_name2nid2weight:
        nid2weight = {
            nid: (weight * 10 if b == bone_name else -weight)
            for b, n2w in bone_name2nid2weight.items()
            for nid, weight in n2w.items()
        }

        print(f'assign deform weights:auto_weight: {bone_name}, {datetime.datetime.now() - start_time}')

        weights = np.zeros(nid_count)
        for _iteration in range(min(60, nid_count//2)):
            for nid, weight in nid2weight.items():
                if weight > 0:
                    weights[nid] += weight
                else:
                    weights[nid] = 0

            weights = eigen_vector.T @ weights
            weights *= diffusion
            weights = eigen_vector @ weights

            for nid in sink_nids:
                weights[nid] = 0

        # normalize
        weights[weights < 0] = 0
        weights = weights / np.max(weights)

        mesh_editor.edit_vertex_group(bone_name, [
            (uid2vids[nid2uid[nid]], weights[nid].item() * vid2weight[nid2uid[nid]]) for nid in range(nid_count)
        ])

    deform_bmesh.free()
    print(f'assign deform weights:finish: {datetime.datetime.now() - start_time}')
Exemple #15
0
    def convert(cls, mmd_root_object: bpy.types.Object,
                rigid_body_objects: List[bpy.types.Object],
                mesh_objects: List[bpy.types.Object], subdivision_level: int,
                ribbon_stiffness: float, physics_mode: PhysicsMode,
                extend_ribbon_area: bool):  # pylint: disable=too-many-arguments
        # pylint: disable=too-many-locals, too-many-statements
        mmd_model = import_mmd_tools().core.model.Model(mmd_root_object)
        mmd_mesh_object = mesh_objects[0]
        mmd_armature_object = mmd_model.armature()

        rigid_bodys_count = len(rigid_body_objects)
        rigid_body_index_dict = {
            rigid_body_objects[i]: i
            for i in range(rigid_bodys_count)
        }

        pose_bones: List[bpy.types.PoseBone] = []
        for rigid_body_object in rigid_body_objects:
            pose_bone = mmd_armature_object.pose.bones.get(
                rigid_body_object.mmd_rigid.bone)

            if pose_bone is None:
                raise MessageException(
                    iface_(
                        'No bones related with {rigid_body_name}, Please relate a bone to the Rigid Body.'
                    ).format(rigid_body_name=rigid_body_object.name))

            pose_bones.append(pose_bone)

        def remove_objects(objects: Iterable[bpy.types.Object]):
            for obj in objects:
                bpy.data.objects.remove(obj)

        joint_objects, joint_edge_indices, side_joint_objects = cls.collect_joints(
            mmd_model, rigid_body_index_dict)

        remove_objects(joint_objects)

        cloth_mesh = bpy.data.meshes.new('physics_cloth')
        cloth_mesh.from_pydata([r.location for r in rigid_body_objects],
                               joint_edge_indices, [])
        cloth_mesh.validate()

        cloth_mesh_object = bpy.data.objects.new('physics_cloth', cloth_mesh)
        cloth_mesh_object.parent = mmd_model.clothGroupObject()
        cloth_mesh_object.hide_render = True
        cloth_mesh_object.display_type = 'WIRE'

        # 标记出特殊边和点
        # These are special edge and vertex
        cloth_bm: bmesh.types.BMesh = bmesh.new()
        cloth_bm.from_mesh(cloth_mesh)

        cls.clean_mesh(cloth_bm, joint_edge_indices)

        # 标出头部,尾部,飘带顶点
        # try mark head,tail,ribbon vertex
        cloth_bm.verts.ensure_lookup_table()
        cloth_bm.edges.ensure_lookup_table()

        vertices = cls.collect_vertices(cloth_bm, pose_bones, physics_mode,
                                        extend_ribbon_area)
        edges = cls.collect_edges(cloth_bm, vertices)

        new_up_verts = cls.extend_up_edges(cloth_bm, pose_bones, vertices,
                                           edges, physics_mode)
        new_down_verts = cls.extend_down_edges(cloth_bm, pose_bones, vertices,
                                               edges)

        cls.fill_faces(cloth_bm, edges.up_edges, new_up_verts)
        cls.fill_faces(cloth_bm, edges.down_edges, new_down_verts)

        cloth_bm.verts.index_update()
        cloth_bm.faces.ensure_lookup_table()

        new_side_verts = cls.extend_side_vertices(cloth_bm, vertices, edges)
        cls.fill_faces(cloth_bm, edges.side_edges, new_side_verts)

        new_ribbon_verts = cls.extend_ribbon_vertices(cloth_bm)
        cls.fill_faces(cloth_bm, [e for e in cloth_bm.edges if e.is_wire],
                       new_ribbon_verts)

        cls.normals_make_consistent(cloth_bm)
        cloth_bm.verts.ensure_lookup_table()
        cloth_bm.edges.ensure_lookup_table()
        cloth_bm.to_mesh(cloth_mesh)

        pin_vertex_group = cls.new_pin_vertex_group(cloth_mesh_object,
                                                    side_joint_objects,
                                                    new_up_verts,
                                                    new_side_verts,
                                                    rigid_body_index_dict)

        remove_objects(side_joint_objects)

        deform_vertex_group: bpy.types.VertexGroup = mmd_mesh_object.vertex_groups.new(
            name='physics_cloth_deform')

        mesh_editor = MeshEditor(cloth_mesh_object)
        mesh_editor.link_to_active_collection()
        mesh_editor.add_subsurface_modifier('physics_cloth_subsurface',
                                            subdivision_level,
                                            subdivision_level)
        mesh_editor.add_armature_modifier('physics_cloth_armature',
                                          mmd_armature_object,
                                          vertex_group=pin_vertex_group.name)
        mesh_editor.edit_cloth_modifier(
            'physics_cloth', vertex_group_mass=pin_vertex_group.name)

        corrective_smooth_modifier = mesh_editor.add_corrective_smooth_modifier(
            'physics_cloth_smooth',
            smooth_type='LENGTH_WEIGHTED',
            rest_source='BIND')
        bpy.ops.object.correctivesmooth_bind(
            modifier=corrective_smooth_modifier.name)
        if subdivision_level == 0:
            corrective_smooth_modifier.show_viewport = False

        deform_vertex_group_index = deform_vertex_group.index
        vertices_ribbon_verts = vertices.ribbon_verts

        cls.bind_mmd_mesh(mmd_mesh_object, cloth_mesh_object, cloth_bm,
                          pose_bones, deform_vertex_group_index,
                          vertices_ribbon_verts, physics_mode)
        cls.set_pin_vertex_weight(pin_vertex_group, vertices_ribbon_verts,
                                  ribbon_stiffness, physics_mode)

        remove_objects(rigid_body_objects)

        if not vertices.all_ribbon and physics_mode in {
                PhysicsMode.AUTO, PhysicsMode.SURFACE_DEFORM
        }:
            bpy.context.view_layer.objects.active = mmd_mesh_object
            bpy.ops.object.surfacedeform_bind(modifier=MeshEditor(
                mmd_mesh_object).add_surface_deform_modifier(
                    'physics_cloth_deform',
                    target=cloth_mesh_object,
                    vertex_group=deform_vertex_group.name).name)

        cloth_bm.free()
 def poll(cls, context: bpy.types.Context):
     return MeshEditor(
         context.active_object).find_rigid_body_object() is not None