MjViewer

Struct MjViewer 

Source
pub struct MjViewer<'m> { /* private fields */ }
Expand description

A Rust-native implementation of the MuJoCo viewer. To confirm to rust safety rules, the viewer doesn’t store a mutable reference to the MjData struct, but it instead accepts it as a parameter at its methods.

Currently supported (to be expanded in the future):

  • Visualization of the 3D scene,
  • Close via Ctrl + Q or by closing the window,
  • Body tracking via Ctrl + Alt + double left click,
  • Camera look at object via Alt + double left click,
  • Escape from tracked camera via Esc.
  • Perturbations:
    • Select the object of interested by double clicking on it,
    • Hold down Control and start dragging for rotational perturbations,
    • Hold down Control+Alt and start dragging for translational perturbations,
    • To move in the XY plane instead of the default XZ plane, hold Shift.

The MjViewer::sync method must be called to sync the state of MjViewer and MjData.

§Safety

Due to the nature of OpenGL, this should only be run in the main thread.

Implementations§

Source§

impl<'m> MjViewer<'m>

Source

pub fn launch_passive( model: &'m MjModel, scene_max_geom: usize, ) -> Result<Self, MjViewerError>

Launches the MuJoCo viewer. A Result struct is returned that either contains MjViewer or a MjViewerError. The scene_max_geom parameter defines how much space will be allocated for additional, user-defined visual-only geoms. It can thus be set to 0 if no additional geoms will be drawn by the user.

Examples found in repository?
examples/rust_viewer.rs (line 28)
25fn main() {
26    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
27    let mut data = model.make_data();  // or MjData::new(&model);
28    let mut viewer = MjViewer::launch_passive(&model, 100)
29        .expect("could not launch the viewer");
30    while viewer.running() {
31        viewer.sync(&mut data);
32        data.step();
33        std::thread::sleep(Duration::from_millis(2));
34    }
35}
More examples
Hide additional examples
examples/tendon.rs (line 43)
37fn main() {
38    /* Load the model and create data */
39    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
40    let mut data = model.make_data();  // or MjData::new(&model);
41
42    /* Launch a passive Rust-native viewer */
43    let mut viewer = MjViewer::launch_passive(&model, 0)
44        .expect("could not launch the viewer");
45
46    while viewer.running() {
47        /* Step the simulation and sync the viewer */
48        viewer.sync(&mut data);
49        data.step();
50
51        std::thread::sleep(Duration::from_secs_f64(0.002));
52    }
53}
examples/ffi_attributes.rs (line 38)
29fn main() {
30    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
31
32    /******************************************/
33    /* Access a FFI attribute */
34    let timestep = model.ffi().opt.timestep;
35    /******************************************/
36
37    let mut data = model.make_data();  // or MjData::new(&model);
38    let mut viewer = MjViewer::launch_passive(&model, 100)
39        .expect("could not launch the viewer");
40
41    while viewer.running() {
42        viewer.sync(&mut data);
43        data.step();
44        std::thread::sleep(Duration::from_secs_f64(timestep));
45    }
46}
examples/touch_sensor.rs (line 38)
32fn main() {
33    /* Load the model and create data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();  // or MjData::new(&model);
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(&model, 0)
39        .expect("could not launch the viewer");
40
41    let sensor_data_info = data.sensor("touch").unwrap();
42    while viewer.running() {
43        /* Step the simulation and sync the viewer */
44        viewer.sync(&mut data);
45        data.step();
46
47        /* Print the touch sensor output, which is the contact force */
48        println!("{}", sensor_data_info.view(&data).data[0]);
49
50        std::thread::sleep(Duration::from_secs_f64(0.002));
51    }
52}
examples/joint_view.rs (line 32)
26fn main() {
27    /* Load the model and create data */
28    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
29    let mut data = model.make_data();  // or MjData::new(&model);
30
31    /* Launch a passive Rust-native viewer */
32    let mut viewer = MjViewer::launch_passive(&model, 0)
33        .expect("could not launch the viewer");
34
35    /* Create the joint info */
36    let ball_info = data.joint("ball_joint").unwrap();
37    while viewer.running() {
38        /* Step the simulation and sync the viewer */
39        viewer.sync(&mut data);
40        data.step();
41
42        /* Obtain the view and access first three variables of `qpos` (x, y, z) */
43        let xyz = &ball_info.view(&data).qpos[..3];
44        println!("The ball's position is: {xyz:.2?}");
45
46        std::thread::sleep(Duration::from_secs_f64(0.002));
47    }
48}
examples/drawing_scene.rs (lines 38-41)
32fn main() {
33    /* Create model and data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(
39        &model,
40        10  // create space for 10 visual-only geoms
41    )
42        .expect("could not launch the viewer");
43
44    /* Obtain joint info */
45    let ball1_joint_info = data.joint("ball1_joint").unwrap();
46    let ball2_joint_info = data.joint("ball2_joint").unwrap();
47
48    /* Give the first ball some y-velocity to showcase the visualization */
49    ball1_joint_info.view_mut(&mut data).qvel[1] = 2.0;
50
51    let timestep = model.ffi().opt.timestep;
52    let mut user_scn;
53    while viewer.running() {
54        /* Step the simulation and sync the viewer */
55        viewer.sync(&mut data);
56        data.step();
57
58        /* Prepare the scene */
59        user_scn = viewer.user_scn_mut();  // obtain a mutable reference to the user scene. The method name mirrors the C++ viewer.
60        user_scn.clear_geom();  // clear existing geoms
61
62        /* Create a line, that (visually) connects the two balls we have in the example model */
63        let new_geom = user_scn.create_geom(
64            MjtGeom::mjGEOM_LINE,  // type of geom to draw.
65            None,  // size, ignore here as we set it below.
66            None,   // position: ignore here as we set it below.
67            None,   // rotational matrix: ignore here as we set it below.
68            Some([1.0, 1.0, 1.0, 1.0])  // color (rgba): pure white.
69        );
70
71        /* Read X, Y and Z coordinates of both balls. */
72        let ball1_position = ball1_joint_info.view(&data).qpos[..3]
73            .try_into().unwrap();
74        let ball2_position = ball2_joint_info.view(&data).qpos[..3]
75            .try_into().unwrap();
76
77        /* Modify the visual geom's position, orientation and length, to connect the balls */
78        new_geom.connect(
79            0.0,            // width
80            ball1_position,  // from
81            ball2_position     //  to
82        );
83
84        std::thread::sleep(Duration::from_secs_f64(timestep));
85    }
86}
Source

