UV Pack Islands
Stop wasting texture resolution
- BPY_OBJ
- BPY_OBJ
UV Pack Islands is the cleanup pass every unwrap needs. After you've projected or flattened your mesh, the UV islands are scattered all over the map with gaps between them - and every gap is texture resolution you paid for and aren't using. This node shoves all the islands into the 0–1 UV square (or a UDIM tile) as tightly as it can, so your character's texture gets the most pixels per inch of face. It's the node you run right before you call the avatar done.
How it works
It's another auto-generated Blender wrapper in the Avatar Graph pack, this time around bpy.ops.uv.pack_islands - Blender's modern, xatlas-based packer, which since 3.x is genuinely good at this. Feed it a BPY_OBJ and it rearranges existing UV islands in place, then returns the same object. There's no reprojection involved; it just moves and rotates what's already there.
Most of the inputs you can leave alone, but a few are worth knowing:
- margin - the gap between islands, in UV units.
0.001is hairline;0.02–0.05gives breathing room. Too small and you get bleeding between islands at low texture res. - rotate and rotate_method - rotation lets the packer fit islands tighter.
ANYallows arbitrary angles (tightest pack),AXIS_ALIGNEDis the safest. If you're OCD about axis-aligned UVs, setrotate_methodtoCARDINALorAXIS_ALIGNED. - scale - when on (default), the packer rescales islands to equal texel density. Turn it off only if you deliberately made some islands bigger and want that respected.
- shape_method -
CONCAVEuses the true island shape (tighter pack),AABBuses bounding boxes (faster, looser). - pin / pin_method - pins islands in place so the packer can't move them. Handy if you've manually placed the face and only want the leftovers packed around it.
- udim_source - where the packer puts things when you have UDIM tiles.
Output is the single BPY_OBJ you fed in.
Where it fits
In an Avatar Graph build, your eye, mouth, and face layers each get their own mesh and their own texture. Running Pack Islands on the shared/joined mesh after unwrapping means all those islands share the same map efficiently - which matters once you're exporting a .GLB/.GLTF for the Avatech editor and real-time preview. A sloppy pack shows up as a soft, blurry mouth close-up; a tight one keeps the lipsync crisp.
One honest note: because the mesh lives inside the pack's embedded Blender session, you won't see a visual UV editor - you judge the result by how the final texture looks. If you're trying to iterate, keep the parameters stable and change one at a time.
Installing Avatar Graph
This node ships in the Avatar Graph pack from Avatech. From ComfyUI/custom_nodes:
git clone https://github.com/avatechai/avatar-graph-comfyui
cd avatar-graph-comfyui
python -m pip install -r requirements.txt
then restart ComfyUI with --enable-cors-header. ComfyUI Manager users: search Avatar Graph → Install.
Gotchas: the pack pins bpy==3.6.0, which needs Python 3.10.x - on any other version the pip install fails and the pack won't load. First launch auto-downloads the SAM ViT-H model (~2.5 GB), so a slow first start is expected. And the pack README openly says it's still changing - pin the version once you have something working.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| BPY_OBJopt | BPY_OBJ | — | |
| udim_sourceopt | COMBO | 3 options: CLOSEST_UDIM, ACTIVE_UDIM, ORIGINAL_AABB | |
| rotateopt | BOOLEAN | true | — |
| rotate_methodopt | COMBO | 3 options: AXIS_ALIGNED, CARDINAL, ANY | |
| scaleopt | BOOLEAN | true | — |
| merge_overlapopt | BOOLEAN | false | — |
| margin_methodopt | COMBO | 3 options: SCALED, ADD, FRACTION | |
| marginopt | FLOAT | 0.000–1 | — |
| pinopt | BOOLEAN | false | — |
| pin_methodopt | COMBO | 4 options: SCALE, ROTATION, ROTATION_SCALE, LOCKED | |
| shape_methodopt | COMBO | 3 options: CONCAVE, CONVEX, AABB |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| BPY_OBJ | BPY_OBJ | — |