//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ENBSeries effect file | ENBSeries 0.101+ // http://enbdev.com // Author: Pascal Matthäus ( Euda ) //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //+++++++++++++++++++++++++++++ // USED EFFECTS //+++++++++++++++++++++++++++++ #define ENABLE_BLOOM 1 #define ENABLE_TONEMAP 1 #define ENABLE_UNSHARPMASK 1 #define ENABLE_FILMGRAIN 1 #define ENABLE_TECHNICOLOR 1 #define ENABLE_LENSDIRT 0 #define ENABLE_LETTERBOX 0 //+++++++++++++++++++++++++++++ // CUSTOM PARAMETERS //+++++++++++++++++++++++++++++ // ** BLOOM ** #define bloomPower 0.550 // Bloom Overall-Power - Too high values will overexpose the bloom, thus leading to a loss of detail in bright areas #define bloomRadius 64 // Bloom Sample Count - Amount of samples taken, directly affects performance #define bloomSkipPixels 1 // Bloom Skipped Samples - Adds banding & reduces precision, therefore much higher performance. Resulting radius is bloomSkipPixels*bloomRadius #define bloomLumaDamp 0.600 // Bloom LumaDamping - Scales bloomPower with original images's brightness to prevent local overexposing. #define bloomContrast 1.550 // Bloom Contrast - The effect's contrast - the higher, the more will bloom be damped in dark areas - and vice versa #define bloomSaturation 3.500 // Bloom Saturation - The effect's color saturation, applied after bloomContrast // ** TONEMAP ** #define tonemapMode 3 // Tonemap Mode - choose a tonemapping algorithm (1/2/3), I prefer the first one #define tonemapGammaCurve 0.800 // Tonemap gamma-curve - insert your monitors gamma-value, 2.2 for calibrated displays with accurate grey-levels #define tonemapAmount 50.000 // Tonemap amount - the amount of tonemapping to be applied to hdr-effects // ** UNSHARP MASK ** #define unsharpMaskA 1 // Unsharp Mask A - Small Radius, performs best for edge sharpening #define unsharpMaskB 1 // Unsharp Mask B - Radius = bloomRadius - performs best at local contrast enhancement, bloom has to be enabled! #define unsharpMaskAIntensity 0.350 // Unsharp Mask A Sharpening Intensity - the effects' intensity, be careful - I wouldn't push it futher than 0.500 #define unsharpMaskBIntensity 0.575 // Unsharp Mask B Sharpening Intensity - the effects' intensity, be careful - I wouldn't push it futher than 0.500 // ** FILMGRAIN ** #define grainAmount 0.015 // Grain Amount - Visibility of the filmgrain on your screen #define grainPower 1.000 // Grain Power - the noise's exposure #define grainFreq 0.550 // Grain Frequency - how fast the noise will change. Zero disables the frequency, thus just showing a grain-texture #define grainSize 0.450 // Grain Scale - the scale of the grain-texture. Too low values will let you see the tiled pattern of the noise. Too high one's are not realistic // ** TECHNICOLOR 3-STRIP ** #define techniAmount 0.200 // Technicolor Strength - This parameter controls how strong the Technicolor-effect is applied, too high is not realistic #define techniPower 1.200 // Technicolor Power - Technically the effect's saturation but good to combine with lower techniAmounts if you like to #define techniPunch 0.750 // Technicolor Punch - Normally the effect's only visible on high-chroma pixels - this value helps to punch bright&dark pixels to prevent that // ** LENSDIRT ** #define lensdirtIntensity 1.200 // Lensdirt Intensity - The dirt texture's maximum intensity #define lensdirtCurve 1.400 // Lensdirt Curve - The curve which the dirt texture's intensity scales with - try higher values to limit visibility solely to bright/almost-white scenes #define lensdirtSmoothmode 1 // Lensdirt Smooth-mode - If enabled, the bloom texture will be used for brightness check, thus scaling the intensity with the local luma instead of the current pixels' one (bloom has to be enabled!) // ** LETTERBOX ** #define letterboxSize 0.015 // Letterbox Size - The vertical range of the letterbox, 0.5 = black screen //+++++++++++++++++++++++++++++ //external parameters, do not modify //+++++++++++++++++++++++++++++ //keyboard controlled temporary variables (in some versions exists in the config file). 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 //x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds) #if (ENABLE_FILMGRAIN == 1) float4 Timer; #endif //x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY float4 ScreenSize; static const float2 pxSize = float2(ScreenSize.y,1/(ScreenSize.x * ScreenSize.w)); static const float3 lumaCoeff = float3(0.2126f,0.7152f,0.0722f); texture2D texColor; #if (ENABLE_FILMGRAIN == 1) texture2D texNoise; #endif #if (ENABLE_LENSDIRT == 1) texture2D texDirt < String ResourceName="ppfx/dirt.png"; >; #endif sampler2D SamplerColor = sampler_state { Texture = <texColor>; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; #if (ENABLE_BLOOM == 1) sampler2D SamplerSplitRGB = sampler_state { Texture = <texColor>; MinFilter = POINT; MagFilter = POINT; MipFilter = NONE; AddressU = Border; AddressV = Border; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; #endif #if (ENABLE_FILMGRAIN == 1) sampler2D SamplerNoise = sampler_state { Texture = <texNoise>; MinFilter = POINT; MagFilter = POINT; MipFilter = NONE; AddressU = Wrap; AddressV = Wrap; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; #endif #if (ENABLE_LENSDIRT == 1) sampler2D SamplerDirt = sampler_state { Texture = <texDirt>; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE; AddressU = Wrap; AddressV = Wrap; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; #endif struct VS_OUTPUT_POST { float4 vpos : POSITION; float2 txcoord : TEXCOORD0; }; struct VS_INPUT_POST { float3 pos : POSITION; float2 txcoord : TEXCOORD0; }; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Vertex-Shader //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Effects //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // *** Bloom *** #if (ENABLE_BLOOM == 1) // Bloom - SplitRGB Prepass half4 FX_BloomSplitRGB( half4 pxInput, half2 txCoords ) { pxInput.w = tex2D(SamplerSplitRGB, txCoords*2.0h).x; pxInput.w += tex2D(SamplerSplitRGB, txCoords*2.0h-half2(1.0h , 0.0h)).y; pxInput.w += tex2D(SamplerSplitRGB, txCoords*2.0h-half2(0.0h , 1.0h)).z; return pxInput; } // Bloom - Horizontal half FX_BloomH( half pxInput, half2 txCoords ) { half2 fetchCoords = txCoords; half weight = 1.0h; half weightDiv = 1.0h+5.0h/(half)bloomRadius; half sampleSum = 0.0h; bool cornerFix = (txCoords.x < 0.5h); [unroll (bloomRadius / 4)] for (half hOffs=1.0h; hOffs<(half)bloomRadius; hOffs+=2) { fetchCoords = txCoords; if (cornerFix == true) fetchCoords.x = clamp(fetchCoords.x + (half)bloomSkipPixels * hOffs * (half)pxSize.x + 0.5h * (half)pxSize.x, 0.0h, 0.499h); else fetchCoords.x = clamp(fetchCoords.x + (half)bloomSkipPixels * hOffs * (half)pxSize.x + 0.5h * (half)pxSize.x, 0.5h, 1.0h); pxInput+=tex2D(SamplerColor, fetchCoords.xy).w * weight; fetchCoords = txCoords; if (cornerFix == true) fetchCoords.x = clamp(fetchCoords.x - (half)bloomSkipPixels * hOffs * (half)pxSize.x + 0.5h * (half)pxSize.x, 0.0h, 0.499h); else fetchCoords.x = clamp(fetchCoords.x - (half)bloomSkipPixels * hOffs * (half)pxSize.x + 0.5h * (half)pxSize.x, 0.5h, 1.0h); pxInput+=tex2D(SamplerColor, fetchCoords.xy).w * weight; sampleSum += 2.0h * weight; weight /= weightDiv; } pxInput /= sampleSum; return pxInput; } // Bloom - Vertical half FX_BloomV( half pxInput, half2 txCoords ) { half2 fetchCoords = txCoords; half weight = 1.0h; half weightDiv = 1.0h+5.0h/(half)bloomRadius; half sampleSum = 0.0h; bool cornerFix = (txCoords.y < 0.5h); [unroll (bloomRadius / 4)] for (half vOffs=1.0h; vOffs<(half)bloomRadius; vOffs+=2) { fetchCoords = txCoords; if (cornerFix == true) fetchCoords.y = clamp(fetchCoords.y + (half)bloomSkipPixels * vOffs * (half)pxSize.y + 0.5h * (half)pxSize.y, 0.0h, 0.499h); else fetchCoords.y = clamp(fetchCoords.y + (half)bloomSkipPixels * vOffs * (half)pxSize.y + 0.5h * (half)pxSize.y, 0.5h, 1.0h); pxInput+=tex2D(SamplerColor, fetchCoords.xy).w * weight; fetchCoords = txCoords; if (cornerFix == true) fetchCoords.y = clamp(fetchCoords.y - (half)bloomSkipPixels * vOffs * (half)pxSize.y + 0.5h * (half)pxSize.y, 0.0h, 0.499h); else fetchCoords.y = clamp(fetchCoords.y - (half)bloomSkipPixels * vOffs * (half)pxSize.y + 0.5h * (half)pxSize.y, 0.5h, 1.0h); pxInput+=tex2D(SamplerColor, fetchCoords.xy).w * weight; sampleSum += 2.0h * weight; weight /= weightDiv; } pxInput /= sampleSum; return pxInput; } // Bloom - MergeRGB Final Pass half3 FX_BloomMergeRGB( half3 pxInput, half2 txCoords ) { half3 origcolor = pxInput; half origLuma = (half)bloomLumaDamp*dot(origcolor.xyz,(half)lumaCoeff.xyz); pxInput.x = tex2D(SamplerColor, txCoords / 2.0h).w; pxInput.y = tex2D(SamplerColor, txCoords / 2.0h + half2(0.5h, 0.0h)).w; pxInput.z = tex2D(SamplerColor, txCoords / 2.0h + half2(0.0h, 0.5h)).w; half3 blurTexture = pxInput; pxInput = pow(pxInput,(half)bloomContrast); pxInput = lerp(dot(pxInput.xyz,(half)lumaCoeff.xyz),pxInput,(half)bloomSaturation); pxInput /= clamp(max(pxInput.x,max(pxInput.y,pxInput.z)),1.0h,100.0h); #if (unsharpMaskB == 1) && (ENABLE_UNSHARPMASK == 1) half3 detailMask = origcolor - blurTexture; pxInput = origcolor+pxInput*(half)bloomPower*(1.0h-origLuma)+detailMask*(half)unsharpMaskBIntensity; #else pxInput = origcolor+pxInput*(half)bloomPower*(1.0h-origLuma); #endif #if (lensdirtSmoothmode == 1) && (ENABLE_LENSDIRT == 1) pxInput += (half)tex2D(SamplerDirt, txCoords).xyz*pow(dot(blurTexture,(half)lumaCoeff),(half)lensdirtCurve)*lensdirtIntensity; #endif return pxInput; } #endif // *** Custom Tonemapping *** #if (ENABLE_TONEMAP == 1) half3 FX_Tonemap( half3 pxInput ) { #if (tonemapMode == 1) half3 pxHDR = saturate(pxInput); pxInput.xyz /= (1.0h+(half)bloomPower); return lerp(pxHDR,lerp(pxHDR.xyz,pow(pxInput.xyz,1.0h/(half)tonemapGammaCurve),dot(pxHDR.xyz,(half)lumaCoeff.xyz)),(half)tonemapAmount); #endif #if (tonemapMode == 2) half3 pxHDR = pxInput.xyz; pxInput.xyz /= (1.0h+(half)bloomPower); return lerp(pxHDR.xyz,pow(lerp(pxInput.xyz,pow(pxInput.xyz,((half)bloomPower+1.0h)-pxHDR),dot(saturate(pxHDR),(half)lumaCoeff.xyz)),1.0h/(half)tonemapGammaCurve),(half)tonemapAmount); #endif #if (tonemapMode == 3) half maxLuma = 1.0h+(half)bloomPower; half exposureDiv = log10(maxLuma+1.0h)/log10(maxLuma*2.0h*(half)tonemapAmount); return lerp(pxInput,pow(log10(pxInput+1.0h)/log10(pxInput+maxLuma*(half)tonemapAmount)/exposureDiv,1.0h/(half)tonemapGammaCurve),saturate(pxInput)); #endif } #endif // *** Unsharp Mask *** #if (ENABLE_UNSHARPMASK == 1) && (unsharpMaskA == 1) half3 FX_UnsharpMask( half3 pxInput, half2 txCoords ) { half2 blurKernel[2] = { half2(-1.5h , 0.0h), half2( 0.5h , 1.5h) }; half3 blurTex = pxInput; [unroll (2)] for (half i = 0.0h; i<2.0h; i++) { blurTex += tex2D(SamplerColor,txCoords.xy+blurKernel[i]*pxSize.xy).xyz*(1.0h/(i+1.0h)); } blurTex /= 2.5h; return pxInput + (pxInput-blurTex) * (half)unsharpMaskAIntensity; } #endif // *** Technicolor *** #if (ENABLE_TECHNICOLOR == 1) half3 FX_Technicolor( half3 pxInput ) { half3 origcolor = pxInput; half redPower = pxInput.x * (max(pxInput.x,max(pxInput.y,pxInput.z))-min(pxInput.x,min(pxInput.y,pxInput.z))+techniPunch); half greenPower = pxInput.y * (max(pxInput.x,max(pxInput.y,pxInput.z))-min(pxInput.x,min(pxInput.y,pxInput.z))+techniPunch); half bluePower = pxInput.z * (max(pxInput.x,max(pxInput.y,pxInput.z))-min(pxInput.x,min(pxInput.y,pxInput.z))+techniPunch); pxInput.yz = lerp(pxInput.yz,pow(pxInput.yz,2.0h),redPower); pxInput.xz = lerp(pxInput.xz,pow(pxInput.xz,1.2h),greenPower); pxInput.xy = lerp(pxInput.xy,pow(pxInput.xy,1.75h),bluePower); pxInput.z *= 0.95h; half techniLuma = dot(pxInput.xyz,(half)lumaCoeff.xyz); return lerp(origcolor.xyz,lerp(techniLuma,pxInput.xyz,(half)techniPower),(half)techniAmount); } #endif // *** Filmgrain *** #if (ENABLE_FILMGRAIN == 1) half3 FX_Filmgrain( half3 pxInput, half2 txCoords ) { half noise1 = tex2D(SamplerNoise,txCoords.xy*(1-grainSize)*16+Timer.x).x; half3 noise2 = tex2D(SamplerNoise,txCoords.xy*(1-grainSize)*16+Timer.x*noise1.x*10000*grainFreq); return lerp(pxInput.xyz,noise2.xyz*(half)grainPower,(half)grainAmount); } #endif // *** Lensdirt *** #if (ENABLE_LENSDIRT == 1) && (lensdirtSmoothmode == 0) half3 FX_Lensdirt( half3 pxInput, half2 txCoords ) { return pxInput+(half)tex2D(SamplerDirt, txCoords).xyz*pow(dot(pxInput.xyz,(half)lumaCoeff),(half)lensdirtCurve)*(half)lensdirtIntensity; } #endif // *** Letterbox *** #if (ENABLE_LETTERBOX == 1) half FX_Letterbox( half vCoord ) { bool setBlack = (vCoord<=(half)letterboxSize) || (vCoord>=1-(half)letterboxSize); if (setBlack == true) return 0.0h; else return 1.0h; } #endif //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Pixel-Shader //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // *** Bloom-passes *** #if (ENABLE_BLOOM == 1) // Bloom - Prepass half4 PS_BloomSplitRGB(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR { return half4(FX_BloomSplitRGB(tex2D(SamplerSplitRGB, IN.txcoord.xy), IN.txcoord.xy)); } // Bloom - Horizontal half4 PS_BloomH(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR { half4 res; res.xyz = tex2D(SamplerColor, IN.txcoord.xy); res.w = FX_BloomH(0.0h, IN.txcoord.xy); return res; } // Bloom - Vertical half4 PS_BloomV(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR { half4 res; res.xyz = tex2D(SamplerColor, IN.txcoord.xy); res.w = FX_BloomV(0.0h, IN.txcoord.xy); return res; } #endif // *** More Effects *** half4 PS_ProcessFX(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR { half2 pxCoord = IN.txcoord.xy; half4 res; res.xyz = tex2D(SamplerColor,pxCoord.xy).xyz; res.w = 1.0h; #if (ENABLE_BLOOM == 1) res.xyz = FX_BloomMergeRGB(res.xyz, pxCoord.xy); #endif #if (ENABLE_TONEMAP == 1) res.xyz = FX_Tonemap(res.xyz); #endif #if (ENABLE_UNSHARPMASK == 1) && (unsharpMaskA == 1) res.xyz = FX_UnsharpMask(res.xyz, pxCoord.xy); #endif #if (ENABLE_TECHNICOLOR == 1) res.xyz = FX_Technicolor(res.xyz); #endif #if (ENABLE_FILMGRAIN == 1) res.xyz = FX_Filmgrain(res.xyz, pxCoord.xy); #endif #if (ENABLE_LENSDIRT == 1) && (lensdirtSmoothmode == 0) res.xyz = FX_Lensdirt(res.xyz, pxCoord.xy); #endif #if (ENABLE_LETTERBOX == 1) res.xyz *= FX_Letterbox(pxCoord.y); #endif return res; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Techniques //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ technique PostProcess { pass P0 { VertexShader = compile vs_3_0 VS_PostProcess(); #if (ENABLE_BLOOM == 1) PixelShader = compile ps_3_0 PS_BloomSplitRGB(); #else PixelShader = compile ps_3_0 PS_ProcessFX(); #endif DitherEnable=FALSE; ZEnable=FALSE; CullMode=NONE; ALPHATESTENABLE=FALSE; SEPARATEALPHABLENDENABLE=FALSE; AlphaBlendEnable=FALSE; StencilEnable=FALSE; FogEnable=FALSE; SRGBWRITEENABLE=FALSE; } } #if (ENABLE_BLOOM == 1) technique PostProcess2 { pass P0 { VertexShader = compile vs_3_0 VS_PostProcess(); PixelShader = compile ps_3_0 PS_BloomH(); 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_BloomV(); 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_ProcessFX(); DitherEnable=FALSE; ZEnable=FALSE; CullMode=NONE; ALPHATESTENABLE=FALSE; SEPARATEALPHABLENDENABLE=FALSE; AlphaBlendEnable=FALSE; StencilEnable=FALSE; FogEnable=FALSE; SRGBWRITEENABLE=FALSE; } } #endif