Ben Traje
← Back to 3ds-max

Batch Enable 'Bone On' for Skin Modifiers in 3ds Max (Python)

03 May 26 (3d ago)

In other DCC, you skin a mesh with a joint. But in 3ds max, you can skin not only with a bone (or joint in other DCC) but also through a helper (or null in other DCC). And it seems like normal since I receive multiple rigs from other riggers that uses this workflow.

Not really a problem per se except when I try to export the rigged mesh outside in 3ds Max. Normally, the Export FBX command has a check box Convert Dummies to Bones but sometimes it doesn't work unless you enable the "Bone On" feature for every helper object.

The script below does that. If you have a selected skinned mesh, it enables every joint of that mesh to be "Bone On" or if no selected, all skinned mesh.

import pymxs
rt = pymxs.runtime

def process_skin_bones(obj):
    try:
        # 1. Look for the Skin modifier on the object
        skin_mod = None
        for mod in obj.modifiers:
            if rt.classOf(mod) == rt.Skin:
                skin_mod = mod
                break
                
        # If no skin modifier is found, skip this object
        if not skin_mod:
            return
            
        print(f"Processing Skin on: {obj.name}")
        
        # 2. Get the number of bones (skinOps uses 1-based indexing)
        num_bones = rt.skinOps.GetNumberBones(skin_mod)
        count = 0
        
        # 3. Loop through the skin's bone list
        for i in range(1, num_bones + 1):
            bone_name = rt.skinOps.GetBoneName(skin_mod, i, 1)
            if bone_name:
                bone_node = rt.getNodeByName(bone_name)
                
                # Turn 'Bone On' to True for the dummy/node
                if bone_node:
                    bone_node.boneEnable = True
                    count += 1
                    
        print(f"  -> Enabled 'Bone On' for {count} dummies/bones.")
        
    except AttributeError:
        # The object doesn't support modifiers (e.g., helpers, lights), just skip it safely
        pass

def main():
    # Grab the current selection
    sel = list(rt.selection)

    if len(sel) > 0:
        print("--- Running Mode 1: Selected Objects Only ---")
        for obj in sel:
            process_skin_bones(obj)
    else:
        print("--- Running Mode 2: All Scene Objects ---")
        # rt.objects gets absolutely everything in the scene
        for obj in rt.objects:
            process_skin_bones(obj)

# Execute the script
main()