From 52317058ba9d44fac335592b55b5987fd45381de Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Wed, 15 Jul 2026 06:49:46 -0700 Subject: [PATCH] Add pan/tilt motions to mjv_moveCamera. PiperOrigin-RevId: 948308546 Change-Id: I2724b889759e652ed50d03bf97f3c7125cd0eb56 --- doc/includes/references.h | 16 +++++++++------- include/mujoco/mjvisualize.h | 16 +++++++++------- python/mujoco/introspect/enums.py | 2 ++ src/engine/engine_vis_interact.c | 19 +++++++++++++++++++ unity/Runtime/Bindings/MjBindings.cs | 2 ++ wasm/codegen/generated/bindings.cc | 4 +++- 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/doc/includes/references.h b/doc/includes/references.h index e813ba53..2dba3b1a 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -3025,13 +3025,15 @@ typedef enum mjtCatBit_ { // bitflags for mjvGeom category } mjtCatBit; typedef enum mjtMouse_ { // mouse interaction mode mjMOUSE_NONE = 0, // no action - mjMOUSE_ROTATE_V, // rotate, vertical plane - mjMOUSE_ROTATE_H, // rotate, horizontal plane - mjMOUSE_MOVE_V, // move, vertical plane - mjMOUSE_MOVE_H, // move, horizontal plane - mjMOUSE_ZOOM, // zoom - mjMOUSE_MOVE_V_REL, // move, vertical plane, relative to target - mjMOUSE_MOVE_H_REL, // move, horizontal plane, relative to target + mjMOUSE_ROTATE_V, // rotate (orbit) vertically + mjMOUSE_ROTATE_H, // rotate (orbit) horizontally + mjMOUSE_MOVE_V, // move along vertical plane + mjMOUSE_MOVE_H, // move along horizontal plane + mjMOUSE_ZOOM, // zoom (towards/away from lookat point) + mjMOUSE_MOVE_V_REL, // move (truck, pedestal), vertical plane rel. to target + mjMOUSE_MOVE_H_REL, // move (truck, dolly), horizontal plane rel. to target + mjMOUSE_TURN_V, // turn (tilt) vertically + mjMOUSE_TURN_H, // turn (pan) horizontally } mjtMouse; typedef enum mjtPertBit_ { // mouse perturbations mjPERT_TRANSLATE = 1, // translation diff --git a/include/mujoco/mjvisualize.h b/include/mujoco/mjvisualize.h index b68234c0..f9a4840f 100644 --- a/include/mujoco/mjvisualize.h +++ b/include/mujoco/mjvisualize.h @@ -40,13 +40,15 @@ typedef enum mjtCatBit_ { // bitflags for mjvGeom category typedef enum mjtMouse_ { // mouse interaction mode mjMOUSE_NONE = 0, // no action - mjMOUSE_ROTATE_V, // rotate, vertical plane - mjMOUSE_ROTATE_H, // rotate, horizontal plane - mjMOUSE_MOVE_V, // move, vertical plane - mjMOUSE_MOVE_H, // move, horizontal plane - mjMOUSE_ZOOM, // zoom - mjMOUSE_MOVE_V_REL, // move, vertical plane, relative to target - mjMOUSE_MOVE_H_REL, // move, horizontal plane, relative to target + mjMOUSE_ROTATE_V, // rotate (orbit) vertically + mjMOUSE_ROTATE_H, // rotate (orbit) horizontally + mjMOUSE_MOVE_V, // move along vertical plane + mjMOUSE_MOVE_H, // move along horizontal plane + mjMOUSE_ZOOM, // zoom (towards/away from lookat point) + mjMOUSE_MOVE_V_REL, // move (truck, pedestal), vertical plane rel. to target + mjMOUSE_MOVE_H_REL, // move (truck, dolly), horizontal plane rel. to target + mjMOUSE_TURN_V, // turn (tilt) vertically + mjMOUSE_TURN_H, // turn (pan) horizontally } mjtMouse; diff --git a/python/mujoco/introspect/enums.py b/python/mujoco/introspect/enums.py index ee8c706b..dfa54efd 100644 --- a/python/mujoco/introspect/enums.py +++ b/python/mujoco/introspect/enums.py @@ -782,6 +782,8 @@ ENUMS: Mapping[str, EnumDecl] = dict([ ('mjMOUSE_ZOOM', 5), ('mjMOUSE_MOVE_V_REL', 6), ('mjMOUSE_MOVE_H_REL', 7), + ('mjMOUSE_TURN_V', 8), + ('mjMOUSE_TURN_H', 9), ]), )), ('mjtPertBit', diff --git a/src/engine/engine_vis_interact.c b/src/engine/engine_vis_interact.c index bc86a273..6822cdc9 100644 --- a/src/engine/engine_vis_interact.c +++ b/src/engine/engine_vis_interact.c @@ -366,6 +366,25 @@ void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy, mj mju_addToScl3(cam->lookat, vec, -scl); break; + case mjMOUSE_TURN_V: + case mjMOUSE_TURN_H: + if (cam->type == mjCAMERA_TRACKING) { + return; + } + + mjv_cameraFrame(headpos, forward, NULL, NULL, NULL, cam); + if (action == mjMOUSE_TURN_H) { + cam->azimuth -= reldx * 180.0; + } + if (action == mjMOUSE_TURN_V) { + cam->elevation -= reldy * 180.0; + } + mjv_cameraFrame(NULL, forward, NULL, NULL, NULL, cam); + + // move lookat point so that camera faces new direction + mju_addScl3(cam->lookat, headpos, forward, cam->distance); + break; + case mjMOUSE_ZOOM: cam->distance -= mju_log(1 + cam->distance/m->stat.extent/3) * reldy * 9 * m->stat.extent; break; diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 97e5c59c..191a22f4 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -616,6 +616,8 @@ public enum mjtMouse : int{ mjMOUSE_ZOOM = 5, mjMOUSE_MOVE_V_REL = 6, mjMOUSE_MOVE_H_REL = 7, + mjMOUSE_TURN_V = 8, + mjMOUSE_TURN_H = 9, } public enum mjtPertBit : int{ mjPERT_TRANSLATE = 1, diff --git a/wasm/codegen/generated/bindings.cc b/wasm/codegen/generated/bindings.cc index 88dc3484..62317c1e 100644 --- a/wasm/codegen/generated/bindings.cc +++ b/wasm/codegen/generated/bindings.cc @@ -4198,7 +4198,9 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { .value("mjMOUSE_MOVE_H", mjMOUSE_MOVE_H) .value("mjMOUSE_ZOOM", mjMOUSE_ZOOM) .value("mjMOUSE_MOVE_V_REL", mjMOUSE_MOVE_V_REL) - .value("mjMOUSE_MOVE_H_REL", mjMOUSE_MOVE_H_REL); + .value("mjMOUSE_MOVE_H_REL", mjMOUSE_MOVE_H_REL) + .value("mjMOUSE_TURN_V", mjMOUSE_TURN_V) + .value("mjMOUSE_TURN_H", mjMOUSE_TURN_H); enum_("mjtObj") .value("mjOBJ_UNKNOWN", mjOBJ_UNKNOWN) .value("mjOBJ_BODY", mjOBJ_BODY)