3D viewer¶
MuJoCo provides an official viewer application, written in C++, which can also be used in MuJoCo’s Python package. To avoid C++ dependencies, MuJoCo-rs provides its own 3D viewer, written in Rust.
We also provide the ability to use the official C++ based viewer, however this requires static linking to modified MuJoCo code, as described in Static linking.
Rust-native 3D viewer¶
Rust-native 3D viewer supports visualization of the 3D scene, as well as interaction via mouse and keyboard. This also includes object perturbations. Currently, no user interface is provided (buttons, drop-downs, etc.), however a sort of additional input is planned for future development.
A screenshot of the Rust 3D viewer is shown below.
Rust-native interactive 3D viewer. Showing the Spot scene from MuJoCo’s menagerie.¶
The viewer can be launched only in passive mode, i.e. it won’t run as a separate application, and needs to be periodically “synced” by the user application. The user application is the one that needs to run the actual physical simulation, like shown in Basic simulation and also below.
The viewer can be launched with MjViewer::launch_passive, like shown in the following example:
fn main() {
/* Initiate the physics simulation */
let model = MjModel::from_xml("path/to/model.xml").expect("could not load the model");
let mut data = model.make_data();
let timestep = model.opt().timestep;
/* Launch the viewer */
let mut viewer = MjViewer::launch_passive(&model, 100).expect("could not launch the viewer");
while viewer.running() {
/* Sync the simulation state with the viewer */
viewer.sync(&mut data);
/* Update the simulation state */
data.step();
std::thread::sleep(Duration::from_secs_f64(timestep));
}
}
The above example runs until the viewer is closed (MjViewer::running) and mirrors/syncs the simulation state with MjViewer::sync.
...
while viewer.running() {
/* Sync the simulation state with the viewer */
viewer.sync(&mut data);
...
}
At the beginning, we also obtained the simulation timestep (time passed in simulation per each call to
MjData::step), which is used to
sleep after the step with std::thread::sleep(Duration::from_secs_f64(timestep));.
This is optional and can be removed or reduced to run the simulation faster than realtime.
Interaction with the viewer is described with a help menu, which is shown on launch of the viewer. For more, refer to MjViewer and examples.
Wrapper of MuJoCo’s C++ 3D viewer¶
MuJoCo-rs also provides a wrapper around a modified MuJoCo’s C++ 3D viewer. Modifications to the C++ viewer are minor with the purpose of preserving future compatibility. The changes to the viewer are made to allow viewer rendering in a user-controller loop.
Attention
To avoid a major rewrite of the C++ viewer, the latter is given raw, mutable pointers to both mujoco_rs::mujoco_c::mjModel and mujoco_rs::mujoco_c::mjData, which are wrapped inside mujoco_rs::wrappers::mj_model::MjModel and mujoco_rs::wrappers::mj_data::MjData, respectively. As a result, Rust’s borrow-checker rules are violated. Although incorrect behavior is unlikely, caution is advised.
It is strongly recommended to use the Rust-native 3D viewer when none of the C++ viewer’s features are required.
Here is an example of using the C++ wrapper:
fn main() {
let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
let mut data = model.make_data(); // or MjData::new(&model);
let mut viewer = MjViewerCpp::launch_passive(&model, &data, 100);
let step = model.opt().timestep;
while viewer.running() {
viewer.sync();
viewer.render(true); // render on screen and update the fps timer
data.step();
std::thread::sleep(Duration::from_secs_f64(step));
}
}
Compared to the Rust-native viewer, the C++ wrapper doesn’t take a data parameter to the sync
method. Additionally, a call to MjViewerCpp::render
is required.