From b966a37855d1451f288d93ec79d52728538228d0 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Fri, 5 Aug 2022 01:03:08 -0700 Subject: [PATCH] Add optional azimuth and elevation to initial free camera. - Add `azimuth` and `elevation` to `visual.global`. - Add `mjv_defaultFreeCamera`. - Use `mjv_defaultFreeCamera` in `simulate`. PiperOrigin-RevId: 465505244 Change-Id: I61e60f14a990d4e2d220958adb75c325001978ee --- doc/APIreference.rst | 13 ++++++++++++- doc/XMLreference.rst | 17 ++++++++++++++--- doc/changelog.rst | 3 +++ include/mujoco/mjmodel.h | 4 +++- include/mujoco/mujoco.h | 3 +++ introspect/functions.py | 20 ++++++++++++++++++++ python/mujoco/functions.cc | 1 + sample/record.cc | 7 ++----- simulate/simulate.cc | 11 +++-------- src/engine/engine_io.c | 2 ++ src/engine/engine_vis_init.c | 17 +++++++++++++++++ src/engine/engine_vis_init.h | 3 +++ src/xml/xml_native_reader.cc | 5 ++++- src/xml/xml_native_writer.cc | 2 ++ unity/Runtime/Bindings/MujocoBindings.cs | 3 +++ 15 files changed, 92 insertions(+), 19 deletions(-) diff --git a/doc/APIreference.rst b/doc/APIreference.rst index 9f4baa52..d1d69629 100644 --- a/doc/APIreference.rst +++ b/doc/APIreference.rst @@ -1230,7 +1230,7 @@ mjVisual { struct // global parameters { - float fovy; // y-field of view (deg) for free camera + float fovy; // y-field of view for free camera (degrees) float ipd; // inter-pupilary distance for free camera float linewidth; // line width for wireframe and ray rendering float glow; // glow coefficient for selected body @@ -4722,6 +4722,17 @@ mjv_defaultCamera Set default camera. +.. _mjv_defaultFreeCamera: + +mjv_defaultFreeCamera +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: C + + void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam); + +Set default free camera. + .. _mjv_defaultPerturb: mjv_defaultPerturb diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 820b2213..2126d773 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -120,9 +120,11 @@ in the second column of the table have the following meaning: | | | :class: mjcf-attributes | | | | | | | | +-------------------------+-------------------------+-------------------------+ | -| | | | :at:`fovy` | :at:`ipd` | :at:`linewidth` | | +| | | | :at:`fovy` | :at:`ipd` | :at:`azimuth` | | | | | +-------------------------+-------------------------+-------------------------+ | -| | | | :at:`glow` | :at:`offwidth` | :at:`offheight` | | +| | | | :at:`elevation` | :at:`linewidth` | :at:`glow` | | +| | | +-------------------------+-------------------------+-------------------------+ | +| | | | :at:`offwidth` | :at:`offheight` | | | | | | +-------------------------+-------------------------+-------------------------+ | +--------------------------+----+------------------------------------------------------------------------------------+ | |_2|:el:`quality` | ? | .. table:: | @@ -1960,6 +1962,14 @@ is effectively a miscellaneous subsection. :at:`ipd`: :at-val:`real, "0.068"` This attribute specifies the inter-pupilary distance of the free camera. It only affects the rendering in stereoscopic mode. The left and right viewpoints are offset by half of this value in the corresponding direction. +:at:`azimuth`: :at-val:`real, "90"` + This attribute specifies the initial azimuth of the free camera around the vertical z-axis, in degrees. A value of 0 + corresponds to looking in the positive x direction, while the default value of 90 corresponds to looking in the + positive y direction. +:at:`elevation`: :at-val:`real, "-45"` + This attribute specifies the initial elevation of the free camera with respect to the lookat point. Note that since + this is a rotation around a vector parallel to the camera's X-axis (right in pixel space), *negative* numbers + correspond to moving the camera *up* from the horizontal plane, and vice-versa. :at:`linewidth`: :at-val:`real, "1"` This attribute specifies the line-width in the sense of OpenGL. It affects the rendering in wire-frame mode. :at:`glow`: :at-val:`real, "0.3"` @@ -2216,7 +2226,8 @@ parameters. :at:`extent`: :at-val:`real, optional` If this attribute is specified, it replaces the value of mjModel.stat.extent computed by the compiler. The computed value is half the side of the bounding box of the model in the initial configuration. At runtime this value is - multiplied by some of the attributes of the :ref:`map ` element above. + multiplied by some of the attributes of the :ref:`map ` element above. When the model is first loaded, the free + camera's initial distance from the :at:`center` (see below) is 1.5 times the :at:`extent`. :at:`center`: :at-val:`real(3), optional` If this attribute is specified, it replaces the value of mjModel.stat.center computed by the compiler. The computed value is the center of the bounding box of the entire model in the initial configuration. This 3D vector is used to diff --git a/doc/changelog.rst b/doc/changelog.rst index b78773c2..11af5d77 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -16,6 +16,9 @@ General computations. This is currently supported only for meshes. - Raise error if the orientation of mesh faces is not consistent, which causes the inertia computations to be inaccurate. If this occurs, open the mesh in MeshLab or Blender and recalculate the faces. +- Added ``azimuth`` and ``elevation`` attributes to :ref:`visual/global`, defining the initial orientation of + the free camera at model load time. + - Added ``mjv_defaultFreeCamera`` which sets the default free camera, respecting the above attributes. Bug fixes ^^^^^^^^^ diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index c6a664dc..cb00f4a3 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -418,8 +418,10 @@ typedef struct mjOption_ mjOption; struct mjVisual_ { // visualization options struct { // global parameters - float fovy; // y-field of view (deg) for free camera + float fovy; // y-field of view for free camera (degrees) float ipd; // inter-pupilary distance for free camera + float azimuth; // initial azimuth of free camera (degrees) + float elevation; // initial elevation of free camera (degrees) float linewidth; // line width for wireframe and ray rendering float glow; // glow coefficient for selected body int offwidth; // width of offscreen buffer diff --git a/include/mujoco/mujoco.h b/include/mujoco/mujoco.h index 55c15694..1847cddf 100644 --- a/include/mujoco/mujoco.h +++ b/include/mujoco/mujoco.h @@ -492,6 +492,9 @@ MJAPI mjtNum mju_raySkin(int nface, int nvert, const int* face, const float* ver // Set default camera. MJAPI void mjv_defaultCamera(mjvCamera* cam); +// Set default free camera. +MJAPI void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam); + // Set default perturbation. MJAPI void mjv_defaultPerturb(mjvPerturb* pert); diff --git a/introspect/functions.py b/introspect/functions.py index e06bfef8..6b7a1965 100644 --- a/introspect/functions.py +++ b/introspect/functions.py @@ -2929,6 +2929,26 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([ ), doc='Set default camera.', )), + ('mjv_defaultFreeCamera', + FunctionDecl( + name='mjv_defaultFreeCamera', + return_type=ValueType(name='void'), + parameters=( + FunctionParameterDecl( + name='m', + type=PointerType( + inner_type=ValueType(name='mjModel', is_const=True), + ), + ), + FunctionParameterDecl( + name='cam', + type=PointerType( + inner_type=ValueType(name='mjvCamera'), + ), + ), + ), + doc='Set default free camera.', + )), ('mjv_defaultPerturb', FunctionDecl( name='mjv_defaultPerturb', diff --git a/python/mujoco/functions.cc b/python/mujoco/functions.cc index d258cd6c..de391f3a 100644 --- a/python/mujoco/functions.cc +++ b/python/mujoco/functions.cc @@ -546,6 +546,7 @@ PYBIND11_MODULE(_functions, pymodule) { // Interaction Def(pymodule); + Def(pymodule); Def(pymodule); Def(pymodule); Def(pymodule); diff --git a/sample/record.cc b/sample/record.cc index fe8e5016..c5d57386 100644 --- a/sample/record.cc +++ b/sample/record.cc @@ -74,11 +74,8 @@ void initMuJoCo(const char* filename) { mjv_makeScene(m, &scn, 2000); mjr_makeContext(m, &con, 200); - // center and scale view - cam.lookat[0] = m->stat.center[0]; - cam.lookat[1] = m->stat.center[1]; - cam.lookat[2] = m->stat.center[2]; - cam.distance = 1.5 * m->stat.extent; + // default free camera + mjv_defaultFreeCamera(m, &cam); } diff --git a/simulate/simulate.cc b/simulate/simulate.cc index 71dc0dff..32707ba2 100644 --- a/simulate/simulate.cc +++ b/simulate/simulate.cc @@ -904,16 +904,11 @@ void makesections(mj::Simulate* sim) { // align and scale view void alignscale(mj::Simulate* sim) { - // autoscale - sim->cam.lookat[0] = sim->m->stat.center[0]; - sim->cam.lookat[1] = sim->m->stat.center[1]; - sim->cam.lookat[2] = sim->m->stat.center[2]; - sim->cam.distance = 1.5 * sim->m->stat.extent; - - // set to free camera - sim->cam.type = mjCAMERA_FREE; + // use default free camera parameters + mjv_defaultFreeCamera(sim->m, &sim->cam); } + // copy qpos to clipboard as key void copykey(mj::Simulate* sim) { char clipboard[5000] = "