From c6961b77d73861337d125e6e624b091e28bdadad Mon Sep 17 00:00:00 2001 From: Levi Burner Date: Mon, 2 Oct 2023 18:20:58 -0400 Subject: [PATCH] Fallback for if GL_ARB_clip_control not available If GL_ARB_clip_control not available then [znear, zfar] -> [1, -1] instead of [1, 0] in normalized device coordinates Thus, Z is still reversed, but not shifted, clipping should still work properly, and conversion to window coordinates does not cause accuracy regression compared to non-reversed Z rendering. --- src/render/render_context.c | 3 --- src/render/render_gl2.c | 7 ++++++- src/render/render_gl3.c | 32 +++++++++++++++++++++++++------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/render/render_context.c b/src/render/render_context.c index 99daf299..cafe9519 100644 --- a/src/render/render_context.c +++ b/src/render/render_context.c @@ -1489,9 +1489,6 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale, if (!mjGLAD_GL_ARB_vertex_buffer_object) { mju_error("OpenGL ARB_vertex_buffer_object required"); } - if (!mjGLAD_GL_ARB_clip_control) { - mju_error("OpenGL ARB_clip_control required"); - } if (!mjGLAD_GL_ARB_depth_buffer_float) { mju_error("OpenGL ARB_depth_buffer_float required"); } diff --git a/src/render/render_gl2.c b/src/render/render_gl2.c index 5ba11d34..88bb6213 100644 --- a/src/render/render_gl2.c +++ b/src/render/render_gl2.c @@ -119,6 +119,9 @@ void mjr_readPixels(unsigned char* rgb, float* depth, 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 } + else if (!mjGLAD_GL_ARB_clip_control) { + mju_warning("ARB_clip_control unavailable while mjDEPTH_ZEROFAR requested, depth accuracy will be limited"); + } } } @@ -163,11 +166,13 @@ 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->readDepthMap == mjDEPTH_ZERONEAR) { 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 } + else if (!mjGLAD_GL_ARB_clip_control) { + mju_warning("ARB_clip_control unavailable while mjDEPTH_ZEROFAR requested, depth accuracy will be limited"); + } } // restore currentBuffer diff --git a/src/render/render_gl3.c b/src/render/render_gl3.c index 833ea69d..fc89aa06 100644 --- a/src/render/render_gl3.c +++ b/src/render/render_gl3.c @@ -498,7 +498,7 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) { // common options glDisable(GL_BLEND); glEnable(GL_NORMALIZE); - glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); + if (mjGLAD_GL_ARB_clip_control) glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); if (scn->flags[mjRND_CULL_FACE]) { @@ -601,9 +601,15 @@ static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrCo // set projection glMatrixMode(GL_PROJECTION); glLoadIdentity(); - // reverse Z rendering mapping [znear, zfar] -> [1, 0] - glTranslatef(0.0f, 0.0f, 0.5f); - glScalef(1.0f, 1.0f, -0.5f); + if (mjGLAD_GL_ARB_clip_control) { + // reverse Z rendering mapping [znear, zfar] -> [1, 0] (ndc) + glTranslatef(0.0f, 0.0f, 0.5f); + glScalef(1.0f, 1.0f, -0.5f); + } + else { + // reverse Z rendering mapping without shift [znear, zfar] -> [1, -1] (ndc) + glScalef(1.0f, 1.0f, -1.0f); + } glFrustum(cam.frustum_center - halfwidth, cam.frustum_center + halfwidth, cam.frustum_bottom, @@ -682,6 +688,12 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.0f, 1.0f }; + if (!mjGLAD_GL_ARB_clip_control) { + // account for conversion from ndc to window coordinates + biasMatrix[2*4+2] = 0.5; + biasMatrix[3*4+2] = 0.5; + } + float tempMatrix[16], textureMatrix[16]; mjvGeom *thisgeom, tempgeom; mjvLight *thislight; @@ -1029,9 +1041,15 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { // set projection: from light viewpoint glMatrixMode(GL_PROJECTION); glLoadIdentity(); - // reverse Z rendering mapping [znear, zfar] -> [1, 0] - glTranslatef(0.0f, 0.0f, 0.5f); - glScalef(1.0f , 1.0f, -0.5f); + if (mjGLAD_GL_ARB_clip_control) { + // reverse Z rendering mapping [znear, zfar] -> [1, 0] (ndc) + glTranslatef(0.0f, 0.0f, 0.5f); + glScalef(1.0f, 1.0f, -0.5f); + } + else { + // reverse Z rendering mapping without shift [znear, zfar] -> [1, -1] (ndc) + glScalef(1.0f, 1.0f, -1.0f); + } if (thislight->directional) { glOrtho(-con->shadowClip, con->shadowClip, -con->shadowClip, con->shadowClip,