Code: Select all
/**
* SHADER ADDON
* Featuring: Gaussian blur passes for Photoshop: Soft Light and Screen blending techniques ( finest Contrast bloom )
* Effect is FPS heavy and subtle. Use as you see fit. Scaled for 1080 resolution. Higher resolutions and effect is minimal ( blur is pixel based ) and FPS hit bigger.
* LumaSharpen by CeeJay.dk & ZeroKing
* By prod80 - Serenity ENB
*/
/**
* ENBSeries
* visit http://enbdev.com for updates
* Copyright (c) 2007-2014 Boris Vorontsov
*/
//--------------------------//
// Internal parameters //
// Can be modified //
//--------------------------//
//////////////////
// DEFINES //
//////////////////
#define SharpMethod 4 //[1, 2, 3, 4] Comment out (add // in front) to disable sharpening pass and GUI for it
#define ECOLORSHIFT
///////////////
// CHOICES //
///////////////
bool C_BLACKLEVEL <
string UIName = "Enable Black Level";
> = {false};
////////////////////
// CONTRAST BLOOM //
////////////////////
float sl_mix_set <
string UIName="Soft Light Intensity";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=1.0;
float UIStep=0.001;
> = {0.275};
float gauss_bloom <
string UIName="Gaussian Bloom Intensity";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=1.0;
float UIStep=0.001;
> = {0.550};
bool lumabloom <
string UIName="Luma based Bloom";
> = {true};
float lumasource <
string UIName="Luma Src 1_orig 2_softlight 3_blend";
string UIWidget="Spinner";
float UIMin=1;
float UIMax=3;
float UIStep=1;
> = {2};
float gauss_blur <
string UIName="Gaussian Blur Strength";
string UIWidget="Spinner";
float UIMin=1;
float UIMax=3;
float UIStep=1;
> = {2};
////////////////////
// BLACK LEVELS //
////////////////////
float BlackPointExt <
string UIName="Black Level - Exterior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=255.0;
> = {16};
float BlackPointInt <
string UIName="Black Level - Interior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=255.0;
> = {16};
float WhitePointExt <
string UIName="White Level - Exterior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=255.0;
> = {235};
float WhitePointInt <
string UIName="White Level - Interior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=255.0;
> = {235};
////////////////////
// LUMASHARPEN //
////////////////////
#ifdef SharpMethod
bool Section_Luma <
string UIName="------Lumasharpen-----------";
> = {false};
float sharp_strengthExt <
string UIName="LumaSharpen Strength Exterior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=5.0;
float UIStep=0.001;
> = {0.315};
float sharp_strengthInt <
string UIName="LumaSharpen Strength Interior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=5.0;
float UIStep=0.001;
> = {0.315};
float sharp_clampExt <
string UIName="LumaSharpen Clamp Exterior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=1.0;
float UIStep=0.001;
> = {0.017};
float sharp_clampInt <
string UIName="LumaSharpen Clamp Interior";
string UIWidget="Spinner";
float UIMin=0.0;
float UIMax=1.0;
float UIStep=0.001;
> = {0.017};
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//--------------------------//
// External parameters //
// Do not modify //
//--------------------------//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Keyboard controlled temporary variables.
// Press and hold key 1,2,3...8 together with PageUp or PageDown to modify.
// By default all set to 1.0
float4 tempF1; //0,1,2,3
float4 tempF2; //5,6,7,8
float4 tempF3; //9,0
float4 Timer; //x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds)
float4 ScreenSize; //x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
float ENightDayFactor; //changes in range 0..1, 0 means that night time, 1 - day time
float EInteriorFactor; //changes 0 or 1. 0 means that exterior, 1 - interior
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////
// TEXTURES //
//////////////////
texture2D texOriginal;
texture2D texColor;
texture2D texNoise;
///////////////////
// SAMPLERS //
///////////////////
sampler2D SamplerColor = sampler_state
{
Texture = <texOriginal>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = NONE;
AddressU = Clamp;
AddressV = Clamp;
SRGBTexture=FALSE;
MaxMipLevel=0;
MipMapLodBias=0;
};
sampler2D SamplerColor2 = sampler_state
{
Texture = <texColor>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = NONE;
AddressU = Clamp;
AddressV = Clamp;
SRGBTexture=FALSE;
MaxMipLevel=0;
MipMapLodBias=0;
};
sampler2D SamplerNoise = sampler_state
{
Texture = <texNoise>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = NONE;
AddressU = Wrap;
AddressV = Wrap;
SRGBTexture=FALSE;
MaxMipLevel=0;
MipMapLodBias=0;
};
//////////////////
// STRUCTS //
//////////////////
struct VS_OUTPUT_POST
{
float4 vpos : POSITION;
float2 txcoord : TEXCOORD0;
};
struct VS_INPUT_POST
{
float3 pos : POSITION;
float2 txcoord : TEXCOORD0;
};
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;
}
//////////////////
// HELPER FUNCS //
//////////////////
//GAUSSIAN WEIGHTS - Linear sampled for high performance
//9 tap reduced to 3 weights ( 17 pixels wide )
static const float sampleOffsets_1[3] = { 0.0, 1.137453814668, 3.013581103919 };
static const float sampleWeights_1[3] = { 0.441440131387, 0.277468870531, 0.001811063775 };
//17 tap reduced to 5 weights ( 33 pixels wide )
static const float sampleOffsets_2[5] = { 0.0, 1.263686497497, 3.083471450524, 5.022636787155, 7.005855649638 };
static const float sampleWeights_2[5] = { 0.330086281980, 0.318351147970, 0.016540813281, 0.000064880504, 0.000000017255 };
//21 tap reduced to 6 weights ( 41 pixels wide )
static const float sampleOffsets_3[6] = { 0.0, 1.452313744966, 3.390210239952, 5.331472958797, 7.277552900121, 9.229394260785 };
static const float sampleWeights_3[6] = { 0.142479385858, 0.244115579374, 0.131636577371, 0.043283482080, 0.008668409765, 0.001056258481 };
float3 softlight(float3 a, float3 b, float s)
{
float3 ret;
float3 b_x2 = 2.0 * b;
float3 a_b_x2 = a * b_x2;
float3 c1 = a_b_x2 + a * a - a * a_b_x2;
float3 c2 = sqrt(a) * ( b_x2 - 1.0 ) + 2.0 * a - a_b_x2;
ret = ( b >= 0.5 ) ? c1 : c2;
return lerp( a, ret, s );
}
float3 screen(float3 a, float3 b)
{
return (1.0f - (1.0f - a) * (1.0f - b));
}
//////////////////
// SHADERS //
//////////////////
float4 PS_LevelsPass(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
float Levels_black_point = BlackPointExt;
float Levels_white_point = WhitePointExt;
if (EInteriorFactor)
{
Levels_black_point = BlackPointInt;
Levels_white_point = WhitePointInt;
};
#define black_point_float ( Levels_black_point / 255.0 )
#define white_point_float ( 255.0 / (Levels_white_point - Levels_black_point))
float4 res;
float3 origcolor = tex2D(SamplerColor, IN.txcoord.xy);
if (C_BLACKLEVEL==true)
{
res.rgb = origcolor.rgb * white_point_float - (black_point_float * white_point_float);
}
if (C_BLACKLEVEL==false)
{
res.rgb = origcolor.rgb;
}
res.w=1.0;
return res;
}
float4 PS_ProcessGaussianH(VS_OUTPUT_POST IN) : COLOR
{
float sHeight = ScreenSize.x * ScreenSize.w;
float2 fvTexelSize = float2(ScreenSize.y, 1.0 / sHeight);
float px = fvTexelSize.x;
float py = fvTexelSize.y;
float4 color = 0.0;
if ( gauss_blur==1 )
{
color = tex2D(SamplerColor2, IN.txcoord.xy) * sampleWeights_1[0];
for(int i = 1; i < 3; ++i) {
color += tex2D(SamplerColor2, IN.txcoord.xy + float2(sampleOffsets_1[i]*px, 0.0)) * sampleWeights_1[i];
color += tex2D(SamplerColor2, IN.txcoord.xy - float2(sampleOffsets_1[i]*px, 0.0)) * sampleWeights_1[i];
}
}
if ( gauss_blur==2 )
{
color = tex2D(SamplerColor2, IN.txcoord.xy) * sampleWeights_2[0];
for(int i = 1; i < 5; ++i) {
color += tex2D(SamplerColor2, IN.txcoord.xy + float2(sampleOffsets_2[i]*px, 0.0)) * sampleWeights_2[i];
color += tex2D(SamplerColor2, IN.txcoord.xy - float2(sampleOffsets_2[i]*px, 0.0)) * sampleWeights_2[i];
}
}
if ( gauss_blur==3 )
{
color = tex2D(SamplerColor2, IN.txcoord.xy) * sampleWeights_3[0];
for(int i = 1; i < 6; ++i) {
color += tex2D(SamplerColor2, IN.txcoord.xy + float2(sampleOffsets_3[i]*px, 0.0)) * sampleWeights_3[i];
color += tex2D(SamplerColor2, IN.txcoord.xy - float2(sampleOffsets_3[i]*px, 0.0)) * sampleWeights_3[i];
}
}
color.w = 1.0f;
return color;
}
float4 PS_ProcessGaussianV(VS_OUTPUT_POST IN) : COLOR
{
float sHeight = ScreenSize.x * ScreenSize.w;
float2 fvTexelSize = float2(ScreenSize.y, 1.0 / sHeight);
float px = fvTexelSize.x;
float py = fvTexelSize.y;
float4 color = 0.0;
if ( gauss_blur==1 )
{
color = tex2D(SamplerColor2, IN.txcoord.xy) * sampleWeights_1[0];
for(int i = 1; i < 3; ++i) {
color += tex2D(SamplerColor2, IN.txcoord.xy + float2(0.0, sampleOffsets_1[i]*py)) * sampleWeights_1[i];
color += tex2D(SamplerColor2, IN.txcoord.xy - float2(0.0, sampleOffsets_1[i]*py)) * sampleWeights_1[i];
}
}
if ( gauss_blur==2 )
{
color = tex2D(SamplerColor2, IN.txcoord.xy) * sampleWeights_2[0];
for(int i = 1; i < 5; ++i) {
color += tex2D(SamplerColor2, IN.txcoord.xy + float2(0.0, sampleOffsets_2[i]*py)) * sampleWeights_2[i];
color += tex2D(SamplerColor2, IN.txcoord.xy - float2(0.0, sampleOffsets_2[i]*py)) * sampleWeights_2[i];
}
}
if ( gauss_blur==3 )
{
color = tex2D(SamplerColor2, IN.txcoord.xy) * sampleWeights_3[0];
for(int i = 1; i < 6; ++i) {
color += tex2D(SamplerColor2, IN.txcoord.xy + float2(0.0, sampleOffsets_3[i]*py)) * sampleWeights_3[i];
color += tex2D(SamplerColor2, IN.txcoord.xy - float2(0.0, sampleOffsets_3[i]*py)) * sampleWeights_3[i];
}
}
color.w = 1.0f;
return color;
}
float4 PS_ProcessSoftLight(VS_OUTPUT_POST IN) : COLOR
{
float4 color = 0.0;
float4 baseC = tex2D(SamplerColor, IN.txcoord.xy);
float4 blendC = tex2D(SamplerColor2, IN.txcoord.xy);
float3 base = baseC.xyz;
float3 blend = blendC.xyz;
color.xyz = softlight( base, blend, sl_mix_set );
color.w = 1.0f;
return color;
}
float4 PS_ProcessGaussBloom(VS_OUTPUT_POST IN) : COLOR
{
float4 scrcolor = 0.0;
float4 color = 0.0;
float3 luma = float3(0.2125, 0.7154, 0.0721);
float pixluma = 0.0;
float4 baseC = tex2D(SamplerColor, IN.txcoord.xy);
float4 blendC = tex2D(SamplerColor2, IN.txcoord.xy);
float3 base = baseC.xyz;
float3 blend = blendC.xyz;
scrcolor.xyz = screen( base, blend );
//Bloom on luma
if (lumabloom==true)
{
if (lumasource==1) pixluma = dot( base, luma );
if (lumasource==2) pixluma = dot( blend, luma );
if (lumasource==3) pixluma = dot( scrcolor, luma );
color.xyz = lerp( base.xyz, scrcolor.xyz, gauss_bloom * pixluma );
};
if (lumabloom==false)
{
color.xyz = lerp( base.xyz, scrcolor.xyz, gauss_bloom );
};
color.w = 1.0f;
return color;
}
#ifdef SharpMethod
float4 PS_ProcessLumaSharpen(VS_OUTPUT_POST IN, float2 vPos : VPOS, float2 tex : TEXCOORD0) : COLOR
{
float2 coord = IN.txcoord.xy;
float sHeight = ScreenSize.x * ScreenSize.w;
float2 fvTexelSize = float2(ScreenSize.y, 1.0 / sHeight);
float px = fvTexelSize.x;
float py = fvTexelSize.y;
// Bias value
float offset_bias = 1.0;
float sharp_strength = sharp_strengthExt;
float sharp_clamp = sharp_clampExt;
if (EInteriorFactor)
{
sharp_strength = sharp_strengthInt;
sharp_clamp = sharp_clampInt;
};
#define sharp_strength_luma (CoefLuma * sharp_strength)
#define CoefLuma float4(0.2126, 0.7152, 0.0722, 0)
half4 ori = tex2D(SamplerColor2, coord.xy);
[branch] if (any(frac(ori.rgb)))
{
#if SharpMethod == 1
// -- Gaussian filter --
// [ 2/9, 4/9, ] [ 1 , 2 , ]
// [ 4/9, 8/9, 4/9] = [ 2 , 4 , 2 ]
// [ , 2/9, 2/9] [ , 2 , 1 ]
half4 blur_ori = tex2Dlod(SamplerColor2, float4(tex,tex) + float4(-px,py,-px,py) / 3 * offset_bias); // North West
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(px,-py,px,-py) / 3 * offset_bias); // South East
//Divide by the number of texture fetches
blur_ori /= 2;
#endif
// -- Pattern 2 -- A 9 tap gaussian using 4+1 texture fetches.
#if SharpMethod == 2
// -- Gaussian filter --
// [ .25, .50, .25] [ 1 , 2 , 1 ]
// [ .50, 1, .50] = [ 2 , 4 , 2 ]
// [ .25, .50, .25] [ 1 , 2 , 1 ]
half4 blur_ori = tex2Dlod(SamplerColor2, float4(tex,tex) + float4(-px,py,-px,py) * 0.5 * offset_bias); // North West
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(px,-py,px,-py) * 0.5 * offset_bias); // South East
if (any((blur_ori.rgb / 2) - ori.rgb))
{
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(-px,-py,-px,-py) * 0.5 * offset_bias); // South West
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(px,py,px,py) * 0.5 * offset_bias); // North East
//Divide by the number of texture fetches
blur_ori *= 0.25;;
}
//Divide by the number of texture fetches
blur_ori *= 0.25;;
#endif
// -- Pattern 3 -- An experimental 17 tap gaussian using 4+1 texture fetches.
#if SharpMethod == 3
// -- Gaussian filter --
// [ , 4 , 6 , , ]
// [ ,16 ,24 ,16 , 4 ]
// [ 6 ,24 ,50 ,24 , 6 ]
// [ 4 ,16 ,24 ,16 , ]
// [ , , 6 , 4 , ]
half4 blur_ori = tex2Dlod(SamplerColor2, float4(tex,tex) + float4(-0.4*px,1.2*py,-0.4*px,1.2*py) * offset_bias); // North North West
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(0.4*px,-1.2*py,0.4*px,-1.2*py) * offset_bias); // South South East
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(1.2*px,0.4*py,0,0) * offset_bias); // East North East
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(-1.2*px,-0.4*py,0,0) * offset_bias); // West South West
blur_ori += ori; // Probably not needed. Only serves to lessen the effect.
blur_ori /= 5; //Divide by the number of texture fetches
#endif
// -- Pattern 4 -- A 9 tap high pass using 4+1 texture fetches.
#if SharpMethod == 4
// -- Gaussian filter --
// [ .50, .50, .50] [ 1 , 1 , 1 ]
// [ .50, , .50] = [ 1 , , 1 ]
// [ .50, .50, .50] [ 1 , 1 , 1 ]
half4 blur_ori = tex2Dlod(SamplerColor2, float4(tex,tex) + float4(0.5 * -px,py,0.5 * -px,py) * offset_bias); // North North West
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(0.5 * px,-py,0.5 * px,-py)); // South South East
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(-px,0.5 * -py,-px,0.5 * -py)); // West South West
blur_ori += tex2Dlod(SamplerColor2, float4(tex,tex) + float4(px,0.5 * py,px,0.5 * py) * offset_bias); // East North East
blur_ori += (2 * ori); // Probably not needed. Only serves to lessen the effect.
blur_ori /= 6; //Divide by the number of texture fetches
#endif
// -- Calculate the sharpening --
half sharp = ori - blur_ori;
// -- Adjust strength of the sharpening --
sharp = dot(sharp, sharp_strength_luma);
// -- Clamping the maximum amount of sharpening to prevent halo artifacts --
sharp = clamp(sharp, -sharp_clamp, sharp_clamp);
// -- Combining the values to get the final sharpened pixel --
half4 done = ori + sharp;
return done;
}
else
{
return ori;
}
}
#endif
///////////////////////
// TECHNIQUES //
///////////////////////
technique PostProcess
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessGaussianH();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
technique PostProcess2
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessGaussianV();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
technique PostProcess3
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessSoftLight();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
technique PostProcess4
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessGaussianH();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
technique PostProcess5
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessGaussianV();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
technique PostProcess6
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessGaussBloom();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
#ifdef SharpMethod
technique PostProcess7
{
pass P0
{
VertexShader = compile vs_3_0 VS_PostProcess();
PixelShader = compile ps_3_0 PS_ProcessLumaSharpen();
DitherEnable=FALSE;
ZEnable=FALSE;
CullMode=NONE;
ALPHATESTENABLE=FALSE;
SEPARATEALPHABLENDENABLE=FALSE;
AlphaBlendEnable=FALSE;
StencilEnable=FALSE;
FogEnable=FALSE;
SRGBWRITEENABLE=FALSE;
}
}
#endif