Browse Source

Added support for HDR

Josh Yelon 18 years ago
parent
commit
7bb510a3ef

+ 3 - 2
panda/src/pgraph/auxBitplaneAttrib.h

@@ -42,8 +42,9 @@ private:
 
 
 PUBLISHED:
 PUBLISHED:
   enum AuxBitplaneOutput {
   enum AuxBitplaneOutput {
-    ABO_color = 1,     // The usual.
-    ABO_csnormal = 2,  // Camera space normal.
+    ABO_color = 1,     // Render an ordinary scene into the ordinary color buffer.
+    ABO_csnormal = 2,  // Render a camera-space normal into an aux bitplane.
+    ABO_glowalpha = 4, // Render all glow maps into the color buffer alpha channel.
   };
   };
   static CPT(RenderAttrib) make();
   static CPT(RenderAttrib) make();
   static CPT(RenderAttrib) make(int outputs);
   static CPT(RenderAttrib) make(int outputs);

+ 1 - 1
panda/src/pgraph/lightRampAttrib.I

@@ -25,7 +25,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE LightRampAttrib::
 INLINE LightRampAttrib::
 LightRampAttrib() {
 LightRampAttrib() {
-  _mode = LRT_identity;
+  _mode = LRT_default;
   _level[0] = 0.0;
   _level[0] = 0.0;
   _level[1] = 0.0;
   _level[1] = 0.0;
   _threshold[0] = 0.0;
   _threshold[0] = 0.0;

+ 132 - 9
panda/src/pgraph/lightRampAttrib.cxx

@@ -26,26 +26,51 @@
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 
 
 TypeHandle LightRampAttrib::_type_handle;
 TypeHandle LightRampAttrib::_type_handle;
-CPT(RenderAttrib) LightRampAttrib::_identity;
+CPT(RenderAttrib) LightRampAttrib::_default;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: LightRampAttrib::make_identity
+//     Function: LightRampAttrib::make_default
 //       Access: Published, Static
 //       Access: Published, Static
-//  Description: Constructs a new LightRampAttrib object.
+//  Description: Constructs a new LightRampAttrib object.  This
+//               is the standard OpenGL lighting ramp, which clamps
+//               the final light total to the 0-1 range.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) LightRampAttrib::
 CPT(RenderAttrib) LightRampAttrib::
-make_identity() {
-  if (_identity == 0) {
+make_default() {
+  if (_default == 0) {
     LightRampAttrib *attrib = new LightRampAttrib();
     LightRampAttrib *attrib = new LightRampAttrib();
-    _identity = return_new(attrib);
+    _default = return_new(attrib);
   }
   }
-  return _identity;
+  return _default;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LightRampAttrib::make_identity
+//       Access: Published, Static
+//  Description: Constructs a new LightRampAttrib object.  This
+//               differs from the usual OpenGL lighting model in that
+//               it does not clamp the final lighting total to (0,1).
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) LightRampAttrib::
+make_identity() {
+  LightRampAttrib *attrib = new LightRampAttrib();
+  attrib->_mode = LRT_identity;
+  return return_new(attrib);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LightRampAttrib::make_single_threshold
 //     Function: LightRampAttrib::make_single_threshold
 //       Access: Published, Static
 //       Access: Published, Static
-//  Description: Constructs a new LightRampAttrib object.
+//  Description: Constructs a new LightRampAttrib object.  This 
+//               causes the luminance of the diffuse lighting
+//               contribution to be quantized using a single threshold:
+//
+//               if (original_luminance > threshold0) {
+//                 luminance = level0;
+//               } else {
+//                 luminance = 0.0;
+//               }
+//               
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) LightRampAttrib::
 CPT(RenderAttrib) LightRampAttrib::
 make_single_threshold(float thresh0, float val0) {
 make_single_threshold(float thresh0, float val0) {
@@ -59,7 +84,18 @@ make_single_threshold(float thresh0, float val0) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LightRampAttrib::make_double_threshold
 //     Function: LightRampAttrib::make_double_threshold
 //       Access: Published, Static
 //       Access: Published, Static
-//  Description: Constructs a new LightRampAttrib object.
+//  Description: Constructs a new LightRampAttrib object.  This 
+//               causes the luminance of the diffuse lighting
+//               contribution to be quantized using two thresholds:
+//
+//               if (original_luminance > threshold1) {
+//                 luminance = level1;
+//               } else if (original_luminance > threshold0) {
+//                 luminance = level0;
+//               } else {
+//                 luminance = 0.0;
+//               }
+//
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) LightRampAttrib::
 CPT(RenderAttrib) LightRampAttrib::
 make_double_threshold(float thresh0, float val0, float thresh1, float val1) {
 make_double_threshold(float thresh0, float val0, float thresh1, float val1) {
@@ -72,6 +108,93 @@ make_double_threshold(float thresh0, float val0, float thresh1, float val1) {
   return return_new(attrib);
   return return_new(attrib);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LightRampAttrib::make_hdr0
+//       Access: Published, Static
+//  Description: Constructs a new LightRampAttrib object.  This causes
+//               an HDR tone mapping operation to be applied.
+//
+//               Normally, brightness values greater than 1 cannot be
+//               distinguished from each other, causing very brightly lit
+//               objects to wash out white and all detail to be erased.
+//               HDR tone mapping remaps brightness values in the range
+//               0-infinity into the range (0,1), making it possible to
+//               distinguish detail in scenes whose brightness exceeds 1.
+//
+//               However, the monitor has finite contrast.  Normally, all
+//               of that contrast is used to represent brightnesses in
+//               the range 0-1.  The HDR0 tone mapping operator 'steals'
+//               one quarter of that contrast to represent brightnesses in
+//               the range 1-infinity.
+//
+//               FINAL_RGB = (RGB^3 + RGB^2 + RGB) / (RGB^3 + RGB^2 + RGB + 1)
+//
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) LightRampAttrib::
+make_hdr0() {
+  LightRampAttrib *attrib = new LightRampAttrib();
+  attrib->_mode = LRT_hdr0;
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LightRampAttrib::make_hdr1
+//       Access: Published, Static
+//  Description: Constructs a new LightRampAttrib object.  This causes
+//               an HDR tone mapping operation to be applied.
+//
+//               Normally, brightness values greater than 1 cannot be
+//               distinguished from each other, causing very brightly lit
+//               objects to wash out white and all detail to be erased.
+//               HDR tone mapping remaps brightness values in the range
+//               0-infinity into the range (0,1), making it possible to
+//               distinguish detail in scenes whose brightness exceeds 1.
+//
+//               However, the monitor has finite contrast.  Normally, all
+//               of that contrast is used to represent brightnesses in
+//               the range 0-1.  The HDR1 tone mapping operator 'steals'
+//               one third of that contrast to represent brightnesses in
+//               the range 1-infinity.
+//
+//               FINAL_RGB = (RGB^2 + RGB) / (RGB^2 + RGB + 1)
+//
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) LightRampAttrib::
+make_hdr1() {
+  LightRampAttrib *attrib = new LightRampAttrib();
+  attrib->_mode = LRT_hdr1;
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LightRampAttrib::make_hdr2
+//       Access: Published, Static
+//  Description: Constructs a new LightRampAttrib object.  This causes
+//               an HDR tone mapping operation to be applied.
+//
+//               Normally, brightness values greater than 1 cannot be
+//               distinguished from each other, causing very brightly lit
+//               objects to wash out white and all detail to be erased.
+//               HDR tone mapping remaps brightness values in the range
+//               0-infinity into the range (0,1), making it possible to
+//               distinguish detail in scenes whose brightness exceeds 1.
+//
+//               However, the monitor has finite contrast.  Normally, all
+//               of that contrast is used to represent brightnesses in
+//               the range 0-1.  The HDR2 tone mapping operator 'steals'
+//               one half of that contrast to represent brightnesses in
+//               the range 1-infinity.
+//
+//               FINAL_RGB = (RGB) / (RGB + 1)
+//
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) LightRampAttrib::
+make_hdr2() {
+  LightRampAttrib *attrib = new LightRampAttrib();
+  attrib->_mode = LRT_hdr2;
+  return return_new(attrib);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LightRampAttrib::output
 //     Function: LightRampAttrib::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 16 - 11
panda/src/pgraph/lightRampAttrib.h

@@ -26,16 +26,12 @@ class FactoryParams;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : LightRampAttrib
 //       Class : LightRampAttrib
-// Description : The LightRampAttrib alters the light level reaching
-//               the surface of the model by applying a "ramp" function.
-//               Typically, this is used for cartoon lighting, in which
-//               case the ramp is a step-function.  
-//
-//               LightRampAttrib is relevant only when lighting and
-//               shader generation are both enabled. Otherwise, it has
-//               no effect.  The light ramp only affects the diffuse
-//               contribution.  Ambient light is not ramped.
-//
+// Description : A Light Ramp is any unary operator that takes a 
+//               rendered pixel as input, and adjusts the brightness
+//               of that pixel.  For example, gamma correction is a
+//               kind of light ramp.  So is HDR tone mapping.  So is
+//               cartoon shading.  See the constructors for an
+//               explanation of each kind of ramp.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH LightRampAttrib : public RenderAttrib {
 class EXPCL_PANDA_PGRAPH LightRampAttrib : public RenderAttrib {
 private:
 private:
@@ -43,14 +39,23 @@ private:
 
 
 PUBLISHED:
 PUBLISHED:
   enum LightRampMode {
   enum LightRampMode {
+    LRT_default,
     LRT_identity,
     LRT_identity,
     LRT_single_threshold,
     LRT_single_threshold,
     LRT_double_threshold,
     LRT_double_threshold,
+    LRT_hdr0,
+    LRT_hdr1,
+    LRT_hdr2,
   };
   };
+  static CPT(RenderAttrib) make_default();
   static CPT(RenderAttrib) make_identity();
   static CPT(RenderAttrib) make_identity();
   static CPT(RenderAttrib) make_single_threshold(float thresh0, float lev0);
   static CPT(RenderAttrib) make_single_threshold(float thresh0, float lev0);
   static CPT(RenderAttrib) make_double_threshold(float thresh0, float lev0, float thresh1, float lev1);
   static CPT(RenderAttrib) make_double_threshold(float thresh0, float lev0, float thresh1, float lev1);
+  static CPT(RenderAttrib) make_hdr0();
+  static CPT(RenderAttrib) make_hdr1();
+  static CPT(RenderAttrib) make_hdr2();
   
   
+
   INLINE LightRampMode get_mode() const;
   INLINE LightRampMode get_mode() const;
   INLINE float get_level(int n) const;
   INLINE float get_level(int n) const;
   INLINE float get_threshold(int n) const;
   INLINE float get_threshold(int n) const;
@@ -68,7 +73,7 @@ private:
   float _level[2];
   float _level[2];
   float _threshold[2];
   float _threshold[2];
 
 
-  static CPT(RenderAttrib) _identity;
+  static CPT(RenderAttrib) _default;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 59 - 30
panda/src/pgraph/shaderGenerator.cxx

@@ -555,9 +555,7 @@ synthesize_shader(const RenderState *rs) {
     text << "\t uniform float4 attr_color\n";
     text << "\t uniform float4 attr_color\n";
   }
   }
   text << ") {\n";
   text << ") {\n";
-  if (_bitplane_color < 0) {
-    text << "float4 \t o_color;\n";
-  }
+  text << "\t float4 result;\n";
   text << "\t // Fetch all textures.\n";
   text << "\t // Fetch all textures.\n";
   for (int i=0; i<_num_textures; i++) {
   for (int i=0; i<_num_textures; i++) {
     text << "\t float4 tex" << i << " = tex2D(tex_" << i << ", float2(l_texcoord" << i << "));\n";
     text << "\t float4 tex" << i << " = tex2D(tex_" << i << ", float2(l_texcoord" << i << "));\n";
@@ -680,8 +678,6 @@ synthesize_shader(const RenderState *rs) {
       }
       }
     }
     }
     switch (_attribs._light_ramp->get_mode()) {
     switch (_attribs._light_ramp->get_mode()) {
-    case LightRampAttrib::LRT_identity:
-      break;
     case LightRampAttrib::LRT_single_threshold:
     case LightRampAttrib::LRT_single_threshold:
       {
       {
         float t = _attribs._light_ramp->get_threshold(0);
         float t = _attribs._light_ramp->get_threshold(0);
@@ -710,60 +706,76 @@ synthesize_shader(const RenderState *rs) {
     }
     }
     text << "\t // Begin model-space light summation\n";
     text << "\t // Begin model-space light summation\n";
     if (_have_emission) {
     if (_have_emission) {
-      text << "\t o_color = attr_material[2];\n";
+      if (_map_index_glow >= 0) {
+        text << "\t result = attr_material[2] * tex" << _map_index_glow << ".a;\n";
+      } else {
+        text << "\t result = attr_material[2];\n";
+      }
     } else {
     } else {
-      text << "\t o_color = float4(0,0,0,0);\n";
+      if (_map_index_glow >= 0) {
+        text << "\t result = tex" << _map_index_glow << ".aaaa;\n";
+      } else {
+        text << "\t result = float4(0,0,0,0);\n";
+      }
     }
     }
     if ((_have_ambient)&&(_separate_ambient_diffuse)) {
     if ((_have_ambient)&&(_separate_ambient_diffuse)) {
       if (_material->has_ambient()) {
       if (_material->has_ambient()) {
-        text << "\t o_color += tot_ambient * attr_material[0];\n";
+        text << "\t result += tot_ambient * attr_material[0];\n";
       } else if (_vertex_colors) {
       } else if (_vertex_colors) {
-        text << "\t o_color += tot_ambient * l_color;\n";
+        text << "\t result += tot_ambient * l_color;\n";
       } else if (_flat_colors) {
       } else if (_flat_colors) {
-        text << "\t o_color += tot_ambient * attr_color;\n";
+        text << "\t result += tot_ambient * attr_color;\n";
       } else {
       } else {
-        text << "\t o_color += tot_ambient;\n";
+        text << "\t result += tot_ambient;\n";
       }
       }
     }
     }
     if (_have_diffuse) {
     if (_have_diffuse) {
       if (_material->has_diffuse()) {
       if (_material->has_diffuse()) {
-        text << "\t o_color += tot_diffuse * attr_material[1];\n";
+        text << "\t result += tot_diffuse * attr_material[1];\n";
       } else if (_vertex_colors) {
       } else if (_vertex_colors) {
-        text << "\t o_color += tot_diffuse * l_color;\n";
+        text << "\t result += tot_diffuse * l_color;\n";
       } else if (_flat_colors) {
       } else if (_flat_colors) {
-        text << "\t o_color += tot_diffuse * attr_color;\n";
+        text << "\t result += tot_diffuse * attr_color;\n";
       } else {
       } else {
-        text << "\t o_color += tot_diffuse;\n";
+        text << "\t result += tot_diffuse;\n";
       }
       }
     }
     }
-    // Use of lerp here is a workaround for a radeon driver bug.
-    if (_vertex_colors) {
-      text << "\t o_color = lerp(o_color, l_color, float4(0,0,0,1));\n";
-    } else if (_flat_colors) {
-      text << "\t o_color = lerp(o_color, attr_color, float4(0,0,0,1));\n";
-    } else {
-      text << "\t o_color.a = lerp(o_color, float4(1,1,1,1), float4(0,0,0,1));\n";
+    if (_attribs._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
+      text << "\t result = saturate(result);\n";
     }
     }
     text << "\t // End model-space light calculations\n";
     text << "\t // End model-space light calculations\n";
+
+    // Combine in alpha, which bypasses lighting calculations.
+    // Use of lerp here is a workaround for a radeon driver bug.
+    if (_map_index_glow < 0) {
+      if (_vertex_colors) {
+        text << "\t result.a = l_color.a;\n";
+      } else if (_flat_colors) {
+        text << "\t result.a = attr_color.a;\n";
+      } else {
+        text << "\t result.a = 1;\n";
+      }
+    }
   } else {
   } else {
     if (_vertex_colors) {
     if (_vertex_colors) {
-      text << "\t o_color = l_color;\n";
+      text << "\t result = l_color;\n";
     } else if (_flat_colors) {
     } else if (_flat_colors) {
-      text << "\t o_color = attr_color;\n";
+      text << "\t result = attr_color;\n";
     } else {
     } else {
-      text << "\t o_color = float4(1,1,1,1);\n";
+      text << "\t result = float4(1,1,1,1);\n";
     }
     }
   }
   }
+
   for (int i=0; i<_num_textures; i++) {
   for (int i=0; i<_num_textures; i++) {
     TextureStage *stage = _attribs._texture->get_on_stage(i);
     TextureStage *stage = _attribs._texture->get_on_stage(i);
     switch (stage->get_mode()) {
     switch (stage->get_mode()) {
     case TextureStage::M_modulate:
     case TextureStage::M_modulate:
     case TextureStage::M_modulate_glow:
     case TextureStage::M_modulate_glow:
     case TextureStage::M_modulate_gloss:
     case TextureStage::M_modulate_gloss:
-      text << "\t o_color *= tex" << i << ";\n";
+      text << "\t result *= tex" << i << ";\n";
       break;
       break;
     case TextureStage::M_decal:
     case TextureStage::M_decal:
-      text << "\t o_color.rgb = lerp(o_color, tex" << i << ", tex" << i << ".a).rgb;\n";
+      text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n";
       break;
       break;
     case TextureStage::M_blend:
     case TextureStage::M_blend:
       pgraph_cat.error() << "TextureStage::Mode BLEND not yet supported in per-pixel mode.\n";
       pgraph_cat.error() << "TextureStage::Mode BLEND not yet supported in per-pixel mode.\n";
@@ -772,8 +784,8 @@ synthesize_shader(const RenderState *rs) {
       pgraph_cat.error() << "TextureStage::Mode REPLACE not yet supported in per-pixel mode.\n";
       pgraph_cat.error() << "TextureStage::Mode REPLACE not yet supported in per-pixel mode.\n";
       break;
       break;
     case TextureStage::M_add:
     case TextureStage::M_add:
-      text << "\t o_color.rbg = o_color.rgb + tex" << i << ".rgb;\n";
-      text << "\t o_color.a   = o_color.a * tex" << i << ".a;\n";
+      text << "\t result.rbg = result.rgb + tex" << i << ".rgb;\n";
+      text << "\t result.a   = result.a * tex" << i << ".a;\n";
       break;
       break;
     case TextureStage::M_combine:
     case TextureStage::M_combine:
       pgraph_cat.error() << "TextureStage::Mode COMBINE not yet supported in per-pixel mode.\n";
       pgraph_cat.error() << "TextureStage::Mode COMBINE not yet supported in per-pixel mode.\n";
@@ -793,9 +805,26 @@ synthesize_shader(const RenderState *rs) {
       if (_map_index_gloss >= 0) {
       if (_map_index_gloss >= 0) {
         text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n";
         text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n";
       }
       }
-      text << "\t o_color.rgb = o_color.rgb + tot_specular.rgb;\n";
+      text << "\t result.rgb = result.rgb + tot_specular.rgb;\n";
     }
     }
   }
   }
+  switch (_attribs._light_ramp->get_mode()) {
+  case LightRampAttrib::LRT_hdr0:
+    text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
+    break;
+  case LightRampAttrib::LRT_hdr1:
+    text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
+    break;
+  case LightRampAttrib::LRT_hdr2:
+    text << "\t result.rgb = result / (result + 1);\n";
+    break;
+  default: break;
+  }
+  if (_bitplane_color >= 0) {
+    // The multiply is a workaround for a radeon driver bug.
+    // It's annoying as heck, since it produces an extra instruction.
+    text << "\t o_color = result * 1.000001;\n"; 
+  }
   text << "}\n";
   text << "}\n";
   
   
   // Insert the shader into the shader attrib.
   // Insert the shader into the shader attrib.