2023-09-23 14:39:09 +06:00

773 lines
25 KiB
HLSL

/*=============================================================================
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
}