Teprite is a Rust-based immersive visualization renderer built on top of Bevy. It’s designed for multi-display / CAVE-style rendering by running your Bevy app as a logic process that spawns one or more render processes. World state is replicated from the logic process to render processes, and render processes present the scene to the configured screens.
- Platforms: macOS + Linux (Windows is WIP)
- Render backends: Vulkan / Metal
- Tracking + input: optional VRPN head tracking and joystick/button events
NRL SWR: SWR 26-061
Tephrite is built off of bevy. You can build your app as usual, and then adopt Teprite’s rendering architecture. To do so:
- Use a supported version of Bevy in your Cargo.toml:
bevy = "0.18.1"- Ensure that you are patching Bevy:
[patch.crates-io]
bevy = { git = "https://github.com/nicholasbl/bevy", branch = "cave_patches" }-
Structure your app to start via a single plugin.
-
Call
tephrite_rs::run(YourPlugin)(notApp::run()directly). -
Make sure you have a valid configuration for your immersive setup. If not, your app will be in simulator mode.
-
Run!
The examples show the intended pattern: define a Bevy plugin, then call tephrite_rs::run(MyPlugin).
use bevy::prelude::*;
use tephrite_rs::prelude::*;
struct MyPlugin;
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup);
}
}
fn setup(mut commands: Commands) {
commands.spawn((DirectionalLight::default(), Transform::default(), Replicated));
}
fn main() {
tephrite_rs::run(MyPlugin);
}- Logic process
- Builds a normal Bevy
Appand adds your plugin(s) - Spawns N render processes (N = number of
[[screens]]entries in the config) - Writes replication data (entities/components/assets/resources) to shared memory
- Optionally consumes VRPN and produces “head” + joystick/button events
- Builds a normal Bevy
- Render process(es)
- Starts renderer and opens a window for its assigned
[[screen]] - Reads replication data and reconstructs the replicated world
- Renders the replicated scene
- Starts renderer and opens a window for its assigned
Replication is opt-in: mark what should appear in the render process.
Replicated: tag an entity to replicate itPropagateReplication: propagate replication through hierarchy (parent/children)
The prelude exports the most commonly used pieces:
tephrite_rs::prelude::runReplicated,PropagateReplication- input utilities (navigator + interactors)
Head,EnvironmentLighting
Teprite loads a TOML configuration file at startup.
Search order:
$TEPH_CONFIG_PATH~/.teph/config.toml~/.config/teph.toml/opt/teph/config.toml/etc/teph/config.toml
You can start from assets/config_example.toml.
use_offaxis = true # enable immersive mode (simulator mode otherwise)
debug_renderer = false # enable renderer-side debug logging
[render]
api = "vulkan" # one of: "vulkan", "metal", "opengl"
[vrpn]
head = "Head0/0@127.0.0.1:3883" # optional; sensor is optional and defaults to 0
joystick = "Joy0@127.0.0.1:3883,Joy1/1@127.0.0.1:3883" # optional, comma-separated
coordinate_transform = "vrpn_bevy" # optional: "vrpn_bevy" (default) or "identity"Notes:
use_offaxis = falseis appropriate for local single-display development.debug_renderercontrols render-process logging (the logic process also uses it to pass a debug env var to children).- VRPN addresses are parsed as
sender@host:portorsender/sensor@host:port. coordinate_transform = "vrpn_bevy"preserves Tephrite's historical VRPN mapping; use"identity"when the VRPN server already reports coordinates in Tephrite/Bevy space.
Each [[display]] describes a physical display plane in 3D space (room coordinates) plus its pixel resolution. If using VRPN, ensure that these coordinates are the same as the tracker coordinates.
[[displays]]
lower_left = [-1.0, 0.0, 0.0]
lower_right = [ 1.0, 0.0, 0.0]
upper_right = [ 1.0, 1.0, 0.0]Semantics:
- The three corners define the display plane and orientation.
Each [[screen]] corresponds to one spawned render process. The Nth entry in [[screens]] is assigned to child process rank N.
[[screens]]
display = 0 # index into [[displays]]
card_index = 0 # optional GPU device index (backend-dependent)
x_display = ":0.0" # optional X11 display string (Linux)
fullscreen = false # optional (default false)
is_right = false # optional (default false); stereo eye selection when use_offaxis=trueNotes:
- If you want a single window, define exactly one
[[screens]]entry. is_rightonly matters whenuse_offaxis = true; it selects left/right eye parameters for stereo setups.x_displayis primarily for multi-X-screen Linux setups.
use_offaxis = false
debug_renderer = false
[[displays]]
lower_left = [-1.0, 0.0, 0.0]
lower_right = [ 1.0, 0.0, 0.0]
upper_right = [ 1.0, 1.0, 0.0]
resolution = [1280, 720]
[[screens]]
display = 0
fullscreen = falseVRPN is optional:
- If
[vrpn].headis set, Teprite spawns a replicatedHeadentity and updates its transform from VRPN. - If
[vrpn].joystickis set, Teprite spawns anInteractorentity and emits button/axis messages from VRPN input.
- Starter:
cargo run --example mesh - Also included:
basic_animation,load_mesh,image_based_lighting
Use cargo test -- --test-threads=1 to avoid some tests deadlocking.
MIT. See LICENSE.