//---------------------------------------------------------------------------------
-----
// SAFE ( SA_For_Effect )
// Tonemaping, bloom & color correction
// Copyright 2014 (c) Buthen
//---------------------------------------------------------------------------------
-----
//---------------------------------------------------------------------------------
-----
// Defines
//---------------------------------------------------------------------------------
-----
#define COLOR_CORRECTION
#define TONEMAPPING_MODE_0
//---------------------------------------------------------------------------------
-----
// Vectors, floats and etc.
//---------------------------------------------------------------------------------
-----
float ScreenScaleY;
float ScreenSize;
float2 screenRes = {1920,1080};
float _ExposureAdjustment = 3.3;
static const float gray = 0.04;
static const float white = 0.4;
float4 _HdrParams = {gray,gray,gray,white*white};
static const float thresh = 0.20;
float4 threshhold = {thresh, 1/(1-thresh), 5.0, 5.0};
float BloomIntensity = 0.30;
//---------------------------------------------------------------------------------
-----
// Textures
//---------------------------------------------------------------------------------
-----
texture2D texColor;
texture2D texDepth;
texture2D texNoise;
//---------------------------------------------------------------------------------
-----
// Sampler Inputs
//---------------------------------------------------------------------------------
-----
sampler2D InputSampler = sampler_state
{
Texture = (texColor);
MinFilter = POINT;
MagFilter = POINT;
MipFilter = POINT;
AddressU = Clamp;
AddressV = Clamp;
SRGBTexture=FALSE;
MaxMipLevel=0;
MipMapLodBias=0;
};
sampler2D SamplerDepth = sampler_state
{
Texture = <texDepth>;
MinFilter = POINT;
MagFilter = POINT;
MipFilter = NONE;
AddressU = Clamp;
AddressV = Clamp;
SRGBTexture=FALSE;
MaxMipLevel=0;
MipMapLodBias=0;
};
sampler2D SamplerNoise = sampler_state
{
Texture = <texNoise>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Wrap;
AddressV = Wrap;
SRGBTexture = FALSE;
MaxMipLevel = 0;
MipMapLodBias = 0;
};
struct VS_OUTPUT_POST
{
float4 vpos : POSITION;
float2 txcoord : TEXCOORD0;
};
struct VS_INPUT_POST
{
float3 pos : POSITION;
float2 txcoord : TEXCOORD0;
};
//---------------------------------------------------------------------------------
-----
// Functions
//---------------------------------------------------------------------------------
-----
float Luminance( float3 c )
{
return dot( c, float3(0.22, 0.707, 0.071) );
}
//---------------------------------------------------------------------------------
-----
// Vertex Shader Input
//---------------------------------------------------------------------------------
-----
VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST IN)
{
VS_OUTPUT_POST OUT;
float4 pos=float4(IN.pos.x,IN.pos.y,IN.pos.z,1.0);
OUT.vpos=pos;
OUT.txcoord.xy=IN.txcoord.xy;
return OUT;
}
float4 paramsS = {1.0,1.0,1.0,1.0};
float4 paramsM = {1.0,1.0,1.0,1.0};
float4 paramsH = {1.0,1.0,1.0,1.0};
float _Saturation = 1.10;
const float blurSize = 0.5/128.0;
const float BlurDownsampling = 8;
float4 CCShadow (VS_OUTPUT_POST i, float2 vPos : VPOS) : COLOR
{
float4 col = tex2D(InputSampler, i.txcoord);
//float4 color = tex2Dlod(InputSampler, float4(i.txcoord,0,8));
float4 sum = float4(0,0,0,0);
// blur this in y (vertical)
// also I downsample it to get interesting result
sum += tex2Dlod(InputSampler, float4(i.txcoord.x - 4.0*blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.05;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x - 3.0*blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.09;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x - 2.0*blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.12;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x - blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.15;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x,
i.txcoord.y,0,BlurDownsampling)) * 0.16;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x + blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.15;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x + 2.0*blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.12;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x + 3.0*blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.09;
sum += tex2Dlod(InputSampler, float4(i.txcoord.x + 4.0*blurSize,
i.txcoord.y,0,BlurDownsampling)) * 0.05;
// do some cool stuff to get bloom...
float4 color = max(float4(0.0,0.0,0.0,0.0), sum-threshhold.x);
float4 toBlend = saturate (color * BloomIntensity);
float4 smpl = 1-(1-col)*(1-toBlend);
float factor = max(smpl.x, max(smpl.y, smpl.z));
float factorM = (smpl.x + smpl.y + smpl.z)/3;
float4 shadows = paramsS;
float4 midtones = paramsM;
float4 highlights = paramsH;
float4 Color;
#ifdef COLOR_CORRECTION
if(factor < 0.1) //Shadows
{
if(factor > 0.01)
{
factor = (factor + 0.09)*10;
shadows.w = shadows.x; //.w is value backup
shadows.x = ((1 - shadows.w) / 2) * factor;
shadows.x += shadows.w; //Adding backup
shadows.w = shadows.y; //.w is value backup
shadows.y = ((1 - shadows.w) / 2) * factor;
shadows.y += shadows.w; //Adding backup
shadows.w = shadows.z; //.w is value backup
shadows.z = ((1 - shadows.w) / 2) * factor;
shadows.z += shadows.w; //Adding backup
}
Color = float4(smpl.x * shadows.x, smpl.y * shadows.y, smpl.z *
shadows.z, smpl.w);
}
else if(factorM >= 0.1 && factorM <= 0.5) //Middle-tones
{
if(factorM > 0.3)
{
factorM = (factorM - 0.31)*10;
midtones.w = midtones.x; //.w is value backup
midtones.x = ((1 - midtones.w) / 2) * factorM;
midtones.x += midtones.w; //Adding backup
midtones.w = midtones.y; //.w is value backup
midtones.y = ((1 - midtones.w) / 2) * factorM;
midtones.y += midtones.w; //Adding backup
midtones.w = midtones.z; //.w is value backup
midtones.z = ((1 - midtones.w) / 2) * factorM;
midtones.z += midtones.w; //Adding backup
}
else if(factorM <= 0.3)
{
factorM = (factorM - 0.1)*10;
midtones.w = midtones.x;
midtones.x = (1 - midtones.w) - (factorM * ((1 - midtones.w) /
2));
midtones.x += midtones.w;
midtones.w = midtones.y;
midtones.y = (1 - midtones.w) - (factorM * ((1 - midtones.w) /
2));
midtones.y += midtones.w;
midtones.w = midtones.z;
midtones.z = (1 - midtones.w) - (factorM * ((1 - midtones.w) /
2));
midtones.z += midtones.w;
}
Color = float4(smpl.x * midtones.x, smpl.y * midtones.y, smpl.z *
midtones.z, smpl.w);
}
else if(factorM > 0.5) //Hightlights
{
if(factorM <= 0.8)
{
factorM = (factorM - 0.51)*10;
highlights.w = highlights.x;
highlights.x = (1 - highlights.w) - (factorM * ((1 -
highlights.w) / 2));
highlights.x += highlights.w;
highlights.w = highlights.y;
highlights.y = (1 - highlights.w) - (factorM * ((1 -
highlights.w) / 2));
highlights.y += highlights.w;
highlights.w = highlights.z;
highlights.z = (1 - highlights.w) - (factorM * ((1 -
highlights.w) / 2));
highlights.z += highlights.w;
}
Color = float4(smpl.x * highlights.x, smpl.y * highlights.y, smpl.z *
highlights.z, smpl.w);
}
else Color = smpl;
#else
Color = smpl;
#endif
float lum = Luminance(Color.xyz);
#ifdef TONEMAPPING_MODE_0
Color = float4(lerp(float3(lum,lum,lum), Color.xyz, _Saturation),1);
return 1-exp2(-_ExposureAdjustment * Color);
#endif
#ifdef TONEMAPPING_MODE_1
float avgLum = tex2Dlod(InputSampler, float4(IN.txcoord,0,4));
float cieLum = max(0.000001, lum); //ToCIE(Color.rgb);
float lumScaled = cieLum * gray / (0.001 + avgLum);
lumScaled = (lumScaled * (1.0f + lumScaled / (white*white)))/(1.0f +
lumScaled);
//cie.r = lumScaled;
Color.rgb = Color.rgb * (lumScaled / cieLum);
//color.rgb = FromCIE(cie);
return Color;
#endif
#ifdef TONEMAPPING_MODE_2
float A = 0.15;
float B = 0.50;
float C = 0.10;
float D = 0.20;
float E = 0.02;
float F = 0.30;
float W = 11.2;
Color *= _ExposureAdjustment;
float ExposureBias = 2.0;
float3 x = ExposureBias*Color;
float3 curr = ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
x = W;
float3 whiteScale = 1.0f/(((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F);
float3 clr = curr*whiteScale;
// float3 retColor = pow(clr,1/2.2); // we have SRGB write enabled at
this stage
return float4(clr, 1.0);
#endif
#ifdef TONEMAPPING_MODE_3
float lum = Luminance(Color.rgb);
float lumTm = lum * _ExposureAdjustment;
float scale = lumTm / (1+lumTm);
return float4(Color.rgb * scale / lum, Color.a);
#endif
#ifdef TONEMAPPING_MODE_4
Color *= _ExposureAdjustment;
float4 X = max(float4(0.0,0.0,0.0,0.0), Color-0.004);
float4 retColor = (X*(6.2*X+.5))/(X*(6.2*X+1.7)+0.06);
return retColor*retColor;
#endif
#ifdef TONEMAPPING_MODE_5
float4 tapA = tex2Dlod(InputSampler, float4(i.txcoord +
float2(1/screenRes.x,1/screenRes.y) * 0.5,0,10));
float4 tapB = tex2Dlod(InputSampler, float4(i.txcoord -
float2(1/screenRes.x,1/screenRes.y) * 0.5,0,10));
float4 tapC = tex2Dlod(InputSampler, float4(i.txcoord +
float2(1/screenRes.x,1/screenRes.y) * float2(0.5,-0.5),0,10));
float4 tapD = tex2Dlod(InputSampler, float4(i.txcoord -
float2(1/screenRes.x,1/screenRes.y) * float2(0.5,-0.5),0,10));
float4 average = (tapA+tapB+tapC+tapD)/4;
average.y = max(max(tapA.y,tapB.y), max(tapC.y,tapD.y));
float2 avgLum = average;
float cieLum = max(0.000001, lum); //ToCIE(color.rgb);
float lumScaled = cieLum * _HdrParams.z / (0.001 + avgLum.x);
lumScaled = (lumScaled * (1.0f + lumScaled /
(avgLum.y*avgLum.y)))/(1.0f + lumScaled);
//cie.r = lumScaled;
Color.rgb = Color.rgb * (lumScaled / cieLum);
//color.rgb = FromCIE(cie);
return Color;
#endif
#ifdef TONEMAPPING_MODE_OFF
return Color;
#endif
}
//---------------------------------------------------------------------------------
-----
// Compiler 1
//---------------------------------------------------------------------------------
-----
technique PostProcess
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 CCShadow();
}
}