Merge pull request #1479 from jmargeta:fix-record-command-docs

PiperOrigin-RevId: 613927858
Change-Id: I8fe30db8677811c98ed4f881b51a0f430d93dd3b
This commit is contained in:
Copybara-Service
2024-03-08 07:29:57 -08:00
2 changed files with 62 additions and 15 deletions
+47 -8
View File
@@ -150,21 +150,60 @@ This code sample simulates the passive dynamics of a given model, renders it off
values, and saves them into a raw data file that can then be converted into a movie file with tools such as ffmpeg. The values, and saves them into a raw data file that can then be converted into a movie file with tools such as ffmpeg. The
rendering is simplified compared to :ref:`simulate.cc <saSimulate>` because there is no user interaction, visualization rendering is simplified compared to :ref:`simulate.cc <saSimulate>` because there is no user interaction, visualization
options or timing; instead we simply render with the default settings as fast as possible. The dimensions and number of options or timing; instead we simply render with the default settings as fast as possible. The dimensions and number of
multi-samples for the offscreen buffer are specified in the MuJoCo model, while the simulation duration, frames-per- multi-samples for the offscreen buffer are specified in the MuJoCo model with the visual/global/{`offwidth
second to be rendered (usually much less than the physics simulation rate), and output file name are specified as <https://mujoco.readthedocs.io/en/stable/XMLreference.html#visual-global-offwidth>`__, `offheight
command-line arguments. For example, a 5 second animation at 60 frames per second is created with: <https://mujoco.readthedocs.io/en/stable/XMLreference.html#visual-global-offheight>`__} and visual/quality/`offsamples
<https://mujoco.readthedocs.io/en/stable/XMLreference.html#visual-quality-offsamples>`_ attributes, while the simulation
duration, frames-per-second to be rendered (usually much less than the physics simulation rate), and output file name
are specified as command-line arguments.
.. code-block:: Shell .. code-block:: Shell
render humanoid.xml 5 60 rgb.out record modelfile duration fps rgbfile [adddepth]
The default humanoid.xml model specifies offscreen rendering with 800x800 resolution. With this information in hand, we Where the command line arguments are
can compress the (large) raw date file into a playable movie file:
.. list-table::
:width: 95%
:align: left
:widths: 1 1 5
:header-rows: 1
* - Argument
- Default
- Meaning
* - ``modelfile``
- (required)
- path to model
* - ``duration``
- (required)
- duration of the recording in seconds
* - ``fps``
- (required)
- number of frames per second
* - ``rgbfile``
- (required)
- path to raw recording file
* - ``adddepth``
- 1
- overlay depth image in the lower left corner (0: none)
For example, a 5 second animation at 60 frames per second is created with:
.. code-block:: Shell .. code-block:: Shell
ffmpeg -f rawvideo -pixel_format rgb24 -video_size 800x800 record humanoid.xml 5 60 rgb.out
-framerate 60 -i rgb.out -vf "vflip" video.mp4
The default `humanoid.xml <https://github.com/google-deepmind/mujoco/blob/main/model/humanoid/humanoid.xml>`__ model
specifies offscreen rendering with 2560x1440 resolution. With this information in hand, we can compress the (large) raw
data file into a playable movie file:
.. code-block:: Shell
ffmpeg -f rawvideo -pixel_format rgb24 -video_size 2560x1440
-framerate 60 -i rgb.out -vf "vflip,format=yuv420p" video.mp4
Note that the offscreen rendering resolution of the model and ffmpeg's video_size must be the identical.
This sample can be compiled in three ways which differ in how the OpenGL context is created: using GLFW with an This sample can be compiled in three ways which differ in how the OpenGL context is created: using GLFW with an
invisible window, using OSMesa, or using EGL. The latter two options are only available on Linux and are envoked by invisible window, using OSMesa, or using EGL. The latter two options are only available on Linux and are envoked by
+15 -7
View File
@@ -217,8 +217,8 @@ void closeOpenGL(void) {
int main(int argc, const char** argv) { int main(int argc, const char** argv) {
// check command-line arguments // check command-line arguments
if (argc!=5) { if (argc < 5 || argc > 6) {
std::printf(" USAGE: record modelfile duration fps rgbfile\n"); std::printf(" USAGE: record modelfile duration fps rgbfile [adddepth]\n");
return 0; return 0;
} }
@@ -255,6 +255,11 @@ int main(int argc, const char** argv) {
mju_error("Could not open rgbfile for writing"); mju_error("Could not open rgbfile for writing");
} }
int adddepth = 1;
if (argc > 5 && std::sscanf(argv[5], "%d", &adddepth) != 1) {
mju_error("Invalid adddepth argument");
}
// main loop // main loop
double frametime = 0; double frametime = 0;
int framecount = 0; int framecount = 0;
@@ -276,12 +281,15 @@ int main(int argc, const char** argv) {
mjr_readPixels(rgb, depth, viewport, &con); mjr_readPixels(rgb, depth, viewport, &con);
// insert subsampled depth image in lower-left corner of rgb image // insert subsampled depth image in lower-left corner of rgb image
const int NS = 3; // depth image sub-sampling if (adddepth) {
for (int r=0; r<H; r+=NS) const int NS = 3; // depth image sub-sampling
for (int c=0; c<W; c+=NS) { for (int r=0; r<H; r+=NS) {
int adr = (r/NS)*W + c/NS; for (int c=0; c<W; c+=NS) {
rgb[3*adr] = rgb[3*adr+1] = rgb[3*adr+2] = (unsigned char)((1.0f-depth[r*W+c])*255.0f); int adr = (r/NS)*W + c/NS;
rgb[3*adr] = rgb[3*adr+1] = rgb[3*adr+2] = (unsigned char)((1.0f-depth[r*W+c])*255.0f);
}
} }
}
// write rgb image to file // write rgb image to file
std::fwrite(rgb, 3, W*H, fp); std::fwrite(rgb, 3, W*H, fp);