Added Contrast Adaptive Sharpening (AMD) by Justin Marshal (IcedTech)

This commit is contained in:
Robert Beckebans 2020-05-13 21:13:43 +02:00
parent 5dedbc70a6
commit 558afdd093
6 changed files with 390 additions and 30 deletions

View file

@ -77,6 +77,8 @@ The main goal is that the new content looks the same in RBDOOM-3-BFG as in Blend
* Added Blue Noise based Filmic Dithering by Timothy Lottes and Chromatic Aberration
* Added Contrast Adaptive Sharpening (AMD) from Just Marshal (IcedTech)
* Improved Shadow Mapping quality with Vogel Disk Sampling by Panos Karabelas and using dithering the result with Blue Noise magic by Alan Wolfe
* Improved Screen Space Ambient Occlusion performance by enhancing the quality with Blue Noise and skipping the expensive extra bilateral filtering pass

View file

@ -335,32 +335,39 @@ float3 Hash33( float3 p3 )
return fract( ( p3.xxy + p3.yxx ) * p3.zyx );
}
static float3 ditherRGB( float3 c, float2 uvSeed )
static float3 ditherRGB( float3 color, float2 uvSeed, float quantSteps )
{
// uniform noise
//float3 whiteNoise = Hash33( float3( uvSeed, rpJitterTexOffset.w ) );
//float3 noise = Hash33( float3( uvSeed, rpJitterTexOffset.w ) );
//float3 whiteNoise = float3( InterleavedGradientNoise( uvSeed ) );
float3 whiteNoise = float3( InterleavedGradientNoiseAnim( uvSeed, rpJitterTexOffset.w ) );
//float3 noise = float3( InterleavedGradientNoise( uvSeed ) );
float3 noise = float3( InterleavedGradientNoiseAnim( uvSeed, rpJitterTexOffset.w ) );
// triangular noise [-0.5;1.5[
#if 1
whiteNoise.x = RemapNoiseTriErp( whiteNoise.x );
whiteNoise = whiteNoise * 2.0 - 0.5;
noise.x = RemapNoiseTriErp( noise.x );
noise = noise * 2.0 - 0.5;
#endif
whiteNoise = float3( whiteNoise.x );
noise = float3( noise.x );
// quantize/truncate color and dither the result
//float scale = exp2( float( TARGET_BITS ) ) - 1.0;
// lets assume 2^3 bits = 8
float scale = 255.0;
//float scale = 7.0;
//const float quantSteps = 8.0;
float scale = quantSteps - 1.0;
float3 color = floor( c * scale + whiteNoise ) / scale;
// apply dither
color += noise / ( quantSteps );
color = floor( color * scale ) / scale;
//float3 color = c + whiteNoise / 255.0;
#if defined( USE_LINEAR_RGB )
@ -368,3 +375,37 @@ static float3 ditherRGB( float3 c, float2 uvSeed )
return color;
}
static float3 ditherChromaticBlueNoise( float3 color, float2 n, sampler2D blueTex )
{
// uniform noise
//float3 noise = Hash33( float3( n, rpJitterTexOffset.w ) );
//float3 noise = float3( InterleavedGradientNoise( n ) );
//float3 noise = float3( InterleavedGradientNoiseAnim( n, rpJitterTexOffset.w ) );
// uv is screen position / sizeof blue noise image
float2 uv = n.xy * rpJitterTexOffset.xy;
float3 noise = tex2D( blueTex, uv ).rgb;
// rpJitterTexOffset.w is frameTime % 64
noise = fract( noise + c_goldenRatioConjugate * rpJitterTexOffset.w );
// triangular noise [-0.5;1.5[
noise.x = RemapNoiseTriErp( noise.x );
noise = noise * 2.0 - 0.5;
//noise = float3( noise.x );
// quantize/truncate color and dither the result
//float scale = exp2( float( TARGET_BITS ) ) - 1.0;
// lets assume 2^3 bits = 8
float quantSteps = 255.0;
//float3 color = floor( c * scale + noise ) / scale;
color = floor( 0.5 + color * quantSteps - 0.5 + noise ) * ( 1.0 / ( quantSteps - 1.0 ) );
return color;
}

