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
This commit is contained in:
Yuval Tassa
2022-08-05 01:03:08 -07:00
committed by Copybara-Service
parent 5ee184ddaa
commit b966a37855
15 changed files with 92 additions and 19 deletions
+12 -1
View File
@@ -1230,7 +1230,7 @@ mjVisual
{ {
struct // global parameters 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 ipd; // inter-pupilary distance for free camera
float linewidth; // line width for wireframe and ray rendering float linewidth; // line width for wireframe and ray rendering
float glow; // glow coefficient for selected body float glow; // glow coefficient for selected body
@@ -4722,6 +4722,17 @@ mjv_defaultCamera
Set default camera. 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:
mjv_defaultPerturb mjv_defaultPerturb
+14 -3
View File
@@ -120,9 +120,11 @@ in the second column of the table have the following meaning:
| | | :class: mjcf-attributes | | | | :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:: | | |_2|:el:`quality` | ? | .. table:: |
@@ -1960,6 +1962,14 @@ is effectively a miscellaneous subsection.
:at:`ipd`: :at-val:`real, "0.068"` :at:`ipd`: :at-val:`real, "0.068"`
This attribute specifies the inter-pupilary distance of the free camera. It only affects the rendering in 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. 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"` :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. 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"` :at:`glow`: :at-val:`real, "0.3"`
@@ -2216,7 +2226,8 @@ parameters.
:at:`extent`: :at-val:`real, optional` :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 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 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 <map>` element above. multiplied by some of the attributes of the :ref:`map <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` :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 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 value is the center of the bounding box of the entire model in the initial configuration. This 3D vector is used to
+3
View File
@@ -16,6 +16,9 @@ General
computations. This is currently supported only for meshes. 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 - 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. inaccurate. If this occurs, open the mesh in MeshLab or Blender and recalculate the faces.
- Added ``azimuth`` and ``elevation`` attributes to :ref:`visual/global<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 Bug fixes
^^^^^^^^^ ^^^^^^^^^
+3 -1
View File
@@ -418,8 +418,10 @@ typedef struct mjOption_ mjOption;
struct mjVisual_ { // visualization options struct mjVisual_ { // visualization options
struct { // global parameters 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 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 linewidth; // line width for wireframe and ray rendering
float glow; // glow coefficient for selected body float glow; // glow coefficient for selected body
int offwidth; // width of offscreen buffer int offwidth; // width of offscreen buffer
+3
View File
@@ -492,6 +492,9 @@ MJAPI mjtNum mju_raySkin(int nface, int nvert, const int* face, const float* ver
// Set default camera. // Set default camera.
MJAPI void mjv_defaultCamera(mjvCamera* cam); MJAPI void mjv_defaultCamera(mjvCamera* cam);
// Set default free camera.
MJAPI void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam);
// Set default perturbation. // Set default perturbation.
MJAPI void mjv_defaultPerturb(mjvPerturb* pert); MJAPI void mjv_defaultPerturb(mjvPerturb* pert);
+20
View File
@@ -2929,6 +2929,26 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Set default camera.', 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', ('mjv_defaultPerturb',
FunctionDecl( FunctionDecl(
name='mjv_defaultPerturb', name='mjv_defaultPerturb',
+1
View File
@@ -546,6 +546,7 @@ PYBIND11_MODULE(_functions, pymodule) {
// Interaction // Interaction
Def<traits::mjv_defaultCamera>(pymodule); Def<traits::mjv_defaultCamera>(pymodule);
Def<traits::mjv_defaultFreeCamera>(pymodule);
Def<traits::mjv_defaultPerturb>(pymodule); Def<traits::mjv_defaultPerturb>(pymodule);
Def<traits::mjv_room2model>(pymodule); Def<traits::mjv_room2model>(pymodule);
Def<traits::mjv_model2room>(pymodule); Def<traits::mjv_model2room>(pymodule);
+2 -5
View File
@@ -74,11 +74,8 @@ void initMuJoCo(const char* filename) {
mjv_makeScene(m, &scn, 2000); mjv_makeScene(m, &scn, 2000);
mjr_makeContext(m, &con, 200); mjr_makeContext(m, &con, 200);
// center and scale view // default free camera
cam.lookat[0] = m->stat.center[0]; mjv_defaultFreeCamera(m, &cam);
cam.lookat[1] = m->stat.center[1];
cam.lookat[2] = m->stat.center[2];
cam.distance = 1.5 * m->stat.extent;
} }
+3 -8
View File
@@ -904,16 +904,11 @@ void makesections(mj::Simulate* sim) {
// align and scale view // align and scale view
void alignscale(mj::Simulate* sim) { void alignscale(mj::Simulate* sim) {
// autoscale // use default free camera parameters
sim->cam.lookat[0] = sim->m->stat.center[0]; mjv_defaultFreeCamera(sim->m, &sim->cam);
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;
} }
// copy qpos to clipboard as key // copy qpos to clipboard as key
void copykey(mj::Simulate* sim) { void copykey(mj::Simulate* sim) {
char clipboard[5000] = "<key qpos='"; char clipboard[5000] = "<key qpos='";
+2
View File
@@ -152,6 +152,8 @@ void mj_defaultVisual(mjVisual* vis) {
// global // global
vis->global.fovy = 45; vis->global.fovy = 45;
vis->global.ipd = 0.068; vis->global.ipd = 0.068;
vis->global.azimuth = 90;
vis->global.elevation = -45;
vis->global.linewidth = 1.0; vis->global.linewidth = 1.0;
vis->global.glow = 0.3; vis->global.glow = 0.3;
vis->global.offwidth = 640; vis->global.offwidth = 640;
+17
View File
@@ -241,6 +241,23 @@ void mjv_defaultCamera(mjvCamera* cam) {
// set default free camera
void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam) {
memset(cam, 0, sizeof(mjvCamera));
cam->type = mjCAMERA_FREE;
cam->fixedcamid = -1;
cam->trackbodyid = -1;
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;
cam->azimuth = m->vis.global.azimuth;
cam->elevation = m->vis.global.elevation;
}
// set default perturbation // set default perturbation
void mjv_defaultPerturb(mjvPerturb* pert) { void mjv_defaultPerturb(mjvPerturb* pert) {
memset(pert, 0, sizeof(mjvPerturb)); memset(pert, 0, sizeof(mjvPerturb));
+3
View File
@@ -43,6 +43,9 @@ MJAPI void mjv_freeScene(mjvScene* scn);
// set default visualization options // set default visualization options
MJAPI void mjv_defaultOption(mjvOption* vopt); MJAPI void mjv_defaultOption(mjvOption* vopt);
// set default free camera
MJAPI void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam);
// set default camera // set default camera
MJAPI void mjv_defaultCamera(mjvCamera* cam); MJAPI void mjv_defaultCamera(mjvCamera* cam);
+4 -1
View File
@@ -75,7 +75,8 @@ static const char* MJCF[nMJCF][mjXATTRNUM] = {
{"visual", "*", "0"}, {"visual", "*", "0"},
{"<"}, {"<"},
{"global", "?", "6", "fovy", "ipd", "linewidth", "glow", "offwidth", "offheight"}, {"global", "?", "8", "fovy", "ipd", "azimuth", "elevation", "linewidth", "glow", "offwidth",
"offheight"},
{"quality", "?", "5", "shadowsize", "offsamples", "numslices", "numstacks", {"quality", "?", "5", "shadowsize", "offsamples", "numslices", "numstacks",
"numquads"}, "numquads"},
{"headlight", "?", "4", "ambient", "diffuse", "specular", "active"}, {"headlight", "?", "4", "ambient", "diffuse", "specular", "active"},
@@ -2034,6 +2035,8 @@ void mjXReader::Visual(XMLElement* section) {
if (name=="global") { if (name=="global") {
ReadAttr(elem, "fovy", 1, &vis->global.fovy, text); ReadAttr(elem, "fovy", 1, &vis->global.fovy, text);
ReadAttr(elem, "ipd", 1, &vis->global.ipd, text); ReadAttr(elem, "ipd", 1, &vis->global.ipd, text);
ReadAttr(elem, "azimuth", 1, &vis->global.azimuth, text);
ReadAttr(elem, "elevation", 1, &vis->global.elevation, text);
ReadAttr(elem, "linewidth", 1, &vis->global.linewidth, text); ReadAttr(elem, "linewidth", 1, &vis->global.linewidth, text);
ReadAttr(elem, "glow", 1, &vis->global.glow, text); ReadAttr(elem, "glow", 1, &vis->global.glow, text);
ReadAttrInt(elem, "offwidth", &vis->global.offwidth); ReadAttrInt(elem, "offwidth", &vis->global.offwidth);
+2
View File
@@ -796,6 +796,8 @@ void mjXWriter::Visual(XMLElement* root) {
elem = InsertEnd(section, "global"); elem = InsertEnd(section, "global");
WriteAttr(elem, "fovy", 1, &vis->global.fovy, &visdef.global.fovy); WriteAttr(elem, "fovy", 1, &vis->global.fovy, &visdef.global.fovy);
WriteAttr(elem, "ipd", 1, &vis->global.ipd, &visdef.global.ipd); WriteAttr(elem, "ipd", 1, &vis->global.ipd, &visdef.global.ipd);
WriteAttr(elem, "azimuth", 1, &vis->global.azimuth, &visdef.global.azimuth);
WriteAttr(elem, "elevation", 1, &vis->global.elevation, &visdef.global.elevation);
WriteAttr(elem, "linewidth", 1, &vis->global.linewidth, &visdef.global.linewidth); WriteAttr(elem, "linewidth", 1, &vis->global.linewidth, &visdef.global.linewidth);
WriteAttr(elem, "glow", 1, &vis->global.glow, &visdef.global.glow); WriteAttr(elem, "glow", 1, &vis->global.glow, &visdef.global.glow);
WriteAttrInt(elem, "offwidth", vis->global.offwidth, visdef.global.offwidth); WriteAttrInt(elem, "offwidth", vis->global.offwidth, visdef.global.offwidth);
+3
View File
@@ -3009,6 +3009,9 @@ public static unsafe extern double mju_raySkin(int nface, int nvert, int* face,
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_defaultCamera(mjvCamera_* cam); public static unsafe extern void mjv_defaultCamera(mjvCamera_* cam);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_defaultFreeCamera(mjModel_* m, mjvCamera_* cam);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_defaultPerturb(mjvPerturb_* pert); public static unsafe extern void mjv_defaultPerturb(mjvPerturb_* pert);