Nodes/Melite Autorig Nodes/🧹 Clean SOMAX Weights (arm-torso isolation)
ComfyUI Node

🧹 Clean SOMAX Weights (arm-torso isolation)

Ray Clean SOMAX Weights

By JayDataEngineer·Created 2 months ago·Updated 4 days ago· 1
🧹 Clean SOMAX Weights (arm-torso isolation)
    • output_path
    â—„rigged_glb_pathâ–º

    Every auto-rigger produces the same five defects, and they all show up at the same moment: the first time the character raises its arms. A wing of skin stretches from the torso to the elbow because torso vertices grabbed arm weights. The shoulders pinch thin because the spine bone is fighting the shoulder bone. There's webbing under the armpits. The wrists collapse into a candy wrapper where the forearm's 100% weight meets the hand's 100%.

    RayCleanWeights is a pre-animation cleanup pass that fixes exactly those, on the GLB itself.

    This is one of the two "weight surgery" nodes in the pack - a ComfyUI port of the author's host-side stage4a_clean_weights, lifted so an entire character pipeline can run inside ComfyUI with no external script. It's pure NumPy. No Blender, no GPU, no torch, no model downloads.

    What it does

    It parses the GLB binary by hand - JSON chunk, BIN chunk, accessor offsets - reads POSITION, JOINTS_0 and WEIGHTS_0 off the first mesh primitive, pulls the joint list from the skin, and classifies each joint by name (stripping the mixamorig: prefix and matching on Arm/ForeArm/Hand/Shoulder versus Spine/Hips/Neck/Head/Leg/Foot). Then six passes:

    1. Arm-torso isolation. Vertices within 4 cm of the centerline, in the mid-body Y band, have arm weights zeroed. This is the wing fix.
    2. Shoulder rebalancing. Torso weight is capped at 15% on vertices near the shoulder joint, and the difference is pushed to shoulder and arm bones. Fixes the thin-shoulder pinch.
    3. Armpit decontamination. Vertices with both arm and torso influence get assigned to whichever joint group they're nearer, and the loser is zeroed. This is the webbing fix.
    4. Wrist blend zone. A gradient is blended in between ForeArm and Hand near the wrist, replacing the hard step.
    5. Cross-body decontamination. A vertex influenced by both left and right arm bones keeps only the dominant side - stops the inner thighs and collarbones from being dragged by the opposite limb.
    6. Renormalise and truncate to top-4 influences, which every realtime engine's 4-bone skinning limit requires anyway.

    Output lands at output/stage4a_cleaned.glb and is returned as output_path.

    Inputs and output

    One required input, rigged_glb_path - a SOMA-rigged GLB whose weights need cleaning. It's a STRING socket wired in, not typed. In the pack's own flow you'd hand it the clean rigged body, or the output of KimodoTransferWeights.

    One output, output_path, a STRING. Wire it into RaySyncSiblingWeights and then KimodoExportFBX.

    Do you need this? If you're animating a character with arms that go above horizontal, yes, you'll see the artifacts. If you're generating static T-poses for a ControlNet, save yourself the step.

    Install

    cd /path/to/ComfyUI/custom_nodes
    git clone https://github.com/JayDataEngineer/melite-autorig-nodes.git
    

    Manager search: "melite". Restart. Dependencies are the pack's trimesh, scipy, requests - none of which this node even imports, so it works on a bare ComfyUI. Blender isn't needed here.

    Where people get burned

    It only knows Mixamo-style names. The classification is string matching on bone names. A rig whose joints are called J39 or bone_042 produces Arm joints: 0 in the log and then quietly changes almost nothing - weights get renormalised and that's it. Check the log line and compare it to your rig's joint count before you trust the result.

    The 4 cm centerline threshold is a hardcoded metric constant. It assumes meters and a roughly 1.7-unit-tall humanoid. A mesh authored in centimetres (height ~176) makes that threshold a rounding error; one that's hip-height to a scaled-up rig makes it huge. Same for the Y band, which is derived from the mesh's own bounding box.

    It reads the first mesh and the first primitive, period. meshes[0].primitives[0] and skins[0]. Multi-part GLBs - body plus separate eyes plus separate clothes as sibling meshes - get one part cleaned and the rest ignored.

    Attribute types are asserted, not negotiated. The write-back assumes float32 WEIGHTS_0 and 16-bit JOINTS_0 and asserts the byte sizes match. A GLB exported with float16 weights or 8-bit joint indices trips Weight bytes mismatch and fails. In practice: re-export as float32 and retry.

    The filename is fixed. Every run overwrites output/stage4a_cleaned.glb, so there's no history and no timestamp. If you want to compare a cleaned and uncleaned rig, rename one of them before running again.

    CategoryMelite/AutoRig

    Inputs (1)

    NameTypeDefaultDescription
    rigged_glb_pathSTRINGSOMA-rigged GLB whose weights need cleanup.

    Outputs (1)

    NameTypeDescription
    output_pathSTRING—