Transform Shrink Fatten
The One That Actually Shapes the Face
- BPY_OBJ
- BPY_OBJ
If you remember one node from Avatar Graph's Transform_ shelf, make it this one. Transform Shrink Fatten is the Blender operator transform.shrink_fatten, and it's the fastest way to give a flat avatar mesh actual volume. Positive value pushes vertices outward along their normals - fattening, puffing, rounding. Negative pulls them in - shrinking, hollowing. For a character built from segmented image layers, this is how a paper-flat mouth becomes a lip you can deform.
How it works
The mechanism is simple and it's why the result looks good: each vertex moves along its own normal direction, not along a single world axis. That means a cheek mesh puffs out uniformly instead of just sliding sideways. Internally the node takes your BPY_OBJ, enters edit mode, and calls bpy.ops.transform.shrink_fatten(value=...). The mesh comes back on the output BPY_OBJ socket, ready to chain into the next op.
The inputs that matter:
value- the amount. 0 is unchanged; 0.2 is a subtle puff; 1+ is a balloon. Negative shrinks. There's no upper clamp, so ease into it.use_even_offset- keeps edge lengths even as vertices move, so you don't get stretched, uneven geometry. Generally leave it on.use_proportional_edit+proportional_size- the secret to a local, organic effect. Enable it and only the region withinproportional_sizeof the pivot transforms, with a falloff you pick (SMOOTH,SPHERE,SHARP...). This is how you fatten just the lips without inflating the whole head.
Everything else (mirror, snap, release_confirm, use_accurate) is Blender operator plumbing you can ignore.
Where it fits in the avatar workflow
The classic Avatar Graph flow is: generate a character image with an open mouth → segment it with the SAM node → Create Mesh Layer for each part (mouth, eyes, head) → join or keep them separate → shape them → build shape keys → export to the Avatech editor. Shrink Fatten lives right after mesh creation. Fatten the mouth layer so there's actual geometry to deform, then let Mesh Modify Shape Key drive it into smile/blink expressions later.
Two gotchas. First, it acts on the whole mesh you feed it - there's no vertex-selection socket, so apply it per-part via separate mesh layers. Second, keep an eye on the mesh's texture: since these layers carry the character image as a texture, heavy shrinkage can warp how the image reads on the surface. Match Texture Aspect Ratio at the end fixes the re-scale.
Installing
This node ships in the Avatar Graph pack (avatechai/avatar-graph-comfyui). The pack's real dependency is bpy==3.6.0, which needs Python 3.10:
conda create --name comfyui python=3.10
conda activate comfyui
Install via ComfyUI Manager (search Avatar Graph) or:
cd ComfyUI/custom_nodes
git clone https://github.com/avatechai/avatar-graph-comfyui
cd avatar-graph-comfyui && python -m pip install -r requirements.txt
Restart with python main.py --enable-cors-header for the live preview. No model downloads for this node - the only heavyweight download in the pack is the SAM segmentation model, which you don't need to touch for shaping.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| BPY_OBJopt | BPY_OBJ | — | |
| valueopt | FLOAT | 0.00-3.402823466385289e+38–3.402823466385289e+38 | — |
| use_even_offsetopt | BOOLEAN | false | — |
| mirroropt | BOOLEAN | false | — |
| use_proportional_editopt | BOOLEAN | false | — |
| proportional_edit_falloffopt | COMBO | 8 options: SMOOTH, SPHERE, ROOT, INVERSE_SQUARE, SHARP, LINEAR, +2 | |
| proportional_sizeopt | FLOAT | 1.009.999999974752427e-7–999999995904 | — |
| use_proportional_connectedopt | BOOLEAN | false | — |
| use_proportional_projectedopt | BOOLEAN | false | — |
| snapopt | BOOLEAN | false | — |
| release_confirmopt | BOOLEAN | false | — |
| use_accurateopt | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| BPY_OBJ | BPY_OBJ | — |