From 7190bd49125c3309b8b3e099bac3be38fa0e8ea2 Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Thu, 18 Dec 2025 04:35:28 -0800 Subject: [PATCH] Add flag for depth rendering. PiperOrigin-RevId: 846203691 Change-Id: I5ec494446bcfc1f7c81536a87dd24f9967973563 --- doc/changelog.rst | 1 + doc/includes/references.h | 1 + include/mujoco/mjvisualize.h | 1 + python/mujoco/introspect/enums.py | 9 ++-- python/mujoco/introspect/structs.py | 2 +- src/engine/engine_vis_init.c | 1 + .../filament/filament/filament_context.cc | 10 ++-- src/render/render_gl3.c | 50 ++++++++++++++++++- unity/Runtime/Bindings/MjBindings.cs | 11 ++-- wasm/codegen/generated/bindings.cc | 3 +- wasm/tests/bindings_test.ts | 4 +- 11 files changed, 76 insertions(+), 17 deletions(-) diff --git a/doc/changelog.rst b/doc/changelog.rst index 8c0adb30..fc5489ec 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -12,6 +12,7 @@ General - The type of the ``sig`` (signature) argument of :ref:`mj_stateSize` and related functions has been changed from ``unsigned int`` to ``int``. Before this change, invalid negative arguments passed to this function would result in a silent implicit cast, now negativity will trigger an error. + - Added a :ref:`depth` rendering flag MJX ^^^ diff --git a/doc/includes/references.h b/doc/includes/references.h index 632a575c..be6e0368 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -2829,6 +2829,7 @@ typedef enum mjtRndFlag_ { // flags enabling rendering effects mjRND_SKYBOX, // skybox mjRND_FOG, // fog mjRND_HAZE, // haze + mjRND_DEPTH, // depth mjRND_SEGMENT, // segmentation with random color mjRND_IDCOLOR, // segmentation with segid+1 color mjRND_CULL_FACE, // cull backward faces diff --git a/include/mujoco/mjvisualize.h b/include/mujoco/mjvisualize.h index 25a28618..10127c7c 100644 --- a/include/mujoco/mjvisualize.h +++ b/include/mujoco/mjvisualize.h @@ -146,6 +146,7 @@ typedef enum mjtRndFlag_ { // flags enabling rendering effects mjRND_SKYBOX, // skybox mjRND_FOG, // fog mjRND_HAZE, // haze + mjRND_DEPTH, // depth mjRND_SEGMENT, // segmentation with random color mjRND_IDCOLOR, // segmentation with segid+1 color mjRND_CULL_FACE, // cull backward faces diff --git a/python/mujoco/introspect/enums.py b/python/mujoco/introspect/enums.py index a4ba2b37..70e2c0d6 100644 --- a/python/mujoco/introspect/enums.py +++ b/python/mujoco/introspect/enums.py @@ -814,10 +814,11 @@ ENUMS: Mapping[str, EnumDecl] = dict([ ('mjRND_SKYBOX', 4), ('mjRND_FOG', 5), ('mjRND_HAZE', 6), - ('mjRND_SEGMENT', 7), - ('mjRND_IDCOLOR', 8), - ('mjRND_CULL_FACE', 9), - ('mjNRNDFLAG', 10), + ('mjRND_DEPTH', 7), + ('mjRND_SEGMENT', 8), + ('mjRND_IDCOLOR', 9), + ('mjRND_CULL_FACE', 10), + ('mjNRNDFLAG', 11), ]), )), ('mjtStereo', diff --git a/python/mujoco/introspect/structs.py b/python/mujoco/introspect/structs.py index 88aac321..5393b5d3 100644 --- a/python/mujoco/introspect/structs.py +++ b/python/mujoco/introspect/structs.py @@ -10169,7 +10169,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([ name='flags', type=ArrayType( inner_type=ValueType(name='mjtByte'), - extents=(10,), + extents=(11,), ), doc='rendering flags (indexed by mjtRndFlag)', ), diff --git a/src/engine/engine_vis_init.c b/src/engine/engine_vis_init.c index 14b9ebb5..5f8a50eb 100644 --- a/src/engine/engine_vis_init.c +++ b/src/engine/engine_vis_init.c @@ -111,6 +111,7 @@ const char* mjRNDSTRING[mjNRNDFLAG][3] = { {"Skybox", "1", "K"}, {"Fog", "0", "G"}, {"Haze", "1", "/"}, + {"Depth", "0", ""}, {"Segment", "0", ","}, {"Id Color", "0", ""}, {"Cull Face", "1", ""} diff --git a/src/experimental/filament/filament/filament_context.cc b/src/experimental/filament/filament/filament_context.cc index ce60a238..305e8474 100644 --- a/src/experimental/filament/filament/filament_context.cc +++ b/src/experimental/filament/filament/filament_context.cc @@ -154,9 +154,13 @@ void FilamentContext::Render(const mjrRect& viewport, const mjvScene* scene, render_gui_ = gui_view_->PrepareRenderable(); } - last_render_mode_ = scene->flags[mjRND_SEGMENT] - ? SceneView::DrawMode::kSegmentation - : SceneView::DrawMode::kNormal; + last_render_mode_ = SceneView::DrawMode::kNormal; + if (scene->flags[mjRND_SEGMENT]) { + last_render_mode_ = SceneView::DrawMode::kSegmentation; + } else if (scene->flags[mjRND_DEPTH]) { + last_render_mode_ = SceneView::DrawMode::kDepth; + } + // Render the frame if we're not rendering to a texture. if (!render_to_texture_) { filament::View* view = scene_view_->PrepareRenderView(last_render_mode_); diff --git a/src/render/render_gl3.c b/src/render/render_gl3.c index b4b9cf71..a13daa0e 100644 --- a/src/render/render_gl3.c +++ b/src/render/render_gl3.c @@ -1019,7 +1019,7 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { //---------------------------------- reflection rendering // plane and box reflection rendering - if (scn->flags[mjRND_REFLECTION]) { + if (scn->flags[mjRND_REFLECTION] && !scn->flags[mjRND_DEPTH]) { for (int i=0; i < ngeom; i++) { // get geom pointer thisgeom = scn->geoms + i; @@ -1481,6 +1481,54 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { glDisable(GL_SCISSOR_TEST); } + if (scn->flags[mjRND_DEPTH]) { + glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_TEXTURE_BIT | + GL_LIGHTING_BIT | GL_POLYGON_BIT); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, 1, 0, 1, -1, 1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + void* depth_buf = mju_malloc(sizeof(float) * viewport.width * viewport.height); + glReadPixels(0, 0, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_FLOAT, depth_buf); + + GLuint depth_tex; + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &depth_tex); + glBindTexture(GL_TEXTURE_2D, depth_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, viewport.width, viewport.height, + 0, GL_LUMINANCE, GL_FLOAT, depth_buf); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glColor4f(1, 1, 1, 1); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(1, 0); glVertex2f(1, 0); + glTexCoord2f(1, 1); glVertex2f(1, 1); + glTexCoord2f(0, 1); glVertex2f(0, 1); + glEnd(); + + glDeleteTextures(1, &depth_tex); + mju_free(depth_buf); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); + } + // restore currentBuffer mjr_restoreBuffer(con); } diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 785d2532..873de91f 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -678,10 +678,11 @@ public enum mjtRndFlag : int{ mjRND_SKYBOX = 4, mjRND_FOG = 5, mjRND_HAZE = 6, - mjRND_SEGMENT = 7, - mjRND_IDCOLOR = 8, - mjRND_CULL_FACE = 9, - mjNRNDFLAG = 10, + mjRND_DEPTH = 7, + mjRND_SEGMENT = 8, + mjRND_IDCOLOR = 9, + mjRND_CULL_FACE = 10, + mjNRNDFLAG = 11, } public enum mjtStereo : int{ mjSTEREO_NONE = 0, @@ -6315,7 +6316,7 @@ public unsafe struct mjvScene_ { public fixed float rotate[4]; public float scale; public int stereo; - public fixed byte flags[10]; + public fixed byte flags[11]; public int framewidth; public fixed float framergb[3]; public int status; diff --git a/wasm/codegen/generated/bindings.cc b/wasm/codegen/generated/bindings.cc index 27ce3adb..15795889 100644 --- a/wasm/codegen/generated/bindings.cc +++ b/wasm/codegen/generated/bindings.cc @@ -7523,7 +7523,7 @@ struct MjvScene { // skinvertadr field is handled manually in template file struct declaration // skinvertnum field is handled manually in template file struct declaration emscripten::val flags() const { - return emscripten::val(emscripten::typed_memory_view(10, ptr_->flags)); + return emscripten::val(emscripten::typed_memory_view(11, ptr_->flags)); } emscripten::val framergb() const { return emscripten::val(emscripten::typed_memory_view(3, ptr_->framergb)); @@ -10511,6 +10511,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { .value("mjRND_SKYBOX", mjRND_SKYBOX) .value("mjRND_FOG", mjRND_FOG) .value("mjRND_HAZE", mjRND_HAZE) + .value("mjRND_DEPTH", mjRND_DEPTH) .value("mjRND_SEGMENT", mjRND_SEGMENT) .value("mjRND_IDCOLOR", mjRND_IDCOLOR) .value("mjRND_CULL_FACE", mjRND_CULL_FACE) diff --git a/wasm/tests/bindings_test.ts b/wasm/tests/bindings_test.ts index 56614d8b..10aac900 100644 --- a/wasm/tests/bindings_test.ts +++ b/wasm/tests/bindings_test.ts @@ -692,8 +692,8 @@ describe('MuJoCo WASM Bindings', () => { expect(mujoco.get_mjRNDSTRING()).toEqual([ ['Shadow', '1', 'S'], ['Wireframe', '0', 'W'], ['Reflection', '1', 'R'], ['Additive', '0', 'L'], ['Skybox', '1', 'K'], ['Fog', '0', 'G'], - ['Haze', '1', '/'], ['Segment', '0', ','], ['Id Color', '0', ''], - ['Cull Face', '1', ''] + ['Haze', '1', '/'], ['Depth', '0', ''], ['Segment', '0', ','], + ['Id Color', '0', ''], ['Cull Face', '1', ''] ]); expect(mujoco.get_mjFRAMESTRING().length) .toEqual(mujoco.mjtFrame.mjNFRAME.value);