Skip to main content

UV unwrapping pipeline with pybind11 bindings and preprocessing utilities

Project description

PartUV: Part-Based UV Unwrapping of 3D Meshes

SIGGRAPH Asia 2025

arXiv Project Page

Official implementation for PartUV: Part-Based UV Unwrapping of 3D Meshes.

---
Table of Contents

🚧 TODO List

  • Resolve the handling of non-2-manifold meshes, see Known Issues
  • Release benchmark code and data
  • Multi-atlas packing with uvpackmaster

Installation

PartUV (for UV Unwrapping)

# 1) Create and activate environment
conda create -y --name partuv python=3.11
conda activate partuv

# 2) Install PyTorch 2.7.1 (CUDA 12.8 wheels) and torch-scatter
# It should work with other PyTorch/CUDA versions, but those are not tested.
# conda install nvidia/label/cuda-12.8.1::cuda-toolkit
pip install torch==2.7.1 --index-url https://download.pytorch.org/whl/cu128
pip install torch-scatter -f https://data.pyg.org/whl/torch-2.7.1+cu128.html

# 3) Install project requirements and local wheel
pip install -r requirements.txt
pip install partuv

Download the PartField checkpoint from PartField:

wget https://huggingface.co/mikaelaangel/partfield-ckpt/resolve/main/model_objaverse.ckpt ./

Packing with bpy (optional)

# For Python 3.11+
pip install bpy
# For Python 3.10
pip install bpy==4.0.0 --extra-index-url https://download.blender.org/pypi/

Demo

TL;DR

# Step 1: UV unwrapping 
python demo/partuv_demo.py --mesh_path {input_mesh_path} --save_visuals

Step 1: UV Unwrapping

The demo takes a 3D mesh (e.g., .obj or .glb) as input and outputs the mesh with unwrapped UVs in a non-packed format.

Input Requirement

We recommend using meshes without 3D self-intersections, as self-intersected meshes may result in highly fragmented UVs.

Preprocessing

The input mesh is first preprocessed, including:

  • Mesh repair (e.g., merging nearby vertices, fixing non–2-manifold meshes, etc.)
  • (Optional) Exporting the mesh to a .obj file
  • Running PartField to obtain the hierarchical part tree

Unwrapping

We then call our pre-built pip wheels for unwrapping. Two main API versions are provided:

  • pipeline_numpy: The default version. It takes mesh NumPy arrays (V and F), the PartField dictionary (a hierarchical tree), a configuration file path, and a distortion threshold as input. Note that the distortion threshold specified here will override the value defined in the configuration file.
  • pipeline: Similar to pipeline_numpy, but it takes file paths as input and performs I/O operations directly from disk.

Output Results

Both APIs save the results to the output folder. The final mesh with unwrapped UVs is saved as final_components.obj. Each chart is flattened to a unit square, but inter-chart arrangement is not yet solved.

Individual parts are also saved as part_{i}.obj, which can be used with UVPackMaster to produce part-based UV packing (where charts belonging to the same part are grouped nearby). See the later section for more details.

The saving behavior can be configured in the save_results function.

If you specify the --pack_method flags, the code will pack the UVs and save the final mesh in final_packed.obj.

Hyperparameters

By default, the API reads all hyperparameters from config/config.yaml. See config.md for more details on hyperparameters and usage examples for customizing them to suit your needs.


Step 2: Packing

The unwrapping API outputs UVs in a non-packed format. You can pack all UV charts together to create a UV map for the input mesh. Two packing methods are supported:

  • blender: The default packing method. We provide a script (pack/pack_blender.py) that uses bpy for packing, which is called by default in the demo file.
  • uvpackmaster: A paid Blender add-on. We use this to achieve part-based packing (charts from the same part are packed close together) or automatic multi-atlas packing. Please see more details below.

Part-Based Packing with UVPackMaster

In our results, we include both part-based packing (where charts from the same part are packed close together) and automatic multi-atlas packing (given N desired tiles, parts are assigned to tiles according to the hierarchical part tree).

These results are packed using UVPackMaster, which unfortunately is a paid tool. We provide scripts to pack the UVs with UVPackMaster.

Installation

  1. Install BlenderProc: We use BlenderProc to run this add-on within Blender. Please follow the instructions in the BlenderProc repository to install it.

    pip install blenderproc
    
  2. Install UVPackMaster: Follow the instructions on the UVPackMaster website to obtain the Linux distribution. Download the ZIP file and place it in the extern/uvpackmaster folder.

  3. Install the add-on: We provide a script to install the add-on:

    blenderproc run pack/install_uvp.py
    

