Browse Source

glgsg: support gl-depth-zero-to-one to get same NDC Z range as D3D

rdb 7 years ago
parent
commit
828233a8f2

+ 10 - 2
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -864,14 +864,22 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       case RTP_depth_stencil:
         if (_fb_properties.get_depth_bits() > 24 ||
             _fb_properties.get_float_depth()) {
-          gl_format = GL_DEPTH32F_STENCIL8;
+          if (!glgsg->_use_remapped_depth_range) {
+            gl_format = GL_DEPTH32F_STENCIL8;
+          } else {
+            gl_format = GL_DEPTH32F_STENCIL8_NV;
+          }
         } else {
           gl_format = GL_DEPTH24_STENCIL8;
         }
         break;
       case RTP_depth:
         if (_fb_properties.get_float_depth()) {
-          gl_format = GL_DEPTH_COMPONENT32F;
+          if (!glgsg->_use_remapped_depth_range) {
+            gl_format = GL_DEPTH_COMPONENT32F;
+          } else {
+            gl_format = GL_DEPTH_COMPONENT32F_NV;
+          }
         } else if (_fb_properties.get_depth_bits() > 24) {
           gl_format = GL_DEPTH_COMPONENT32;
         } else if (_fb_properties.get_depth_bits() > 16) {

+ 64 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2997,6 +2997,50 @@ reset() {
   }
 #endif
 
+  // Set depth range from zero to one if requested.
+#ifndef OPENGLES
+  _use_depth_zero_to_one = false;
+  _use_remapped_depth_range = false;
+
+  if (gl_depth_zero_to_one) {
+    if (is_at_least_gl_version(4, 5) || has_extension("GL_ARB_clip_control")) {
+      PFNGLCLIPCONTROLPROC pglClipControl =
+        (PFNGLCLIPCONTROLPROC)get_extension_func("glClipControl");
+
+      if (pglClipControl != nullptr) {
+        pglClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
+        _use_depth_zero_to_one = true;
+
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "Set zero-to-one depth using glClipControl\n";
+        }
+      }
+    }/* else if (has_extension("GL_NV_depth_buffer_float")) {
+      // Alternatively, all GeForce 8+ and even some AMD drivers support this
+      // extension, which (unlike the core glDepthRange, which clamps its
+      // input parameters) can compensate for the built-in depth remapping.
+      _glDepthRangedNV = (PFNGLDEPTHRANGEDNVPROC)get_extension_func("glDepthRangedNV");
+
+      if (_glDepthRangedNV != nullptr) {
+        _glDepthRangedNV(-1.0, 1.0);
+        _use_depth_zero_to_one = true;
+        _use_remapped_depth_range = true;
+
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "Set zero-to-one depth using glDepthRangedNV\n";
+        }
+      }
+    }*/
+
+    if (!_use_depth_zero_to_one) {
+      GLCAT.warning()
+        << "Zero-to-one depth was requested, but driver does not support it.\n";
+    }
+  }
+#endif
+
   // Set up all the enableddisabled flags to GL's known initial values:
   // everything off.
   _multisample_mode = 0;
@@ -3646,6 +3690,19 @@ calc_projection_mat(const Lens *lens) {
                           lens->get_coordinate_system()) *
     lens->get_projection_mat(_current_stereo_channel);
 
+#ifndef OPENGLES
+  if (_use_depth_zero_to_one) {
+    // If we requested that the OpenGL NDC Z goes from zero to one like in
+    // Direct3D, we need to scale the projection matrix, which assumes -1..1.
+    static const LMatrix4 rescale_mat
+      (1, 0, 0, 0,
+       0, 1, 0, 0,
+       0, 0, 0.5, 0,
+       0, 0, 0.5, 1);
+    result *= rescale_mat;
+  }
+#endif
+
   if (_scene_setup->get_inverted()) {
     // If the scene is supposed to be inverted, then invert the projection
     // matrix.
@@ -7452,7 +7509,13 @@ do_issue_depth_offset() {
   glDepthRangef((GLclampf)min_value, (GLclampf)max_value);
 #else
   // Mainline OpenGL uses a double-precision call.
-  glDepthRange((GLclampd)min_value, (GLclampd)max_value);
+  if (!_use_remapped_depth_range) {
+    glDepthRange((GLclampd)min_value, (GLclampd)max_value);
+  } else {
+    // If we have a remapped depth range, we should adjust the values to range
+    // from -1 to 1.  We need to use an NV extension to pass unclamped values.
+    _glDepthRangedNV(min_value * 2.0 - 1.0, max_value * 2.0 - 1.0);
+  }
 #endif  // OPENGLES
 
   report_my_gl_errors();

+ 6 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -743,6 +743,12 @@ protected:
 #endif
 
 public:
+#ifndef OPENGLES
+  bool _use_depth_zero_to_one;
+  bool _use_remapped_depth_range;
+  PFNGLDEPTHRANGEDNVPROC _glDepthRangedNV;
+#endif
+
   bool _supports_point_parameters;
   PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
   bool _supports_point_sprite;

+ 7 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -313,6 +313,13 @@ ConfigVariableEnum<CoordinateSystem> gl_coordinate_system
             "creating a shader-only application, it may be easier and "
             "more efficient to set this to default."));
 
+ConfigVariableBool gl_depth_zero_to_one
+  ("gl-depth-zero-to-one", false,
+   PRC_DESC("Normally, OpenGL uses an NDC coordinate space wherein the Z "
+            "ranges from -1 to 1.  This setting can be used to instead use a "
+            "range from 0 to 1, matching other graphics APIs.  This setting "
+            "requires OpenGL 4.5, or NVIDIA GeForce 8+ hardware."));
+
 extern ConfigVariableBool gl_parallel_arrays;
 
 void CLP(init_classes)() {