Skip to content

revoconner/UV-Texture-Repacker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

90 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UV Texture Repacker

This tool is a part of Rév's UV suite and will likely merge into a single app.

Takes N input meshes, each with its own texture(s), and produces one square atlas texture plus N output meshes whose UV channel now points into the packed atlas.

The transfer is pixel-based, not bake-based, mitigating the problems associated with baking. Every output texel is sampled directly from one source texture via the barycentric coordinates of the triangle that covers it. What the artist painted is what lands in the atlas.

Why does this tool exists

The usual atlas pipeline in Blender / Substance / Max rebakes via a renderer. Bakes can miss occluded geometry, introduce sampling noise, or need cage tuning. For the common case of "I already have good textures and I just want them repacked onto a shared atlas", a render pass is unnecessary and may cause artifacts. This tool does the repack by direct pixel copy.

Screenshots

image
image
image

Using the source code

Source

Python 3.11.9 with a venv at multi_uv_repack/venv/.

pip install -r requirements.txt

fbxsdkpy (the optional FBX backend) is hosted on Inria's GitLab package registry, not PyPI. The --extra-index-url is already declared inside requirements.txt, so the line above installs everything in one shot. To install it manually:

pip install fbxsdkpy --extra-index-url https://gitlab.inria.fr/api/v4/projects/18692/packages/pypi/simple
Details

Use - CLI

python -m multi_uv_repack.main \
    --mesh path/to/mesh_a.obj --tex albedo=path/to/a_albedo.png \
    --mesh path/to/mesh_b.fbx --tex albedo=path/to/b_albedo.png \
                              --tex normal=path/to/b_normal.png \
    --out out/ \
    --resolution 2048 \
    --padding 16 \
    --dilation 8 \
    --filter bilinear \
    --allow-rotation
Read More

Each --mesh starts a new asset record. --tex CHANNEL=PATH flags that follow attach to the most recent --mesh until the next one. Paths can be absolute and come from any folder - there is no project-root constraint. Channel names are free-form strings; albedo, normal, roughness, metallic, ao, emissive are conventional.

Optional flags:

  • --packer bitmap|xatlas - which packer to run. bitmap (default) uses the in-tree SimpleBitmapPacker port (numba-accelerated, matches brute-force utilization in ~1.5s at any resolution). xatlas delegates to the xatlas C++ library.
  • --brute-force - enable xatlas bruteForce packing. xatlas-only; ignored by bitmap. Off by default because at 4k it raises pack time from ~2s to ~200s for a few percent utilization gain.
  • --world-scale-priority - pre-scale each asset's UVs by sqrt(3D surface area / UV area) so physically larger meshes claim proportionally more atlas texels. Off by default (equal-priority packing).
  • --allow-rotation - let the bitmap packer rotate shells 90 degrees CCW when it tightens the fit. Tangent-space normal maps are re-shaded automatically. Bitmap packer only.

Use - GUI

python -m multi_uv_repack.ui_web

Parameters

  • Atlas resolution (512px to 32,768px). Output is forced square. The bitmap packer respects this exactly; xatlas treats it as a hint and may inflate the output 1.4-1.5x for better utilization.
  • Padding (range 8-64 texels). Default scales with resolution: 64 at 8192, halving each step down with an 8-texel floor. Space reserved between islands by the packer.
  • Dilation ring (range 4-32 texels, default 8). Post-process pixel bleed out of each island so bilinear filtering / mip generation does not pull in black edge.
  • Filter (nearest / bilinear / bicubic, default bilinear). Resampling filter when the packer scales an island.

Known limits

  • glTF still goes through trimesh on read / write, which merges per-position and loses per-corner seams. Same limitation OBJ used to have. Swap in pygltflib if / when a real asset exhibits the problem.
  • No live preview on field change. Pack on button press only (by spec).
  • No GPU path. CPU numba throughput is sufficient for 4k / ~20 assets in seconds.
  • Mixing authored unit systems across input meshes (one mesh in cm, another in m) will break --world-scale-priority. Not fixable inside the tool.

Bitmap Packer

The bitmap packer is a new integration of existing research into bin packing. Read the bitmap_uv_packing.pdf to learn more about it.

The CPU bound packer, can reach utilisation ratios upto ~94% and while offline, is still fast irrespective of output resolution.

Credits

  • Packing by xatlas via xatlas-python, plus the in-tree bitmap packer ported from the author's Maya UV-packer project.

About

A tool to pack UV and textures of multiple already textured meshes together into a single packed Atlas texture.

Resources

License

Stars

Watchers

Forks

Contributors