Seonghun Oh*, Xiaodi Yuan*, Xinyue Wei*, Ruoxi Shi, Fanbo Xiang, Minghua Liu, Hao Su
[Project Page] [Paper]
We present a novel GPU-based mesh optimization pipeline with three core components:
- Parallel remeshing: Converts arbitrary meshes into watertight, manifold, and intersection-free meshes while improving triangle quality.
- Robust parallel simplification: Reduces mesh complexity with guaranteed intersection-free results.
- Optimization-based safe projection: Realigns the simplified mesh to the original input, eliminating surface shifts from remeshing and restoring sharp features.
Our approach is highly efficient, simplifying a 2-million-face mesh to 2k triangles in just 3 seconds on an RTX 4090.
Left: Reducing the 2M-face “crab” to 0.1% in 2.29s. Right: Reducing the 7M-face “dragon” to 0.1% in 5.32s. (Only the output
meshes are shown above; qem [1], rolopm [2]).
docker run --name pamo -i -t --gpus all -e NVIDIA_DRIVER_CAPABILITIES=graphics,compute,utility sarahwei0210/pamo:0.0.2 /bin/bash
PaMO environment is ready under /workspace/pamo
git clone --recurse-submodules https://github.com/SarahWeiii/pamo.git
conda env create -f env.yaml
conda activate pamo
bash setup.sh
bash demo.sh
We offer three meshes stored under ./mesh
folder (from DTC dataset) for the demo. The results will be saved under ./examples
folder.
python example.py --input INPUT_DIR --output OUTPUT_DIR --ratio 0.001
--input
: Specify the path to the input mesh file. If not provided, it defaults to./mesh/crab.obj
.--ratio
: Set the simplification ratio to control the target reduction in the number of triangles. For example,--ratio 0.001
(default) means reducing the number of triangles to 0.1% of the original.--min-vertex
: Add this flag to constrain the minimum number of vertices after simplification, default=0.--disable_stage1
: Add this flag to skip the remeshing process (stage 1), default=false.--disable_stage3
: Add this flag to skip the safe projection process (stage 3), default=false.
from pamo import PaMO
Creates an instance of the PAMO
class using the input mesh data.
pamo = PaMO(input_mesh, use_stage1=True, use_stage3=True)
Performs mesh optimization to reduce the complexity of the mesh while preserving essential details according to specified parameters.
pamo.run(points, triangles, ratio, tolerance=4, threshold=1e-3, iter=100000)
points (float Tensor
): Vertices of the mesh. A tensor of floating-point numbers representing the 3D coordinates of each vertex.
triangles (int Tensor
): Faces of the mesh. A tensor of integers where each row represents a triangle in the mesh defined by indices into the points array.
ratio (float
): Decimation ratio specifying the target reduction in the number of triangles.
use_stage1 (bool
, default = True): Whether to use a remeshing (stage 1) before simplification.
use_stage3 (bool
, default = True): Whether to use a safe projection (stage 3) after simplification.
tolerance (int
, default = 4): Defines the number of iterations to run without edge collapses before stopping, accumulating invalid edges that do not qualify for collapsing. Lower values quicken termination, while higher values allow more iterations for potential optimization
[1] Jiang, Zhongshi, et al. "Declarative Specification for Unstructured Mesh Editing Algorithms." ACM Trans. Graph. 41.6 (2022): 251-1.
[2] Chen, Zhen, et al. "Robust low-poly meshing for general 3d models." ACM Transactions on Graphics (TOG) 42.4 (2023): 1-20.
@article{oh2025pamo,
title={PaMO: Parallel Mesh Optimization for Intersection-Free Low-Poly Modeling on the GPU},
author={Oh, Seonghun and Yuan, Xiaodi and Wei, Xinyue and Shi, Ruoxi and Xiang, Fanbo and Liu, Minghua and Su, Hao},
journal={arXiv preprint arXiv:2509.05595},
year={2025}
}