/*============================================================================= ReShade 4 effect file github.com/martymcmodding Support me: paypal.me/mcflypg patreon.com/mcflypg Advanced Depth of Field "ADoF" by Marty McFly / P.Gilcher part of qUINT shader library for ReShade 4 Copyright (c) Pascal Gilcher / Marty McFly. All rights reserved. =============================================================================*/ /* TODO: extend tiles to contain min abs depth for better high precision sampling */ /*============================================================================= Preprocessor settings =============================================================================*/ //------------------------------------------------------------------ //Enables partial occlusion of bokeh disc at screen corners #ifndef ADOF_OPTICAL_VIGNETTE_ENABLE #define ADOF_OPTICAL_VIGNETTE_ENABLE 0 //[0 or 1] #endif //------------------------------------------------------------------ //Enables chromatic aberration at bokeh shape borders. #ifndef ADOF_CHROMATIC_ABERRATION_ENABLE #define ADOF_CHROMATIC_ABERRATION_ENABLE 1 //[0 or 1] #endif /*============================================================================= UI Uniforms =============================================================================*/ uniform bool bADOF_AutofocusEnable < ui_type = "bool"; ui_label = "Enable Autofocus"; ui_tooltip = "Enables automated focus calculation."; ui_category = "Focusing"; > = true; uniform float2 fADOF_AutofocusCenter < ui_type = "drag"; ui_min = 0.0; ui_max = 1.0; ui_label = "Autofocus Center"; ui_tooltip = "X and Y coordinates of autofocus center. Axes start from upper left screen corner."; ui_category = "Focusing"; > = float2(0.5, 0.5); uniform float fADOF_AutofocusRadius < ui_type = "drag"; ui_min = 0.0; ui_max = 1.0; ui_label = "Autofocus sample radius"; ui_tooltip = "Radius of area contributing to focus calculation."; ui_category = "Focusing"; > = 0.6; uniform float fADOF_AutofocusSpeed < ui_type = "drag"; ui_min = 0.05; ui_max = 1.0; ui_label = "Autofocus Adjustment Speed"; ui_tooltip = "Adjustment speed of autofocus on focus change"; ui_category = "Focusing"; > = 0.1; uniform float fADOF_ManualfocusDepth < ui_type = "drag"; ui_min = 0.0; ui_max = 1.0; ui_label = "Manual focus depth"; ui_tooltip = "Manually adjusted static focus depth, disable autofocus to use it."; ui_category = "Focusing"; > = 0.001; uniform float fADOF_NearBlurCurve < ui_type = "drag"; ui_min = 0.5; ui_max = 6.0; ui_label = "Near blur curve"; ui_category = "Focusing"; > = 6.0; uniform float fADOF_FarBlurCurve < ui_type = "drag"; ui_min = 0.5; ui_max = 6.0; ui_label = "Far blur curve"; ui_category = "Focusing"; > = 1.5; uniform float fADOF_HyperFocus < ui_type = "drag"; ui_min = 0.0; ui_max = 1.0; ui_label = "Hyperfocal depth distance"; ui_category = "Focusing"; > = 0.10; uniform float fADOF_RenderResolutionMult < ui_type = "drag"; ui_min = 0.5; ui_max = 1.0; ui_label = "Size Scale"; ui_tooltip = "Resolution Scale of bokeh blur. 0.5 means 1/2 screen width and height."; ui_category = "Blur & Quality"; > = 0.5; uniform float fADOF_ShapeRadius < ui_type = "drag"; ui_min = 0.0; ui_max = 100.0; ui_label = "Bokeh Maximal Blur Size"; ui_tooltip = "Blur size of areas entirely out of focus."; ui_category = "Blur & Quality"; > = 20.5; uniform float fADOF_SmootheningAmount < ui_type = "drag"; ui_min = 0.0; ui_max = 20.0; ui_label = "Gaussian blur width"; ui_tooltip = "Width of gaussian blur after bokeh filter."; ui_category = "Blur & Quality"; > = 4.0; uniform float fADOF_BokehIntensity < ui_type = "drag"; ui_min = 0.0; ui_max = 1.0; ui_label = "Bokeh Intensity"; ui_tooltip = "Intensity of bokeh discs."; ui_category = "Bokeh"; > = 0.3; uniform int iADOF_BokehMode < ui_type = "slider"; ui_min = 0; ui_max = 3; ui_label = "Bokeh highlight type"; ui_tooltip = "Different methods to emphasize bokeh sprites"; ui_category = "Bokeh"; > = 2; uniform int iADOF_ShapeVertices < ui_type = "drag"; ui_min = 3; ui_max = 9; ui_label = "Bokeh shape vertices"; ui_tooltip = "Vertices of bokeh kernel. 5 = pentagon, 6 = hexagon etc."; ui_category = "Bokeh"; > = 6; uniform int iADOF_ShapeQuality < ui_type = "drag"; ui_min = 2; ui_max = 25; ui_label = "Bokeh shape quality"; ui_category = "Bokeh"; > = 5; uniform float fADOF_ShapeCurvatureAmount < ui_type = "drag"; ui_min = -1.0; ui_max = 1.0; ui_label = "Bokeh shape roundness"; ui_tooltip = "Roundness of bokeh kernel. 1.0 = circle, 0.0 = polygon."; ui_category = "Bokeh"; > = 1.0; uniform float fADOF_ShapeRotation < ui_type = "drag"; ui_min = 0.0; ui_max = 360.0; ui_label = "Bokeh shape rotation"; ui_category = "Bokeh"; > = 0.0; uniform float fADOF_ShapeAnamorphRatio < ui_type = "drag"; ui_min = 0.0; ui_max = 1.0; ui_label = "Bokeh shape aspect ratio"; ui_category = "Bokeh"; > = 1.0; #if(ADOF_OPTICAL_VIGNETTE_ENABLE != 0) uniform float fADOF_ShapeVignetteCurve < ui_type = "drag"; ui_min = 0.5; ui_max = 2.5; ui_label = "Bokeh shape vignette curve"; ui_category = "Bokeh"; > = 0.75; uniform float fADOF_ShapeVignetteAmount < ui_type = "drag"; ui_min = 0.0; ui_max = 2.0; ui_label = "Bokeh shape vignette amount"; ui_category = "Bokeh"; > = 1.0; #endif #if(ADOF_CHROMATIC_ABERRATION_ENABLE != 0) uniform float fADOF_ShapeChromaAmount < ui_type = "drag"; ui_min = -1.0; ui_max = 1.0; ui_label = "Shape chromatic aberration amount"; ui_category = "Chromatic Aberration"; > = -0.1; uniform int iADOF_ShapeChromaMode < ui_type = "drag"; ui_min = 0; ui_max = 2; ui_label = "Shape chromatic aberration type"; ui_category = "Chromatic Aberration"; > = 2; #endif /*============================================================================= Textures, Samplers, Globals =============================================================================*/ #define RESHADE_QUINT_COMMON_VERSION_REQUIRE 202 #define RESHADE_QUINT_EFFECT_DEPTH_REQUIRE //effect requires depth access #include "qUINT_common.fxh" #define DISCRADIUS_RESOLUTION_BOUNDARY_LOWER 0.25//1.0 //used for blending blurred scene. #define DISCRADIUS_RESOLUTION_BOUNDARY_UPPER 2.0//6.0 //used for blending blurred scene. #define DISCRADIUS_RESOLUTION_BOUNDARY_CURVE 0.5 //used for blending blurred scene. #define FPS_HAND_BLUR_CUTOFF_DIST 0.3353 //fps hand depth (x10.000), change if you perceive blurred fps weapons. #define FPS_HAND_BLUR_CUTOFF_CHECK 0 //blur = max if depth > hand depth, else 0, useful for tweaking above param #define GAUSSIAN_BUILDUP_MULT 4.0 //value of x -> gaussian reaches max radius at |CoC| == 1/x texture2D ADOF_FocusTex { Format = R16F; }; texture2D ADOF_FocusTexPrev { Format = R16F; }; sampler2D sADOF_FocusTex { Texture = ADOF_FocusTex; }; sampler2D sADOF_FocusTexPrev { Texture = ADOF_FocusTexPrev; }; texture2D CommonTex0 { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA8; }; sampler2D sCommonTex0 { Texture = CommonTex0; }; texture2D CommonTex1 { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA8; }; sampler2D sCommonTex1 { Texture = CommonTex1; }; /*============================================================================= Vertex Shader =============================================================================*/ struct ADOF_VSOUT { float4 vpos : SV_Position; float4 txcoord : TEXCOORD0; float4 offset0 : TEXCOORD1; float2x2 offsmat : TEXCOORD2; }; ADOF_VSOUT VS_ADOF(in uint id : SV_VertexID) { ADOF_VSOUT OUT; OUT.txcoord.x = (id == 2) ? 2.0 : 0.0; OUT.txcoord.y = (id == 1) ? 2.0 : 0.0; OUT.txcoord.zw = OUT.txcoord.xy / fADOF_RenderResolutionMult; OUT.vpos = float4(OUT.txcoord.xy * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); //can't precompute vertices directly, not enough registers in sm3 sincos(6.2831853 / iADOF_ShapeVertices, OUT.offsmat._21, OUT.offsmat._22); OUT.offsmat._11 = OUT.offsmat._22; OUT.offsmat._12 = -OUT.offsmat._21; sincos(radians(fADOF_ShapeRotation), OUT.offset0.x, OUT.offset0.y); OUT.offset0.zw = mul(OUT.offset0.xy, OUT.offsmat); return OUT; } /*============================================================================= Functions =============================================================================*/ float GetLinearDepth(float2 coords) { return qUINT::linear_depth(coords); } float CircleOfConfusion(float2 texcoord, bool aggressiveLeakReduction) { float2 depthdata; //x - linear scene depth, y - linear scene focus float scenecoc; //blur value, signed by position relative to focus plane depthdata.x = GetLinearDepth(texcoord.xy); [branch] if(aggressiveLeakReduction) { float3 neighbourOffsets = float3(qUINT::PIXEL_SIZE.xy, 0); //sadly, flipped depth buffers etc don't allow for gather or linearizing in batch float4 neighbourDepths = float4(GetLinearDepth(texcoord.xy - neighbourOffsets.xz), //left GetLinearDepth(texcoord.xy + neighbourOffsets.xz), //right GetLinearDepth(texcoord.xy - neighbourOffsets.zy), //top GetLinearDepth(texcoord.xy + neighbourOffsets.zy));//bottom float neighbourMin = min(min(neighbourDepths.x,neighbourDepths.y),min(neighbourDepths.z,neighbourDepths.w)); depthdata.x = lerp(min(neighbourMin, depthdata.x), depthdata.x, 0.001); } depthdata.y = tex2D(sADOF_FocusTex, texcoord.xy).x; float handdepth = depthdata.x; depthdata.xy = saturate(depthdata.xy / fADOF_HyperFocus); [branch] if(depthdata.x < depthdata.y) { scenecoc = depthdata.x / depthdata.y - 1.0; scenecoc *= exp2(-0.5*fADOF_NearBlurCurve*fADOF_NearBlurCurve); } else { scenecoc = (depthdata.x - depthdata.y)/((depthdata.y * exp2(fADOF_FarBlurCurve*fADOF_FarBlurCurve)) - depthdata.y); scenecoc = saturate(scenecoc); } #if(FPS_HAND_BLUR_CUTOFF_CHECK != 0) scenecoc = (handdepth < FPS_HAND_BLUR_CUTOFF_DIST * 1e-4) ? 0.0 : 1.0; #else //FPS_HAND_BLUR_CUTOFF_CHECK scenecoc = (handdepth < FPS_HAND_BLUR_CUTOFF_DIST * 1e-4) ? 0.0 : scenecoc; #endif //FPS_HAND_BLUR_CUTOFF_CHECK return scenecoc; } void ShapeRoundness(inout float2 sampleOffset, in float roundness) { sampleOffset *= (1.0-roundness) + rsqrt(dot(sampleOffset,sampleOffset))*roundness; } void OpticalVignette(in float2 sampleOffset, in float2 centerVec, inout float sampleWeight) { sampleOffset -= centerVec; //scaled by vignette intensity sampleWeight *= saturate(3.333 - dot(sampleOffset,sampleOffset) * 1.666); //notsosmoothstep to avoid aliasing } float2 CoC2BlurRadius(float CoC) { return float2(fADOF_ShapeAnamorphRatio, qUINT::ASPECT_RATIO.y) * CoC * fADOF_ShapeRadius * 6e-4; } /*============================================================================= Pixel Shaders =============================================================================*/ void PS_CopyBackBuffer(in ADOF_VSOUT IN, out float4 color : SV_Target0) { color = tex2D(qUINT::sBackBufferTex, IN.txcoord.xy); } void PS_ReadFocus(in ADOF_VSOUT IN, out float focus : SV_Target0) { float scenefocus = 0.0; [branch] if(bADOF_AutofocusEnable == true) { float samples = 10.0; float weightsum = 1e-6; for(float xcoord = 0.0; xcoord < samples; xcoord++) for(float ycoord = 0.0; ycoord < samples; ycoord++) { float2 sampleOffset = (float2(xcoord,ycoord) + 0.5) / samples; sampleOffset = sampleOffset * 2.0 - 1.0; sampleOffset *= fADOF_AutofocusRadius; sampleOffset += (fADOF_AutofocusCenter - 0.5); float sampleWeight = saturate(1.2 * exp2(-dot(sampleOffset,sampleOffset)*4.0)); float tempfocus = GetLinearDepth(sampleOffset * 0.5 + 0.5); sampleWeight *= rcp(tempfocus + 0.001); sampleWeight *= saturate(tempfocus > FPS_HAND_BLUR_CUTOFF_DIST * 1e-4); //remove fps hands from focus calculations scenefocus += tempfocus * sampleWeight; weightsum += sampleWeight; } scenefocus /= weightsum; } else { scenefocus = fADOF_ManualfocusDepth * fADOF_ManualfocusDepth; } float prevscenefocus = tex2D(sADOF_FocusTexPrev, 0.5).x; float adjustmentspeed = fADOF_AutofocusSpeed * fADOF_AutofocusSpeed; adjustmentspeed *= prevscenefocus > scenefocus ? 2.0 : 1.0; focus = lerp(prevscenefocus, scenefocus, saturate(adjustmentspeed)); } void PS_CopyFocus(in ADOF_VSOUT IN, out float focus : SV_Target0) { focus = tex2D(sADOF_FocusTex, IN.txcoord.xy).x; } void PS_CoC(in ADOF_VSOUT IN, out float4 color : SV_Target0) { color = tex2D(qUINT::sBackBufferTex, IN.txcoord.xy); static const float2 sampleOffsets[4] = { float2( 1.5, 0.5) * qUINT::PIXEL_SIZE.xy, float2( 0.5,-1.5) * qUINT::PIXEL_SIZE.xy, float2(-1.5,-0.5) * qUINT::PIXEL_SIZE.xy, float2(-0.5, 1.5) * qUINT::PIXEL_SIZE.xy}; float centerDepth = GetLinearDepth(IN.txcoord.xy); float4 sampleCoord = 0.0; float3 neighbourOffsets = float3(qUINT::PIXEL_SIZE.xy, 0); float4 coccolor = 0.0; [loop] for(int i=0; i<4; i++) { sampleCoord.xy = IN.txcoord.xy + sampleOffsets[i]; float3 sampleColor = tex2Dlod(qUINT::sBackBufferTex, sampleCoord).rgb; float4 sampleDepths = float4(GetLinearDepth(sampleCoord.xy + neighbourOffsets.xz), //right GetLinearDepth(sampleCoord.xy - neighbourOffsets.xz), //left GetLinearDepth(sampleCoord.xy + neighbourOffsets.zy), //bottom GetLinearDepth(sampleCoord.xy - neighbourOffsets.zy)); //top float sampleDepthMin = min(min(sampleDepths.x,sampleDepths.y),min(sampleDepths.z,sampleDepths.w)); sampleColor /= 1.0 + max(max(sampleColor.r, sampleColor.g), sampleColor.b); float sampleWeight = saturate(sampleDepthMin * rcp(centerDepth) + 1e-3); coccolor += float4(sampleColor.rgb * sampleWeight, sampleWeight); } coccolor.rgb /= coccolor.a; coccolor.rgb /= 1.0 - max(coccolor.r, max(coccolor.g, coccolor.b)); color.rgb = lerp(color.rgb, coccolor.rgb, saturate(coccolor.w * 8.0)); color.w = CircleOfConfusion(IN.txcoord.xy, 1); color.w = saturate(color.w * 0.5 + 0.5); } void unpack_hdr(inout float3 color) { color = color * rcp(1.2 - saturate(color)); } void pack_hdr(inout float3 color) { color = 1.2 * color * rcp(color + 1.0); } float4 PS_DoF_Main(in ADOF_VSOUT IN) : SV_Target0 { if(max(IN.txcoord.z,IN.txcoord.w) > 1.01) discard; float4 BokehSum, BokehMax; BokehMax = tex2D(sCommonTex0, IN.txcoord.zw); BokehSum = BokehMax; float weightSum = 1.0; float CoC = abs(BokehSum.w * 2.0 - 1.0); float2 bokehRadiusScaled = CoC2BlurRadius(CoC); float nRings = lerp(1.0,iADOF_ShapeQuality,saturate(CoC)) + (dot(IN.vpos.xy,1) % 2) * 0.5; if(bokehRadiusScaled.x < DISCRADIUS_RESOLUTION_BOUNDARY_LOWER * qUINT::PIXEL_SIZE.x) return BokehSum; bokehRadiusScaled /= nRings; CoC /= nRings; #if (ADOF_OPTICAL_VIGNETTE_ENABLE != 0) float2 centerVec = IN.txcoord.zw - 0.5; float centerDist = sqrt(dot(centerVec,centerVec)); float vignette = pow(centerDist, fADOF_ShapeVignetteCurve) * fADOF_ShapeVignetteAmount; centerVec = centerVec / centerDist * vignette; weightSum *= saturate(3.33 - vignette * 2.0); BokehSum *= weightSum; BokehMax *= weightSum; #endif int densityScale = max(1, 6 - iADOF_ShapeVertices); [loop] for (int iVertices = 0; iVertices < iADOF_ShapeVertices && iVertices < 10; iVertices++) { [loop] for(float iRings = 1; iRings <= nRings && iRings < 26; iRings++) { [loop] for(float iSamplesPerRing = 0; iSamplesPerRing < iRings * densityScale && iSamplesPerRing < 26*2; iSamplesPerRing++) { float x = iSamplesPerRing/(iRings * densityScale); float a = x * x * (3.0 - 2.0 * x); float l = 2.55 * rcp(iADOF_ShapeVertices * iADOF_ShapeVertices * 0.4 - 1.0); x = lerp(x, (1.0 + l) * x - a * l, fADOF_ShapeCurvatureAmount); float2 sampleOffset = lerp(IN.offset0.xy,IN.offset0.zw, x); ShapeRoundness(sampleOffset,fADOF_ShapeCurvatureAmount); float4 sampleBokeh = tex2Dlod(sCommonTex0, float4(IN.txcoord.zw + sampleOffset.xy * (bokehRadiusScaled * iRings),0,0)); float sampleWeight = saturate(1e6 * (abs(sampleBokeh.a * 2.0 - 1.0) - CoC * (float)iRings) + 1.0); #if (ADOF_OPTICAL_VIGNETTE_ENABLE != 0) OpticalVignette(sampleOffset.xy * iRings/nRings, centerVec, sampleWeight); #endif sampleBokeh.rgb *= sampleWeight; weightSum += sampleWeight; BokehSum += sampleBokeh; BokehMax = max(BokehMax,sampleBokeh); } } IN.offset0.xy = IN.offset0.zw; IN.offset0.zw = mul(IN.offset0.zw, IN.offsmat); } // return lerp(BokehSum / weightSum, BokehMax, fADOF_BokehIntensity * saturate(CoC*nRings*2.0)); float4 ret = 0; BokehSum /= weightSum; unpack_hdr(BokehSum.rgb); unpack_hdr(BokehMax.rgb); if(iADOF_BokehMode == 0) { ret = lerp(BokehSum, BokehMax, fADOF_BokehIntensity * saturate(CoC * nRings * 2.0)); } else if(iADOF_BokehMode == 1) { float maxlum = dot(float3(0.3, 0.59, 0.11), BokehMax.rgb); float avglum = dot(float3(0.3, 0.59, 0.11), BokehSum.rgb); ret = BokehSum * lerp(avglum, maxlum, fADOF_BokehIntensity * saturate(CoC * nRings * 2.0)) / avglum; } else if(iADOF_BokehMode == 2) { float maxlum = dot(float3(0.3, 0.59, 0.11), BokehMax.rgb); float avglum = dot(float3(0.3, 0.59, 0.11), BokehSum.rgb); float bokehweight = max(0, maxlum - avglum); bokehweight = bokehweight * fADOF_BokehIntensity * 2.0; bokehweight *= bokehweight; ret = BokehSum + BokehMax * saturate(bokehweight * CoC * nRings); } else if(iADOF_BokehMode == 3) { float maxlum = dot(float3(0.3, 0.59, 0.11), BokehMax.rgb); float avglum = dot(float3(0.3, 0.59, 0.11), BokehSum.rgb); float bokehweight = maxlum - avglum; ret = lerp(BokehSum, BokehMax, saturate(bokehweight * CoC * nRings * fADOF_BokehIntensity)); } pack_hdr(ret.rgb); return ret; } void PS_DoF_Combine(in ADOF_VSOUT IN, out float4 color : SV_Target0) { float4 blurredColor = tex2D(sCommonTex1, IN.txcoord.xy * fADOF_RenderResolutionMult); float4 originalColor = tex2D(qUINT::sBackBufferTex, IN.txcoord.xy); float CoC = abs(CircleOfConfusion(IN.txcoord.xy, 0)); float bokehRadiusPixels = CoC2BlurRadius(CoC).x * BUFFER_WIDTH; #define linearstep(a,b,x) saturate((x-a)/(b-a)) float blendWeight = linearstep(DISCRADIUS_RESOLUTION_BOUNDARY_LOWER, DISCRADIUS_RESOLUTION_BOUNDARY_UPPER, bokehRadiusPixels); blendWeight = pow(blendWeight,DISCRADIUS_RESOLUTION_BOUNDARY_CURVE); color.rgb = lerp(originalColor.rgb, blurredColor.rgb, blendWeight); color.a = saturate(CoC * GAUSSIAN_BUILDUP_MULT) * 0.5 + 0.5; } void PS_DoF_Gauss1(in ADOF_VSOUT IN, out float4 color : SV_Target0) { float4 centerTap = tex2D(sCommonTex0, IN.txcoord.xy); float CoC = abs(centerTap.a * 2.0 - 1.0); float nSteps = floor(CoC * (fADOF_SmootheningAmount + 0.0)); float expCoeff = -2.0 * rcp(nSteps * nSteps + 1e-3); //sigma adjusted for blur width float2 blurAxisScaled = float2(1,0) * qUINT::PIXEL_SIZE.xy; float4 gaussianSum = 0.0; float gaussianSumWeight = 1e-3; for(float iStep = -nSteps; iStep <= nSteps; iStep++) { float currentWeight = exp(iStep * iStep * expCoeff); float currentOffset = 2.0 * iStep - 0.5; //Sample between texels to double blur width at no cost float4 currentTap = tex2Dlod(sCommonTex0, float4(IN.txcoord.xy + blurAxisScaled.xy * currentOffset, 0, 0)); currentWeight *= saturate(abs(currentTap.a * 2.0 - 1.0) - CoC * 0.25); //bleed fix gaussianSum += currentTap * currentWeight; gaussianSumWeight += currentWeight; } gaussianSum /= gaussianSumWeight; color.rgb = lerp(centerTap.rgb, gaussianSum.rgb, saturate(gaussianSumWeight)); color.a = centerTap.a; } void PS_DoF_Gauss2(in ADOF_VSOUT IN, out float4 color : SV_Target0) { float4 centerTap = tex2D(sCommonTex1, IN.txcoord.xy); float CoC = abs(centerTap.a * 2.0 - 1.0); float nSteps = min(50,floor(CoC * (fADOF_SmootheningAmount + 0.0))); float expCoeff = -2.0 * rcp(nSteps * nSteps + 1e-3); //sigma adjusted for blur width float2 blurAxisScaled = float2(0,1) * qUINT::PIXEL_SIZE.xy; float4 gaussianSum = 0.0; float gaussianSumWeight = 1e-3; for(float iStep = -nSteps; iStep <= nSteps; iStep++) { float currentWeight = exp(iStep * iStep * expCoeff); float currentOffset = 2.0 * iStep - 0.5; //Sample between texels to double blur width at no cost float4 currentTap = tex2Dlod(sCommonTex1, float4(IN.txcoord.xy + blurAxisScaled.xy * currentOffset, 0, 0)); currentWeight *= saturate(abs(currentTap.a * 2.0 - 1.0) - CoC * 0.25); //bleed fix gaussianSum += currentTap * currentWeight; gaussianSumWeight += currentWeight; } gaussianSum /= gaussianSumWeight; color.rgb = lerp(centerTap.rgb, gaussianSum.rgb, saturate(gaussianSumWeight)); color.a = centerTap.a; } #if (ADOF_CHROMATIC_ABERRATION_ENABLE != 0) void PS_DoF_ChromaticAberration(in ADOF_VSOUT IN, out float4 color : SV_Target0) { float4 colorVals[5]; float3 neighbourOffsets = float3(qUINT::PIXEL_SIZE.xy, 0); colorVals[0] = tex2D(sCommonTex0, IN.txcoord.xy); //C colorVals[1] = tex2D(sCommonTex0, IN.txcoord.xy - neighbourOffsets.xz); //L colorVals[2] = tex2D(sCommonTex0, IN.txcoord.xy - neighbourOffsets.zy); //T colorVals[3] = tex2D(sCommonTex0, IN.txcoord.xy + neighbourOffsets.xz); //R colorVals[4] = tex2D(sCommonTex0, IN.txcoord.xy + neighbourOffsets.zy); //B float CoC = abs(colorVals[0].a * 2.0 - 1.0); float2 bokehRadiusScaled = CoC2BlurRadius(CoC); float4 vGradTwosided = float4(dot(colorVals[0].rgb - colorVals[1].rgb, 1), //C - L dot(colorVals[0].rgb - colorVals[2].rgb, 1), //C - T dot(colorVals[3].rgb - colorVals[0].rgb, 1), //R - C dot(colorVals[4].rgb - colorVals[0].rgb, 1)); //B - C float2 vGrad = min(vGradTwosided.xy, vGradTwosided.zw); float vGradLen = sqrt(dot(vGrad,vGrad)) + 1e-6; vGrad = vGrad / vGradLen * saturate(vGradLen * 32.0) * bokehRadiusScaled * 0.125 * fADOF_ShapeChromaAmount; float4 chromaVals[3]; chromaVals[0] = colorVals[0]; chromaVals[1] = tex2D(sCommonTex0, IN.txcoord.xy + vGrad); chromaVals[2] = tex2D(sCommonTex0, IN.txcoord.xy - vGrad); chromaVals[1].rgb = lerp(chromaVals[0].rgb, chromaVals[1].rgb, saturate(4.0 * abs(chromaVals[1].w))); chromaVals[2].rgb = lerp(chromaVals[0].rgb, chromaVals[2].rgb, saturate(4.0 * abs(chromaVals[2].w))); uint3 chromaMode = (uint3(0,1,2) + iADOF_ShapeChromaMode.xxx) % 3; color.rgb = float3(chromaVals[chromaMode.x].r, chromaVals[chromaMode.y].g, chromaVals[chromaMode.z].b); color.a = 1.0; } #endif /*============================================================================= Techniques =============================================================================*/ technique ADOF < ui_tooltip = " >> qUINT::ADOF <<\n\n" "ADOF is a bokeh depth of field shader.\n" "It blurs the scene in front of and behind the focus plane\n" "to simulate the behaviour of real lenses. A multitude of features\n" "allows to simulate various types of bokeh blur that cameras produce.\n" "\nADOF is written by Marty McFly / Pascal Gilcher"; > { /* pass { VertexShader = VS_ADOF; PixelShader = PS_CopyBackBuffer; RenderTarget = texOriginal; }*/ pass { VertexShader = VS_ADOF; PixelShader = PS_ReadFocus; RenderTarget = ADOF_FocusTex; } pass { VertexShader = VS_ADOF; PixelShader = PS_CopyFocus; RenderTarget = ADOF_FocusTexPrev; } pass { VertexShader = VS_ADOF; PixelShader = PS_CoC; RenderTarget = CommonTex0; } pass { VertexShader = VS_ADOF; PixelShader = PS_DoF_Main; RenderTarget = CommonTex1; } pass { VertexShader = VS_ADOF; PixelShader = PS_DoF_Combine; RenderTarget = CommonTex0; } pass { VertexShader = VS_ADOF; PixelShader = PS_DoF_Gauss1; RenderTarget = CommonTex1; } #if(ADOF_CHROMATIC_ABERRATION_ENABLE != 0) pass { VertexShader = VS_ADOF; PixelShader = PS_DoF_Gauss2; RenderTarget = CommonTex0; } pass { VertexShader = VS_ADOF; PixelShader = PS_DoF_ChromaticAberration; } #else pass { VertexShader = VS_ADOF; PixelShader = PS_DoF_Gauss2; } #endif }