Usage

To pack UVs with UVPackMaster, use the same command as the default packing method, changing the --pack_method flag to uvpackmaster:

python demo/partuv_demo.py --mesh_path {input_mesh_path} --pack_method uvpackmaster --save_visuals

Multi-Atlas Packing 🚧


Benchmarking

We provide the datasets used to benchmark our method here. The meshes are preprocessed, and we also provide the PartField hierarchy binary files.

You can run the benchmark directly using the provided Bash script.

Note: This script runs preprocessing and PartField by default. To skip preprocessing and load the binary files directly, add the -ub flag.

cd demo/benchmark
bash benchmark.sh

Building from Source

Please refer to build.md for detailed build instructions.


Known Issues

Handling of non-2-manifold meshes

The ABF assumes the mesh is 2-manifold (each edge is incident to at most two faces). This is currently handled in the preprocessing step, by splitting vertices on non-manifold edges. However, this may create split faces which could result in single-face UV charts. We are working on a better solution to handle this.

Common Problems

Below are common issues and their solutions:

1. Problem with cuda crt/math_functions.h

Modify math_functions.h according to the fix described at: https://forums.developer.nvidia.com/t/error-exception-specification-is-incompatible-for-cospi-sinpi-cospif-sinpif-with-glibc-2-41/323591/3

2. Floating-Point Error

Disable PAMO when running the pipeline on CPU machines.

3. ImportError: GLIBCXX_3.4.32 not found

export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6
python demo/partuv_demo.py

4. (Build) nvcc fatal: Unsupported gpu architecture 'compute_120'

Remove compute_120 from the CMAKE_CUDA_ARCHITECTURES in CMakeLists.txt.



🍀 Acknowledgement

We acknowledge the following repositories for their contributions and code:

and all the libraries in the extern/ folder.


BibTeX

If this repository helps your research or project, please consider citing our work:

@inproceedings{wang2025partuv,
  title     = {PartUV: Part-Based UV Unwrapping of 3D Meshes},
  author    = {Wang, Zhaoning and Wei, Xinyue and Shi, Ruoxi and Zhang, Xiaoshuai and Su, Hao and Liu, Minghua},
  booktitle = {ACM SIGGRAPH Asia Conference and Exhibition on Computer Graphics and Interactive Techniques},
  year      = {2025}
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

partuv-0.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

partuv-0.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

partuv-0.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

partuv-0.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

partuv-0.1.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file partuv-0.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for partuv-0.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 df06039b6d23d77cc3e7e378088606d7dc3518bf91438d274f77defda4257754
MD5 62c2e95aa028b35f3229fa76b4969c77
BLAKE2b-256 f08dcc167763a84ec2a191e29708233cc07c14a5d0d5a8078b30fe778e7252fd

See more details on using hashes here.

File details

Details for the file partuv-0.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for partuv-0.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 5c45f6cd5314a4b5fef24a97cfa6abc51be28689f841eb7cfdf6dfa66c5fcd1a
MD5 1c202d42b2b1923cbbc1df26b2539327
BLAKE2b-256 f225b5bfcd338f7138d8a3a7b1786550dfd6a23c9918ff82620dd1cf90b97f8d

See more details on using hashes here.

File details

Details for the file partuv-0.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for partuv-0.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 42dd93f9b991e32189ad70952cad3e73095bb794b4bef647c245235a546cf760
MD5 98f656640f637940fa94ef8746090127
BLAKE2b-256 5361638dc4b3b307cea44c0fd8e47fff99aa7e69b084df9ea9956d4a10a431d7

See more details on using hashes here.

File details

Details for the file partuv-0.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for partuv-0.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b937167bb0142e323ec7c2aee43ba46d9a9ceac72cca06f793f34ca53e3b541d
MD5 c0ee7fdc4e2a4857d232e04c5768a0e0
BLAKE2b-256 4f786344ffbe801d0a849bd62073dfe95d8cca8a3fd089f8a25eddc223ebea73

See more details on using hashes here.

File details

Details for the file partuv-0.1.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for partuv-0.1.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b2a7c458ed024d67ea663ee9385638d557342700eb2e67423f24696b2d716fc9
MD5 4e79310ba1931c5a711b9ae365ebd946
BLAKE2b-256 e4cb49a3febe76b311a77b2cf3b3f0b8dbb99646de951118d7c506935a036e29

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page