Browse Source

shadows: provide dummy shadow maps for nonexistent/noncasting lights

rdb 8 years ago
parent
commit
7755a2e1c7

+ 51 - 3
panda/src/display/graphicsStateGuardian.cxx

@@ -1798,6 +1798,13 @@ fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler,
           }
           }
         }
         }
       }
       }
+
+      // There is no such light assigned.  Bind a dummy shadow map.
+      PT(Texture) tex = get_dummy_shadow_map((Texture::TextureType)spec._desired_type);
+      if (tex != nullptr) {
+        sampler = tex->get_default_sampler();
+      }
+      return tex;
     }
     }
     break;
     break;
 
 
@@ -3152,9 +3159,14 @@ get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) {
            node->is_of_type(Spotlight::get_class_type()), NULL);
            node->is_of_type(Spotlight::get_class_type()), NULL);
 
 
   LightLensNode *light = (LightLensNode *)node;
   LightLensNode *light = (LightLensNode *)node;
-  if (light == NULL || !light->_shadow_caster) {
-    // TODO: return dummy shadow map (all white).
-    return NULL;
+  if (light == nullptr || !light->_shadow_caster) {
+    // This light does not have a shadow caster.  Return a dummy shadow map
+    // that is filled with a depth value of 1.
+    if (node->is_of_type(PointLight::get_class_type())) {
+      return get_dummy_shadow_map(Texture::TT_cube_map);
+    } else {
+      return get_dummy_shadow_map(Texture::TT_2d_texture);
+    }
   }
   }
 
 
   // See if we already have a buffer.  If not, create one.
   // See if we already have a buffer.  If not, create one.
@@ -3173,6 +3185,42 @@ get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) {
   }
   }
 }
 }
 
 
+/**
+ * Returns a dummy shadow map that can be used for a light of the given type
+ * that does not cast shadows.
+ */
+PT(Texture) GraphicsStateGuardian::
+get_dummy_shadow_map(Texture::TextureType texture_type) const {
+  if (texture_type != Texture::TT_cube_map) {
+    static PT(Texture) dummy_2d;
+    if (dummy_2d == nullptr) {
+      dummy_2d = new Texture("dummy-shadow-2d");
+      dummy_2d->setup_2d_texture(1, 1, Texture::T_unsigned_byte, Texture::F_depth_component);
+      dummy_2d->set_clear_color(1);
+      if (get_supports_shadow_filter()) {
+        // If we have the ARB_shadow extension, enable shadow filtering.
+        dummy_2d->set_minfilter(SamplerState::FT_shadow);
+        dummy_2d->set_magfilter(SamplerState::FT_shadow);
+      } else {
+        dummy_2d->set_minfilter(SamplerState::FT_linear);
+        dummy_2d->set_magfilter(SamplerState::FT_linear);
+      }
+    }
+    return dummy_2d;
+  } else {
+    static PT(Texture) dummy_cube;
+    if (dummy_cube == nullptr) {
+      dummy_cube = new Texture("dummy-shadow-cube");
+      dummy_cube->setup_cube_map(1, Texture::T_unsigned_byte, Texture::F_depth_component);
+      dummy_cube->set_clear_color(1);
+      // Note: cube map shadow filtering doesn't seem to work in Cg.
+      dummy_cube->set_minfilter(SamplerState::FT_linear);
+      dummy_cube->set_magfilter(SamplerState::FT_linear);
+    }
+    return dummy_cube;
+  }
+}
+
 /**
 /**
  * Creates a depth buffer for shadow mapping.  This is a convenience function
  * Creates a depth buffer for shadow mapping.  This is a convenience function
  * for the ShaderGenerator; putting this directly in the ShaderGenerator would
  * for the ShaderGenerator; putting this directly in the ShaderGenerator would

+ 1 - 0
panda/src/display/graphicsStateGuardian.h

@@ -424,6 +424,7 @@ public:
   static void create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table);
   static void create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table);
 
 
   PT(Texture) get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host=NULL);
   PT(Texture) get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host=NULL);
+  PT(Texture) get_dummy_shadow_map(Texture::TextureType texture_type) const;
   PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
   PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS

+ 1 - 2
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -1078,8 +1078,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
     if (tex.is_null()) {
     if (tex.is_null()) {
       // Apply a white texture in order to make it easier to use a shader that
       // Apply a white texture in order to make it easier to use a shader that
       // takes a texture on a model that doesn't have a texture applied.
       // takes a texture on a model that doesn't have a texture applied.
-      _glgsg->set_active_texture_stage(i);
-      _glgsg->apply_white_texture();
+      _glgsg->apply_white_texture(i);
       continue;
       continue;
     }
     }
 
 

+ 21 - 17
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -10906,25 +10906,20 @@ update_standard_texture_bindings() {
 
 
 /**
 /**
  * Applies a white dummy texture.  This is useful to bind to a texture slot
  * Applies a white dummy texture.  This is useful to bind to a texture slot
- * when a texture is missing.
+ * when a texture is missing.  Also binds the default sampler to the unit.
  */
  */
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-apply_white_texture() {
-  if (_white_texture != 0) {
-    glBindTexture(GL_TEXTURE_2D, _white_texture);
-    return;
-  }
+apply_white_texture(GLuint unit) {
+  set_active_texture_stage(unit);
+  glBindTexture(GL_TEXTURE_2D, get_white_texture());
 
 
-  glGenTextures(1, &_white_texture);
-  glBindTexture(GL_TEXTURE_2D, _white_texture);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-  unsigned char data[] = {0xff, 0xff, 0xff, 0xff};
-  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
-               GL_RGBA, GL_UNSIGNED_BYTE, data);
+  // Also apply the default sampler, if there's a chance we'd applied anything
+  // else.
+#ifndef OPENGLES_1
+  if (_supports_sampler_objects) {
+    _glBindSampler(unit, 0);
+  }
+#endif
 }
 }
 
 
 /**
 /**
@@ -10934,7 +10929,16 @@ apply_white_texture() {
 GLuint CLP(GraphicsStateGuardian)::
 GLuint CLP(GraphicsStateGuardian)::
 get_white_texture() {
 get_white_texture() {
   if (_white_texture == 0) {
   if (_white_texture == 0) {
-    apply_white_texture();
+    glGenTextures(1, &_white_texture);
+    glBindTexture(GL_TEXTURE_2D, _white_texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    unsigned char data[] = {0xff, 0xff, 0xff, 0xff};
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
+                 GL_RGBA, GL_UNSIGNED_BYTE, data);
   }
   }
   return _white_texture;
   return _white_texture;
 }
 }

+ 1 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -567,7 +567,7 @@ protected:
   void update_shader_vertex_format(const GeomVertexFormat *format);
   void update_shader_vertex_format(const GeomVertexFormat *format);
 #endif
 #endif
 
 
-  void apply_white_texture();
+  void apply_white_texture(GLuint unit);
   GLuint get_white_texture();
   GLuint get_white_texture();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG

+ 1 - 2
panda/src/glstuff/glShaderContext_src.cxx

@@ -2617,8 +2617,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
         textures[i] = _glgsg->get_white_texture();
         textures[i] = _glgsg->get_white_texture();
         samplers[i] = 0;
         samplers[i] = 0;
       } else {
       } else {
-        _glgsg->set_active_texture_stage(i);
-        _glgsg->apply_white_texture();
+        _glgsg->apply_white_texture(i);
       }
       }
       continue;
       continue;
     }
     }