Added support for HDR

This commit is contained in:
Josh Yelon 2008-02-21 19:54:40 +00:00
parent 3882d21189
commit 7bb510a3ef
5 changed files with 211 additions and 53 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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.