UV unwrapping pipeline with pybind11 bindings and preprocessing utilities
Project description
PartUV: Part-Based UV Unwrapping of 3D Meshes
SIGGRAPH Asia 2025
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
.objfile - 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 (VandF), 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 topipeline_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 usesbpyfor 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
-
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
-
Install UVPackMaster: Follow the instructions on the UVPackMaster website to obtain the Linux distribution. Download the ZIP file and place it in the
extern/uvpackmasterfolder. -
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
-ubflag.
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
- Download URL: partuv-0.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.4 MB
- Tags: CPython 3.13, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df06039b6d23d77cc3e7e378088606d7dc3518bf91438d274f77defda4257754
|
|
| MD5 |
62c2e95aa028b35f3229fa76b4969c77
|
|
| BLAKE2b-256 |
f08dcc167763a84ec2a191e29708233cc07c14a5d0d5a8078b30fe778e7252fd
|
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
- Download URL: partuv-0.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.4 MB
- Tags: CPython 3.12, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c45f6cd5314a4b5fef24a97cfa6abc51be28689f841eb7cfdf6dfa66c5fcd1a
|
|
| MD5 |
1c202d42b2b1923cbbc1df26b2539327
|
|
| BLAKE2b-256 |
f225b5bfcd338f7138d8a3a7b1786550dfd6a23c9918ff82620dd1cf90b97f8d
|
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
- Download URL: partuv-0.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.4 MB
- Tags: CPython 3.11, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42dd93f9b991e32189ad70952cad3e73095bb794b4bef647c245235a546cf760
|
|
| MD5 |
98f656640f637940fa94ef8746090127
|
|
| BLAKE2b-256 |
5361638dc4b3b307cea44c0fd8e47fff99aa7e69b084df9ea9956d4a10a431d7
|
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
- Download URL: partuv-0.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.4 MB
- Tags: CPython 3.10, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b937167bb0142e323ec7c2aee43ba46d9a9ceac72cca06f793f34ca53e3b541d
|
|
| MD5 |
c0ee7fdc4e2a4857d232e04c5768a0e0
|
|
| BLAKE2b-256 |
4f786344ffbe801d0a849bd62073dfe95d8cca8a3fd089f8a25eddc223ebea73
|
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
- Download URL: partuv-0.1.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.4 MB
- Tags: CPython 3.9, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2a7c458ed024d67ea663ee9385638d557342700eb2e67423f24696b2d716fc9
|
|
| MD5 |
4e79310ba1931c5a711b9ae365ebd946
|
|
| BLAKE2b-256 |
e4cb49a3febe76b311a77b2cf3b3f0b8dbb99646de951118d7c506935a036e29
|