View file

@ -424,9 +424,15 @@ void main( PS_IN fragment, out PS_OUT result )
// rpDiffuseModifier contains light color multiplier
half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );
//lightColor = ditherRGB( lightColor, fragment.position.xy );
//lightColor *= sRGBToLinearRGB( lightFalloff.xyz );// * rpDiffuseModifier.xyz;
//lightFalloff.xyz = ditherRGB( lightFalloff.xyz, fragment.texcoord2.xy );
//lightProj.xyz = ditherRGB( lightProj.xyz, fragment.texcoord3.xy );
//half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );
//lightColor = ditherChromaticBlueNoise( lightColor, fragment.position.xy, samp6 );
//lightColor *= sRGBToLinearRGB( lightFalloff.xyz );// * rpDiffuseModifier.xyz;
//lightColor = ditherRGB( lightColor, fragment.position.xy );
@ -463,6 +469,10 @@ void main( PS_IN fragment, out PS_OUT result )
//half3 diffuseColor = mix( diffuseMap, F0, metal ) * rpDiffuseModifier.xyz;
half3 diffuseBRDF = diffuseColor * lambert * ( rpDiffuseModifier.xyz );
result.color.xyz = ( diffuseBRDF + specularBRDF ) * lightColor * fragment.color.rgb * shadow;
result.color.w = 1.0;
float3 color = ( diffuseBRDF + specularBRDF ) * lightColor * fragment.color.rgb * shadow;
//color = ditherChromaticBlueNoise( color, fragment.position.xy, samp6 );
result.color.rgb = color;
result.color.a = 1.0;
}

View file

