problem with rigging belts and straps on a character

I’ve been working on a character model for my Unity project and I rigged the clothing using a separate mesh that would deform the clothing using Deform Mesh modifier. When I exported it to Unity, I realized that the modifier is not supported (as well as the most of the other modifiers) .

I came back to Blender and tried to rig the clothing using armature.

The clothing of the character has many belts and straps and they always clip through the rest of the outfit. I don’t know how to rig them. Is there any technique I could use to solve this problem or does it all rely solely on weight painting at this point?

This is how it looks with Deform Mesh and how it is supposed to look (so you can see all the straps):


And here is the problem that I am currently having (as you can see the straps and belts are clipping):


I tried using Transfer Weights, and i can’t use modifiers that are not supported by Unity, so I guess the rig needs to rely solely on the armature.

I am really hoping that somebody here can help me, I am struggling with this for a long time :frowning:

Modifiers are generally not supported in other programs, as they are either applied or discarded on export.
Transfer weights is a possibility, if it is ok for you to separate the meshes of the straps from the rest. You just have to apply Transfer Weights manually (I admit, that modifier is somewhat tricky to use somethimes)

I had the same problem and came up with this script that copies the weight from the nearest vertex. I’m not a very good programmer so, however, if you have a slow PC or many vertices, this might be very slow.
It adds a button in the Weight Painting Tools, you have to register the script through the text editor first.

import bpy
from bpy.types import Panel, Operator
import math

#Hide all vertices that you do not want to copy from (Hide as many as possible for better performance)
#Select all the vertices you want to copy to
#Hit "Copy Weights" in the Weight Painting Tools Tab

def VectorDistance(VectorA,VectorB):    
    x = VectorA[0] - VectorB[0]
    y = VectorA[1] - VectorB[1]
    z = VectorA[2] - VectorB[2]
    
    return (x**2 + y**2 + z**2)**0.5

def main(isMirrored):
    print("Start copying weights.")
    bpy.ops.object.mode_set(mode='OBJECT')
    myObject = bpy.context.active_object
    
    #save seleced and nonselected verts in lists
    selectedVerts = [v for v in myObject.data.vertices if v.select == True and v.hide != True]
    nonSelectedVerts = [a for a in myObject.data.vertices if a.select != True  and a.hide != True]
 
    #cycle through all target vertices        
    for target in selectedVerts:
        distance = float('inf')          #start distance can be used as a threshold if needed
        closestVert = target 
        
        target_position = [0,0,0]
            
        if isMirrored == True:
            #copy and mirror position vector (currently along local x, add or remove - for other axis
            target_position[0] = -target.undeformed_co[0]  # mirrored x value
            target_position[1] = target.undeformed_co[1]   # y value
            target_position[2] = target.undeformed_co[2]   # z value
        else:
            target_position = target.undeformed_co
        
        #cycle through all source vertices
        for source in nonSelectedVerts:
            newDistance = VectorDistance(target_position,source.undeformed_co)
            
            #save new source if it is closer to the target than the currently saved one
            if newDistance < distance:
                distance = newDistance
                closestVert = source
        
        #avoid copying from self in case nothing was found
        if(closestVert != target):
            #empty old vertex groups in target
            for oldGroup in target.groups:
                oldGroup.weight = 0.00            #Note: oldGroup is of type VertexGroupElement, not VertexGroup. Same for verifyGroup below
                
            #find the right vertex groups to copy weights from
            for sourceGroup in myObject.vertex_groups:
                for verifyGroup in closestVert.groups:
                    #copy weights from source to target
                    if verifyGroup.group == sourceGroup.index:
                        if isMirrored == True:
                            name = sourceGroup.name
                            
                            isMirrorGroup = False;
                            
                            #Checks if the group is part of a left/right pair. Change the letters according to your naming habits
                            if name[-2:] == "_L":
                              name = name[:-2] + "_R"
                              isMirrorGroup = True
                            elif name[-2:] == "_R":
                              name = name[:-2] + "_L"
                              isMirrorGroup = True
                              
                            #copy weights from source to target
                            if isMirrorGroup == True:
                                #find the other part of the group pair by name
                                for mirroredGroup in myObject.vertex_groups:
                                    if mirroredGroup.name == name:
                                        weight = sourceGroup.weight(closestVert.index)
                                        mirroredGroup.add(([target.index]),weight,'REPLACE')
                            else:
                                weight = sourceGroup.weight(closestVert.index)
                                sourceGroup.add(([target.index]),weight,'REPLACE') 
                        else:
                            weight = sourceGroup.weight(closestVert.index)
                            sourceGroup.add(([target.index]),weight,'REPLACE')          
                    
        else:
            print("Warning, some vertices remain unchanged.")
    
    #go back to weightpaint mode
    bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)


#Operators
class Operator(bpy.types.Operator):
    bl_idname = "object.copy_weights"
    bl_label = "Copy Weights"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        main(isMirrored = False)
        return {'FINISHED'}

def updateIntParameter(self,context):
    # This def gets called when one of the properties changes state.
    print(self.my_int)
    
class MirOperator(bpy.types.Operator):
    bl_idname = "object.copy_weights_mirrored"
    bl_label = "Copy Weights with x-Mirror"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        main(isMirrored = True)
        return {'FINISHED'}

#Panel with Input UI
class Panel(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'Copy Weights'
    bl_context = 'weightpaint'
    bl_category = 'Tools'

    def draw(self, context):
        layout = self.layout
        layout.operator("object.copy_weights")
        layout.operator("object.copy_weights_mirrored")
        
def register():
    bpy.utils.register_class(Operator)
    bpy.utils.register_class(MirOperator)
    bpy.utils.register_class(Panel)


def unregister():
    bpy.utils.unregister_class(Operator)
    bpy.utils.unregister_class(MirOperator)
    bpy.utils.unregister_class(Panel)


if __name__ == "__main__":
    register()

That’s going to be a tough one. If you can’t get the straps by weight painting, you might want to try textures. You can use normal maps on the straps and they will look like they are attached. If your vertices are not the aligned with the under mesh, yes it will be hard.

Like the script BenitaS. There is a modifier now that will also work called data transfer that will also transfer weights.

if u can share your rig… i can fixe it for u. its pretty simple!!

Thank you, everyone who tried to help me
I was finally able to solve the problem by using Transfer Weights tool. However initially when I separated the straps and clothing as 2 separate meshes it didn’t work. I had to separate the mesh into smaller segments and apply transfer weights to each one of them. After that I just had to paint some weights manually to fix little problems and it was done, It looks brilliant now :slight_smile:

yes, you need a matching topology and vertex groups value for that you work. Or the meshes don’t deform exactly the same way.

If you don’t intend to animate the belt/straps I would have baked it as a texture . The other option is to put simples bones on them and animate them when the meshes are intersecting. You can even add detail to the animation by giving it a bit of offset in time.

Having bones that adjust automatically can be done , but that may fail at some point depending on the pose, so you also need to be able to correct it by hand. This is generally a can of worm , but if you have time that can be a good solution too.

I’m glad it as worked for you !