Specify camera parameters using standard robotics conventions.
PiperOrigin-RevId: 569147555 Change-Id: I3443f95e5de56a17024f5e5c03f33888dd583edb
This commit is contained in:
committed by
Copybara-Service
parent
ca60de79c8
commit
36d2ffe4f2
+45
-3
@@ -3053,6 +3053,35 @@ and the +Y axis points up. Thus the frame position and orientation are the key a
|
|||||||
dimensions are determined by the size of the rendering context. This attribute serves as a convenient
|
dimensions are determined by the size of the rendering context. This attribute serves as a convenient
|
||||||
location to save the required resolution when creating a context.
|
location to save the required resolution when creating a context.
|
||||||
|
|
||||||
|
.. _body-camera-focal:
|
||||||
|
|
||||||
|
:at:`focal`: :at-val:`real(2), "0 0"`
|
||||||
|
Focal length of the camera in length units. It is mutually exclusive with :ref:`fovy <body-camera-fovy>`.
|
||||||
|
See :ref:`CCamera` for details.
|
||||||
|
|
||||||
|
.. _body-camera-focalpixel:
|
||||||
|
|
||||||
|
:at:`focalpixel`: :at-val:`int(2), "0 0"`
|
||||||
|
Focal length of the camera in pixel units. If both :at:`focal`: and :at:`focalpixel`: are specified, the former is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
.. _body-camera-principal:
|
||||||
|
|
||||||
|
:at:`principal`: :at-val:`real(2), "0 0"`
|
||||||
|
Principal point of the camera in length units. It is mutually exclusive with :ref:`fovy <body-camera-fovy>`.
|
||||||
|
|
||||||
|
.. _body-camera-principalpixel:
|
||||||
|
|
||||||
|
:at:`principalpixel`: :at-val:`real(2), "0 0"`
|
||||||
|
Principal point of the camera in pixel units. If both :at:`principal`: and :at:`principalpixel`: are specified, the
|
||||||
|
former is ignored.
|
||||||
|
|
||||||
|
.. _body-camera-sensorsize:
|
||||||
|
|
||||||
|
:at:`sensorsize`: :at-val:`real(2), "0 0"`
|
||||||
|
Size of the camera sensor in length units. It is mutually exclusive with :ref:`fovy <body-camera-fovy>`. If
|
||||||
|
specified, :ref:`resolution <body-camera-resolution>` and :ref:`focal <body-camera-focal>` are required.
|
||||||
|
|
||||||
.. _body-camera-ipd:
|
.. _body-camera-ipd:
|
||||||
|
|
||||||
:at:`ipd`: :at-val:`real, "0.068"`
|
:at:`ipd`: :at-val:`real, "0.068"`
|
||||||
@@ -6700,8 +6729,6 @@ if omitted.
|
|||||||
| All site attributes are available here except: name, class.
|
| All site attributes are available here except: name, class.
|
||||||
|
|
||||||
|
|
||||||
.. _default-camera:
|
|
||||||
|
|
||||||
.. _default-camera-fovy:
|
.. _default-camera-fovy:
|
||||||
|
|
||||||
.. _default-camera-resolution:
|
.. _default-camera-resolution:
|
||||||
@@ -6724,11 +6751,26 @@ if omitted.
|
|||||||
|
|
||||||
.. _default-camera-user:
|
.. _default-camera-user:
|
||||||
|
|
||||||
|
.. _default-camera-resolution:
|
||||||
|
|
||||||
|
.. _default-camera-focal:
|
||||||
|
|
||||||
|
.. _default-camera-focalpixel:
|
||||||
|
|
||||||
|
.. _default-camera-principal:
|
||||||
|
|
||||||
|
.. _default-camera-principalpixel:
|
||||||
|
|
||||||
|
.. _default-camera-sensorsize:
|
||||||
|
|
||||||
|
.. _default-camera:
|
||||||
|
|
||||||
|
|
||||||
:el-prefix:`default/` |-| **camera** (?)
|
:el-prefix:`default/` |-| **camera** (?)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
| This element sets the attributes of the dummy :ref:`camera <body-camera>` element of the defaults class.
|
| This element sets the attributes of the dummy :ref:`camera <body-camera>` element of the defaults class.
|
||||||
| All camera attributes are available here except: name, class.
|
| All camera attributes are available here except: name, class, mode, target.
|
||||||
|
|
||||||
|
|
||||||
.. _default-light:
|
.. _default-light:
|
||||||
|
|||||||
+8
-4
@@ -354,7 +354,9 @@
|
|||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`xyaxes<body-camera-xyaxes>` | :ref:`zaxis<body-camera-zaxis>` | :ref:`euler<body-camera-euler>` | :ref:`mode<body-camera-mode>` | |
|
| | | | :ref:`xyaxes<body-camera-xyaxes>` | :ref:`zaxis<body-camera-zaxis>` | :ref:`euler<body-camera-euler>` | :ref:`mode<body-camera-mode>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`target<body-camera-target>` | :ref:`user<body-camera-user>` | | | |
|
| | | | :ref:`target<body-camera-target>` | :ref:`focal<body-camera-focal>` | :ref:`focalpixel<body-camera-focalpixel>` | :ref:`principal<body-camera-principal>` | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`principalpixel<body-camera-principalpixel>` | :ref:`sensorsize<body-camera-sensorsize>` | :ref:`user<body-camera-user>` | | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
| |_| body |br| |_| |L| | | .. table:: |
|
| |_| body |br| |_| |L| | | .. table:: |
|
||||||
@@ -1230,11 +1232,13 @@
|
|||||||
| :ref:`camera | ? | :class: mjcf-attributes |
|
| :ref:`camera | ? | :class: mjcf-attributes |
|
||||||
| <default-camera>` | | |
|
| <default-camera>` | | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`fovy<default-camera-fovy>` | :ref:`ipd<default-camera-ipd>` | :ref:`pos<default-camera-pos>` | :ref:`quat<default-camera-quat>` | |
|
| | | | :ref:`fovy<default-camera-fovy>` | :ref:`ipd<default-camera-ipd>` | :ref:`resolution<default-camera-resolution>` | :ref:`pos<default-camera-pos>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`resolution<default-camera-resolution>` | :ref:`axisangle<default-camera-axisangle>` | :ref:`xyaxes<default-camera-xyaxes>` | :ref:`zaxis<default-camera-zaxis>` | |
|
| | | | :ref:`quat<default-camera-quat>` | :ref:`axisangle<default-camera-axisangle>` | :ref:`xyaxes<default-camera-xyaxes>` | :ref:`zaxis<default-camera-zaxis>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`euler<default-camera-euler>` | :ref:`mode<default-camera-mode>` | :ref:`user<default-camera-user>` | | |
|
| | | | :ref:`euler<default-camera-euler>` | :ref:`mode<default-camera-mode>` | :ref:`focal<default-camera-focal>` | :ref:`focalpixel<default-camera-focalpixel>` | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`principal<default-camera-principal>` | :ref:`principalpixel<default-camera-principalpixel>` | :ref:`sensorsize<default-camera-sensorsize>` | :ref:`user<default-camera-user>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
| |_| default |br| |_| |L| | | .. table:: |
|
| |_| default |br| |_| |L| | | .. table:: |
|
||||||
|
|||||||
+11
-2
@@ -106,17 +106,26 @@ General
|
|||||||
19. Added camera :ref:`resolution<body-camera-resolution>` attribute and :ref:`camprojection<sensor-camprojection>`
|
19. Added camera :ref:`resolution<body-camera-resolution>` attribute and :ref:`camprojection<sensor-camprojection>`
|
||||||
sensor. If camera resolution is set to positive values, the camera projection sensor will report the location of a
|
sensor. If camera resolution is set to positive values, the camera projection sensor will report the location of a
|
||||||
target site, projected onto the camera image, in pixel coordinates.
|
target site, projected onto the camera image, in pixel coordinates.
|
||||||
|
20. Added :ref:`camera<body-camera>` calibration attributes:
|
||||||
|
|
||||||
|
- The new attributes are :ref:`resolution<body-camera-resolution>`, :ref:`focal<body-camera-focal>`,
|
||||||
|
:ref:`focalpixel<body-camera-focalpixel>`, :ref:`principal<body-camera-principal>`,
|
||||||
|
:ref:`principalpixel<body-camera-principalpixel>` and :ref:`sensorsize<body-camera-sensorsize>`.
|
||||||
|
- Visualize the calibrated frustum using the :ref:`mjVIS_CAMERA<mjtVisFlag>` visualization flag when these
|
||||||
|
attributes are specified. See the following
|
||||||
|
`example model <https://github.com/deepmind/mujoco/blob/main/test/engine/testdata/vis_visualize/frustum.xml>`__.
|
||||||
|
- Note that these attributes only take effect for offline rendering and do not affect interactive visualisation.
|
||||||
|
|
||||||
Python bindings
|
Python bindings
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
20. Fixed `#870 <https://github.com/google-deepmind/mujoco/issues/870>`__ where calling ``update_scene`` with an invalid
|
21. Fixed `#870 <https://github.com/google-deepmind/mujoco/issues/870>`__ where calling ``update_scene`` with an invalid
|
||||||
camera name used the default camera.
|
camera name used the default camera.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
21. Fixed a bug that was causing :ref:`geom margin<body-geom-margin>` to be ignored during the construction of
|
22. Fixed a bug that was causing :ref:`geom margin<body-geom-margin>` to be ignored during the construction of
|
||||||
midphase collision trees.
|
midphase collision trees.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -440,6 +440,7 @@ typedef enum mjtGeom_ { // type of geometric shape
|
|||||||
mjGEOM_LINE, // line
|
mjGEOM_LINE, // line
|
||||||
mjGEOM_SKIN, // skin
|
mjGEOM_SKIN, // skin
|
||||||
mjGEOM_LABEL, // text label
|
mjGEOM_LABEL, // text label
|
||||||
|
mjGEOM_TRIANGLE, // triangle connecting a frame
|
||||||
|
|
||||||
mjGEOM_NONE = 1001 // missing geom type
|
mjGEOM_NONE = 1001 // missing geom type
|
||||||
} mjtGeom;
|
} mjtGeom;
|
||||||
@@ -1010,6 +1011,8 @@ struct mjModel_ {
|
|||||||
mjtNum* cam_mat0; // global orientation in qpos0 (ncam x 9)
|
mjtNum* cam_mat0; // global orientation in qpos0 (ncam x 9)
|
||||||
int* cam_resolution; // [width, height] in pixels (ncam x 2)
|
int* cam_resolution; // [width, height] in pixels (ncam x 2)
|
||||||
mjtNum* cam_fovy; // y-field of view (deg) (ncam x 1)
|
mjtNum* cam_fovy; // y-field of view (deg) (ncam x 1)
|
||||||
|
float* cam_intrinsic; // [focal length; principal point] (ncam x 4)
|
||||||
|
float* cam_sensorsize; // sensor size (ncam x 2)
|
||||||
mjtNum* cam_ipd; // inter-pupilary distance (ncam x 1)
|
mjtNum* cam_ipd; // inter-pupilary distance (ncam x 1)
|
||||||
mjtNum* cam_user; // user data (ncam x nuser_cam)
|
mjtNum* cam_user; // user data (ncam x nuser_cam)
|
||||||
|
|
||||||
@@ -1822,6 +1825,7 @@ struct mjvGLCamera_ { // OpenGL camera
|
|||||||
|
|
||||||
// camera projection
|
// camera projection
|
||||||
float frustum_center; // hor. center (left,right set to match aspect)
|
float frustum_center; // hor. center (left,right set to match aspect)
|
||||||
|
float frustum_width; // width (not used for rendering)
|
||||||
float frustum_bottom; // bottom
|
float frustum_bottom; // bottom
|
||||||
float frustum_top; // top
|
float frustum_top; // top
|
||||||
float frustum_near; // near
|
float frustum_near; // near
|
||||||
@@ -2053,6 +2057,7 @@ struct mjvSceneState_ {
|
|||||||
|
|
||||||
mjtNum* cam_fovy;
|
mjtNum* cam_fovy;
|
||||||
mjtNum* cam_ipd;
|
mjtNum* cam_ipd;
|
||||||
|
float* cam_sensorsize;
|
||||||
|
|
||||||
mjtByte* light_directional;
|
mjtByte* light_directional;
|
||||||
mjtByte* light_castshadow;
|
mjtByte* light_castshadow;
|
||||||
|
|||||||
@@ -973,6 +973,31 @@ Here we describe the XML attributes common to all sensor types, so as to avoid r
|
|||||||
:at:`user`: :at-val:`real(nuser_sensor), "0 0 ..."`
|
:at:`user`: :at-val:`real(nuser_sensor), "0 0 ..."`
|
||||||
See :ref:`User parameters <CUser>`.
|
See :ref:`User parameters <CUser>`.
|
||||||
|
|
||||||
|
.. _CCamera:
|
||||||
|
|
||||||
|
Cameras
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Besides the default, user-controllable, free camera, "fixed" cameras can be attached to the kinematic tree.
|
||||||
|
|
||||||
|
Extrinsics
|
||||||
|
By default, camera frames are attached to the parent body. The optional :ref:`mode<body-camera-mode>` and
|
||||||
|
:ref:`target<body-camera-target>` attributes can be used to specify camera that track (move with) or target (look at)
|
||||||
|
a body or subtree. Cameras look towards the negative Z axis of the camera frame, while positive X and Y correspond to
|
||||||
|
*right* and *up* in the image plane, respectively.
|
||||||
|
|
||||||
|
Intrinsics
|
||||||
|
Camera intrinsics are specified using :ref:`ipd<body-camera-ipd>` (inter-pupilary distance, required for
|
||||||
|
stereoscopic rendering and VR) and :ref:`fovy<body-camera-fovy>` (vertical field of view, in degrees).
|
||||||
|
|
||||||
|
The above specification implies a perfect point camera with no aberrations. However when calibrating real cameras,
|
||||||
|
two types of linear aberration can be expressed using standard rendering pipelines. The first is different focal
|
||||||
|
lengths in the vertical and horizontal directions (axis-aligned astigmatism). The second is a non-centered principal
|
||||||
|
point. These can be specified using the :ref:`focal<body-camera-focal>` and :ref:`principal<body-camera-principal>`
|
||||||
|
attributes. When these calibration-related attributes are used, the physical
|
||||||
|
:ref:`sensor size<body-camera-sensorsize>` and camera :ref:`resolution<body-camera-resolution>` must also be
|
||||||
|
specified. In this case, the rendering frustum can be visualized.
|
||||||
|
|
||||||
.. _CComposite:
|
.. _CComposite:
|
||||||
|
|
||||||
Composite objects
|
Composite objects
|
||||||
|
|||||||
+4
-2
@@ -515,8 +515,10 @@ Camera
|
|||||||
Multiple cameras can be defined in a model. There is always a default camera which the user can freely move with the
|
Multiple cameras can be defined in a model. There is always a default camera which the user can freely move with the
|
||||||
mouse in the interactive visualizer. However it is often convenient to define additional cameras that are either
|
mouse in the interactive visualizer. However it is often convenient to define additional cameras that are either
|
||||||
fixed to the world, or are attached to one of the bodies and move with it. In addition to the camera position and
|
fixed to the world, or are attached to one of the bodies and move with it. In addition to the camera position and
|
||||||
orientation, the user can adjust the field of view and the inter-pupilary distance for stereoscopic rendering, as
|
orientation, the user can adjust the vertical field of view and the inter-pupilary distance for stereoscopic rendering,
|
||||||
well as create oblique projections needed for stereoscopic virtual environments.
|
as well as create oblique projections needed for stereoscopic virtual environments. When modeling real cameras with
|
||||||
|
imperfect optics, it is possible to specify separate focal lengths for the horizontal and vertical directions and a
|
||||||
|
non-centered principal point.
|
||||||
|
|
||||||
Light
|
Light
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ typedef enum mjtGeom_ { // type of geometric shape
|
|||||||
mjGEOM_LINE, // line
|
mjGEOM_LINE, // line
|
||||||
mjGEOM_SKIN, // skin
|
mjGEOM_SKIN, // skin
|
||||||
mjGEOM_LABEL, // text label
|
mjGEOM_LABEL, // text label
|
||||||
|
mjGEOM_TRIANGLE, // triangle connecting a frame
|
||||||
|
|
||||||
mjGEOM_NONE = 1001 // missing geom type
|
mjGEOM_NONE = 1001 // missing geom type
|
||||||
} mjtGeom;
|
} mjtGeom;
|
||||||
@@ -742,6 +743,8 @@ struct mjModel_ {
|
|||||||
mjtNum* cam_mat0; // global orientation in qpos0 (ncam x 9)
|
mjtNum* cam_mat0; // global orientation in qpos0 (ncam x 9)
|
||||||
int* cam_resolution; // [width, height] in pixels (ncam x 2)
|
int* cam_resolution; // [width, height] in pixels (ncam x 2)
|
||||||
mjtNum* cam_fovy; // y-field of view (deg) (ncam x 1)
|
mjtNum* cam_fovy; // y-field of view (deg) (ncam x 1)
|
||||||
|
float* cam_intrinsic; // [focal length; principal point] (ncam x 4)
|
||||||
|
float* cam_sensorsize; // sensor size (ncam x 2)
|
||||||
mjtNum* cam_ipd; // inter-pupilary distance (ncam x 1)
|
mjtNum* cam_ipd; // inter-pupilary distance (ncam x 1)
|
||||||
mjtNum* cam_user; // user data (ncam x nuser_cam)
|
mjtNum* cam_user; // user data (ncam x nuser_cam)
|
||||||
|
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ struct mjvGLCamera_ { // OpenGL camera
|
|||||||
|
|
||||||
// camera projection
|
// camera projection
|
||||||
float frustum_center; // hor. center (left,right set to match aspect)
|
float frustum_center; // hor. center (left,right set to match aspect)
|
||||||
|
float frustum_width; // width (not used for rendering)
|
||||||
float frustum_bottom; // bottom
|
float frustum_bottom; // bottom
|
||||||
float frustum_top; // top
|
float frustum_top; // top
|
||||||
float frustum_near; // near
|
float frustum_near; // near
|
||||||
@@ -454,6 +455,7 @@ struct mjvSceneState_ {
|
|||||||
|
|
||||||
mjtNum* cam_fovy;
|
mjtNum* cam_fovy;
|
||||||
mjtNum* cam_ipd;
|
mjtNum* cam_ipd;
|
||||||
|
float* cam_sensorsize;
|
||||||
|
|
||||||
mjtByte* light_directional;
|
mjtByte* light_directional;
|
||||||
mjtByte* light_castshadow;
|
mjtByte* light_castshadow;
|
||||||
|
|||||||
@@ -261,6 +261,8 @@
|
|||||||
X ( int, cam_bodyid, ncam, 1 ) \
|
X ( int, cam_bodyid, ncam, 1 ) \
|
||||||
X ( int, cam_targetbodyid, ncam, 1 ) \
|
X ( int, cam_targetbodyid, ncam, 1 ) \
|
||||||
X ( int, cam_resolution, ncam, 2 ) \
|
X ( int, cam_resolution, ncam, 2 ) \
|
||||||
|
XMJV( float, cam_sensorsize, ncam, 2 ) \
|
||||||
|
X ( float, cam_intrinsic, ncam, 4 ) \
|
||||||
X ( mjtNum, cam_pos, ncam, 3 ) \
|
X ( mjtNum, cam_pos, ncam, 3 ) \
|
||||||
X ( mjtNum, cam_quat, ncam, 4 ) \
|
X ( mjtNum, cam_quat, ncam, 4 ) \
|
||||||
X ( mjtNum, cam_poscom0, ncam, 3 ) \
|
X ( mjtNum, cam_poscom0, ncam, 3 ) \
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ ENUMS: Mapping[str, EnumDecl] = dict([
|
|||||||
('mjGEOM_LINE', 103),
|
('mjGEOM_LINE', 103),
|
||||||
('mjGEOM_SKIN', 104),
|
('mjGEOM_SKIN', 104),
|
||||||
('mjGEOM_LABEL', 105),
|
('mjGEOM_LABEL', 105),
|
||||||
|
('mjGEOM_TRIANGLE', 106),
|
||||||
('mjGEOM_NONE', 1001),
|
('mjGEOM_NONE', 1001),
|
||||||
]),
|
]),
|
||||||
)),
|
)),
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class EnumsTest(absltest.TestCase):
|
|||||||
self.assertEqual(enum_decl.values['mjGEOM_ARROW'], 100)
|
self.assertEqual(enum_decl.values['mjGEOM_ARROW'], 100)
|
||||||
self.assertEqual(enum_decl.values['mjGEOM_ARROW1'], 101)
|
self.assertEqual(enum_decl.values['mjGEOM_ARROW1'], 101)
|
||||||
self.assertEqual(enum_decl.values['mjGEOM_ARROW2'], 102)
|
self.assertEqual(enum_decl.values['mjGEOM_ARROW2'], 102)
|
||||||
|
self.assertEqual(enum_decl.values['mjGEOM_TRIANGLE'], 106)
|
||||||
# Skip a few...
|
# Skip a few...
|
||||||
|
|
||||||
self.assertEqual(enum_decl.values['mjGEOM_NONE'], 1001)
|
self.assertEqual(enum_decl.values['mjGEOM_NONE'], 1001)
|
||||||
|
|||||||
@@ -1899,6 +1899,20 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
),
|
),
|
||||||
doc='y-field of view (deg) (ncam x 1)',
|
doc='y-field of view (deg) (ncam x 1)',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='cam_intrinsic',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='float'),
|
||||||
|
),
|
||||||
|
doc='[focal length; principal point] (ncam x 4)',
|
||||||
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='cam_sensorsize',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='float'),
|
||||||
|
),
|
||||||
|
doc='sensor size (ncam x 2)',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='cam_ipd',
|
name='cam_ipd',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
@@ -4730,6 +4744,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='float'),
|
type=ValueType(name='float'),
|
||||||
doc='hor. center (left,right set to match aspect)',
|
doc='hor. center (left,right set to match aspect)',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='frustum_width',
|
||||||
|
type=ValueType(name='float'),
|
||||||
|
doc='width (not used for rendering)',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='frustum_bottom',
|
name='frustum_bottom',
|
||||||
type=ValueType(name='float'),
|
type=ValueType(name='float'),
|
||||||
@@ -5885,6 +5904,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
),
|
),
|
||||||
doc='',
|
doc='',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='cam_sensorsize',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='float'),
|
||||||
|
),
|
||||||
|
doc='',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='light_directional',
|
name='light_directional',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
|
|||||||
@@ -829,6 +829,7 @@ Euler integrator, semi-implicit in velocity.
|
|||||||
self.assertEqual(mujoco.mjtGeom.mjGEOM_ARROW, 100)
|
self.assertEqual(mujoco.mjtGeom.mjGEOM_ARROW, 100)
|
||||||
self.assertEqual(mujoco.mjtGeom.mjGEOM_ARROW1, 101)
|
self.assertEqual(mujoco.mjtGeom.mjGEOM_ARROW1, 101)
|
||||||
self.assertEqual(mujoco.mjtGeom.mjGEOM_ARROW2, 102)
|
self.assertEqual(mujoco.mjtGeom.mjGEOM_ARROW2, 102)
|
||||||
|
self.assertEqual(mujoco.mjtGeom.mjGEOM_TRIANGLE, 106)
|
||||||
self.assertEqual(mujoco.mjtGeom.mjGEOM_NONE, 1001)
|
self.assertEqual(mujoco.mjtGeom.mjGEOM_NONE, 1001)
|
||||||
|
|
||||||
def test_enum_from_int(self):
|
def test_enum_from_int(self):
|
||||||
|
|||||||
@@ -2044,6 +2044,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
c.get()->var = rhs; \
|
c.get()->var = rhs; \
|
||||||
})
|
})
|
||||||
X(frustum_center);
|
X(frustum_center);
|
||||||
|
X(frustum_width);
|
||||||
X(frustum_bottom);
|
X(frustum_bottom);
|
||||||
X(frustum_top);
|
X(frustum_top);
|
||||||
X(frustum_near);
|
X(frustum_near);
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ void mj_defaultVisual(mjVisual* vis) {
|
|||||||
setf4(vis->rgba.actuatornegative, .2, .6, .9, 1.);
|
setf4(vis->rgba.actuatornegative, .2, .6, .9, 1.);
|
||||||
setf4(vis->rgba.actuatorpositive, .9, .4, .2, 1.);
|
setf4(vis->rgba.actuatorpositive, .9, .4, .2, 1.);
|
||||||
setf4(vis->rgba.com, .9, .9, .9, 1.);
|
setf4(vis->rgba.com, .9, .9, .9, 1.);
|
||||||
setf4(vis->rgba.camera, .6, .9, .6, 1.);
|
setf4(vis->rgba.camera, .6, .9, .6, .3);
|
||||||
setf4(vis->rgba.light, .6, .6, .9, 1.);
|
setf4(vis->rgba.light, .6, .6, .9, 1.);
|
||||||
setf4(vis->rgba.selectpoint, .9, .9, .1, 1.);
|
setf4(vis->rgba.selectpoint, .9, .9, .1, 1.);
|
||||||
setf4(vis->rgba.connect, .2, .2, .8, 1.);
|
setf4(vis->rgba.connect, .2, .2, .8, 1.);
|
||||||
|
|||||||
@@ -188,7 +188,10 @@ static void get_xquat(const mjModel* m, const mjData* d, mjtObj type, int id, in
|
|||||||
|
|
||||||
static void cam_project(mjtNum sensordata[2], const mjtNum target_xpos[3],
|
static void cam_project(mjtNum sensordata[2], const mjtNum target_xpos[3],
|
||||||
const mjtNum cam_xpos[3], const mjtNum cam_xmat[9],
|
const mjtNum cam_xpos[3], const mjtNum cam_xmat[9],
|
||||||
const int cam_res[2], mjtNum cam_fovy) {
|
const int cam_res[2], mjtNum cam_fovy,
|
||||||
|
const float cam_intrinsic[4], const float cam_sensorsize[2]) {
|
||||||
|
mjtNum fx, fy;
|
||||||
|
|
||||||
// translation matrix (4x4)
|
// translation matrix (4x4)
|
||||||
mjtNum translation[4][4] = {0};
|
mjtNum translation[4][4] = {0};
|
||||||
translation[0][0] = 1;
|
translation[0][0] = 1;
|
||||||
@@ -212,10 +215,15 @@ static void cam_project(mjtNum sensordata[2], const mjtNum target_xpos[3],
|
|||||||
}
|
}
|
||||||
|
|
||||||
// focal transformation matrix (3x4)
|
// focal transformation matrix (3x4)
|
||||||
mjtNum height = (mjtNum) cam_res[1];
|
if (cam_sensorsize[0] && cam_sensorsize[1]) {
|
||||||
mjtNum fy = .5 / mju_tan(cam_fovy * mjPI / 360.) * height;
|
fx = cam_intrinsic[0] / cam_sensorsize[0] * cam_res[0];
|
||||||
|
fy = cam_intrinsic[1] / cam_sensorsize[1] * cam_res[1];
|
||||||
|
} else {
|
||||||
|
fx = fy = .5 / mju_tan(cam_fovy * mjPI / 360.) * cam_res[1];
|
||||||
|
}
|
||||||
|
|
||||||
mjtNum focal[3][4] = {0};
|
mjtNum focal[3][4] = {0};
|
||||||
focal[0][0] = -fy;
|
focal[0][0] = -fx;
|
||||||
focal[1][1] = fy;
|
focal[1][1] = fy;
|
||||||
focal[2][2] = 1.0;
|
focal[2][2] = 1.0;
|
||||||
|
|
||||||
@@ -307,7 +315,8 @@ void mj_sensorPos(const mjModel* m, mjData* d) {
|
|||||||
|
|
||||||
case mjSENS_CAMPROJECTION: // camera projection
|
case mjSENS_CAMPROJECTION: // camera projection
|
||||||
cam_project(d->sensordata+adr, d->site_xpos+3*objid, d->cam_xpos+3*refid,
|
cam_project(d->sensordata+adr, d->site_xpos+3*objid, d->cam_xpos+3*refid,
|
||||||
d->cam_xmat+9*refid, m->cam_resolution+2*refid, m->cam_fovy[refid]);
|
d->cam_xmat+9*refid, m->cam_resolution+2*refid, m->cam_fovy[refid],
|
||||||
|
m->cam_intrinsic+4*refid, m->cam_sensorsize+2*refid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case mjSENS_RANGEFINDER: // rangefinder
|
case mjSENS_RANGEFINDER: // rangefinder
|
||||||
|
|||||||
@@ -722,6 +722,7 @@ mjvGLCamera mjv_averageCamera(const mjvGLCamera* cam1, const mjvGLCamera* cam2)
|
|||||||
cam.frustum_bottom = 0.5f * (cam1->frustum_bottom + cam2->frustum_bottom);
|
cam.frustum_bottom = 0.5f * (cam1->frustum_bottom + cam2->frustum_bottom);
|
||||||
cam.frustum_top = 0.5f * (cam1->frustum_top + cam2->frustum_top);
|
cam.frustum_top = 0.5f * (cam1->frustum_top + cam2->frustum_top);
|
||||||
cam.frustum_center = 0.5f * (cam1->frustum_center + cam2->frustum_center);
|
cam.frustum_center = 0.5f * (cam1->frustum_center + cam2->frustum_center);
|
||||||
|
cam.frustum_width = 0.5f * (cam1->frustum_width + cam2->frustum_width);
|
||||||
cam.frustum_near = 0.5f * (cam1->frustum_near + cam2->frustum_near);
|
cam.frustum_near = 0.5f * (cam1->frustum_near + cam2->frustum_near);
|
||||||
cam.frustum_far = 0.5f * (cam1->frustum_far + cam2->frustum_far);
|
cam.frustum_far = 0.5f * (cam1->frustum_far + cam2->frustum_far);
|
||||||
|
|
||||||
|
|||||||
@@ -523,6 +523,17 @@ static void drawBoundingBox(mjvGeom* thisgeom, mjData* d, mjvScene* scn,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// computes the camera frustum
|
||||||
|
static void getFrustum(float zver[2], float zhor[2], float znear,
|
||||||
|
const float K[4], const float sensorsize[2]) {
|
||||||
|
zhor[0] = znear / K[0] * (sensorsize[0]/2.f - K[2]);
|
||||||
|
zhor[1] = znear / K[0] * (sensorsize[0]/2.f + K[2]);
|
||||||
|
zver[0] = znear / K[1] * (sensorsize[1]/2.f - K[3]);
|
||||||
|
zver[1] = znear / K[1] * (sensorsize[1]/2.f + K[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// add abstract geoms
|
// add abstract geoms
|
||||||
void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
|
void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
|
||||||
const mjvPerturb* pert, int catmask, mjvScene* scn) {
|
const mjvPerturb* pert, int catmask, mjvScene* scn) {
|
||||||
@@ -1461,6 +1472,87 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// camera frustum
|
||||||
|
if (vopt->flags[mjVIS_CAMERA]) {
|
||||||
|
float rgba[] = {1, 1, 0, .2};
|
||||||
|
mjtNum vnear[4][3], vfar[4][3];
|
||||||
|
mjtNum center[3];
|
||||||
|
mjtNum znear = m->vis.map.znear * m->stat.extent;
|
||||||
|
mjtNum zfar = m->vis.map.zfar * m->stat.extent;
|
||||||
|
float zver[2], zhor[2];
|
||||||
|
for (int i=0; i < m->ncam; i++) {
|
||||||
|
if (m->cam_sensorsize[2*i+1] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
getFrustum(zver, zhor, znear, m->cam_intrinsic + 4*i, m->cam_sensorsize + 2*i);
|
||||||
|
|
||||||
|
// frustum frame to convert from planes to vertex representation
|
||||||
|
mjtNum *cam_xpos = d->cam_xpos+3*i;
|
||||||
|
mjtNum *cam_xmat = d->cam_xmat+9*i;
|
||||||
|
mjtNum x[] = {cam_xmat[0], cam_xmat[3], cam_xmat[6]};
|
||||||
|
mjtNum y[] = {cam_xmat[1], cam_xmat[4], cam_xmat[7]};
|
||||||
|
mjtNum z[] = {cam_xmat[2], cam_xmat[5], cam_xmat[8]};
|
||||||
|
|
||||||
|
// vertices of the near plane
|
||||||
|
mju_addScl3(center, cam_xpos, z, -znear);
|
||||||
|
mju_addScl3(vnear[0], center, x, -zhor[0]);
|
||||||
|
mju_addScl3(vnear[1], center, x, zhor[1]);
|
||||||
|
mju_addScl3(vnear[2], center, x, zhor[1]);
|
||||||
|
mju_addScl3(vnear[3], center, x, -zhor[0]);
|
||||||
|
mju_addToScl3(vnear[0], y, -zver[0]);
|
||||||
|
mju_addToScl3(vnear[1], y, -zver[0]);
|
||||||
|
mju_addToScl3(vnear[2], y, zver[1]);
|
||||||
|
mju_addToScl3(vnear[3], y, zver[1]);
|
||||||
|
|
||||||
|
// vertices of the far plane
|
||||||
|
zhor[0] *= zfar / znear;
|
||||||
|
zhor[1] *= zfar / znear;
|
||||||
|
zver[0] *= zfar / znear;
|
||||||
|
zver[1] *= zfar / znear;
|
||||||
|
mju_addScl3(center, cam_xpos, z, -zfar);
|
||||||
|
mju_addScl3(vfar[0], center, x, -zhor[0]);
|
||||||
|
mju_addScl3(vfar[1], center, x, zhor[1]);
|
||||||
|
mju_addScl3(vfar[2], center, x, zhor[1]);
|
||||||
|
mju_addScl3(vfar[3], center, x, -zhor[0]);
|
||||||
|
mju_addToScl3(vfar[0], y, -zver[0]);
|
||||||
|
mju_addToScl3(vfar[1], y, -zver[0]);
|
||||||
|
mju_addToScl3(vfar[2], y, zver[1]);
|
||||||
|
mju_addToScl3(vfar[3], y, zver[1]);
|
||||||
|
|
||||||
|
// triangulation and wireframe of the frustum
|
||||||
|
for (int e=0; e<4; e++) {
|
||||||
|
START
|
||||||
|
mju_sub3(x, vfar[e], vnear[e]);
|
||||||
|
mju_sub3(y, vnear[(e+1)%4], vnear[e]);
|
||||||
|
mju_cross(z, x, y);
|
||||||
|
mjtNum tri1[3] = {mju_normalize3(x), mju_normalize3(y), mju_normalize3(z)};
|
||||||
|
mjtNum xmat1[9] = {x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]};
|
||||||
|
mjv_initGeom(thisgeom, mjGEOM_TRIANGLE, tri1, vnear[e], xmat1, rgba);
|
||||||
|
FINISH
|
||||||
|
START
|
||||||
|
mju_sub3(y, vnear[(e+1)%4], vfar[e]);
|
||||||
|
mju_sub3(x, vfar[(e+1)%4], vfar[e]);
|
||||||
|
mju_cross(z, x, y);
|
||||||
|
mjtNum tri2[3] = {mju_normalize3(x), mju_normalize3(y), mju_normalize3(z)};
|
||||||
|
mjtNum xmat2[9] = {x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]};
|
||||||
|
mjv_initGeom(thisgeom, mjGEOM_TRIANGLE, tri2, vfar[e], xmat2, rgba);
|
||||||
|
FINISH
|
||||||
|
START
|
||||||
|
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vnear[(e+1)%4]);
|
||||||
|
f2f(thisgeom->rgba, rgba, 4);
|
||||||
|
FINISH
|
||||||
|
START
|
||||||
|
mjv_connector(thisgeom, mjGEOM_LINE, 3, vfar[e], vfar[(e+1)%4]);
|
||||||
|
f2f(thisgeom->rgba, rgba, 4);
|
||||||
|
FINISH
|
||||||
|
START
|
||||||
|
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vfar[e]);
|
||||||
|
f2f(thisgeom->rgba, rgba, 4);
|
||||||
|
FINISH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// lights
|
// lights
|
||||||
objtype = mjOBJ_LIGHT;
|
objtype = mjOBJ_LIGHT;
|
||||||
category = mjCAT_DECOR;
|
category = mjCAT_DECOR;
|
||||||
@@ -1907,24 +1999,27 @@ void mjv_makeLights(const mjModel* m, mjData* d, mjvScene* scn) {
|
|||||||
// update camera only
|
// update camera only
|
||||||
void mjv_updateCamera(const mjModel* m, mjData* d, mjvCamera* cam, mjvScene* scn) {
|
void mjv_updateCamera(const mjModel* m, mjData* d, mjvCamera* cam, mjvScene* scn) {
|
||||||
mjtNum ca, sa, ce, se, move[3], *mat;
|
mjtNum ca, sa, ce, se, move[3], *mat;
|
||||||
mjtNum headpos[3], forward[3], up[3], right[3], ipd, fovy, znear, zfar;
|
mjtNum headpos[3], forward[3], up[3], right[3], ipd;
|
||||||
|
|
||||||
// return if nothing to do
|
// return if nothing to do
|
||||||
if (!m || !cam || cam->type == mjCAMERA_USER) {
|
if (!m || !cam || cam->type == mjCAMERA_USER) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get znear, zfar
|
// initialize frustum
|
||||||
znear = m->vis.map.znear * m->stat.extent;
|
float zver[2], zhor[2] = {0, 0};
|
||||||
zfar = m->vis.map.zfar * m->stat.extent;
|
float znear = m->vis.map.znear * m->stat.extent;
|
||||||
|
float zfar = m->vis.map.zfar * m->stat.extent;
|
||||||
|
|
||||||
// get headpos, forward[3], up, right, ipd, fovy
|
// get headpos, forward[3], up, right, ipd, fovy
|
||||||
switch (cam->type) {
|
switch (cam->type) {
|
||||||
case mjCAMERA_FREE:
|
case mjCAMERA_FREE:
|
||||||
case mjCAMERA_TRACKING:
|
case mjCAMERA_TRACKING:
|
||||||
// get global ipd and fovy
|
// get global ipd
|
||||||
ipd = m->vis.global.ipd;
|
ipd = m->vis.global.ipd;
|
||||||
fovy = m->vis.global.fovy;
|
|
||||||
|
// compute image size from global fovy
|
||||||
|
zver[0] = zver[1] = (float)znear * mju_tan(m->vis.global.fovy * (float)(mjPI/360.0));
|
||||||
|
|
||||||
// move lookat for tracking
|
// move lookat for tracking
|
||||||
if (cam->type == mjCAMERA_TRACKING) {
|
if (cam->type == mjCAMERA_TRACKING) {
|
||||||
@@ -1965,7 +2060,13 @@ void mjv_updateCamera(const mjModel* m, mjData* d, mjvCamera* cam, mjvScene* scn
|
|||||||
|
|
||||||
// get camera-specific ipd and fovy
|
// get camera-specific ipd and fovy
|
||||||
ipd = m->cam_ipd[cid];
|
ipd = m->cam_ipd[cid];
|
||||||
fovy = m->cam_fovy[cid];
|
|
||||||
|
// get frustum from intrinsics or from fovy
|
||||||
|
if (m->cam_sensorsize[2*cid+1]) {
|
||||||
|
getFrustum(zver, zhor, znear, m->cam_intrinsic + 4*cid, m->cam_sensorsize + 2*cid);
|
||||||
|
} else {
|
||||||
|
zver[0] = zver[1] = (float)znear * mju_tan(m->cam_fovy[cid] * (float)(mjPI/360.0));
|
||||||
|
}
|
||||||
|
|
||||||
// get pointer to camera orientation matrix
|
// get pointer to camera orientation matrix
|
||||||
mat = d->cam_xmat + 9*cid;
|
mat = d->cam_xmat + 9*cid;
|
||||||
@@ -1997,12 +2098,13 @@ void mjv_updateCamera(const mjModel* m, mjData* d, mjvCamera* cam, mjvScene* scn
|
|||||||
scn->camera[view].up[i] = (float)up[i];
|
scn->camera[view].up[i] = (float)up[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// set symmetric frustum
|
// set symmetric frustum using intrinsic camera matrix
|
||||||
scn->camera[view].frustum_center = 0;
|
scn->camera[view].frustum_top = zver[1];
|
||||||
scn->camera[view].frustum_top = (float)znear * tanf(fovy * (float)(mjPI/360.0));
|
scn->camera[view].frustum_bottom = -zver[0];
|
||||||
scn->camera[view].frustum_bottom = -scn->camera[view].frustum_top;
|
scn->camera[view].frustum_center = (zhor[1] - zhor[0]) / 2;
|
||||||
scn->camera[view].frustum_near = (float)znear;
|
scn->camera[view].frustum_width = (zhor[1] + zhor[0]) / 2;
|
||||||
scn->camera[view].frustum_far = (float)zfar;
|
scn->camera[view].frustum_near = znear;
|
||||||
|
scn->camera[view].frustum_far = zfar;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable model transformation (do not clear float data; user may need it later)
|
// disable model transformation (do not clear float data; user may need it later)
|
||||||
|
|||||||
+11
-2
@@ -404,6 +404,14 @@ static void renderGeom(const mjvGeom* geom, int mode, const float* headpos,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case mjGEOM_TRIANGLE: // triangle
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
glVertex3f(0, 0, 0);
|
||||||
|
glVertex3f(size[0], 0, 0);
|
||||||
|
glVertex3f(0, size[1], 0);
|
||||||
|
glEnd();
|
||||||
|
break;
|
||||||
|
|
||||||
case mjGEOM_SKIN: // skin
|
case mjGEOM_SKIN: // skin
|
||||||
// vertex positions
|
// vertex positions
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
@@ -585,8 +593,9 @@ static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute frustum halfwidth so as to match viewport aspect ratio
|
// compute frustum halfwidth so as to match viewport aspect ratio
|
||||||
float halfwidth = 0.5f * (float)viewport.width/(float)viewport.height *
|
float halfwidth = cam.frustum_width ? cam.frustum_width
|
||||||
(cam.frustum_top - cam.frustum_bottom);
|
: 0.5f * (float)viewport.width / (float)viewport.height *
|
||||||
|
(cam.frustum_top - cam.frustum_bottom);
|
||||||
|
|
||||||
// set projection
|
// set projection
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
|||||||
@@ -1623,6 +1623,8 @@ void mjCModel::CopyTree(mjModel* m) {
|
|||||||
m->cam_fovy[cid] = (mjtNum)pc->fovy;
|
m->cam_fovy[cid] = (mjtNum)pc->fovy;
|
||||||
m->cam_ipd[cid] = (mjtNum)pc->ipd;
|
m->cam_ipd[cid] = (mjtNum)pc->ipd;
|
||||||
copyvec(m->cam_resolution+2*cid, pc->resolution, 2);
|
copyvec(m->cam_resolution+2*cid, pc->resolution, 2);
|
||||||
|
copyvec(m->cam_sensorsize+2*cid, pc->sensor_size, 2);
|
||||||
|
copyvec(m->cam_intrinsic+4*cid, pc->intrinsic, 4);
|
||||||
copyvec(m->cam_user+nuser_cam*cid, pc->userdata.data(), nuser_cam);
|
copyvec(m->cam_user+nuser_cam*cid, pc->userdata.data(), nuser_cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3084,6 +3086,7 @@ bool mjCModel::CopyBack(const mjModel* m) {
|
|||||||
cameras[i]->fovy = (double)m->cam_fovy[i];
|
cameras[i]->fovy = (double)m->cam_fovy[i];
|
||||||
cameras[i]->ipd = (double)m->cam_ipd[i];
|
cameras[i]->ipd = (double)m->cam_ipd[i];
|
||||||
copyvec(cameras[i]->resolution, m->cam_resolution+2*i, 2);
|
copyvec(cameras[i]->resolution, m->cam_resolution+2*i, 2);
|
||||||
|
copyvec(cameras[i]->intrinsic, m->cam_intrinsic+4*i, 4);
|
||||||
|
|
||||||
if (nuser_cam) {
|
if (nuser_cam) {
|
||||||
copyvec(cameras[i]->userdata.data(), m->cam_user + nuser_cam*i, nuser_cam);
|
copyvec(cameras[i]->userdata.data(), m->cam_user + nuser_cam*i, nuser_cam);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -1950,6 +1951,12 @@ mjCCamera::mjCCamera(mjCModel* _model, mjCDef* _def) {
|
|||||||
ipd = 0.068;
|
ipd = 0.068;
|
||||||
userdata.clear();
|
userdata.clear();
|
||||||
resolution[0] = resolution[1] = 1;
|
resolution[0] = resolution[1] = 1;
|
||||||
|
principal_length[0] = principal_length[1] = 0;
|
||||||
|
principal_pixel[0] = principal_pixel[1] = 0;
|
||||||
|
focal_length[0] = focal_length[1] = 0;
|
||||||
|
focal_pixel[0] = focal_pixel[1] = 0;
|
||||||
|
sensor_size[0] = sensor_size[1] = 0;
|
||||||
|
mjuu_setvec(intrinsic, 0, 0, 0, 0);
|
||||||
|
|
||||||
// clear private variables
|
// clear private variables
|
||||||
body = 0;
|
body = 0;
|
||||||
@@ -2010,6 +2017,39 @@ void mjCCamera::Compile(void) {
|
|||||||
throw mjCError(this, "fovy too large in camera '%s' (id = %d, value = %d)",
|
throw mjCError(this, "fovy too large in camera '%s' (id = %d, value = %d)",
|
||||||
name.c_str(), id, fovy);
|
name.c_str(), id, fovy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check that specs are not duplicated
|
||||||
|
if ((principal_length[0] && principal_pixel[0]) ||
|
||||||
|
(principal_length[1] && principal_pixel[1])) {
|
||||||
|
throw mjCError(this, "principal length duplicated in camera '%s' (id = %d)",
|
||||||
|
name.c_str(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((focal_length[0] && focal_pixel[0]) ||
|
||||||
|
(focal_length[1] && focal_pixel[1])) {
|
||||||
|
throw mjCError(this, "focal length duplicated in camera '%s' (id = %d)",
|
||||||
|
name.c_str(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute number of pixels per unit length
|
||||||
|
if (sensor_size[0]>0 && sensor_size[1]>0) {
|
||||||
|
float pixel_density[2] = {
|
||||||
|
(float)resolution[0] / sensor_size[0],
|
||||||
|
(float)resolution[1] / sensor_size[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
// defaults are zero, so only one term in each sum is nonzero
|
||||||
|
intrinsic[0] = focal_pixel[0] / pixel_density[0] + focal_length[0];
|
||||||
|
intrinsic[1] = focal_pixel[1] / pixel_density[1] + focal_length[1];
|
||||||
|
intrinsic[2] = principal_pixel[0] / pixel_density[0] + principal_length[0];
|
||||||
|
intrinsic[3] = principal_pixel[1] / pixel_density[1] + principal_length[1];
|
||||||
|
|
||||||
|
// fovy with principal point at (0, 0)
|
||||||
|
fovy = mju_atan2((float)sensor_size[1]/2, intrinsic[1]) * 360.0 / mjPI;
|
||||||
|
} else {
|
||||||
|
intrinsic[0] = model->visual.map.znear;
|
||||||
|
intrinsic[1] = model->visual.map.znear;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -465,7 +465,13 @@ class mjCCamera : public mjCBase {
|
|||||||
double ipd; // inter-pupilary distance
|
double ipd; // inter-pupilary distance
|
||||||
double pos[3]; // position
|
double pos[3]; // position
|
||||||
double quat[4]; // orientation
|
double quat[4]; // orientation
|
||||||
|
float intrinsic[4]; // camera intrinsics [length]
|
||||||
|
float sensor_size[2]; // sensor size [length]
|
||||||
float resolution[2]; // resolution [pixel]
|
float resolution[2]; // resolution [pixel]
|
||||||
|
float focal_length[2]; // focal length [length]
|
||||||
|
float focal_pixel[2]; // focal length [pixel]
|
||||||
|
float principal_length[2]; // principal point [length]
|
||||||
|
float principal_pixel[2]; // principal point [pixel]
|
||||||
std::vector<double> userdata; // user data
|
std::vector<double> userdata; // user data
|
||||||
mjCAlternative alt; // alternative orientation specification
|
mjCAlternative alt; // alternative orientation specification
|
||||||
|
|
||||||
|
|||||||
@@ -148,8 +148,9 @@ static const char* MJCF[nMJCF][mjXATTRNUM] = {
|
|||||||
"hfield", "mesh", "fitscale", "rgba", "fluidshape", "fluidcoef", "user"},
|
"hfield", "mesh", "fitscale", "rgba", "fluidshape", "fluidcoef", "user"},
|
||||||
{"site", "?", "13", "type", "group", "pos", "quat", "material",
|
{"site", "?", "13", "type", "group", "pos", "quat", "material",
|
||||||
"size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"},
|
"size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"},
|
||||||
{"camera", "?", "11", "fovy", "ipd", "pos", "quat", "resolution",
|
{"camera", "?", "16", "fovy", "ipd", "resolution", "pos", "quat", "axisangle", "xyaxes",
|
||||||
"axisangle", "xyaxes", "zaxis", "euler", "mode", "user"},
|
"zaxis", "euler", "mode", "focal", "focalpixel", "principal", "principalpixel",
|
||||||
|
"sensorsize", "user"},
|
||||||
{"light", "?", "12", "pos", "dir", "directional", "castshadow", "active",
|
{"light", "?", "12", "pos", "dir", "directional", "castshadow", "active",
|
||||||
"attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular", "mode"},
|
"attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular", "mode"},
|
||||||
{"pair", "?", "7", "condim", "friction", "solref", "solreffriction", "solimp",
|
{"pair", "?", "7", "condim", "friction", "solref", "solreffriction", "solimp",
|
||||||
@@ -257,9 +258,9 @@ static const char* MJCF[nMJCF][mjXATTRNUM] = {
|
|||||||
{">"},
|
{">"},
|
||||||
{"site", "*", "15", "name", "class", "type", "group", "pos", "quat",
|
{"site", "*", "15", "name", "class", "type", "group", "pos", "quat",
|
||||||
"material", "size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"},
|
"material", "size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"},
|
||||||
{"camera", "*", "14", "name", "class", "fovy", "ipd", "resolution",
|
{"camera", "*", "19", "name", "class", "fovy", "ipd", "resolution", "pos", "quat",
|
||||||
"pos", "quat", "axisangle", "xyaxes", "zaxis", "euler",
|
"axisangle", "xyaxes", "zaxis", "euler", "mode", "target", "focal", "focalpixel",
|
||||||
"mode", "target", "user"},
|
"principal", "principalpixel", "sensorsize", "user"},
|
||||||
{"light", "*", "15", "name", "class", "directional", "castshadow", "active",
|
{"light", "*", "15", "name", "class", "directional", "castshadow", "active",
|
||||||
"pos", "dir", "attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular",
|
"pos", "dir", "attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular",
|
||||||
"mode", "target"},
|
"mode", "target"},
|
||||||
@@ -1461,13 +1462,28 @@ void mjXReader::OneCamera(XMLElement* elem, mjCCamera* pcam) {
|
|||||||
ReadAttr(elem, "pos", 3, pcam->pos, text);
|
ReadAttr(elem, "pos", 3, pcam->pos, text);
|
||||||
ReadQuat(elem, "quat", pcam->quat, text);
|
ReadQuat(elem, "quat", pcam->quat, text);
|
||||||
ReadAlternative(elem, pcam->alt);
|
ReadAlternative(elem, pcam->alt);
|
||||||
ReadAttr(elem, "fovy", 1, &pcam->fovy, text);
|
|
||||||
ReadAttr(elem, "ipd", 1, &pcam->ipd, text);
|
ReadAttr(elem, "ipd", 1, &pcam->ipd, text);
|
||||||
ReadAttr(elem, "resolution", 2, pcam->resolution, text);
|
|
||||||
|
bool has_principal = ReadAttr(elem, "principalpixel", 2, pcam->principal_pixel, text) ||
|
||||||
|
ReadAttr(elem, "principal", 2, pcam->principal_length, text);
|
||||||
|
bool has_focal = ReadAttr(elem, "focalpixel", 2, pcam->focal_pixel, text) ||
|
||||||
|
ReadAttr(elem, "focal", 2, pcam->focal_length, text);
|
||||||
|
bool needs_sensorsize = has_principal || has_focal;
|
||||||
|
bool has_sensorsize = ReadAttr(elem, "sensorsize", 2, pcam->sensor_size, text, needs_sensorsize);
|
||||||
|
bool has_fovy = ReadAttr(elem, "fovy", 1, &pcam->fovy, text);
|
||||||
|
bool needs_resolution = has_focal || has_sensorsize;
|
||||||
|
ReadAttr(elem, "resolution", 2, pcam->resolution, text, needs_resolution);
|
||||||
|
|
||||||
if (pcam->resolution[0] < 0 || pcam->resolution[1] < 0) {
|
if (pcam->resolution[0] < 0 || pcam->resolution[1] < 0) {
|
||||||
throw mjXError(elem, "camera resolution cannot be negative");
|
throw mjXError(elem, "camera resolution cannot be negative");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_fovy && has_sensorsize) {
|
||||||
|
throw mjXError(
|
||||||
|
elem,
|
||||||
|
"either 'fovy' or 'sensorsize' attribute can be specified, not both");
|
||||||
|
}
|
||||||
|
|
||||||
// read userdata
|
// read userdata
|
||||||
ReadVector(elem, "user", pcam->userdata, text);
|
ReadVector(elem, "user", pcam->userdata, text);
|
||||||
|
|
||||||
|
|||||||
@@ -406,10 +406,23 @@ void mjXWriter::OneCamera(XMLElement* elem, mjCCamera* pcam, mjCDef* def) {
|
|||||||
|
|
||||||
// defaults and regular
|
// defaults and regular
|
||||||
WriteAttr(elem, "ipd", 1, &pcam->ipd, &def->camera.ipd);
|
WriteAttr(elem, "ipd", 1, &pcam->ipd, &def->camera.ipd);
|
||||||
WriteAttr(elem, "fovy", 1, &pcam->fovy, &def->camera.fovy);
|
|
||||||
WriteAttrKey(elem, "mode", camlight_map, camlight_sz, pcam->mode, def->camera.mode);
|
WriteAttrKey(elem, "mode", camlight_map, camlight_sz, pcam->mode, def->camera.mode);
|
||||||
WriteAttr(elem, "resolution", 2, pcam->resolution, def->camera.resolution);
|
WriteAttr(elem, "resolution", 2, pcam->resolution, def->camera.resolution);
|
||||||
|
|
||||||
|
// resolution if positive
|
||||||
|
WriteAttr(elem, "resolution", 2, pcam->resolution, def->camera.resolution);
|
||||||
|
|
||||||
|
// camera intrinsics if specified
|
||||||
|
if (pcam->sensor_size[0]>0 && pcam->sensor_size[1]>0) {
|
||||||
|
WriteAttr(elem, "sensorsize", 2, pcam->sensor_size);
|
||||||
|
WriteAttr(elem, "focal", 2, pcam->focal_length, def->camera.focal_length);
|
||||||
|
WriteAttr(elem, "focalpixel", 2, pcam->focal_pixel, def->camera.focal_pixel);
|
||||||
|
WriteAttr(elem, "principal", 2, pcam->principal_length, def->camera.principal_length);
|
||||||
|
WriteAttr(elem, "principalpixel", 2, pcam->principal_pixel, def->camera.principal_pixel);
|
||||||
|
} else {
|
||||||
|
WriteAttr(elem, "fovy", 1, &pcam->fovy, &def->camera.fovy);
|
||||||
|
}
|
||||||
|
|
||||||
// userdata
|
// userdata
|
||||||
if (writingdefaults) {
|
if (writingdefaults) {
|
||||||
WriteVector(elem, "user", pcam->userdata);
|
WriteVector(elem, "user", pcam->userdata);
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
<!-- Please activate Camera rendering when loading this model.
|
||||||
|
The frustum should match exactly the fron face of the box. -->
|
||||||
|
|
||||||
|
<mujoco>
|
||||||
|
<visual>
|
||||||
|
<map znear="0.01"/>
|
||||||
|
</visual>
|
||||||
|
|
||||||
|
<asset>
|
||||||
|
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".8 .6 .4" rgb2=".2 .3 .4"/>
|
||||||
|
<material name="grid" texture="grid" texrepeat="9 16" texuniform="false" reflectance=".2"/>
|
||||||
|
</asset>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 3"/>
|
||||||
|
<geom type="plane" size="10 10 .01"/>
|
||||||
|
|
||||||
|
<geom type="box" size=".375 .6 .1" pos="1.1 0 1" material="grid" euler="0 90 0"/>
|
||||||
|
<!-- 8mm focal length lenses -->
|
||||||
|
<camera pos="0 0 1" xyaxes="0 -1 0 0 0 1" focalpixel="1600 1600" resolution="1920 1200"
|
||||||
|
sensorsize="9.6e-3 6e-3"/>
|
||||||
|
|
||||||
|
<body euler="0 0 90">
|
||||||
|
<geom type="box" size=".375 .6 .1" pos="1.1 2 1" material="grid" euler="0 90 0"/>
|
||||||
|
<!-- 8mm focal length lenses -->
|
||||||
|
<camera pos="0 2 1" xyaxes="0 -1 0 0 0 1" focal="8e-3 8e-3" resolution="1920 1200"
|
||||||
|
sensorsize="9.6e-3 6e-3" principalpixel="200 0"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
@@ -754,6 +754,81 @@ TEST_F(CameraSpecTest, FovyLimits) {
|
|||||||
mj_deleteModel(m);
|
mj_deleteModel(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CameraSpecTest, DuplicatedFocalIgnorePixel) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<visual>
|
||||||
|
<map znear="0.01"/>
|
||||||
|
</visual>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<camera focal="8e-3 8e-3" focalpixel="100 100"
|
||||||
|
resolution="1920 1200" sensorsize="9.6e-3 6e-3"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, NotNull()) << error.data();
|
||||||
|
EXPECT_NEAR(m->cam_intrinsic[0], 5e-4, 1e-6); // focal length in meters (x)
|
||||||
|
EXPECT_NEAR(m->cam_intrinsic[1], 5e-4, 1e-6); // focal length in meters (y)
|
||||||
|
mj_deleteModel(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CameraSpecTest, FovyFromResolution) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<visual>
|
||||||
|
<map znear="0.01"/>
|
||||||
|
</visual>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<!-- 8mm focal length lenses -->
|
||||||
|
<camera focal="8e-3 8e-3" resolution="1920 1200" sensorsize="9.6e-3 6e-3"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, NotNull()) << error.data();
|
||||||
|
EXPECT_NEAR(m->cam_fovy[0], 41.112, 1e-3);
|
||||||
|
EXPECT_NEAR(m->cam_intrinsic[0], 8e-3, 1e-6); // focal length in meters (x)
|
||||||
|
EXPECT_NEAR(m->cam_intrinsic[1], 8e-3, 1e-6); // focal length in meters (y)
|
||||||
|
EXPECT_EQ(m->cam_intrinsic[2], 0); // principal point in meters (x)
|
||||||
|
EXPECT_EQ(m->cam_intrinsic[3], 0); // principal point in meters (y)
|
||||||
|
mj_deleteModel(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CameraSpecTest, FovyFromResolutionPixel) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<visual>
|
||||||
|
<map znear="0.01"/>
|
||||||
|
</visual>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<!-- 8mm focal length lenses -->
|
||||||
|
<camera focalpixel="1600 1600" resolution="1920 1200" sensorsize="9.6e-3 6e-3"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, NotNull()) << error.data();
|
||||||
|
EXPECT_NEAR(m->cam_fovy[0], 41.112, 1e-3);
|
||||||
|
EXPECT_NEAR(m->cam_intrinsic[0], 8e-3, 1e-6); // focal length in meters (x)
|
||||||
|
EXPECT_NEAR(m->cam_intrinsic[1], 8e-3, 1e-6); // focal length in meters (y)
|
||||||
|
EXPECT_EQ(m->cam_intrinsic[2], 0); // principal point in meters (x)
|
||||||
|
EXPECT_EQ(m->cam_intrinsic[3], 0); // principal point in meters (y)
|
||||||
|
mj_deleteModel(m);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------- test actuator order -------------------------------------------
|
// ------------- test actuator order -------------------------------------------
|
||||||
|
|
||||||
using ActuatorTest = MujocoTest;
|
using ActuatorTest = MujocoTest;
|
||||||
|
|||||||
@@ -407,6 +407,61 @@ TEST_F(XMLReaderTest, InvalidDoubleOrientation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------- test camera parsing ---------------------------------
|
||||||
|
|
||||||
|
TEST_F(XMLReaderTest, CameraInvalidFovyAndSensorsize) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<camera fovy="1" sensorsize="1 1" resolution="100 100"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, testing::IsNull());
|
||||||
|
EXPECT_THAT(error.data(), HasSubstr("either 'fovy' or 'sensorsize'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLReaderTest, CameraPricipalRequiresSensorsize) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<camera principal="1 1"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, testing::IsNull());
|
||||||
|
EXPECT_THAT(error.data(), HasSubstr("attribute missing: 'sensorsize'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLReaderTest, CameraSensorsizeRequiresResolution) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom size="1"/>
|
||||||
|
<camera sensorsize="1 1"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, testing::IsNull());
|
||||||
|
EXPECT_THAT(error.data(), HasSubstr("attribute missing: 'resolution'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- test inertia parsing --------------------------------
|
||||||
|
|
||||||
TEST_F(XMLReaderTest, InvalidInertialOrientation) {
|
TEST_F(XMLReaderTest, InvalidInertialOrientation) {
|
||||||
static constexpr char xml[] = R"(
|
static constexpr char xml[] = R"(
|
||||||
<mujoco>
|
<mujoco>
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ public enum mjtGeom : int{
|
|||||||
mjGEOM_LINE = 103,
|
mjGEOM_LINE = 103,
|
||||||
mjGEOM_SKIN = 104,
|
mjGEOM_SKIN = 104,
|
||||||
mjGEOM_LABEL = 105,
|
mjGEOM_LABEL = 105,
|
||||||
|
mjGEOM_TRIANGLE = 106,
|
||||||
mjGEOM_NONE = 1001,
|
mjGEOM_NONE = 1001,
|
||||||
}
|
}
|
||||||
public enum mjtCamLight : int{
|
public enum mjtCamLight : int{
|
||||||
@@ -5218,6 +5219,8 @@ public unsafe struct mjModel_ {
|
|||||||
public double* cam_mat0;
|
public double* cam_mat0;
|
||||||
public int* cam_resolution;
|
public int* cam_resolution;
|
||||||
public double* cam_fovy;
|
public double* cam_fovy;
|
||||||
|
public float* cam_intrinsic;
|
||||||
|
public float* cam_sensorsize;
|
||||||
public double* cam_ipd;
|
public double* cam_ipd;
|
||||||
public double* cam_user;
|
public double* cam_user;
|
||||||
public int* light_mode;
|
public int* light_mode;
|
||||||
@@ -5699,6 +5702,7 @@ public unsafe struct mjvGLCamera_ {
|
|||||||
public fixed float forward[3];
|
public fixed float forward[3];
|
||||||
public fixed float up[3];
|
public fixed float up[3];
|
||||||
public float frustum_center;
|
public float frustum_center;
|
||||||
|
public float frustum_width;
|
||||||
public float frustum_bottom;
|
public float frustum_bottom;
|
||||||
public float frustum_top;
|
public float frustum_top;
|
||||||
public float frustum_near;
|
public float frustum_near;
|
||||||
@@ -5993,6 +5997,7 @@ public unsafe struct model {
|
|||||||
public float* site_rgba;
|
public float* site_rgba;
|
||||||
public double* cam_fovy;
|
public double* cam_fovy;
|
||||||
public double* cam_ipd;
|
public double* cam_ipd;
|
||||||
|
public float* cam_sensorsize;
|
||||||
public byte* light_directional;
|
public byte* light_directional;
|
||||||
public byte* light_castshadow;
|
public byte* light_castshadow;
|
||||||
public byte* light_active;
|
public byte* light_active;
|
||||||
|
|||||||
Reference in New Issue
Block a user