@ -5,6 +5,7 @@ Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015-2020 Robert Beckebans
Copyright (C) 2014 Timothy Lottes (AMD)
Copyright (C) 2019 Justin Marshal (IcedTech)
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -61,7 +62,9 @@ struct PS_OUT
#define Vibrance 0.5 // [-1.00 to 1.00]
#define Vibrance_RGB_Balance float3( 1.0, 1.0, 1.0 )
#define USE_DITHERING 1
#define USE_CAS 1
#define USE_DITHERING 0
#define Dithering_QuantizationSteps 8.0 // 8.0 = 2 ^ 3 quantization bits
#define Dithering_NoiseBoost 1.0
#define Dithering_Wide 1.0
@ -460,6 +463,107 @@ void DitheringPass( inout float4 fragColor )
}
float Min3( float x, float y, float z )
{
return min( x, min( y, z ) );
}
float Max3( float x, float y, float z )
{
return max( x, max( y, z ) );
}
float rcp( float v )
{
return 1.0 / v;
}
void ContrastAdaptiveSharpeningPass( inout float4 fragColor )
{
float2 texcoord = fragment.texcoord0;
float Sharpness = 1;
// fetch a 3x3 neighborhood around the pixel 'e',
// a b c
// d(e)f
// g h i
int2 bufferSize = textureSize( samp0, 0 );
float pixelX = ( 1.0 / bufferSize.x );
float pixelY = ( 1.0 / bufferSize.y );
float3 a = tex2D( samp0, texcoord + float2( -pixelX, -pixelY ) ).rgb;
float3 b = tex2D( samp0, texcoord + float2( 0.0, -pixelY ) ).rgb;
float3 c = tex2D( samp0, texcoord + float2( pixelX, -pixelY ) ).rgb;
float3 d = tex2D( samp0, texcoord + float2( -pixelX, 0.0 ) ).rgb;
float3 e = tex2D( samp0, texcoord ).rgb;
float3 f = tex2D( samp0, texcoord + float2( pixelX, 0.0 ) ).rgb;
float3 g = tex2D( samp0, texcoord + float2( -pixelX, pixelY ) ).rgb;
float3 h = tex2D( samp0, texcoord + float2( 0.0, pixelY ) ).rgb;
float3 i = tex2D( samp0, texcoord + float2( pixelX, pixelY ) ).rgb;
// Soft min and max.
// a b c b
// d e f * 0.5 + d e f * 0.5
// g h i h
// These are 2.0x bigger (factored out the extra multiply).
float mnR = Min3( Min3( d.r, e.r, f.r ), b.r, h.r );
float mnG = Min3( Min3( d.g, e.g, f.g ), b.g, h.g );
float mnB = Min3( Min3( d.b, e.b, f.b ), b.b, h.b );
float mnR2 = Min3( Min3( mnR, a.r, c.r ), g.r, i.r );
float mnG2 = Min3( Min3( mnG, a.g, c.g ), g.g, i.g );
float mnB2 = Min3( Min3( mnB, a.b, c.b ), g.b, i.b );
mnR = mnR + mnR2;
mnG = mnG + mnG2;
mnB = mnB + mnB2;
float mxR = Max3( Max3( d.r, e.r, f.r ), b.r, h.r );
float mxG = Max3( Max3( d.g, e.g, f.g ), b.g, h.g );
float mxB = Max3( Max3( d.b, e.b, f.b ), b.b, h.b );
float mxR2 = Max3( Max3( mxR, a.r, c.r ), g.r, i.r );
float mxG2 = Max3( Max3( mxG, a.g, c.g ), g.g, i.g );
float mxB2 = Max3( Max3( mxB, a.b, c.b ), g.b, i.b );
mxR = mxR + mxR2;
mxG = mxG + mxG2;
mxB = mxB + mxB2;
// Smooth minimum distance to signal limit divided by smooth max.
float rcpMR = rcp( mxR );
float rcpMG = rcp( mxG );
float rcpMB = rcp( mxB );
float ampR = saturate( min( mnR, 2.0 - mxR ) * rcpMR );
float ampG = saturate( min( mnG, 2.0 - mxG ) * rcpMG );
float ampB = saturate( min( mnB, 2.0 - mxB ) * rcpMB );
// Shaping amount of sharpening.
ampR = sqrt( ampR );
ampG = sqrt( ampG );
ampB = sqrt( ampB );
// Filter shape.
// 0 w 0
// w 1 w
// 0 w 0
float peak = -rcp( lerp( 8.0, 5.0, saturate( Sharpness ) ) );
float wR = ampR * peak;
float wG = ampG * peak;
float wB = ampB * peak;
float rcpWeightR = rcp( 1.0 + 4.0 * wR );
float rcpWeightG = rcp( 1.0 + 4.0 * wG );
float rcpWeightB = rcp( 1.0 + 4.0 * wB );
float3 outColor = float3( saturate( ( b.r * wR + d.r * wR + f.r * wR + h.r * wR + e.r ) * rcpWeightR ),
saturate( ( b.g * wG + d.g * wG + f.g * wG + h.g * wG + e.g ) * rcpWeightG ),
saturate( ( b.b * wB + d.b * wB + f.b * wB + h.b * wB + e.b ) * rcpWeightB ) );
fragColor.rgb = outColor;
}
void main( PS_IN fragment, out PS_OUT result )
{
float2 tCoords = fragment.texcoord0;
@ -479,6 +583,10 @@ void main( PS_IN fragment, out PS_OUT result )
VibrancePass( color );
#endif
#if USE_CAS
ContrastAdaptiveSharpeningPass( color );
#endif
#if USE_DITHERING
DitheringPass( color );
#endif

View file

@ -69,6 +69,8 @@ float3 ACESFilm( float3 x )
return saturate( ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e ) );
}
#define USE_DITHERING 0
void main( PS_IN fragment, out PS_OUT result )
{
float2 tCoords = fragment.texcoord0;
@ -93,6 +95,14 @@ void main( PS_IN fragment, out PS_OUT result )
color.b = pow( color.b, gamma );
#endif
#if USE_DITHERING
const float quantSteps = 256.0;
// dither
color.rgb = ditherRGB( color.rgb, fragment.position.xy, quantSteps );
#endif
#if defined(BRIGHTPASS)
if( Y < 0.1 )
{
@ -197,7 +207,16 @@ void main( PS_IN fragment, out PS_OUT result )
color.rgb *= clamp( B, 0.0, 1.0 );
#endif
#if 1
#if USE_DITHERING
// The following represents hardware linear->sRGB xform
// which happens on sRGB formatted render targets,
// except using a lot less bits/pixel.
color.rgb = max( float3( 0.0 ), color.rgb );
color.rgb = Srgb3( color.rgb );
color.rgb = floor( color.rgb * quantSteps ) * ( 1.0 / ( quantSteps - 1.0 ) );
#else
// convert from linear RGB to sRGB
//float hdrGamma = 2.2;
@ -205,6 +224,7 @@ void main( PS_IN fragment, out PS_OUT result )
color.r = pow( color.r, gamma );
color.g = pow( color.g, gamma );
color.b = pow( color.b, gamma );
#endif
#if defined(HDR_DEBUG)

View file

@ -349,32 +349,39 @@ static const cgShaderDef_t cg_renderprogs[] =
" return fract( ( p3.xxy + p3.yxx ) * p3.zyx );\n"
"}\n"
"\n"
"static float3 ditherRGB( float3 c, float2 uvSeed )\n"
"static float3 ditherRGB( float3 color, float2 uvSeed, float quantSteps )\n"
"{\n"
" // uniform noise\n"
" //float3 whiteNoise = Hash33( float3( uvSeed, rpJitterTexOffset.w ) );\n"
" //float3 noise = Hash33( float3( uvSeed, rpJitterTexOffset.w ) );\n"
"\n"
" //float3 whiteNoise = float3( InterleavedGradientNoise( uvSeed ) );\n"
" float3 whiteNoise = float3( InterleavedGradientNoiseAnim( uvSeed, rpJitterTexOffset.w ) );\n"
" //float3 noise = float3( InterleavedGradientNoise( uvSeed ) );\n"
" float3 noise = float3( InterleavedGradientNoiseAnim( uvSeed, rpJitterTexOffset.w ) );\n"
"\n"
"\n"
" // triangular noise [-0.5;1.5[\n"
"\n"
"#if 1\n"
" whiteNoise.x = RemapNoiseTriErp( whiteNoise.x );\n"
" whiteNoise = whiteNoise * 2.0 - 0.5;\n"
" noise.x = RemapNoiseTriErp( noise.x );\n"
" noise = noise * 2.0 - 0.5;\n"
"#endif\n"
"\n"
" whiteNoise = float3( whiteNoise.x );\n"
" noise = float3( noise.x );\n"
"\n"
"\n"
" // quantize/truncate color and dither the result\n"
" //float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
"\n"
" // lets assume 2^3 bits = 8\n"
" float scale = 255.0;\n"
" //float scale = 7.0;\n"
" //const float quantSteps = 8.0;\n"
" float scale = quantSteps - 1.0;\n"
"\n"
" float3 color = floor( c * scale + whiteNoise ) / scale;\n"
" // apply dither\n"
" color += noise / ( quantSteps );\n"
"\n"
" color = floor( color * scale ) / scale;\n"
"\n"
" //float3 color = c + whiteNoise / 255.0;\n"
"\n"
"#if defined( USE_LINEAR_RGB )\n"
"\n"
@ -383,6 +390,40 @@ static const cgShaderDef_t cg_renderprogs[] =
" return color;\n"
"}\n"
"\n"
"static float3 ditherChromaticBlueNoise( float3 color, float2 n, sampler2D blueTex )\n"
"{\n"
" // uniform noise\n"
" //float3 noise = Hash33( float3( n, rpJitterTexOffset.w ) );\n"
"\n"
" //float3 noise = float3( InterleavedGradientNoise( n ) );\n"
" //float3 noise = float3( InterleavedGradientNoiseAnim( n, rpJitterTexOffset.w ) );\n"
"\n"
" // uv is screen position / sizeof blue noise image\n"
" float2 uv = n.xy * rpJitterTexOffset.xy;\n"
" float3 noise = tex2D( blueTex, uv ).rgb;\n"
"\n"
" // rpJitterTexOffset.w is frameTime % 64\n"
" noise = fract( noise + c_goldenRatioConjugate * rpJitterTexOffset.w );\n"
"\n"
" // triangular noise [-0.5;1.5[\n"
" noise.x = RemapNoiseTriErp( noise.x );\n"
" noise = noise * 2.0 - 0.5;\n"
"\n"
" //noise = float3( noise.x );\n"
"\n"
" // quantize/truncate color and dither the result\n"
" //float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
"\n"
" // lets assume 2^3 bits = 8\n"
" float quantSteps = 255.0;\n"
"\n"
" //float3 color = floor( c * scale + noise ) / scale;\n"
"\n"
" color = floor( 0.5 + color * quantSteps - 0.5 + noise ) * ( 1.0 / ( quantSteps - 1.0 ) );\n"
"\n"
" return color;\n"
"}\n"
"\n"
},
@ -10294,9 +10335,15 @@ static const cgShaderDef_t cg_renderprogs[] =
"\n"
" // rpDiffuseModifier contains light color multiplier\n"
" half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );\n"
" //lightColor = ditherRGB( lightColor, fragment.position.xy );\n"
" //lightColor *= sRGBToLinearRGB( lightFalloff.xyz );// * rpDiffuseModifier.xyz;\n"
"\n"
" //lightFalloff.xyz = ditherRGB( lightFalloff.xyz, fragment.texcoord2.xy );\n"
" //lightProj.xyz = ditherRGB( lightProj.xyz, fragment.texcoord3.xy );\n"
"\n"
" //half3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );\n"
"\n"
" //lightColor = ditherChromaticBlueNoise( lightColor, fragment.position.xy, samp6 );\n"
"\n"
" //lightColor *= sRGBToLinearRGB( lightFalloff.xyz );// * rpDiffuseModifier.xyz;\n"
" //lightColor = ditherRGB( lightColor, fragment.position.xy );\n"
"\n"
"\n"
@ -10333,8 +10380,12 @@ static const cgShaderDef_t cg_renderprogs[] =
" //half3 diffuseColor = mix( diffuseMap, F0, metal ) * rpDiffuseModifier.xyz;\n"
" half3 diffuseBRDF = diffuseColor * lambert * ( rpDiffuseModifier.xyz );\n"
"\n"
" result.color.xyz = ( diffuseBRDF + specularBRDF ) * lightColor * fragment.color.rgb * shadow;\n"
" result.color.w = 1.0;\n"
" float3 color = ( diffuseBRDF + specularBRDF ) * lightColor * fragment.color.rgb * shadow;\n"
"\n"
" //color = ditherChromaticBlueNoise( color, fragment.position.xy, samp6 );\n"
"\n"
" result.color.rgb = color;\n"
" result.color.a = 1.0;\n"
"}\n"
"\n"
@ -10732,6 +10783,7 @@ static const cgShaderDef_t cg_renderprogs[] =
"Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n"
"Copyright (C) 2015-2020 Robert Beckebans\n"
"Copyright (C) 2014 Timothy Lottes (AMD)\n"
"Copyright (C) 2019 Justin Marshal (IcedTech)\n"
"\n"
"This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n"
"\n"
@ -10788,7 +10840,9 @@ static const cgShaderDef_t cg_renderprogs[] =
"#define Vibrance 0.5 // [-1.00 to 1.00]\n"
"#define Vibrance_RGB_Balance float3( 1.0, 1.0, 1.0 )\n"
"\n"
"#define USE_DITHERING 1\n"
"#define USE_CAS 1\n"
"\n"
"#define USE_DITHERING 0\n"
"#define Dithering_QuantizationSteps 8.0 // 8.0 = 2 ^ 3 quantization bits\n"
"#define Dithering_NoiseBoost 1.0\n"
"#define Dithering_Wide 1.0\n"
@ -11187,6 +11241,107 @@ static const cgShaderDef_t cg_renderprogs[] =
"}\n"
"\n"
"\n"
"float Min3( float x, float y, float z )\n"
"{\n"
" return min( x, min( y, z ) );\n"
"}\n"
"\n"
"float Max3( float x, float y, float z )\n"
"{\n"
" return max( x, max( y, z ) );\n"
"}\n"
"\n"
"\n"
"float rcp( float v )\n"
"{\n"
" return 1.0 / v;\n"
"}\n"
"\n"
"void ContrastAdaptiveSharpeningPass( inout float4 fragColor )\n"
"{\n"
" float2 texcoord = fragment.texcoord0;\n"
" float Sharpness = 1;\n"
"\n"
" // fetch a 3x3 neighborhood around the pixel 'e',\n"
" // a b c\n"
" // d(e)f\n"
" // g h i\n"
" int2 bufferSize = textureSize( samp0, 0 );\n"
" float pixelX = ( 1.0 / bufferSize.x );\n"
" float pixelY = ( 1.0 / bufferSize.y );\n"
"\n"
" float3 a = tex2D( samp0, texcoord + float2( -pixelX, -pixelY ) ).rgb;\n"
" float3 b = tex2D( samp0, texcoord + float2( 0.0, -pixelY ) ).rgb;\n"
" float3 c = tex2D( samp0, texcoord + float2( pixelX, -pixelY ) ).rgb;\n"
" float3 d = tex2D( samp0, texcoord + float2( -pixelX, 0.0 ) ).rgb;\n"
" float3 e = tex2D( samp0, texcoord ).rgb;\n"
" float3 f = tex2D( samp0, texcoord + float2( pixelX, 0.0 ) ).rgb;\n"
" float3 g = tex2D( samp0, texcoord + float2( -pixelX, pixelY ) ).rgb;\n"
" float3 h = tex2D( samp0, texcoord + float2( 0.0, pixelY ) ).rgb;\n"
" float3 i = tex2D( samp0, texcoord + float2( pixelX, pixelY ) ).rgb;\n"
"\n"
" // Soft min and max.\n"
" // a b c b\n"
" // d e f * 0.5 + d e f * 0.5\n"
" // g h i h\n"
" // These are 2.0x bigger (factored out the extra multiply).\n"
" float mnR = Min3( Min3( d.r, e.r, f.r ), b.r, h.r );\n"
" float mnG = Min3( Min3( d.g, e.g, f.g ), b.g, h.g );\n"
" float mnB = Min3( Min3( d.b, e.b, f.b ), b.b, h.b );\n"
"\n"
" float mnR2 = Min3( Min3( mnR, a.r, c.r ), g.r, i.r );\n"
" float mnG2 = Min3( Min3( mnG, a.g, c.g ), g.g, i.g );\n"
" float mnB2 = Min3( Min3( mnB, a.b, c.b ), g.b, i.b );\n"
" mnR = mnR + mnR2;\n"
" mnG = mnG + mnG2;\n"
" mnB = mnB + mnB2;\n"
"\n"
" float mxR = Max3( Max3( d.r, e.r, f.r ), b.r, h.r );\n"
" float mxG = Max3( Max3( d.g, e.g, f.g ), b.g, h.g );\n"
" float mxB = Max3( Max3( d.b, e.b, f.b ), b.b, h.b );\n"
"\n"
" float mxR2 = Max3( Max3( mxR, a.r, c.r ), g.r, i.r );\n"
" float mxG2 = Max3( Max3( mxG, a.g, c.g ), g.g, i.g );\n"
" float mxB2 = Max3( Max3( mxB, a.b, c.b ), g.b, i.b );\n"
" mxR = mxR + mxR2;\n"
" mxG = mxG + mxG2;\n"
" mxB = mxB + mxB2;\n"
"\n"
" // Smooth minimum distance to signal limit divided by smooth max.\n"
" float rcpMR = rcp( mxR );\n"
" float rcpMG = rcp( mxG );\n"
" float rcpMB = rcp( mxB );\n"
"\n"
" float ampR = saturate( min( mnR, 2.0 - mxR ) * rcpMR );\n"
" float ampG = saturate( min( mnG, 2.0 - mxG ) * rcpMG );\n"
" float ampB = saturate( min( mnB, 2.0 - mxB ) * rcpMB );\n"
"\n"
" // Shaping amount of sharpening.\n"
" ampR = sqrt( ampR );\n"
" ampG = sqrt( ampG );\n"
" ampB = sqrt( ampB );\n"
"\n"
" // Filter shape.\n"
" // 0 w 0\n"
" // w 1 w\n"
" // 0 w 0\n"
" float peak = -rcp( lerp( 8.0, 5.0, saturate( Sharpness ) ) );\n"
"\n"
" float wR = ampR * peak;\n"
" float wG = ampG * peak;\n"
" float wB = ampB * peak;\n"
"\n"
" float rcpWeightR = rcp( 1.0 + 4.0 * wR );\n"
" float rcpWeightG = rcp( 1.0 + 4.0 * wG );\n"
" float rcpWeightB = rcp( 1.0 + 4.0 * wB );\n"
"\n"
" float3 outColor = float3( saturate( ( b.r * wR + d.r * wR + f.r * wR + h.r * wR + e.r ) * rcpWeightR ),\n"
" saturate( ( b.g * wG + d.g * wG + f.g * wG + h.g * wG + e.g ) * rcpWeightG ),\n"
" saturate( ( b.b * wB + d.b * wB + f.b * wB + h.b * wB + e.b ) * rcpWeightB ) );\n"
"\n"
" fragColor.rgb = outColor;\n"
"}\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
" float2 tCoords = fragment.texcoord0;\n"
@ -11206,6 +11361,10 @@ static const cgShaderDef_t cg_renderprogs[] =
" VibrancePass( color );\n"
"#endif\n"
"\n"
"#if USE_CAS\n"
" ContrastAdaptiveSharpeningPass( color );\n"
"#endif\n"
"\n"
"#if USE_DITHERING\n"
" DitheringPass( color );\n"
"#endif\n"
@ -13599,6 +13758,8 @@ static const cgShaderDef_t cg_renderprogs[] =
" return saturate( ( x * ( a * x + b ) ) / ( x * ( c * x + d ) + e ) );\n"
"}\n"
"\n"
"#define USE_DITHERING 0\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
" float2 tCoords = fragment.texcoord0;\n"
@ -13623,6 +13784,14 @@ static const cgShaderDef_t cg_renderprogs[] =
" color.b = pow( color.b, gamma );\n"
"#endif\n"
"\n"
"#if USE_DITHERING\n"
"\n"
" const float quantSteps = 256.0;\n"
"\n"
" // dither\n"
" color.rgb = ditherRGB( color.rgb, fragment.position.xy, quantSteps );\n"
"#endif\n"
"\n"
"#if defined(BRIGHTPASS)\n"
" if( Y < 0.1 )\n"
" {\n"
@ -13727,7 +13896,16 @@ static const cgShaderDef_t cg_renderprogs[] =
" color.rgb *= clamp( B, 0.0, 1.0 );\n"
"#endif\n"
"\n"
"#if 1\n"
"#if USE_DITHERING\n"
" // The following represents hardware linear->sRGB xform\n"
" // which happens on sRGB formatted render targets,\n"
" // except using a lot less bits/pixel.\n"
" color.rgb = max( float3( 0.0 ), color.rgb );\n"
" color.rgb = Srgb3( color.rgb );\n"
" color.rgb = floor( color.rgb * quantSteps ) * ( 1.0 / ( quantSteps - 1.0 ) );\n"
"\n"
"#else\n"
"\n"
" // convert from linear RGB to sRGB\n"
"\n"
" //float hdrGamma = 2.2;\n"
@ -13735,6 +13913,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" color.r = pow( color.r, gamma );\n"
" color.g = pow( color.g, gamma );\n"
" color.b = pow( color.b, gamma );\n"
"\n"
"#endif\n"
"\n"
"#if defined(HDR_DEBUG)\n"