diff --git a/include/mujoco/mjrender.h b/include/mujoco/mjrender.h index fb37d926..6d304f89 100644 --- a/include/mujoco/mjrender.h +++ b/include/mujoco/mjrender.h @@ -39,6 +39,10 @@ typedef enum mjtFramebuffer_ { // OpenGL framebuffer option mjFB_OFFSCREEN // offscreen buffer } mjtFramebuffer; +typedef enum mjtDepthMapping_ { // OpenGL depth buffer readout mapping (from znear to zfar) + mjDM_ZEROTOONE = 0, // Legacy default, reverses reversed Z rendering, performance penalty + mjDM_ONETOZERO // Native output of reversed Z rendering, decreases numerical error +} mjtDepthMapping; typedef enum mjtFontScale_ { // font scale, used at context creation mjFONTSCALE_50 = 50, // 50% scale, suitable for low-res rendering @@ -151,6 +155,9 @@ struct mjrContext_ { // custom OpenGL context // pixel output format int readPixelFormat; // default color pixel format for mjr_readPixels + + // depth output format + int readDepthMapping; // depth mapping, 0 to 1 (default, legacy), or 1 to 0 (reversed, native) }; typedef struct mjrContext_ mjrContext; diff --git a/introspect/enums.py b/introspect/enums.py index fbee5402..4c9efece 100644 --- a/introspect/enums.py +++ b/introspect/enums.py @@ -621,6 +621,15 @@ ENUMS: Mapping[str, EnumDecl] = dict([ ('mjFB_OFFSCREEN', 1), ]), )), + ('mjtDepthMapping', + EnumDecl( + name='mjtDepthMapping', + declname='enum mjtDepthMapping_', + values=dict([ + ('mjDM_ZEROTOONE', 0), + ('mjDM_ONETOZERO', 1), + ]), + )), ('mjtFontScale', EnumDecl( name='mjtFontScale', diff --git a/introspect/structs.py b/introspect/structs.py index a06e9a67..81e90786 100644 --- a/introspect/structs.py +++ b/introspect/structs.py @@ -7126,6 +7126,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='int'), doc='default color pixel format for mjr_readPixels', ), + StructFieldDecl( + name='readDepthMapping', + type=ValueType(name='int'), + doc='depth mapping, 0 to 1 (default, legacy), or 1 to 0 (reversed, native)', # pylint: disable=line-too-long + ), ), )), ('mjuiState', diff --git a/python/mujoco/render.cc b/python/mujoco/render.cc index 622bbb7a..bae7a299 100644 --- a/python/mujoco/render.cc +++ b/python/mujoco/render.cc @@ -215,6 +215,7 @@ PYBIND11_MODULE(_render, pymodule) { X(windowDoublebuffer); X(currentBuffer); X(readPixelFormat); + X(readDepthMapping); #undef X #define X(var) \ diff --git a/python/mujoco/renderer.py b/python/mujoco/renderer.py index 3360523c..c1471485 100644 --- a/python/mujoco/renderer.py +++ b/python/mujoco/renderer.py @@ -86,6 +86,7 @@ the clause: _render.mjr_setBuffer( _enums.mjtFramebuffer.mjFB_OFFSCREEN.value, self._mjr_context ) + self._mjr_context.readDepthMapping = _enums.mjtDepthMapping.mjDM_ONETOZERO # Default render flags. self._depth_rendering = False @@ -196,6 +197,7 @@ the clause: out_64 = D / (out_64 + C) # Cast result back to float32 for backwards compatibility + # This has a small accuracy cost out[:] = out_64.astype(np.float32) # Reset scene flags. diff --git a/src/render/render_context.c b/src/render/render_context.c index 0d673de2..86c04151 100644 --- a/src/render/render_context.c +++ b/src/render/render_context.c @@ -1612,6 +1612,9 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale, // set default color pixel format for mjr_readPixels con->readPixelFormat = GL_RGB; + + // set default depth mapping for mjr_readPixels + con->readDepthMapping = mjDM_ZEROTOONE; } diff --git a/src/render/render_gl2.c b/src/render/render_gl2.c index 095d5b41..91084eb4 100644 --- a/src/render/render_gl2.c +++ b/src/render/render_gl2.c @@ -115,6 +115,10 @@ void mjr_readPixels(unsigned char* rgb, float* depth, if (depth) { glReadPixels(viewport.left, viewport.bottom, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_FLOAT, depth); + if (con->readDepthMapping == mjDM_ZEROTOONE) { + int N_pixels = viewport.width * viewport.height; + for (int i = 0; i < N_pixels; i++) depth[i] = 1.0 - depth[i]; // Reverse the reversed Z buffer + } } } @@ -159,6 +163,11 @@ void mjr_readPixels(unsigned char* rgb, float* depth, if (depth) { glReadPixels(viewport.left, viewport.bottom, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_FLOAT, depth); + + if (con->readDepthMapping == mjDM_ZEROTOONE) { + int N_pixels = viewport.width * viewport.height; + for (int i = 0; i < N_pixels; i++) depth[i] = 1.0 - depth[i]; // Reverse the reversed Z buffer + } } // restore currentBuffer diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index ac5c8161..4afa8597 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -389,6 +389,10 @@ public enum mjtFramebuffer : int{ mjFB_WINDOW = 0, mjFB_OFFSCREEN = 1, } +public enum mjtDepthMapping : int{ + mjDM_ZEROTOONE = 0, + mjDM_ONETOZERO = 1, +} public enum mjtFontScale : int{ mjFONTSCALE_50 = 50, mjFONTSCALE_100 = 100,