pub fn running(&self) -> bool

Checks whether the window is still open.

Examples found in repository?
examples/rust_viewer.rs (line 30)
25fn main() {
26    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
27    let mut data = model.make_data();  // or MjData::new(&model);
28    let mut viewer = MjViewer::launch_passive(&model, 100)
29        .expect("could not launch the viewer");
30    while viewer.running() {
31        viewer.sync(&mut data);
32        data.step();
33        std::thread::sleep(Duration::from_millis(2));
34    }
35}
More examples
Hide additional examples
examples/tendon.rs (line 46)
37fn main() {
38    /* Load the model and create data */
39    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
40    let mut data = model.make_data();  // or MjData::new(&model);
41
42    /* Launch a passive Rust-native viewer */
43    let mut viewer = MjViewer::launch_passive(&model, 0)
44        .expect("could not launch the viewer");
45
46    while viewer.running() {
47        /* Step the simulation and sync the viewer */
48        viewer.sync(&mut data);
49        data.step();
50
51        std::thread::sleep(Duration::from_secs_f64(0.002));
52    }
53}
examples/ffi_attributes.rs (line 41)
29fn main() {
30    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
31
32    /******************************************/
33    /* Access a FFI attribute */
34    let timestep = model.ffi().opt.timestep;
35    /******************************************/
36
37    let mut data = model.make_data();  // or MjData::new(&model);
38    let mut viewer = MjViewer::launch_passive(&model, 100)
39        .expect("could not launch the viewer");
40
41    while viewer.running() {
42        viewer.sync(&mut data);
43        data.step();
44        std::thread::sleep(Duration::from_secs_f64(timestep));
45    }
46}
examples/touch_sensor.rs (line 42)
32fn main() {
33    /* Load the model and create data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();  // or MjData::new(&model);
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(&model, 0)
39        .expect("could not launch the viewer");
40
41    let sensor_data_info = data.sensor("touch").unwrap();
42    while viewer.running() {
43        /* Step the simulation and sync the viewer */
44        viewer.sync(&mut data);
45        data.step();
46
47        /* Print the touch sensor output, which is the contact force */
48        println!("{}", sensor_data_info.view(&data).data[0]);
49
50        std::thread::sleep(Duration::from_secs_f64(0.002));
51    }
52}
examples/joint_view.rs (line 37)
26fn main() {
27    /* Load the model and create data */
28    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
29    let mut data = model.make_data();  // or MjData::new(&model);
30
31    /* Launch a passive Rust-native viewer */
32    let mut viewer = MjViewer::launch_passive(&model, 0)
33        .expect("could not launch the viewer");
34
35    /* Create the joint info */
36    let ball_info = data.joint("ball_joint").unwrap();
37    while viewer.running() {
38        /* Step the simulation and sync the viewer */
39        viewer.sync(&mut data);
40        data.step();
41
42        /* Obtain the view and access first three variables of `qpos` (x, y, z) */
43        let xyz = &ball_info.view(&data).qpos[..3];
44        println!("The ball's position is: {xyz:.2?}");
45
46        std::thread::sleep(Duration::from_secs_f64(0.002));
47    }
48}
examples/drawing_scene.rs (line 53)
32fn main() {
33    /* Create model and data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(
39        &model,
40        10  // create space for 10 visual-only geoms
41    )
42        .expect("could not launch the viewer");
43
44    /* Obtain joint info */
45    let ball1_joint_info = data.joint("ball1_joint").unwrap();
46    let ball2_joint_info = data.joint("ball2_joint").unwrap();
47
48    /* Give the first ball some y-velocity to showcase the visualization */
49    ball1_joint_info.view_mut(&mut data).qvel[1] = 2.0;
50
51    let timestep = model.ffi().opt.timestep;
52    let mut user_scn;
53    while viewer.running() {
54        /* Step the simulation and sync the viewer */
55        viewer.sync(&mut data);
56        data.step();
57
58        /* Prepare the scene */
59        user_scn = viewer.user_scn_mut();  // obtain a mutable reference to the user scene. The method name mirrors the C++ viewer.
60        user_scn.clear_geom();  // clear existing geoms
61
62        /* Create a line, that (visually) connects the two balls we have in the example model */
63        let new_geom = user_scn.create_geom(
64            MjtGeom::mjGEOM_LINE,  // type of geom to draw.
65            None,  // size, ignore here as we set it below.
66            None,   // position: ignore here as we set it below.
67            None,   // rotational matrix: ignore here as we set it below.
68            Some([1.0, 1.0, 1.0, 1.0])  // color (rgba): pure white.
69        );
70
71        /* Read X, Y and Z coordinates of both balls. */
72        let ball1_position = ball1_joint_info.view(&data).qpos[..3]
73            .try_into().unwrap();
74        let ball2_position = ball2_joint_info.view(&data).qpos[..3]
75            .try_into().unwrap();
76
77        /* Modify the visual geom's position, orientation and length, to connect the balls */
78        new_geom.connect(
79            0.0,            // width
80            ball1_position,  // from
81            ball2_position     //  to
82        );
83
84        std::thread::sleep(Duration::from_secs_f64(timestep));
85    }
86}
Source

