348 objects from Thingi10K packed into a 240×123×100mm tray at 60.8% density
Cross-section reveals dense interior packing
GPU-accelerated 3D bin packing using FFT-based collision detection.
This library implements (unofficially) the spectral packing algorithm described in Dense, Interlocking-Free and Scalable Spectral Packing of Generic 3D Objects (SIGGRAPH 2023), which uses Fast Fourier Transform (FFT) operations for efficient collision detection and optimal placement finding.
- GPU-accelerated packing using CUDA FFT operations
- Simple Python API with NumPy integration
- Blender export for visualization and rendering
- Python: 3.8+
- CUDA: 11.0+ with CUDA Toolkit
- GPU: NVIDIA GPU with compute capability 6.0+
- OS: Linux (tested on Ubuntu)
- CMake 3.18+
- C++17 compiler (gcc 8+)
- CUDA Toolkit
- FFTW3 library (
libfftw3-dev) - pybind11
# Clone the repository
git clone https://github.com/Vrroom/psacking.git
cd psacking
# Install build dependencies
pip install scikit-build-core pybind11 cmake ninja
# Install the package
pip install -e .# CUDA Toolkit (if not already installed)
sudo apt install nvidia-cuda-toolkit
# FFTW3
sudo apt install libfftw3-dev
# Build tools
sudo apt install cmake build-essentialfrom spectral_packer import BinPacker
import numpy as np
# Create a packer with a 100x100x100 voxel tray
packer = BinPacker(tray_size=(100, 100, 100))
# Create some voxelized items (3D numpy arrays)
items = [
np.ones((5, 5, 5), dtype=np.int32), # 5x5x5 cube
np.ones((3, 3, 8), dtype=np.int32), # 3x3x8 tall box
np.ones((6, 6, 2), dtype=np.int32), # 6x6x2 flat box
]
# Pack the items
result = packer.pack_voxels(items)
print(f"Packed {result.num_placed}/{len(items)} items")
print(f"Packing density: {result.density:.1%}")from spectral_packer import BinPacker
packer = BinPacker(tray_size=(100, 100, 100))
# Pack directly from STL files
result = packer.pack_files([
"item1.stl",
"item2.stl",
"item3.stl"
])
print(result.summary())Main class for 3D bin packing operations.
BinPacker(
tray_size: Tuple[int, int, int],
voxel_resolution: int = 128,
height_penalty: float = 1e8
)Methods:
pack_files(paths, sort_by_volume=True)- Pack meshes from filespack_voxels(items, sort_by_volume=True)- Pack voxelized itemspack_single(item, tray=None)- Find placement for single item
Results from a packing operation.
Attributes:
tray: Final voxel grid with placed itemsplacements: List of placement info for each itemnum_placed: Number of successfully placed itemsnum_failed: Number of items that couldn't be placeddensity: Packing density (0.0 to 1.0)total_volume: Total occupied voxels
Methods:
get_item_mask(item_id)- Get binary mask for specific itemsave_vox(path)- Save to MagicaVoxel formatsummary()- Get human-readable summary
Mesh to voxel grid converter.
Voxelizer(resolution: int = 128)Methods:
voxelize_file(path)- Voxelize a mesh filevoxelize_mesh(vertices, faces)- Voxelize from arrays
The spectral packing algorithm works as follows:
- Voxelization: Convert 3D meshes to binary occupancy grids (using VoxSurf)
- Collision Detection: Use FFT correlation to efficiently compute where items can be placed without collision
- Scoring: For each valid position, compute a score based on:
- Proximity to existing items (encourages tight packing)
- Height penalty (prefers bottom placements)
- Greedy Placement: Place items one by one in descending volume order
See the examples/ directory for complete examples:
basic_packing.py- Simple packing demonstrationbenchmark.py- Performance benchmarkinggithub_teaser.py- Generate the README teaser renders (requires Blender)
The teaser images at the top of this README were generated using examples/github_teaser.py. This script:
- Filters Thingi10K objects to similar physical sizes (20-50mm)
- Uses pitch=1.0 so 1 voxel = 1mm
- Packs into a 240×123×100mm tray
- Exports to Blender and renders high-quality images
# Run from project root (requires Blender with spectral_packer installed)
~/blender-4.5.0-linux-x64/blender --background --python examples/github_teaser.pyTo install spectral_packer for Blender's Python:
# Find Blender's Python
BLENDER_PYTHON=~/blender-4.5.0-linux-x64/4.5/python/bin/python3.11
# Install dependencies
$BLENDER_PYTHON -m pip install numpy trimesh
# Install spectral_packer
$BLENDER_PYTHON -m pip install -e /path/to/psacking# Install test dependencies
pip install pytest pytest-cov
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=spectral_packer# Create a build directory
mkdir build && cd build
# Configure with CMake
cmake .. -DBUILD_PYTHON_BINDINGS=ON
# Build
make -j$(nproc)psacking/
├── README.md # This file
├── pyproject.toml # Python package config
├── CMakeLists.txt # Root CMake config
├── spectral_packing/ # C++/CUDA implementation
│ ├── bindings.cpp # pybind11 bindings
│ ├── packing.cpp # Core algorithm
│ ├── fft3.cu # CUDA FFT operations
│ └── VoxSurf/ # Voxelization library
├── spectral_packer/ # Python package
│ ├── __init__.py # Public API
│ ├── packer.py # BinPacker class
│ ├── mesh_io.py # Mesh loading
│ └── voxelizer.py # Voxelization
├── tests/ # Test suite
└── examples/ # Example scripts
MIT License
If you use this code in your research, please cite the original paper:
@article{10.1145/3592126,
author = {Cui, Qiaodong and Rong, Victor and Chen, Desai and Matusik, Wojciech},
title = {Dense, Interlocking-Free and Scalable Spectral Packing of Generic 3D Objects},
year = {2023},
issue_date = {August 2023},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
volume = {42},
number = {4},
issn = {0730-0301},
url = {https://doi.org/10.1145/3592126},
doi = {10.1145/3592126},
abstract = {Packing 3D objects into a known container is a very common task in many industries such as packaging, transportation, and manufacturing. This important problem is known to be NP-hard and even approximate solutions are challenging. This is due to the difficulty of handling interactions between objects with arbitrary 3D geometries and a vast combinatorial search space. Moreover, the packing must be interlocking-free for real-world applications. In this work, we first introduce a novel packing algorithm to search for placement locations given an object. Our method leverages a discrete voxel representation. We formulate collisions between objects as correlations of functions computed efficiently using Fast Fourier Transform (FFT). To determine the best placements, we utilize a novel cost function, which is also computed efficiently using FFT. Finally, we show how interlocking detection and correction can be addressed in the same framework resulting in interlocking-free packing. We propose a challenging benchmark with thousands of 3D objects to evaluate our algorithm. Our method demonstrates state-of-the-art performance on the benchmark when compared to existing methods in both density and speed.},
journal = {ACM Trans. Graph.},
month = jul,
articleno = {141},
numpages = {14},
keywords = {3D packing}
}- Dense, Interlocking-Free and Scalable Spectral Packing of Generic 3D Objects - Original paper (SIGGRAPH 2023)
- pybind11 - C++/Python bindings
- trimesh - Mesh processing library
- VoxSurf - For extracting voxels from STL

