From 7bb510a3efda5dc4e248a5a0b9d13ea01957c0a3 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Thu, 21 Feb 2008 19:54:40 +0000 Subject: [PATCH] Added support for HDR --- panda/src/pgraph/auxBitplaneAttrib.h | 5 +- panda/src/pgraph/lightRampAttrib.I | 2 +- panda/src/pgraph/lightRampAttrib.cxx | 141 +++++++++++++++++++++++++-- panda/src/pgraph/lightRampAttrib.h | 27 ++--- panda/src/pgraph/shaderGenerator.cxx | 89 +++++++++++------ 5 files changed, 211 insertions(+), 53 deletions(-) diff --git a/panda/src/pgraph/auxBitplaneAttrib.h b/panda/src/pgraph/auxBitplaneAttrib.h index d55691971b..a98c0e8c98 100644 --- a/panda/src/pgraph/auxBitplaneAttrib.h +++ b/panda/src/pgraph/auxBitplaneAttrib.h @@ -42,8 +42,9 @@ private: PUBLISHED: 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(int outputs); diff --git a/panda/src/pgraph/lightRampAttrib.I b/panda/src/pgraph/lightRampAttrib.I index d8a0e4b5e3..4bb72a5d9a 100644 --- a/panda/src/pgraph/lightRampAttrib.I +++ b/panda/src/pgraph/lightRampAttrib.I @@ -25,7 +25,7 @@ //////////////////////////////////////////////////////////////////// INLINE LightRampAttrib:: LightRampAttrib() { - _mode = LRT_identity; + _mode = LRT_default; _level[0] = 0.0; _level[1] = 0.0; _threshold[0] = 0.0; diff --git a/panda/src/pgraph/lightRampAttrib.cxx b/panda/src/pgraph/lightRampAttrib.cxx index dd8c50c077..3e87ff999b 100644 --- a/panda/src/pgraph/lightRampAttrib.cxx +++ b/panda/src/pgraph/lightRampAttrib.cxx @@ -26,26 +26,51 @@ #include "datagramIterator.h" TypeHandle LightRampAttrib::_type_handle; -CPT(RenderAttrib) LightRampAttrib::_identity; +CPT(RenderAttrib) LightRampAttrib::_default; + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::make_default +// Access: Published, Static +// 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:: +make_default() { + if (_default == 0) { + LightRampAttrib *attrib = new LightRampAttrib(); + _default = return_new(attrib); + } + return _default; +} //////////////////////////////////////////////////////////////////// // Function: LightRampAttrib::make_identity // Access: Published, Static -// Description: Constructs a new LightRampAttrib object. +// 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() { - if (_identity == 0) { - LightRampAttrib *attrib = new LightRampAttrib(); - _identity = return_new(attrib); - } - return _identity; + LightRampAttrib *attrib = new LightRampAttrib(); + attrib->_mode = LRT_identity; + return return_new(attrib); } //////////////////////////////////////////////////////////////////// // Function: LightRampAttrib::make_single_threshold // 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:: make_single_threshold(float thresh0, float val0) { @@ -59,7 +84,18 @@ make_single_threshold(float thresh0, float val0) { //////////////////////////////////////////////////////////////////// // Function: LightRampAttrib::make_double_threshold // 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:: 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); } +//////////////////////////////////////////////////////////////////// +// 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 // Access: Public, Virtual diff --git a/panda/src/pgraph/lightRampAttrib.h b/panda/src/pgraph/lightRampAttrib.h index 3d64d78b2f..0d46929037 100644 --- a/panda/src/pgraph/lightRampAttrib.h +++ b/panda/src/pgraph/lightRampAttrib.h @@ -26,16 +26,12 @@ class FactoryParams; //////////////////////////////////////////////////////////////////// // 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 { private: @@ -43,14 +39,23 @@ private: PUBLISHED: enum LightRampMode { + LRT_default, LRT_identity, LRT_single_threshold, LRT_double_threshold, + LRT_hdr0, + LRT_hdr1, + LRT_hdr2, }; + static CPT(RenderAttrib) make_default(); static CPT(RenderAttrib) make_identity(); 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_hdr0(); + static CPT(RenderAttrib) make_hdr1(); + static CPT(RenderAttrib) make_hdr2(); + INLINE LightRampMode get_mode() const; INLINE float get_level(int n) const; INLINE float get_threshold(int n) const; @@ -68,7 +73,7 @@ private: float _level[2]; float _threshold[2]; - static CPT(RenderAttrib) _identity; + static CPT(RenderAttrib) _default; public: static void register_with_read_factory(); diff --git a/panda/src/pgraph/shaderGenerator.cxx b/panda/src/pgraph/shaderGenerator.cxx index 759d9dd40f..7e6332b0c3 100644 --- a/panda/src/pgraph/shaderGenerator.cxx +++ b/panda/src/pgraph/shaderGenerator.cxx @@ -555,9 +555,7 @@ synthesize_shader(const RenderState *rs) { text << "\t uniform float4 attr_color\n"; } text << ") {\n"; - if (_bitplane_color < 0) { - text << "float4 \t o_color;\n"; - } + text << "\t float4 result;\n"; text << "\t // Fetch all textures.\n"; for (int i=0; i<_num_textures; i++) { 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()) { - case LightRampAttrib::LRT_identity: - break; case LightRampAttrib::LRT_single_threshold: { 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"; 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 { - 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 (_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) { - text << "\t o_color += tot_ambient * l_color;\n"; + text << "\t result += tot_ambient * l_color;\n"; } else if (_flat_colors) { - text << "\t o_color += tot_ambient * attr_color;\n"; + text << "\t result += tot_ambient * attr_color;\n"; } else { - text << "\t o_color += tot_ambient;\n"; + text << "\t result += tot_ambient;\n"; } } if (_have_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) { - text << "\t o_color += tot_diffuse * l_color;\n"; + text << "\t result += tot_diffuse * l_color;\n"; } else if (_flat_colors) { - text << "\t o_color += tot_diffuse * attr_color;\n"; + text << "\t result += tot_diffuse * attr_color;\n"; } 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"; + + // 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 { if (_vertex_colors) { - text << "\t o_color = l_color;\n"; + text << "\t result = l_color;\n"; } else if (_flat_colors) { - text << "\t o_color = attr_color;\n"; + text << "\t result = attr_color;\n"; } 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++) { TextureStage *stage = _attribs._texture->get_on_stage(i); switch (stage->get_mode()) { case TextureStage::M_modulate: case TextureStage::M_modulate_glow: case TextureStage::M_modulate_gloss: - text << "\t o_color *= tex" << i << ";\n"; + text << "\t result *= tex" << i << ";\n"; break; 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; case TextureStage::M_blend: 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"; break; 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; case TextureStage::M_combine: 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) { 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"; // Insert the shader into the shader attrib.