pub fn user_scn(&self) -> &MjvScene<'m>

Returns an immutable reference to a user scene for drawing custom visual-only geoms.

Source

pub fn user_scn_mut(&mut self) -> &mut MjvScene<'m>

Returns a mutable reference to a user scene for drawing custom visual-only geoms.

Examples found in repository?
examples/drawing_scene.rs (line 59)
32fn main() {
33    /* Create model and data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(
39        &model,
40        10  // create space for 10 visual-only geoms
41    )
42        .expect("could not launch the viewer");
43
44    /* Obtain joint info */
45    let ball1_joint_info = data.joint("ball1_joint").unwrap();
46    let ball2_joint_info = data.joint("ball2_joint").unwrap();
47
48    /* Give the first ball some y-velocity to showcase the visualization */
49    ball1_joint_info.view_mut(&mut data).qvel[1] = 2.0;
50
51    let timestep = model.ffi().opt.timestep;
52    let mut user_scn;
53    while viewer.running() {
54        /* Step the simulation and sync the viewer */
55        viewer.sync(&mut data);
56        data.step();
57
58        /* Prepare the scene */
59        user_scn = viewer.user_scn_mut();  // obtain a mutable reference to the user scene. The method name mirrors the C++ viewer.
60        user_scn.clear_geom();  // clear existing geoms
61
62        /* Create a line, that (visually) connects the two balls we have in the example model */
63        let new_geom = user_scn.create_geom(
64            MjtGeom::mjGEOM_LINE,  // type of geom to draw.
65            None,  // size, ignore here as we set it below.
66            None,   // position: ignore here as we set it below.
67            None,   // rotational matrix: ignore here as we set it below.
68            Some([1.0, 1.0, 1.0, 1.0])  // color (rgba): pure white.
69        );
70
71        /* Read X, Y and Z coordinates of both balls. */
72        let ball1_position = ball1_joint_info.view(&data).qpos[..3]
73            .try_into().unwrap();
74        let ball2_position = ball2_joint_info.view(&data).qpos[..3]
75            .try_into().unwrap();
76
77        /* Modify the visual geom's position, orientation and length, to connect the balls */
78        new_geom.connect(
79            0.0,            // width
80            ball1_position,  // from
81            ball2_position     //  to
82        );
83
84        std::thread::sleep(Duration::from_secs_f64(timestep));
85    }
86}
Source

