Nodes/Melite Poser Nodes/🦴 Poser Bind Pose (SOMA-77 joints)
ComfyUI Node

🦴 Poser Bind Pose (SOMA-77 joints)

Shaped SOMA-77 joints, in centimetres, on purpose

By JayDataEngineer·Created 2 months ago·Updated 4 days ago· 1
🦴 Poser Bind Pose (SOMA-77 joints)
    • joints
    â—„identity_modelannyâ–º
    â—„identity_coeffsâ–º
    â—„unitscmâ–º
    â—„local_changesâ–º

    Every body-shape pipeline has a "where does the skeleton start" problem. For a rigged humanoid template you need the canonical rest pose - 77 joints, world-space rotations, consistent units - before you can deform anything, and you need it matching whatever the weight-transfer step used or nothing lines up downstream. Poser Bind Pose is that node: it hands you the SOMA-77 bind-pose joints for a chosen identity model, optionally shaped toward a body type.

    It's the first node in the poser half of the pack. PoserDeformSoma consumes its output, PoserRender renders the resulting mesh, and PoserRenderOpenPose can draw the same joints as a skeleton that lines up pixel-for-pixel with the depth pass.

    How it works

    It asks the pack's SkinEngine for the identity model's bind pose, then does the unit conversion on the way out. The engine works in metres - that's the internal convention - and the JOINTS wire format this node emits is in centimetres. Output positions come out as (1, 77, 3) float32 (the leading 1 is a single frame, so the shape is (T, 77, 3)), and rotations as (1, 77, 3, 3) float32 world-space matrices.

    Two contract details the author calls out in the docstring because they've been burned:

    • Rotations are world-space and carry no translation. The homogeneous bottom row of the original 4×4 transform is dropped. If you need where a joint is, read it from the positions, not from the rotation.
    • The engine is a process-wide singleton, cached per identity model. First call builds it (and the anny forward pass is ~10× faster on GPU); subsequent calls are free. That's why slider-style workflows stay responsive.

    Inputs and outputs

    • identity_model (default anny) - the body model. soma is the neutral mannequin, anny is the anime-stylised adult female used by the pack's anny_depth conditioning, and the docstring also names child. It's a plain STRING, not a combo, so a typo surfaces as an engine error rather than a red widget - worth knowing.
    • identity_coeffs - comma-separated body-shape coefficients in [0, 1]; 0.5 is neutral for anny. Empty means neutral. '0.7,0.4,0.55' is the example in the tooltip. These are the gross phenotype dimensions.
    • units - cm or m, and it controls the output unit of positions. Rotations are unitless either way. This exists because the rest of the pipeline speaks centimetres; if you're feeding something that speaks metres, you don't have to post-process.
    • local_changes (optional, multiline) - a JSON object of fine-grained detail morphs, each in [0, 1]. This is the interesting one: beyond the ~11 global phenotype coefficients there are 189+ named body-part morphs. {"hip-width-incr":0.7,"waist-narrow":0.5} is the tooltip's example.

    One output: joints, typed JOINTS. Wire it into PoserDeformSoma to get a mesh, or into PoserRenderOpenPose to get a skeleton.

    Install

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

    Then restart, or install through ComfyUI Manager by searching melite-poser-nodes.

    This one does need the heavy dependency. py-soma-x[anny] is the parametric identity layer, and the pack's requirements.txt carries a warning worth repeating: the 0.3.0 wheel has a packaging bug - soma/body/soma.py lazily imports soma.body.assets, which was never shipped in the wheel. The pack's own skin.py works around it by passing a local data_root. So if you hit an import error mentioning soma.body.assets from your own code, that's the bug; from inside this pack, it should already be dodged. py-soma-x also expects a local HF snapshot for the model assets, so a bare pip install without the weights will fail at engine construction, not at node execution.

    Where people get burned

    The unit contract is the number-one silent failure in this whole chain. Centimetres go out. PoserDeformSoma expects centimetres and converts to metres internally. If you bypass one of those nodes, or hand-roll a conversion, your deformed mesh comes out 100× too small and renders as an invisible dot. Nothing errors - the numbers are all legal floats.

    The shape knobs only mean something for models that support them. soma loads a neutral NPZ directly; anny and mhr go through the parametric layer. Coefficients that are meaningful for one identity aren't for another.

    local_changes names come from documentation you may not have. The docstring points at docs/anny-phenotype-mapping.md, which lives in the author's private estate repo, not the public one. Unknown morph names are the kind of thing that silently does nothing. Start with the two examples in the tooltip and grow from there, verifying visually each time.

    identity_model is a free-text string. "Anny", "anny" and "anny " are handled (it lowercases), but "anime" is not a thing, and you'll only find out when the engine refuses.

    CategoryTechNoir/Poser

    Inputs (4)

    NameTypeDefaultDescription
    identity_modelSTRINGanny—
    identity_coeffsSTRINGComma-separated body-shape coefficients in [0,1]. Empty = neutral. Example: '0.7,0.4,0.55'
    unitsCOMBOcm2 options: cm, m
    local_changesoptSTRINGJSON object of detail morph → value in [0,1]. Empty = none. Example: {"hip-width-incr":0.7,"waist-narrow":0.5}

    Outputs (1)

    NameTypeDescription
    jointsJOINTS—