////////////////////////////////////////////////////////////////////////// // // // ENBSeries effect file // // visit http://enbdev.com for updates // // Copyright (c) 2007-2013 Boris Vorontsov // // // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// // // // by kingeric1992, based on GDC 2004 presentation // // "Advanced Depth of Field" by Thorsten Scheuermann // // more info at // // http://enbseries.enbdev.com/forum/viewtopic.php?f=7&t=3224 // // update: Dec.13.2014 // // // ////////////////////////////////////////////////////////////////////////// // // // internal parameters, can be modified // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// // // // place "//" before "#define" to disable specific feature entirely, // // equivalent to setting effect intensity 0, but save some performance // // by skipping computation. // // // // example: // // //#define example // // // ////////////////////////////////////////////////////////////////////////// #define CHROMATIC_ABERRATION //Axial & Transverse chromatic aberration #define VIGNETTE //Optical vignette #define NOISE //Noise grain //#define SPEEDDIAL //control MF_FOCUSED, FocalLength, F_Number by temp variables without opening ENB console(To do) #define zF 750 // == fBlockMaximumDistance/100 in SkyrimPerfs.ini #define zN 0.15 // == fNearDistance/100 in Skyrim.ini, game default == 15(i.e., set 0.15 here.) float AFRange = 0.5; //AF sample range(px) float FilmWide = 0.0359; //D3X, 35mm film. float Fmin = 2.8; //maximum F-number to have circle shape. float Fmax = 4; //minimum F-number to have solid polygon shape. float CoClerp = 0.1; //near blur cap, usage: lerp(FarEndCoC, NearEndCoC, CoClerp). float fix = 10; //fix to adapt lens parameters to "smart blur". float fixfix = 4; //fix"fix"...curve control. bool AFsettings = {false}; bool MF_MODE = {false}; bool AF_CURSOR = {false}; float2 AF_POS = {0.5, 0.5}; //(0, 0) at top left corner. float MF_FOCUSED = {0.00}; float FocalLength = {35}; float F_Number = {5.6}; int ShutterLeaf = {6}; int LeafOffset = {0}; bool TSsettings = {false}; int TS_Axis = {0}; //Rotate tilt shift axis float TS_Angle = {0.00}; //0 == no tilt shift bool DoFsettings = {false}; int QUALITY = {4}; //DoF quality, 8 == max. float Highlight = {3}; // > 1 to increace highlight, < 1 to decreace. float BokehRatio = {1}; //Bokeh shape, 0.66 for anamorphic float BokehBias = {0.5}; //Brightness of center point float BokehBiasCurve = {0.5}; //Brightness curve from center to edge float GuassianColor = {1}; //Guassian Size. #ifdef VIGNETTE bool OVsettings = {false}; float VigBias = {0}; //0 == no vignette. float VigScale = {0}; //vignette radius, Maxumum == 1 focal length. #endif #ifdef CHROMATIC_ABERRATION bool CAsettings = {false}; float CA_axial = {0}; //Axial(longitudinal) & Transverse(lateral) CA float CA_trans = {0}; #endif #ifdef NOISE bool noisesettings = {false}; float NoiseAmount = {0.01}; float NoiseCurve = {0.95}; #endif ////////////////////////////////////////////////////////////////////// // 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 float4 ScreenSize; //x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY float4 Timer; //x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds) float FadeFactor; //adaptation delta time for focusing //textures texture2D texColor; texture2D texDepth; texture2D texNoise; texture2D texPalette; texture2D texFocus; //computed focusing depth texture2D texCurr; //4*4 texture for focusing texture2D texPrev; //4*4 texture for focusing sampler2D SamplerColor = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE;//NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; sampler2D SamplerDepth = sampler_state { Texture = ; MinFilter = POINT; MagFilter = POINT; MipFilter = NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; sampler2D SamplerNoise = sampler_state { Texture = ; MinFilter = POINT; MagFilter = POINT; MipFilter = NONE;//NONE; AddressU = Wrap; AddressV = Wrap; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; sampler2D SamplerPalette = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE;//NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; //for focus computation sampler2D SamplerCurr = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = LINEAR;//NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; //for focus computation sampler2D SamplerPrev = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; //for dof only in PostProcess techniques sampler2D SamplerFocus = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE; AddressU = Clamp; AddressV = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0; }; ////////////////////////////////////////////////////////////////////// // Functions ////////////////////////////////////////////////////////////////////// struct VS_OUTPUT_POST { float4 vpos : POSITION; float2 txcoord : TEXCOORD0; }; struct VS_INPUT_POST { float3 pos : POSITION; float2 txcoord : TEXCOORD0; }; struct VS_CONEBLUR_POST { float4 vpos : POSITION; float2 txcoord : TEXCOORD0; float2 maxCoC : TEXCOORD1; }; float2 LensDistortion( float2 tex, float s) { float r2 = (tex.x - 0.5) * (tex.x - 0.5) + (tex.y - 0.5) * (tex.y - 0.5); float f = s; float2 uv = tex + f * (tex - 0.5); return uv; } float linearizeDepth(float zB) { return zF * zN / (zF + zB * ( zN - zF)); } ////////////////////////////////////////////////////////////////////// // begin focusing code ////////////////////////////////////////////////////////////////////// VS_OUTPUT_POST VS_Focus(VS_INPUT_POST IN) { VS_OUTPUT_POST OUT; OUT.vpos = float4(IN.pos.xyz,1.0); OUT.txcoord = IN.txcoord; return OUT; } //SRCpass1X=ScreenWidth; //SRCpass1Y=ScreenHeight; //DESTpass2X=4; //DESTpass2Y=4; float4 PS_ReadFocus(VS_OUTPUT_POST IN) : COLOR { float2 pixelSize = ScreenSize.y; pixelSize.y *= ScreenSize.z; const float2 offset[4]= { float2(0.0, 1.0), float2(0.0, -1.0), float2(1.0, 0.0), float2(-1.0, 0.0) }; float res = linearizeDepth(tex2D(SamplerDepth, AF_POS).x); for (int i=0; i<4; i++) { res += linearizeDepth(tex2D(SamplerDepth, AF_POS + offset[i] * pixelSize * AFRange).x); } return res * 0.2; } //SRCpass1X=4; //SRCpass1Y=4; //DESTpass2X=4; //DESTpass2Y=4; float4 PS_WriteFocus(VS_OUTPUT_POST IN) : COLOR { float curr = ( MF_MODE == true)? MF_FOCUSED : tex2D(SamplerCurr, AF_POS).x; float prev = tex2D(SamplerPrev, AF_POS).x; float res = lerp(prev, curr, saturate(FadeFactor));//time elapsed factor return res; } ////////////////////////////////////////////////////////////////////// // Focus pass ////////////////////////////////////////////////////////////////////// technique ReadFocus { pass P0 { VertexShader = compile vs_3_0 VS_Focus(); PixelShader = compile ps_3_0 PS_ReadFocus(); ZEnable=FALSE; CullMode=NONE; ALPHATESTENABLE=FALSE; SEPARATEALPHABLENDENABLE=FALSE; AlphaBlendEnable=FALSE; FogEnable=FALSE; SRGBWRITEENABLE=FALSE; } } technique WriteFocus { pass P0 { VertexShader = compile vs_3_0 VS_Focus(); PixelShader = compile ps_3_0 PS_WriteFocus(); ZEnable=FALSE; CullMode=NONE; ALPHATESTENABLE=FALSE; SEPARATEALPHABLENDENABLE=FALSE; AlphaBlendEnable=FALSE; FogEnable=FALSE; SRGBWRITEENABLE=FALSE; } } ////////////////////////////////////////////////////////////////////// // end focusing, starting DoF ////////////////////////////////////////////////////////////////////// VS_CONEBLUR_POST VS_PostProcess(VS_INPUT_POST IN) { VS_CONEBLUR_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; float focallength = FocalLength / 1000; float CenterFocusDepth = tex2Dlod(SamplerFocus, 0.5).x; OUT.maxCoC = (focallength / F_Number) * (focallength / (CenterFocusDepth - focallength)) / FilmWide; OUT.maxCoC.x *= lerp((zF - CenterFocusDepth) / zF, (CenterFocusDepth - zN) / zN, CoClerp);//lerp(Far CoC, Near CoC, CoClerp) == BlurDisk OUT.maxCoC.y *= F_Number; return OUT; } //Calculate CoC & Tilt_Shift float4 PS_CoCtoAlpha(VS_CONEBLUR_POST IN, float2 vPos : VPOS) : COLOR { float2 coord = IN.txcoord; float BlurDisk = IN.maxCoC.x; float4 res = tex2D(SamplerColor, coord); float depth = linearizeDepth(tex2D(SamplerDepth, coord).x); float focallength = FocalLength / 1000; float TS_Dist = ((coord.x - 0.5) * tan(TS_Axis * 0.0174533) - ScreenSize.z * ( coord.y - 0.5)) * FilmWide; TS_Dist /= length(float2( tan(TS_Axis * 0.0174533), ScreenSize.z));//in m float CenterFocusDepth = tex2D(SamplerFocus, 0.5).x; float PrincipalDist = CenterFocusDepth * focallength / (CenterFocusDepth - focallength); PrincipalDist += tan( TS_Angle * 0.0174533) * TS_Dist; float FocusDepth = PrincipalDist * focallength / (PrincipalDist - focallength); res.w = (focallength / F_Number ) * ((FocusDepth - depth) / depth) * (PrincipalDist / FocusDepth); res.w /= FilmWide * BlurDisk;// in % to x 0~1 , convert to BlurDisk unit res.w = clamp(res.w + 1, 0, 2);//Clamp CoC between +- BlurDisk, in BlurDisk unit. [0. 2] return res; } //Dof pass float4 PS_DepthOfField(VS_CONEBLUR_POST IN, float2 vPos : VPOS) : COLOR { float2 coord = IN.txcoord.xy; float BlurDisk = IN.maxCoC.x; //is diameter float2 pixelSize = float2(1, ScreenSize.z); float4 CenterColor = tex2D(SamplerColor, coord.xy); //.a is CenterDepth, near is larger than far, float CenterCoC = abs(CenterColor.a - 1) * BlurDisk; //is diameter // float Highlight = CenterCoC * Highlight #ifdef VIGNETTE float vigradius = IN.maxCoC.y * VigScale; float2 vigcenter = LensDistortion(coord, lerp(0, vigradius, VigBias)/ 0.707) - coord;//in sample coord sys #endif float4 res; res.xyz = CenterColor.xyz * (1 - BokehBias); res.xyz = pow(res.xyz, (CenterCoC + 1) * Highlight); res.w = 1; float leafangle = 6.28318530 / ShutterLeaf; float shutterShape = smoothstep(Fmin, Fmax, F_Number); float sampleCycleCounter; float sampleCounterInCycle; float2 sampleOffset; int dofTaps = QUALITY * (QUALITY + 1) * 3; for(int i=0; i < 246 && i < dofTaps; i++) { if((sampleCounterInCycle % (sampleCycleCounter * 6)) == 0) { sampleCounterInCycle = 0; sampleCycleCounter++; } float sampleAngle = 1.04719755 * ( sampleCounterInCycle / sampleCycleCounter); sampleCounterInCycle++; sincos(sampleAngle, sampleOffset.y, sampleOffset.x); sampleOffset *= pixelSize * CenterCoC * sampleCycleCounter / QUALITY / 2; sampleOffset.x *= BokehRatio;//[0,1] float deltaAngle = (sampleAngle + leafangle * shutterShape + LeafOffset) % leafangle; deltaAngle -= leafangle / 2; sampleOffset *= lerp( 1, (cos(leafangle/2)/cos(deltaAngle)), shutterShape); float4 tap; float3 weight; #ifdef CHROMATIC_ABERRATION tap.ra = tex2Dlod(SamplerColor, float4(LensDistortion(coord + sampleOffset * ( 1 + CA_axial), CenterCoC * CA_trans), 0, 0)).ra; weight.r = (tap.a > CenterColor.a)? abs(tap.a - 1): 1.0; tap.ga = tex2Dlod(SamplerColor, float4(coord + sampleOffset, 0, 0)).ga; weight.g = (tap.a > CenterColor.a)? abs(tap.a - 1): 1.0; tap.ba = tex2Dlod(SamplerColor, float4(LensDistortion(coord + sampleOffset * ( 1 - CA_axial), CenterCoC * -CA_trans), 0, 0)).ba; weight.b = (tap.a > CenterColor.a)? abs(tap.a - 1): 1.0; #else tap = tex2Dlod(SamplerColor, float4(coord + sampleOffset, 0, 0)); weight.rgb = (tap.a > CenterColor.a)? abs(tap.a - 1): 1.0; #endif weight = saturate(pow(weight * fix, fixfix)); tap.rgb *= lerp(1.0, pow(sampleCycleCounter/QUALITY, BokehBiasCurve), BokehBias);//Brightness of each ring #ifdef VIGNETTE weight *= (length(sampleOffset - vigcenter) > vigradius)? 0 : 1; #endif res.rgb += pow(tap.rgb * weight.rgb, (CenterCoC + 1) * Highlight); res.a += pow(weight.g, (CenterCoC + 1) * Highlight); } res.rgb = pow( res.rgb / res.a, 1 / ((CenterCoC + 1) * Highlight)); res.a = CenterCoC; return res; } float4 PS_GuassianH(VS_OUTPUT_POST IN, float2 vPos : VPOS, uniform float BlurStrength) : COLOR { float2 coord = IN.txcoord.xy; float4 CenterColor = tex2D(SamplerColor, coord); float blurAmount = CenterColor.a / 20 / QUALITY; float weight[11] = {0.082607, 0.080977, 0.076276, 0.069041, 0.060049, 0.050187, 0.040306, 0.031105, 0.023066, 0.016436, 0.011254}; float4 res = CenterColor * weight[0]; for(int i=1; i < 11; i++) { res += tex2D(SamplerColor, coord + float2(i * blurAmount * BlurStrength * BokehRatio, 0)) * weight[i]; res += tex2D(SamplerColor, coord - float2(i * blurAmount * BlurStrength * BokehRatio, 0)) * weight[i]; } return res; } float4 PS_GuassianV(VS_OUTPUT_POST IN, float2 vPos : VPOS, uniform float BlurStrength) : COLOR { float2 coord = IN.txcoord.xy; float4 CenterColor = tex2D(SamplerColor, coord); float blurAmount = CenterColor.a / 20 / QUALITY; float weight[11] = {0.082607, 0.080977, 0.076276, 0.069041, 0.060049, 0.050187, 0.040306, 0.031105, 0.023066, 0.016436, 0.011254}; float4 res = CenterColor * weight[0]; for(int i=1; i < 11; i++) { res += tex2D(SamplerColor, coord + float2(0, i * ScreenSize.z * blurAmount * BlurStrength)) * weight[i]; res += tex2D(SamplerColor, coord - float2(0, i * ScreenSize.z * blurAmount * BlurStrength)) * weight[i]; } return res; } //Noise + AF cursor float4 PS_PostProcess(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR { float2 coord = IN.txcoord.xy; float4 res = tex2D(SamplerColor, coord); #ifdef NOISE float origgray = dot(res.xyz, 0.3333); origgray /= origgray + 1.0; float4 cnoi = tex2D(SamplerNoise, coord * 16.0 + origgray); float noiseAmount = NoiseAmount * pow(res.a, NoiseCurve); res *= lerp( 1, (cnoi.x+0.5), noiseAmount * saturate( 1.0 - origgray * 1.8)); #endif if(AF_CURSOR == true) { float2 pixelSize = ScreenSize.y; pixelSize.y *= ScreenSize.z; if( ( abs(coord.x - AF_POS.x) < 5 * pixelSize.x) && ( abs(coord.y - AF_POS.y) < 5 * pixelSize.y)) res.rgb = float3(2.0, 0, 0); } return res; } ////////////////////////////////////////////////////////////////////// // DoF Pass ////////////////////////////////////////////////////////////////////// technique PostProcess { pass P0 { VertexShader = compile vs_3_0 VS_PostProcess(); PixelShader = compile ps_3_0 PS_CoCtoAlpha(); 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_DepthOfField(); 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_GuassianH(GuassianColor); 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_GuassianV(GuassianColor); 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_PostProcess(); DitherEnable=FALSE; ZEnable=FALSE; CullMode=NONE; ALPHATESTENABLE=FALSE; SEPARATEALPHABLENDENABLE=FALSE; AlphaBlendEnable=FALSE; StencilEnable=FALSE; FogEnable=FALSE; SRGBWRITEENABLE=FALSE; } }