pub fn sync(&mut self, data: &mut MjData<'_>)

Syncs the state of data with the viewer as well as perform rendering on the viewer.

Examples found in repository?
examples/rust_viewer.rs (line 31)
25fn main() {
26    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
27    let mut data = model.make_data();  // or MjData::new(&model);
28    let mut viewer = MjViewer::launch_passive(&model, 100)
29        .expect("could not launch the viewer");
30    while viewer.running() {
31        viewer.sync(&mut data);
32        data.step();
33        std::thread::sleep(Duration::from_millis(2));
34    }
35}
More examples
Hide additional examples
examples/tendon.rs (line 48)
37fn main() {
38    /* Load the model and create data */
39    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
40    let mut data = model.make_data();  // or MjData::new(&model);
41
42    /* Launch a passive Rust-native viewer */
43    let mut viewer = MjViewer::launch_passive(&model, 0)
44        .expect("could not launch the viewer");
45
46    while viewer.running() {
47        /* Step the simulation and sync the viewer */
48        viewer.sync(&mut data);
49        data.step();
50
51        std::thread::sleep(Duration::from_secs_f64(0.002));
52    }
53}
examples/ffi_attributes.rs (line 42)
29fn main() {
30    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
31
32    /******************************************/
33    /* Access a FFI attribute */
34    let timestep = model.ffi().opt.timestep;
35    /******************************************/
36
37    let mut data = model.make_data();  // or MjData::new(&model);
38    let mut viewer = MjViewer::launch_passive(&model, 100)
39        .expect("could not launch the viewer");
40
41    while viewer.running() {
42        viewer.sync(&mut data);
43        data.step();
44        std::thread::sleep(Duration::from_secs_f64(timestep));
45    }
46}
examples/touch_sensor.rs (line 44)
32fn main() {
33    /* Load the model and create data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();  // or MjData::new(&model);
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(&model, 0)
39        .expect("could not launch the viewer");
40
41    let sensor_data_info = data.sensor("touch").unwrap();
42    while viewer.running() {
43        /* Step the simulation and sync the viewer */
44        viewer.sync(&mut data);
45        data.step();
46
47        /* Print the touch sensor output, which is the contact force */
48        println!("{}", sensor_data_info.view(&data).data[0]);
49
50        std::thread::sleep(Duration::from_secs_f64(0.002));
51    }
52}
examples/joint_view.rs (line 39)
26fn main() {
27    /* Load the model and create data */
28    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
29    let mut data = model.make_data();  // or MjData::new(&model);
30
31    /* Launch a passive Rust-native viewer */
32    let mut viewer = MjViewer::launch_passive(&model, 0)
33        .expect("could not launch the viewer");
34
35    /* Create the joint info */
36    let ball_info = data.joint("ball_joint").unwrap();
37    while viewer.running() {
38        /* Step the simulation and sync the viewer */
39        viewer.sync(&mut data);
40        data.step();
41
42        /* Obtain the view and access first three variables of `qpos` (x, y, z) */
43        let xyz = &ball_info.view(&data).qpos[..3];
44        println!("The ball's position is: {xyz:.2?}");
45
46        std::thread::sleep(Duration::from_secs_f64(0.002));
47    }
48}
examples/drawing_scene.rs (line 55)
32fn main() {
33    /* Create model and data */
34    let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
35    let mut data = model.make_data();
36
37    /* Launch a passive Rust-native viewer */
38    let mut viewer = MjViewer::launch_passive(
39        &model,
40        10  // create space for 10 visual-only geoms
41    )
42        .expect("could not launch the viewer");
43
44    /* Obtain joint info */
45    let ball1_joint_info = data.joint("ball1_joint").unwrap();
46    let ball2_joint_info = data.joint("ball2_joint").unwrap();
47
48    /* Give the first ball some y-velocity to showcase the visualization */
49    ball1_joint_info.view_mut(&mut data).qvel[1] = 2.0;
50
51    let timestep = model.ffi().opt.timestep;
52    let mut user_scn;
53    while viewer.running() {
54        /* Step the simulation and sync the viewer */
55        viewer.sync(&mut data);
56        data.step();
57
58        /* Prepare the scene */
59        user_scn = viewer.user_scn_mut();  // obtain a mutable reference to the user scene. The method name mirrors the C++ viewer.
60        user_scn.clear_geom();  // clear existing geoms
61
62        /* Create a line, that (visually) connects the two balls we have in the example model */
63        let new_geom = user_scn.create_geom(
64            MjtGeom::mjGEOM_LINE,  // type of geom to draw.
65            None,  // size, ignore here as we set it below.
66            None,   // position: ignore here as we set it below.
67            None,   // rotational matrix: ignore here as we set it below.
68            Some([1.0, 1.0, 1.0, 1.0])  // color (rgba): pure white.
69        );
70
71        /* Read X, Y and Z coordinates of both balls. */
72        let ball1_position = ball1_joint_info.view(&data).qpos[..3]
73            .try_into().unwrap();
74        let ball2_position = ball2_joint_info.view(&data).qpos[..3]
75            .try_into().unwrap();
76
77        /* Modify the visual geom's position, orientation and length, to connect the balls */
78        new_geom.connect(
79            0.0,            // width
80            ball1_position,  // from
81            ball2_position     //  to
82        );
83
84        std::thread::sleep(Duration::from_secs_f64(timestep));
85    }
86}

Trait Implementations§

Source§

impl<'m> Debug for MjViewer<'m>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'m> Freeze for MjViewer<'m>

§

impl<'m> RefUnwindSafe for MjViewer<'m>

§

impl<'m> !Send for MjViewer<'m>

§

impl<'m> !Sync for MjViewer<'m>

§

impl<'m> Unpin for MjViewer<'m>

§

impl<'m> UnwindSafe for MjViewer<'m>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.