viewport-lib
viewport-lib is a gpu-accelerated 3D viewport library for rust. It works with any GUI framework that gives you access to a wgpu device, queue, and render target: eframe/egui, winit, Iced, Slint, and others.
viewport-lib covers rendering, cameras, and post-processing. Your application owns the window, event loop, and tool state.
WARNING: The viewport has only recently been extracted as a stand-alone library from a separate project and the API is still somewhat unstable. When things become more solid I will release v1.0.0
Core features
- Geometry: mesh, point cloud, polyline, volume, glyph, and streamtube rendering
- Lighting: directional, point, and spot lights; shadow maps;
- Materials: PBR and Blinn-Phong shading, normal maps, transparency
- Scene tools: clip planes, section views, scalar coloring, and colourmaps
- Camera: arcball orbit, orthographic projection, view presets, smooth animation, and frame-to-selection
- Interaction: CPU/GPU picking, rectangle selection, transform gizmos, and snapping
- Overlays: labels, scalar bar, rulers, and axes indicator
Examples
The examples/ directory contains working integrations for several GUI frameworks.
- eframe-showcase: run this first: demonstrates many of the viewport's built-in capabilities across multiple showcases (not exhaustive).
- eframe-minimal: the simplest integration: start here if you want to understand the minimal setup.
- eframe-primitives: demonstrates the built-in geometry primitives.
- eframe-viewport: a mid-complexity example with scene graph, picking, and gizmos.
- eframe-input-controllers: shows custom input bindings and controller configuration.
Other examples: winit-viewport, winit-showcase, winit-primitives, winit-multi-viewport, iced-viewport, slint-viewport, gtk4-viewport
Run examples with:
cargo run --release --example eframe-showcase
Quick start
In a typical app you will need to use both the renderer (to build and submit a FrameData) and the input handler to define and handle keys and events.
Rendering
use ;
use ;
// Upload the cube primitive mesh once at startup
let mesh_index = renderer.resources_mut.upload_mesh_data?;
// Build a frame each render tick
let camera = default;
let model = from_translation;
let item = SceneRenderItem ;
let fd = new;
renderer.prepare;
// then call the renderer -- this will depend on what GUI you are using
// renderer.paint_to(&mut render_pass, &fd);
Input handling
OrbitCameraController is one of the available built-in controllers. You can also build your own controller directly on top of ViewportInput and ViewportBinding if you need different navigation behaviour - but OrbitCameraController is a good starting point. Push events each frame, then call apply_to_camera to orbit/pan/zoom and get back an ActionFrame for the rest of your input logic.
use ;
// --- app state ---
let mut orbit = new;
let mut manip = new;
// prime the controller before the first frame
orbit.begin_frame;
// --- each frame ---
// 1. drive camera navigation; get the action frame for this frame
let frame = if manip.is_active else ;
// 2. drive the manipulation controller
let ctx = ManipulationContext ;
match manip.update
// 3. reset for next frame
orbit.begin_frame;
License
This project is licensed under the GNU General Public License v3.0. See LICENSE for details. Get in contact for details on purchasing a commercial license.