当前位置:网站首页>Mujoco produces analog video
Mujoco produces analog video
2022-07-07 00:28:00 【Feisy】
This code sample simulates the passive dynamics of a given model, renders it offscreen, reads the color and depth pixel 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 simulate.cc 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 multi-samples for the offscreen buffer are specified in the MuJoCo model, 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. For example, a 5 second animation at 60 frames per second is created with:
render humanoid.xml 5 60 rgb.out
The default humanoid.xml model specifies offscreen rendering with 800x800 resolution. With this information in hand, we can compress the (large) raw date file into a playable movie file:
ffmpeg -f rawvideo -pixel_format rgb24 -video_size 800x800
-framerate 60 -i rgb.out -vf "vflip" video.mp4
But I failed several times , Find out ffmpeg There are size requirements inside , We will
Make a size setting for the model :
<visual>
<map force="0.1" zfar="30"/>
<rgba haze="0.15 0.25 0.35 1"/>
<quality shadowsize="4096"/>
<global offwidth="800" offheight="800"/>
</visual>
In this way, the video is successfully produced
take record.cc The problem of compiling to your own project
For the moment , I can't embed the recording function directly into the project , Feel the recording function
Eat resources very much , And when recording OPENGL To do it , The test found that it would follow mujoco Of UI
A little conflict , Lead to mujoco Of UI No display .
Possible problems
Use Mujoco Self contained record.cc Just change it
But be careful , use g++ compile , If you use gcc compile ,
May report cstdio Can't find such a mistake .
in addition , The file name cannot be too long , Otherwise std::fopen It won't open
record.cc Useful to mujoco Of array_safe.h, This is the source code , It can be copied directly
Into your own project
Example : The test can pass
Mujoco Record analog video
// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "mujoco.h"
// select EGL, OSMESA or GLFW
#if defined(MJ_EGL)
#include <EGL/egl.h>
#elif defined(MJ_OSMESA)
#include <GL/osmesa.h>
OSMesaContext ctx;
unsigned char buffer[10000000];
#else
#include <GLFW/glfw3.h>
#endif
#include "array_safety.h"
namespace mju = ::mujoco::sample_util;
//-------------------------------- global data ------------------------------------------
char xmlpath[] = "./dbpendulum/doublependulum.xml";
char rgb_file[] = "./rgb.out";
// MuJoCo model and data
mjModel* m = 0;
mjData* d = 0;
// MuJoCo visualization
mjvScene scn;
mjvCamera cam;
mjvOption opt;
mjrContext con;
//-------------------------------- utility functions ------------------------------------
// load model, init simulation and rendering
void initMuJoCo(const char* filename) {
// load and compile
char error[1000] = "Could not load binary model";
if (std::strlen(filename)>4 && !std::strcmp(filename+std::strlen(filename)-4, ".mjb")) {
m = mj_loadModel(filename, 0);
} else {
m = mj_loadXML(filename, 0, error, 1000);
}
if (!m) {
mju_error_s("Load model error: %s", error);
}
// make data, run one computation to initialize all fields
d = mj_makeData(m);
mj_forward(m, d);
// initialize visualization data structures
mjv_defaultCamera(&cam);
mjv_defaultOption(&opt);
mjv_defaultScene(&scn);
mjr_defaultContext(&con);
// create scene and context
mjv_makeScene(m, &scn, 2000);
mjr_makeContext(m, &con, 200);
// center and scale view
double arr_view[] = {
89.608063, -11.588379, 5, 0.000000, 0.000000, 2.000000};
cam.azimuth = arr_view[0];
cam.elevation = arr_view[1];
cam.distance = arr_view[2];
cam.lookat[0] = arr_view[3];
cam.lookat[1] = arr_view[4];
cam.lookat[2] = arr_view[5];
}
// deallocate everything
void closeMuJoCo(void) {
mj_deleteData(d);
mj_deleteModel(m);
mjr_freeContext(&con);
mjv_freeScene(&scn);
}
// create OpenGL context/window
void initOpenGL(void) {
//------------------------ EGL
#if defined(MJ_EGL)
// desired config
const EGLint configAttribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
};
// get default display
EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (eglDpy==EGL_NO_DISPLAY) {
mju_error_i("Could not get EGL display, error 0x%x\n", eglGetError());
}
// initialize
EGLint major, minor;
if (eglInitialize(eglDpy, &major, &minor)!=EGL_TRUE) {
mju_error_i("Could not initialize EGL, error 0x%x\n", eglGetError());
}
// choose config
EGLint numConfigs;
EGLConfig eglCfg;
if (eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs)!=EGL_TRUE) {
mju_error_i("Could not choose EGL config, error 0x%x\n", eglGetError());
}
// bind OpenGL API
if (eglBindAPI(EGL_OPENGL_API)!=EGL_TRUE) {
mju_error_i("Could not bind EGL OpenGL API, error 0x%x\n", eglGetError());
}
// create context
EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, NULL);
if (eglCtx==EGL_NO_CONTEXT) {
mju_error_i("Could not create EGL context, error 0x%x\n", eglGetError());
}
// make context current, no surface (let OpenGL handle FBO)
if (eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglCtx)!=EGL_TRUE) {
mju_error_i("Could not make EGL context current, error 0x%x\n", eglGetError());
}
//------------------------ OSMESA
#elif defined(MJ_OSMESA)
// create context
ctx = OSMesaCreateContextExt(GL_RGBA, 24, 8, 8, 0);
if (!ctx) {
mju_error("OSMesa context creation failed");
}
// make current
if (!OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, 800, 800)) {
mju_error("OSMesa make current failed");
}
//------------------------ GLFW
#else
// init GLFW
if (!glfwInit()) {
mju_error("Could not initialize GLFW");
}
// create invisible window, single-buffered
glfwWindowHint(GLFW_VISIBLE, 0);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_FALSE);
GLFWwindow* window = glfwCreateWindow(800, 800, "Invisible window", NULL, NULL);
if (!window) {
mju_error("Could not create GLFW window");
}
// make context current
glfwMakeContextCurrent(window);
#endif
}
// close OpenGL context/window
void closeOpenGL(void) {
//------------------------ EGL
#if defined(MJ_EGL)
// get current display
EGLDisplay eglDpy = eglGetCurrentDisplay();
if (eglDpy==EGL_NO_DISPLAY) {
return;
}
// get current context
EGLContext eglCtx = eglGetCurrentContext();
// release context
eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// destroy context if valid
if (eglCtx!=EGL_NO_CONTEXT) {
eglDestroyContext(eglDpy, eglCtx);
}
// terminate display
eglTerminate(eglDpy);
//------------------------ OSMESA
#elif defined(MJ_OSMESA)
OSMesaDestroyContext(ctx);
//------------------------ GLFW
#else
// terminate GLFW (crashes with Linux NVidia drivers)
#if defined(__APPLE__) || defined(_WIN32)
glfwTerminate();
#endif
#endif
}
//-------------------------------- main function ----------------------------------------
int main(int argc, const char** argv) {
// parse numeric arguments
double duration = 10, fps = 60;
// initialize OpenGL and MuJoCo
initOpenGL();
initMuJoCo(xmlpath);
// set rendering to offscreen buffer
mjr_setBuffer(mjFB_OFFSCREEN, &con);
if (con.currentBuffer!=mjFB_OFFSCREEN) {
std::printf("Warning: offscreen rendering not supported, using default/window framebuffer\n");
}
// get size of active renderbuffer
mjrRect viewport = mjr_maxViewport(&con);
int W = viewport.width;
int H = viewport.height;
// allocate rgb and depth buffers
unsigned char* rgb = (unsigned char*)std::malloc(3*W*H);
float* depth = (float*)std::malloc(sizeof(float)*W*H);
if (!rgb || !depth) {
mju_error("Could not allocate buffers");
}
// create output rgb file
std::FILE* fp = std::fopen(rgb_file, "wb");
if (!fp) {
mju_error("Could not open rgbfile for writing");
}
d->qpos[0] = 0.5;
// main loop
double frametime = 0;
int framecount = 0;
while (d->time<duration) {
// render new frame if it is time (or first frame)
if ((d->time-frametime)>1/fps || frametime==0) {
// update abstract scene
mjv_updateScene(m, d, &opt, NULL, &cam, mjCAT_ALL, &scn);
// render scene in offscreen buffer
mjr_render(viewport, &scn, &con);
// add time stamp in upper-left corner
char stamp[50];
mju::sprintf_arr(stamp, "Time = %.3f", d->time);
mjr_overlay(mjFONT_NORMAL, mjGRID_TOPLEFT, viewport, stamp, NULL, &con);
// read rgb and depth buffers
mjr_readPixels(rgb, depth, viewport, &con);
// insert subsampled depth image in lower-left corner of rgb image
const int NS = 3; // depth image sub-sampling
for (int r=0; r<H; r+=NS)
for (int c=0; c<W; c+=NS) {
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
std::fwrite(rgb, 3, W*H, fp);
// print every 10 frames: '.' if ok, 'x' if OpenGL error
if (((framecount++)%10)==0) {
if (mjr_getError()) {
std::printf("x");
} else {
std::printf(".");
}
}
// save simulation time
frametime = d->time;
}
// advance simulation
mj_step(m, d);
}
std::printf("\n");
// close file, free buffers
std::fclose(fp);
std::free(rgb);
std::free(depth);
// close MuJoCo and OpenGL
closeMuJoCo();
closeOpenGL();
return 1;
}
#MAC
#COMMON=-O2 -I../../include -L../../bin -mavx -pthread
#LIBS = -w -lmujoco200 -lglfw.3
#CC = gcc
#LINUX
#COMMON=-O2 -I../../include -L../../bin -mavx -pthread -Wl,-rpath,'$$ORIGIN'
#LIBS = -lmujoco200 -lGL -lm -lglew ../../bin/libglfw.so.3
COMMON=-O2 -I../include -L../bin -mavx -pthread -Wl,-rpath,'$$ORIGIN'
LIBS = ../bin/libmujoco.so -lGL -lm ../bin/libglew.so ../bin/libglfw.so.3
CC = g++
#WINDOWS
#COMMON=/O2 /MT /EHsc /arch:AVX /I../../include /Fe../../bin/
#LIBS = ../../bin/glfw3.lib ../../bin/mujoco200.lib
#CC = cl
ROOT = dbpendulum
RECORD=db_record
all:
$(CC) $(COMMON) main.c $(LIBS) -o ../bin/$(ROOT)
$(CC) $(COMMON) record.c $(LIBS) -o ../bin/$(RECORD)
main.o:
$(CC) $(COMMON) -c main.c
record.o:
$(CC) $(COMMON) -c record.c
clean:
rm *.o ../../bin/$(ROOT)
边栏推荐
- @TableId can‘t more than one in Class: “com.example.CloseContactSearcher.entity.Activity“.
- What is a responsive object? How to create a responsive object?
- Testers, how to prepare test data
- Oracle EMCC 13.5 environment in docker every minute
- Liuyongxin report | microbiome data analysis and science communication (7:30 p.m.)
- DAY ONE
- 2022/2/11 summary
- Are you ready to automate continuous deployment in ci/cd?
- Sword finger offer 26 Substructure of tree
- A way of writing SQL, update when matching, or insert
猜你喜欢

GEO数据挖掘(三)使用DAVID数据库进行GO、KEGG富集分析

DAY SIX

工程师如何对待开源 --- 一个老工程师的肺腑之言
![[2022 the finest in the whole network] how to test the interface test generally? Process and steps of interface test](/img/8d/b59cf466031f36eb50d4d06aa5fbe4.jpg)
[2022 the finest in the whole network] how to test the interface test generally? Process and steps of interface test

2022年PMP项目管理考试敏捷知识点(9)

Are you ready to automate continuous deployment in ci/cd?

Liuyongxin report | microbiome data analysis and science communication (7:30 p.m.)

How engineers treat open source -- the heartfelt words of an old engineer

Clipboard management tool paste Chinese version

DAY TWO
随机推荐
【CVPR 2022】目标检测SOTA:DINO: DETR with Improved DeNoising Anchor Boxes for End-to-End Object Detection
How to use vector_ How to use vector pointer
MySQL主从之多源复制(3主1从)搭建及同步测试
On February 19, 2021ccf award ceremony will be held, "why in Hengdian?"
JWT signature does not match locally computed signature. JWT validity cannot be asserted and should
Leecode brush questions record interview questions 32 - I. print binary tree from top to bottom
【vulnhub】presidential1
509 certificat basé sur Go
MIT 6.824 - Raft学生指南
48 page digital government smart government all in one solution
AI超清修复出黄家驹眼里的光、LeCun大佬《深度学习》课程生还报告、绝美画作只需一行代码、AI最新论文 | ShowMeAI资讯日报 #07.06
Things like random
Core knowledge of distributed cache
【自动化测试框架】关于unittest你需要知道的事
DAY THREE
[boutique] Pinia Persistence Based on the plug-in Pinia plugin persist
Quickly use various versions of PostgreSQL database in docker
Pytest multi process / multi thread execution test case
《LaTex》LaTex数学公式简介「建议收藏」
pinia 模块划分