# polyscope-rs

A Rust-native 3D visualization library for geometric data, inspired by [Polyscope](https://polyscope.run).
[](https://opensource.org/licenses/MIT)
<table>
<tr>
<td align="center"><img src="docs/images/polyscope_materials.png" alt="Materials" width="400"/><br><b>Materials</b></td>
<td align="center"><img src="docs/images/polyscope_tet_mesh.png" alt="Volume Mesh" width="400"/><br><b>Volume Mesh</b></td>
</tr>
<tr>
<td align="center"><img src="docs/images/polyscope_camera_view.png" alt="Camera View" width="400"/><br><b>Camera View</b></td>
<td align="center"><img src="docs/images/polyscope_volume_grid.png" alt="Volume Grid" width="400"/><br><b>Volume Grid</b></td>
</tr>
</table>
## Overview
polyscope-rs is a viewer and user interface for 3D data such as meshes and point clouds. It allows you to register your data and quickly generate informative visualizations, either programmatically or via a dynamic GUI.
This is a Rust reimplementation of the original C++ [Polyscope](https://github.com/nmwsharp/polyscope) library, using modern Rust graphics libraries (wgpu, winit, egui).
## Disclaimer
This project is an experiment in **AI-driven software development**. I have limited Rust experience but have used [Polyscope](https://polyscope.run) extensively and contributed PRs to the original C++ library. It validates the hypothesis that languages with **informative compiler feedback** (like Rust) work better with AI-assisted development.
**Note:** This project has reached full feature parity with C++ Polyscope 2.x but is still maturing. Contributions and feedback are welcome in the [Discussions](https://github.com/xarthurx/polyscope-rs/discussions) section.
## Project Status
**Current Version:** 0.5.6
**Feature Parity:** Full parity with C++ Polyscope 2.x for all core functionality
### What's Working
| Point Clouds | ✅ Full support |
| Surface Meshes | ✅ Triangles + arbitrary polygons, full quantity support |
| Curve Networks | ✅ Full support |
| Volume Meshes | ✅ Tet/Hex cells |
| Volume Grids | ✅ Node/cell scalars, gridcube + isosurface (marching cubes) |
| Camera Views | ✅ Full support |
| Materials | ✅ 8 built-in + custom material loading |
| Color Maps | ✅ 10+ maps |
| Ground Plane | ✅ Tile/Shadow/Reflection |
| Slice Planes | ✅ Up to 4 planes |
| Groups | ✅ Hierarchical |
| Gizmos | ✅ Translate/Rotate/Scale |
| Transparency | ✅ Depth peeling (Pretty) + alpha blending (Simple) |
| Tone Mapping | ✅ HDR pipeline |
| SSAO | ✅ Ambient occlusion |
| RGBA Colors | ✅ Per-element alpha on all structures |
| Headless Rendering | ✅ `render_to_image()` / `render_to_file()` without a window |
| Screenshots | ✅ PNG/JPEG export |
| Picking | ✅ Structure/Element |
| Camera Navigation | ✅ Turntable/Free/Planar/Arcball/First-person |
| Parameterization | ✅ Checker/Grid/Local styles |
| Intrinsic Vectors | ✅ Tangent-space with symmetry |
| One-Forms | ✅ Edge-based differential forms |
| Floating Quantities | ✅ Scalar/Color/Render images |
See [docs/architecture-differences.md](docs/architecture-differences.md) for a detailed comparison with C++ Polyscope.
## Features
- **Point Clouds** - Visualize point sets with scalar, vector, and color quantities
- **Surface Meshes** - Render triangular meshes with scalars, vectors, colors, parameterization, intrinsic vectors, and one-forms
- **Curve Networks** - Display networks of curves and edges
- **Volume Meshes** - Visualize tetrahedral and hexahedral meshes
- **Volume Grids** - Render regular 3D grids with node/cell scalar quantities
- **Camera Views** - Visualize camera frustums and poses
- **Slice Planes** - Cut through geometry to see interiors
- **Groups** - Organize structures hierarchically
- **Gizmos** - Interactive transform manipulation
## Quick Start
```rust
use polyscope_rs::*;
fn main() -> Result<()> {
// Initialize polyscope
init()?;
// Register a point cloud
let points = vec![
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
];
let pc = register_point_cloud("my points", points);
// Add a scalar quantity
pc.add_scalar_quantity("height", vec![0.0, 0.5, 1.0]);
// Show the viewer
show();
Ok(())
}
```
## Headless Rendering
Render scenes without opening a window -- useful for batch processing, automated testing, and server-side rendering:
```rust
use polyscope_rs::*;
fn main() -> Result<()> {
init()?;
register_point_cloud("pts", vec![Vec3::ZERO, Vec3::X, Vec3::Y]);
// Render to pixel buffer (RGBA, 4 bytes per pixel)
let pixels = render_to_image(800, 600)?;
// Or render directly to a PNG file
render_to_file("output.png", 800, 600)?;
Ok(())
}
```
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
polyscope-rs = "0.5"
```
## Demos
Run any demo with:
```bash
cargo run --example <demo_name>
```
| Point Cloud | `cargo run --example point_cloud_demo` | Scalar, vector, and color quantities on point sets |
| Surface Mesh | `cargo run --example surface_mesh_demo` | Stanford Bunny with full quantity support |
| Curve Network | `cargo run --example curve_network_demo` | Curve and edge network visualization |
| Volume Mesh | `cargo run --example volume_mesh_demo` | Tet/hex meshes with interior face detection and quantities |
| Volume Grid | `cargo run --example volume_grid_demo` | Gridcube mode, isosurface (marching cubes), cell scalars |
| Camera View | `cargo run --example camera_view_demo` | Camera frustum visualization |
| Slice Planes | `cargo run --example slice_plane_demo` | Fragment-level slicing, volume mesh capping, gizmo control |
| Groups & Gizmos | `cargo run --example groups_and_gizmos_demo` | Hierarchical groups, transform gizmos, structure selection |
| Ground Plane | `cargo run --example ground_plane_demo` | Ground plane modes, shadows, reflections |
| Polygon Mesh | `cargo run --example polygon_mesh_demo` | Arbitrary n-gon faces (quads, hexagons, octagons) |
| Materials | `cargo run --example materials_demo` | All 8 matcap materials across structure types |
| Transparency | `cargo run --example transparency_demo` | Depth peeling (Pretty) and alpha blending (Simple) modes |
**Controls** (common to all demos):
- Left drag: Orbit camera
- Right drag: Pan camera
- Scroll: Zoom
- ESC: Exit
## Architecture
polyscope-rs uses a paradigm of **structures** and **quantities**:
- A **structure** is a geometric object in the scene (point cloud, mesh, etc.)
- A **quantity** is data associated with a structure (scalar field, vector field, colors)
For detailed documentation, see the [docs/](docs/) directory.
## Crate Structure
- `polyscope` - Main crate with public API
- `polyscope-core` - Core traits and state management
- `polyscope-render` - wgpu rendering backend
- `polyscope-ui` - egui UI integration
- `polyscope-structures` - Structure implementations
## Technology Stack
| Rendering | [wgpu](https://wgpu.rs) | OpenGL |
| UI | [egui](https://github.com/emilk/egui) | Dear ImGui (C++) |
| Math | [glam](https://github.com/bitshifter/glam-rs) | GLM |
| Windowing | [winit](https://github.com/rust-windowing/winit) | GLFW |
| Shaders | WGSL | GLSL |
| Build | Cargo | CMake |
## Comparison with C++ Polyscope
For developers familiar with the C++ version or considering migration, see:
- [Architecture Differences](docs/architecture-differences.md) - C++ vs Rust rendering implementation differences
- [Feature Status & Roadmap](docs/feature-status.md) - Feature comparison tables and planned work
- [Development Guide](docs/development-guide.md) - Adding structures/quantities, API patterns, migration tips
### Key Differences
1. **Graphics Backend**: Uses wgpu instead of OpenGL, providing native support for Vulkan, Metal, DirectX 12, and WebGPU
2. **Error Handling**: Uses Rust's `Result<T, E>` instead of exceptions
3. **Memory Safety**: Leverages Rust's ownership model for memory safety
4. **API Style**: Uses handles and closure-based access instead of raw pointers
## Platform Support
| Linux (X11/Wayland) | ✅ Tested |
| Windows | ✅ Tested |
| macOS | ✅ Should work |
| WebGPU | 🔄 Planned |
## Known Issues
- **Intermittent SIGSEGV on WSL2**: When running under Windows Subsystem for Linux 2 with GPU passthrough, the application may occasionally crash with exit code 139 (SIGSEGV) inside the GPU driver. This is a known class of WSL2/GPU driver instability issues, not a bug in polyscope-rs. Native Linux, Windows, and macOS are unaffected.
- **wgpu late binding validation workaround**: All uniform buffer bindings use explicit `min_binding_size` to work around [wgpu#7359](https://github.com/gfx-rs/wgpu/issues/7359), where late buffer binding size validation cross-contaminates between pipelines in the same command encoder. This is transparent to users but relevant for contributors adding new pipelines or bind group layouts.
- **Pretty mode non-linear opacity**: In Pretty (depth peeling) transparency mode, opacity response is non-linear compared to Simple mode. Both front and back faces of closed meshes are peeled, giving effective alpha = `2α - α²`. This is inherent to depth peeling and matches C++ Polyscope behavior. Transparency only becomes visually apparent at lower opacity values.
- **Pretty mode f16 depth precision**: The depth peeling min-depth texture uses `Rgba16Float` (half precision) because WebGPU's `R32Float` does not support blending without the optional `float32-blendable` feature. This requires a larger depth comparison epsilon (`2e-3`) than C++ Polyscope's `1e-6` (which uses 24-bit depth). Very closely spaced geometry layers (within 0.002 NDC depth) may not be correctly distinguished during peeling.
## License
MIT License - see [LICENSE](LICENSE) for details.
## Acknowledgments
This project is inspired by the original [Polyscope](https://github.com/nmwsharp/polyscope) C++ library by [Nicholas Sharp](https://nmwsharp.com).
## Contributing
Contributions are welcome! Key areas where help is needed:
- Documentation and examples
- Testing on different platforms (macOS, WebGPU)