From d32eb6bd123156985fa38653384145559d2fc9e7 Mon Sep 17 00:00:00 2001 From: Levi Burner Date: Tue, 11 Jul 2023 14:10:14 -0400 Subject: [PATCH] In place change to reverse Z rendering and 32 bit float offscreen depth buffer --- include/mujoco/mjrender.h | 15 --------- introspect/enums.py | 18 ----------- introspect/structs.py | 10 ------ python/mujoco/render.cc | 34 -------------------- python/mujoco/renderer.py | 23 ++++--------- simulate/platform_ui_adapter.cc | 1 - src/render/render_context.c | 28 ++++------------ src/render/render_gl3.c | 48 ++++++---------------------- unity/Runtime/Bindings/MjBindings.cs | 8 ----- 9 files changed, 24 insertions(+), 161 deletions(-) diff --git a/include/mujoco/mjrender.h b/include/mujoco/mjrender.h index cd11423b..fb37d926 100644 --- a/include/mujoco/mjrender.h +++ b/include/mujoco/mjrender.h @@ -39,15 +39,6 @@ typedef enum mjtFramebuffer_ { // OpenGL framebuffer option mjFB_OFFSCREEN // offscreen buffer } mjtFramebuffer; -typedef enum mjtDepthMapping_ { // OpenGL depth buffer mapping (from znear to zfar) - mjDB_NEGONETOONE = 0, // Negative one to one (OpenGL default) - mjDB_ONETOZERO // Reversed Z buffer (decreases numerical error) -} mjtDepthMapping; - -typedef enum mjtDepthPrecision_ { // OpenGL depth buffer precision - mjDB_INT24 = 0, // 24 bit integer buffer (OpenGL default) - mjDB_FLOAT32 // 32 bit float buffer -} mjtDepthPrecision; typedef enum mjtFontScale_ { // font scale, used at context creation mjFONTSCALE_50 = 50, // 50% scale, suitable for low-res rendering @@ -160,12 +151,6 @@ struct mjrContext_ { // custom OpenGL context // pixel output format int readPixelFormat; // default color pixel format for mjr_readPixels - - // depth buffer mode - int depthMapping; // depth buffer mapping from [znear zfar] to normalized device coordinates: mjDB_NEGONETOONE or mjDB_ONETOZERO - - // depth buffer precision - int depthPrecision; // depth buffer precision: mjDB_INT24 or mjDB_FLOAT32 }; typedef struct mjrContext_ mjrContext; diff --git a/introspect/enums.py b/introspect/enums.py index d14523b3..fbee5402 100644 --- a/introspect/enums.py +++ b/introspect/enums.py @@ -621,24 +621,6 @@ ENUMS: Mapping[str, EnumDecl] = dict([ ('mjFB_OFFSCREEN', 1), ]), )), - ('mjtDepthMapping', - EnumDecl( - name='mjtDepthMapping', - declname='enum mjtDepthMapping_', - values=dict([ - ('mjDB_NEGONETOONE', 0), - ('mjDB_ONETOZERO', 1), - ]), - )), - ('mjtDepthPrecision', - EnumDecl( - name='mjtDepthPrecision', - declname='enum mjtDepthPrecision_', - values=dict([ - ('mjDB_INT24', 0), - ('mjDB_FLOAT32', 1), - ]), - )), ('mjtFontScale', EnumDecl( name='mjtFontScale', diff --git a/introspect/structs.py b/introspect/structs.py index fd718da4..a06e9a67 100644 --- a/introspect/structs.py +++ b/introspect/structs.py @@ -7126,16 +7126,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='int'), doc='default color pixel format for mjr_readPixels', ), - StructFieldDecl( - name='depthMapping', - type=ValueType(name='int'), - doc='depth buffer mapping from [znear zfar] to normalized device coordinates: mjDB_NEGONETOONE or mjDB_ONETOZERO', # pylint: disable=line-too-long - ), - StructFieldDecl( - name='depthPrecision', - type=ValueType(name='int'), - doc='depth buffer precision: mjDB_INT24 or mjDB_FLOAT32', - ), ), )), ('mjuiState', diff --git a/python/mujoco/render.cc b/python/mujoco/render.cc index c1d2b9c8..622bbb7a 100644 --- a/python/mujoco/render.cc +++ b/python/mujoco/render.cc @@ -34,10 +34,6 @@ class MjWrapper : public WrapperBase { public: MjWrapper(); MjWrapper(const MjModelWrapper& model, int fontscale); - MjWrapper(const MjModelWrapper& model, - int fontscale, - mjtDepthMapping depthmapping, - mjtDepthPrecision depthprecision); MjWrapper(const MjWrapper&) = delete; MjWrapper(MjWrapper&&) = default; ~MjWrapper() = default; @@ -126,35 +122,6 @@ MjrContextWrapper::MjWrapper(const MjModelWrapper& model, int fontscale) X_SKIN(skinfaceVBO), X(charWidth), X(charWidthBig) {} - -MjrContextWrapper::MjWrapper(const MjModelWrapper& model, - int fontscale, - mjtDepthMapping depthmapping, - mjtDepthPrecision depthprecision) - : WrapperBase([fontscale, depthmapping, depthprecision](const raw::MjModel* m) { - raw::MjrContext *const ctx = new raw::MjrContext; - mjr_defaultContext(ctx); - ctx->depthMapping = depthmapping; - ctx->depthPrecision = depthprecision; - InterceptMjErrors(mjr_makeContext)(m, ctx, fontscale); - return ctx; - }(model.get()), &MjrContextCapsuleDestructor), - X(fogRGBA), - X(auxWidth), - X(auxHeight), - X(auxSamples), - X(auxFBO), - X(auxFBO_r), - X(auxColor), - X(auxColor_r), - X(textureType), - X(texture), - X_SKIN(skinvertVBO), - X_SKIN(skinnormalVBO), - X_SKIN(skintexcoordVBO), - X_SKIN(skinfaceVBO), - X(charWidth), - X(charWidthBig) {} #undef X_SKIN #undef X @@ -199,7 +166,6 @@ PYBIND11_MODULE(_render, pymodule) { py::class_ mjrContext(pymodule, "MjrContext"); mjrContext.def(py::init<>()); mjrContext.def(py::init()); - mjrContext.def(py::init()); mjrContext.def( "free", [](MjrContextWrapper& self) { self.Free(); }, py::doc("Frees resources in current active OpenGL context, sets struct " diff --git a/python/mujoco/renderer.py b/python/mujoco/renderer.py index e83f2435..3360523c 100644 --- a/python/mujoco/renderer.py +++ b/python/mujoco/renderer.py @@ -32,9 +32,7 @@ class Renderer: model: _structs.MjModel, height: int = 240, width: int = 320, - max_geom: int = 10000, - depth_mapping: _enums.mjtDepthMapping = _enums.mjtDepthMapping.mjDB_NEGONETOONE, - depth_precision: _enums.mjtDepthPrecision = _enums.mjtDepthPrecision.mjDB_INT24, + max_geom: int = 10000 ) -> None: """Initializes a new `Renderer`. @@ -45,8 +43,6 @@ class Renderer: max_geom: Optional integer specifying the maximum number of geoms that can be rendered in the same scene. If None this will be chosen automatically based on the estimated maximum number of renderable geoms in the model. - depth_mapping: Type of mapping from znear to zfar to z buffer ndc values - depth_precision: Precision of z buffer Raises: ValueError: If `camera_id` is outside the valid range, or if `width` or `height` exceed the dimensions of MuJoCo's offscreen framebuffer. @@ -74,7 +70,6 @@ the clause: self._width = width self._height = height self._model = model - self._depth_mapping = depth_mapping self._scene = _structs.MjvScene(model=model, maxgeom=max_geom) self._scene_option = _structs.MjvOption() @@ -86,7 +81,7 @@ the clause: self._gl_context = gl_context.GLContext(width, height) # type: ignore self._gl_context.make_current() self._mjr_context = _render.MjrContext( - model, _enums.mjtFontScale.mjFONTSCALE_150.value, depth_mapping, depth_precision + model, _enums.mjtFontScale.mjFONTSCALE_150.value ) _render.mjr_setBuffer( _enums.mjtFramebuffer.mjFB_OFFSCREEN.value, self._mjr_context @@ -188,20 +183,16 @@ the clause: D = -(np.float32(2)*zfar*znear)/(zfar - znear) # In reverse Z mode the perspective matrix is transformed by the following - if self._depth_mapping == _enums.mjtDepthMapping.mjDB_ONETOZERO: - C = np.float32(-0.5)*C - np.float32(0.5) - D = np.float32(-0.5)*D + C = np.float32(-0.5)*C - np.float32(0.5) + D = np.float32(-0.5)*D # We need 64 bits to convert Z from ndc to metric depth without noticeable losses in precision out_64 = out.astype(np.float64) - # Convert depth from window coordinates to normalized device coordinates - # In reversed Z mode the mapping is identity - # https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDepthRange.xhtml - if self._depth_mapping == _enums.mjtDepthMapping.mjDB_NEGONETOONE: - out_64 = 2.0*out_64 - 1.0 - # Undo OpenGL projection + # Note: We do not need to take action to convert from window coordinates to + # normalized device coordinates because in reversed Z mode the mapping + # is identity out_64 = D / (out_64 + C) # Cast result back to float32 for backwards compatibility diff --git a/simulate/platform_ui_adapter.cc b/simulate/platform_ui_adapter.cc index f5b154ed..5f502a47 100644 --- a/simulate/platform_ui_adapter.cc +++ b/simulate/platform_ui_adapter.cc @@ -27,7 +27,6 @@ void PlatformUIAdapter::FreeMjrContext() { bool PlatformUIAdapter::RefreshMjrContext(const mjModel* m, int fontscale) { if (m != last_model_ || fontscale != last_fontscale_) { - // con_.depthMapping = mjDB_ONETOZERO; mjr_makeContext(m, &con_, fontscale); last_model_ = m; last_fontscale_ = fontscale; diff --git a/src/render/render_context.c b/src/render/render_context.c index 6ba5da82..0d673de2 100644 --- a/src/render/render_context.c +++ b/src/render/render_context.c @@ -1062,11 +1062,7 @@ static void makeShadow(const mjModel* m, mjrContext* con) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - if (con->depthMapping == mjDB_ONETOZERO) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GEQUAL); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); @@ -1125,17 +1121,16 @@ static void makeOff(mjrContext* con) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, con->offColor); // create depth and stencil buffer - GLenum depth_buffer_format = con->depthPrecision == mjDB_FLOAT32 ? GL_DEPTH32F_STENCIL8 : GL_DEPTH24_STENCIL8; glGenRenderbuffers(1, &con->offDepthStencil); if (!con->offDepthStencil) { mju_error("Could not allocate offscreen depth and stencil buffer"); } glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil); if (con->offSamples) { - glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, depth_buffer_format, + glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight); } else { - glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight); } glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, con->offDepthStencil); @@ -1174,7 +1169,7 @@ static void makeOff(mjrContext* con) { mju_error("Could not allocate offscreen depth and stencil buffer_r"); } glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r); - glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, con->offDepthStencil_r); @@ -1546,15 +1541,7 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale, glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // free previous context but keep depth settings - // Doing this is the only way users can control these - // settings without breaking changes to either the - // behaviour of mjr_makeContext or the signature - int oldDepthMapping = con->depthMapping; - int oldDepthPrecision = con->depthPrecision; mjr_freeContext(con); - con->depthMapping = oldDepthMapping; - con->depthPrecision = oldDepthPrecision; // no model: offscreen and font only if (!m) { @@ -1847,13 +1834,12 @@ MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) { } - GLenum depth_buffer_format = con->depthPrecision == mjDB_FLOAT32 ? GL_DEPTH32F_STENCIL8 : GL_DEPTH24_STENCIL8; glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil); if (con->offSamples) { - glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, depth_buffer_format, + glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight); } else { - glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight); } if (con->offSamples) { @@ -1861,6 +1847,6 @@ MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) { glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight); glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r); - glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight); } } diff --git a/src/render/render_gl3.c b/src/render/render_gl3.c index 97e18715..2833665b 100644 --- a/src/render/render_gl3.c +++ b/src/render/render_gl3.c @@ -498,11 +498,7 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) { // common options glDisable(GL_BLEND); glEnable(GL_NORMALIZE); - if (con->depthMapping == mjDB_ONETOZERO) { - glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); - } else { - glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); - } + glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); if (scn->flags[mjRND_CULL_FACE]) { @@ -511,19 +507,11 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) { glDisable(GL_CULL_FACE); } glShadeModel(GL_SMOOTH); - if (con->depthMapping == mjDB_ONETOZERO) { - glDepthFunc(GL_GEQUAL); - } else { - glDepthFunc(GL_LEQUAL); - } + glDepthFunc(GL_GEQUAL); glDepthRange(0, 1); glAlphaFunc(GL_GEQUAL, 0.99f); glClearColor(0, 0, 0, 0); - if (con->depthMapping == mjDB_ONETOZERO) { - glClearDepth(0); - } else { - glClearDepth(1); - } + glClearDepth(0); glClearStencil(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); @@ -613,11 +601,9 @@ static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrCo // set projection glMatrixMode(GL_PROJECTION); glLoadIdentity(); - if (con->depthMapping == mjDB_ONETOZERO) { - // account for GL_ZERO_TO_ONE and reverse Z - glTranslatef(0,0,0.5); - glScalef(1,1,-0.5); - } + // reverse Z rendering mapping (znear, zfar) -> (1, 0) + glTranslatef(0,0,0.5); + glScalef(1,1,-0.5); glFrustum(cam.frustum_center - halfwidth, cam.frustum_center + halfwidth, cam.frustum_bottom, @@ -690,24 +676,12 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { float temp[4], headpos[3], forward[3], skyboxdst; float camProject[16], camView[16], lightProject[16], lightView[16]; double clipplane[4]; - float biasMatrixOneToZero[16] = { + float biasMatrix[16] = { 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.0f, 1.0f }; - float biasMatrixNegOneToOne[16] = { - 0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f - }; - float* biasMatrix; - if (con->depthMapping == mjDB_ONETOZERO) { - biasMatrix = biasMatrixOneToZero; - } else { - biasMatrix = biasMatrixNegOneToOne; - } float tempMatrix[16], textureMatrix[16]; mjvGeom *thisgeom, tempgeom; @@ -1056,11 +1030,9 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { // set projection: from light viewpoint glMatrixMode(GL_PROJECTION); glLoadIdentity(); - if (con->depthMapping == mjDB_ONETOZERO) { - // account for GL_ZERO_TO_ONE and reverse Z - glTranslatef(0,0,0.5); - glScalef(1,1,-0.5); - } + // reverse Z rendering mapping (znear, zfar) -> (1, 0) + glTranslatef(0,0,0.5); + glScalef(1,1,-0.5); if (thislight->directional) { glOrtho(-con->shadowClip, con->shadowClip, -con->shadowClip, con->shadowClip, diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 40e938b3..ac5c8161 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -389,14 +389,6 @@ public enum mjtFramebuffer : int{ mjFB_WINDOW = 0, mjFB_OFFSCREEN = 1, } -public enum mjtDepthMapping : int{ - mjDB_NEGONETOONE = 0, - mjDB_ONETOZERO = 1, -} -public enum mjtDepthPrecision : int{ - mjDB_INT24 = 0, - mjDB_FLOAT32 = 1, -} public enum mjtFontScale : int{ mjFONTSCALE_50 = 50, mjFONTSCALE_100 = 100,