Nodes/ComfyUI libigl/UV Xatlas (backend)
ComfyUI Node

UV Xatlas (backend)

The automatic UV unwrap that game engines trust

By PozzettiAndrea·Created 10 months ago·Updated 4 days ago· 218
UV Xatlas (backend)
  • trimesh
  • unwrapped_mesh
  • info

When you want a usable UV map and you don't want to think about it, this is the backend you pick. GeomPackUV_Xatlas is the hidden worker that runs when you choose xatlas from the backend dropdown on the UV Unwrap node in ComfyUI-GeometryPack. Like the other backends in that dropdown, it's a dev-only node - ComfyUI's node expansion calls it for you, so you'll almost never place it on a canvas directly. But it's the one most people end up leaning on, because xatlas is the de-facto standard for automatic UV unwrapping. It's what your favorite 3D tool is probably using under the hood anyway.

Why xatlas wins the "just unwrap it" contest

xatlas is a fork of the-atlas, and it does the whole job automatically: it detects features, cuts the mesh into islands along natural seams, flattens each island, then packs everything into the 0–1 UV space. No manual seam marking, no projection setup - drop a mesh in, get a texture-ready layout out. It's optimized for lightmaps and texture atlasing, which is the same thing you're doing when you bake a texture in ComfyUI. For anything like a scanned object or an organic model where you'd otherwise spend twenty minutes marking seams in a modeling app, this is the one to reach for.

The tradeoff versus the libigl backends in the same pack is worth knowing: xatlas splits vertices where seams cut the mesh, so your unwrapped mesh has more vertices than the input. That's normal and expected - the info output reports the exact duplication ratio so you can see it. The angle-preserving libigl LSCM backend keeps topology intact instead, but doesn't cut islands, so complex meshes distort more.

How it works

The code is refreshingly short: it calls xatlas.parametrize() on your vertices and faces, which returns a vertex remapping, new face indices, and UV coordinates. The node rebuilds a trimesh from the remapped vertices, attaches the UVs to its texture visuals, and stamps the algorithm plus the duplication ratio into the mesh metadata. Fast, CPU-only, and it handles tricky inputs far more gracefully than you'd expect from something this terse.

Inputs and outputs

  • trimesh - the only input; the pack-wide TRIMESH type, so wire it from a Load Mesh node.
  • unwrapped_mesh - your UV'd mesh, ready for a preview node, a texture bake, or Save Mesh.
  • info - a string with before/after vertex and face counts plus the vertex-duplication ratio, which is the honest way to tell how much seam-splitting happened.

Installing it

The node ships with the pack, so install the pack:

cd ComfyUI/custom_nodes
git clone https://github.com/PozzettiAndrea/ComfyUI-GeometryPack.git
cd ComfyUI-GeometryPack
pip install -r requirements.txt --upgrade
python install.py

Or search GeometryPack in ComfyUI Manager (try nightly if the listed version misbehaves - the README is upfront that the isolated comfy-env install is experimental and that manual is "most reliable"). Restart ComfyUI after.

Where people get burned

First-launch patience is the big one: the pack pulls an isolated environment with pixi plus heavy native deps (Blender, CGAL, libigl, VTK), and building it takes a while on the first run. If the environment fails to provision you can hit the node's own error - "xatlas not installed. Install with: pip install xatlas" - and in a manual install that command genuinely fixes it. Otherwise, remember you're getting the automatic-unwrap experience: for a mesh that's supposed to keep one continuous UV sheet (say, a flat panel you'll texture with a decal), xatlas's seam-splitting may not be what you want - that's the moment to switch the dropdown to libigl_lscm instead. For everything else, xatlas is the "just works" button, and in a pack that's otherwise full of heavy geometry machinery, that's high praise.

Categorygeompack/uv

Inputs (1)

NameTypeDefaultDescription
trimeshTRIMESH

Outputs (2)

NameTypeDescription
unwrapped_meshTRIMESH
infoSTRING