// Copyright (c) 2009-2015 Gilcher Pascal aka Marty McFly #include "ReShadeUI.fxh" uniform int iBloomMixmode < ui_type = "combo"; ui_items = "Linear add\0Screen add\0Screen/Lighten/Opacity\0Lighten\0"; > = 2; uniform float fBloomThreshold < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.1; ui_max = 1.0; ui_tooltip = "Every pixel brighter than this value triggers bloom."; > = 0.8; uniform float fBloomAmount < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.0; ui_max = 20.0; ui_tooltip = "Intensity of bloom."; > = 0.8; uniform float fBloomSaturation < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.0; ui_max = 2.0; ui_tooltip = "Bloom saturation. 0.0 means white bloom, 2.0 means very, very colorful bloom."; > = 0.8; uniform float3 fBloomTint < __UNIFORM_COLOR_FLOAT3 ui_tooltip = "R, G and B components of bloom tint the bloom color gets shifted to."; > = float3(0.7, 0.8, 1.0); uniform bool bLensdirtEnable < > = false; uniform int iLensdirtMixmode < ui_type = "combo"; ui_items = "Linear add\0Screen add\0Screen/Lighten/Opacity\0Lighten\0"; > = 1; uniform float fLensdirtIntensity < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.0; ui_max = 2.0; ui_tooltip = "Intensity of lensdirt."; > = 0.4; uniform float fLensdirtSaturation < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.0; ui_max = 2.0; ui_tooltip = "Color saturation of lensdirt."; > = 2.0; uniform float3 fLensdirtTint < __UNIFORM_COLOR_FLOAT3 ui_tooltip = "R, G and B components of lensdirt tint the lensdirt color gets shifted to."; > = float3(1.0, 1.0, 1.0); uniform bool bAnamFlareEnable < > = false; uniform float fAnamFlareThreshold < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.1; ui_max = 1.0; ui_tooltip = "Every pixel brighter than this value gets a flare."; > = 0.9; uniform float fAnamFlareWideness < __UNIFORM_SLIDER_FLOAT1 ui_min = 1.0; ui_max = 2.5; ui_tooltip = "Horizontal wideness of flare. Don't set too high, otherwise the single samples are visible."; > = 2.4; uniform float fAnamFlareAmount < __UNIFORM_SLIDER_FLOAT1 ui_min = 1.0; ui_max = 20.0; ui_tooltip = "Intensity of anamorphic flare."; > = 14.5; uniform float fAnamFlareCurve < __UNIFORM_SLIDER_FLOAT1 ui_min = 1.0; ui_max = 2.0; ui_tooltip = "Intensity curve of flare with distance from source."; > = 1.2; uniform float3 fAnamFlareColor < __UNIFORM_COLOR_FLOAT3 ui_tooltip = "R, G and B components of anamorphic flare. Flare is always same color."; > = float3(0.012, 0.313, 0.588); uniform bool bLenzEnable < > = false; uniform float fLenzIntensity < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.2; ui_max = 3.0; ui_tooltip = "Power of lens flare effect"; > = 1.0; uniform float fLenzThreshold < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.6; ui_max = 1.0; ui_tooltip = "Minimum brightness an object must have to cast lensflare."; > = 0.8; uniform bool bChapFlareEnable < > = false; uniform float fChapFlareTreshold < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.70; ui_max = 0.99; ui_tooltip = "Brightness threshold for lensflare generation. Everything brighter than this value gets a flare."; > = 0.90; uniform int iChapFlareCount < __UNIFORM_SLIDER_INT1 ui_min = 1; ui_max = 20; ui_tooltip = "Number of single halos to be generated. If set to 0, only the curved halo around is visible."; > = 15; uniform float fChapFlareDispersal < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.25; ui_max = 1.00; ui_tooltip = "Distance from screen center (and from themselves) the flares are generated. "; > = 0.25; uniform float fChapFlareSize < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.20; ui_max = 0.80; ui_tooltip = "Distance (from screen center) the halo and flares are generated."; > = 0.45; uniform float3 fChapFlareCA < __UNIFORM_SLIDER_FLOAT3 ui_min = -0.5; ui_max = 0.5; ui_tooltip = "Offset of RGB components of flares as modifier for Chromatic abberation. Same 3 values means no CA."; > = float3(0.00, 0.01, 0.02); uniform float fChapFlareIntensity < __UNIFORM_SLIDER_FLOAT1 ui_min = 5.0; ui_max = 200.0; ui_tooltip = "Intensity of flares and halo, remember that higher threshold lowers intensity, you might play with both values to get desired result."; > = 100.0; uniform bool bGodrayEnable < > = false; uniform float fGodrayDecay < ui_type = "drag"; ui_min = 0.5000; ui_max = 0.9999; ui_tooltip = "How fast they decay. It's logarithmic, 1.0 means infinite long rays which will cover whole screen"; > = 0.9900; uniform float fGodrayExposure < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.7; ui_max = 1.5; ui_tooltip = "Upscales the godray's brightness"; > = 1.0; uniform float fGodrayWeight < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.80; ui_max = 1.70; ui_tooltip = "weighting"; > = 1.25; uniform float fGodrayDensity < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.2; ui_max = 2.0; ui_tooltip = "Density of rays, higher means more and brighter rays"; > = 1.0; uniform float fGodrayThreshold < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.6; ui_max = 1.0; ui_tooltip = "Minimum brightness an object must have to cast godrays"; > = 0.9; uniform int iGodraySamples < ui_tooltip = "2^x format values; How many samples the godrays get"; > = 128; uniform float fFlareLuminance < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.000; ui_max = 1.000; ui_tooltip = "bright pass luminance value "; > = 0.095; uniform float fFlareBlur < __UNIFORM_SLIDER_FLOAT1 ui_min = 1.0; ui_max = 10000.0; ui_tooltip = "manages the size of the flare"; > = 200.0; uniform float fFlareIntensity < __UNIFORM_SLIDER_FLOAT1 ui_min = 0.20; ui_max = 5.00; ui_tooltip = "effect intensity"; > = 2.07; uniform float3 fFlareTint < __UNIFORM_COLOR_FLOAT3 ui_tooltip = "effect tint RGB"; > = float3(0.137, 0.216, 1.0); // If 1, only pixels with depth = 1 get lens flares // This prevents white objects from getting lens flares sources, which would normally happen in LDR #ifndef LENZ_DEPTH_CHECK #define LENZ_DEPTH_CHECK 0 #endif #ifndef CHAPMAN_DEPTH_CHECK #define CHAPMAN_DEPTH_CHECK 0 #endif #ifndef GODRAY_DEPTH_CHECK #define GODRAY_DEPTH_CHECK 0 #endif #ifndef FLARE_DEPTH_CHECK #define FLARE_DEPTH_CHECK 0 #endif texture texDirt < source = "LensDB.png"; > { Width = 1920; Height = 1080; Format = RGBA8; }; texture texSprite < source = "LensSprite.png"; > { Width = 1920; Height = 1080; Format = RGBA8; }; sampler SamplerDirt { Texture = texDirt; }; sampler SamplerSprite { Texture = texSprite; }; texture texBloom1 { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA16F; }; texture texBloom2 { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA16F; }; texture texBloom3 { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; texture texBloom4 { Width = BUFFER_WIDTH / 4; Height = BUFFER_HEIGHT / 4; Format = RGBA16F; }; texture texBloom5 { Width = BUFFER_WIDTH / 8; Height = BUFFER_HEIGHT / 8; Format = RGBA16F; }; texture texLensFlare1 { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; texture texLensFlare2 { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; sampler SamplerBloom1 { Texture = texBloom1; }; sampler SamplerBloom2 { Texture = texBloom2; }; sampler SamplerBloom3 { Texture = texBloom3; }; sampler SamplerBloom4 { Texture = texBloom4; }; sampler SamplerBloom5 { Texture = texBloom5; }; sampler SamplerLensFlare1 { Texture = texLensFlare1; }; sampler SamplerLensFlare2 { Texture = texLensFlare2; }; #include "ReShade.fxh" float4 GaussBlur22(float2 coord, sampler tex, float mult, float lodlevel, bool isBlurVert) { float4 sum = 0; float2 axis = isBlurVert ? float2(0, 1) : float2(1, 0); const 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 }; for (int i = -10; i < 11; i++) { float currweight = weight[abs(i)]; sum += tex2Dlod(tex, float4(coord.xy + axis.xy * (float)i * BUFFER_PIXEL_SIZE * mult, 0, lodlevel)) * currweight; } return sum; } float3 GetDnB(sampler tex, float2 coords) { float3 color = max(0, dot(tex2Dlod(tex, float4(coords.xy, 0, 4)).rgb, 0.333) - fChapFlareTreshold) * fChapFlareIntensity; #if CHAPMAN_DEPTH_CHECK if (tex2Dlod(ReShade::DepthBuffer, float4(coords.xy, 0, 3)).x < 0.99999) color = 0; #endif return color; } float3 GetDistortedTex(sampler tex, float2 sample_center, float2 sample_vector, float3 distortion) { float2 final_vector = sample_center + sample_vector * min(min(distortion.r, distortion.g), distortion.b); if (final_vector.x > 1.0 || final_vector.y > 1.0 || final_vector.x < -1.0 || final_vector.y < -1.0) return float3(0, 0, 0); else return float3( GetDnB(tex, sample_center + sample_vector * distortion.r).r, GetDnB(tex, sample_center + sample_vector * distortion.g).g, GetDnB(tex, sample_center + sample_vector * distortion.b).b); } float3 GetBrightPass(float2 coords) { float3 c = tex2D(ReShade::BackBuffer, coords).rgb; float3 bC = max(c - fFlareLuminance.xxx, 0.0); float bright = dot(bC, 1.0); bright = smoothstep(0.0f, 0.5, bright); float3 result = lerp(0.0, c, bright); #if FLARE_DEPTH_CHECK float checkdepth = tex2D(ReShade::DepthBuffer, coords).x; if (checkdepth < 0.99999) result = 0; #endif return result; } float3 GetAnamorphicSample(int axis, float2 coords, float blur) { coords = 2.0 * coords - 1.0; coords.x /= -blur; coords = 0.5 * coords + 0.5; return GetBrightPass(coords); } void BloomPass0(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 bloom : SV_Target) { bloom = 0.0; const float2 offset[4] = { float2(1.0, 1.0), float2(1.0, 1.0), float2(-1.0, 1.0), float2(-1.0, -1.0) }; for (int i = 0; i < 4; i++) { float2 bloomuv = offset[i] * BUFFER_PIXEL_SIZE * 2; bloomuv += texcoord; float4 tempbloom = tex2Dlod(ReShade::BackBuffer, float4(bloomuv.xy, 0, 0)); tempbloom.w = max(0, dot(tempbloom.xyz, 0.333) - fAnamFlareThreshold); tempbloom.xyz = max(0, tempbloom.xyz - fBloomThreshold); bloom += tempbloom; } bloom *= 0.25; } void BloomPass1(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 bloom : SV_Target) { bloom = 0.0; const float2 offset[8] = { float2(1.0, 1.0), float2(0.0, -1.0), float2(-1.0, 1.0), float2(-1.0, -1.0), float2(0.0, 1.0), float2(0.0, -1.0), float2(1.0, 0.0), float2(-1.0, 0.0) }; for (int i = 0; i < 8; i++) { float2 bloomuv = offset[i] * BUFFER_PIXEL_SIZE * 4; bloomuv += texcoord; bloom += tex2Dlod(SamplerBloom1, float4(bloomuv, 0, 0)); } bloom *= 0.125; } void BloomPass2(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 bloom : SV_Target) { bloom = 0.0; const float2 offset[8] = { float2(0.707, 0.707), float2(0.707, -0.707), float2(-0.707, 0.707), float2(-0.707, -0.707), float2(0.0, 1.0), float2(0.0, -1.0), float2(1.0, 0.0), float2(-1.0, 0.0) }; for (int i = 0; i < 8; i++) { float2 bloomuv = offset[i] * BUFFER_PIXEL_SIZE * 8; bloomuv += texcoord; bloom += tex2Dlod(SamplerBloom2, float4(bloomuv, 0, 0)); } bloom *= 0.5; // brighten up the sample, it will lose brightness in H/V Gaussian blur } void BloomPass3(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 bloom : SV_Target) { bloom = GaussBlur22(texcoord.xy, SamplerBloom3, 16, 0, 0); bloom.w *= fAnamFlareAmount; bloom.xyz *= fBloomAmount; } void BloomPass4(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 bloom : SV_Target) { bloom.xyz = GaussBlur22(texcoord, SamplerBloom4, 16, 0, 1).xyz * 2.5; bloom.w = GaussBlur22(texcoord, SamplerBloom4, 32 * fAnamFlareWideness, 0, 0).w * 2.5; // to have anamflare texture (bloom.w) avoid vertical blur } void LensFlarePass0(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 lens : SV_Target) { lens = 0; // Lenz if (bLenzEnable) { const float3 lfoffset[19] = { float3(0.9, 0.01, 4), float3(0.7, 0.25, 25), float3(0.3, 0.25, 15), float3(1, 1.0, 5), float3(-0.15, 20, 1), float3(-0.3, 20, 1), float3(6, 6, 6), float3(7, 7, 7), float3(8, 8, 8), float3(9, 9, 9), float3(0.24, 1, 10), float3(0.32, 1, 10), float3(0.4, 1, 10), float3(0.5, -0.5, 2), float3(2, 2, -5), float3(-5, 0.2, 0.2), float3(20, 0.5, 0), float3(0.4, 1, 10), float3(0.00001, 10, 20) }; const float3 lffactors[19] = { float3(1.5, 1.5, 0), float3(0, 1.5, 0), float3(0, 0, 1.5), float3(0.2, 0.25, 0), float3(0.15, 0, 0), float3(0, 0, 0.15), float3(1.4, 0, 0), float3(1, 1, 0), float3(0, 1, 0), float3(0, 0, 1.4), float3(1, 0.3, 0), float3(1, 1, 0), float3(0, 2, 4), float3(0.2, 0.1, 0), float3(0, 0, 1), float3(1, 1, 0), float3(1, 1, 0), float3(0, 0, 0.2), float3(0.012,0.313,0.588) }; float2 lfcoord = 0; float3 lenstemp = 0; float2 distfact = texcoord.xy - 0.5; distfact.x *= BUFFER_ASPECT_RATIO; for (int i = 0; i < 19; i++) { lfcoord.xy = lfoffset[i].x * distfact; lfcoord.xy *= pow(2.0 * length(distfact), lfoffset[i].y * 3.5); lfcoord.xy *= lfoffset[i].z; lfcoord.xy = 0.5 - lfcoord.xy; float2 tempfact = (lfcoord.xy - 0.5) * 2; float templensmult = clamp(1.0 - dot(tempfact, tempfact), 0, 1); float3 lenstemp1 = dot(tex2Dlod(ReShade::BackBuffer, float4(lfcoord.xy, 0, 1)).rgb, 0.333); #if LENZ_DEPTH_CHECK float templensdepth = tex2D(ReShade::DepthBuffer, lfcoord.xy).x; if (templensdepth < 0.99999) lenstemp1 = 0; #endif lenstemp1 = max(0, lenstemp1.xyz - fLenzThreshold); lenstemp1 *= lffactors[i] * templensmult; lenstemp += lenstemp1; } lens.rgb += lenstemp * fLenzIntensity; } // Chapman Lens if (bChapFlareEnable) { float2 sample_vector = (float2(0.5, 0.5) - texcoord.xy) * fChapFlareDispersal; float2 halo_vector = normalize(sample_vector) * fChapFlareSize; float3 chaplens = GetDistortedTex(ReShade::BackBuffer, texcoord.xy + halo_vector, halo_vector, fChapFlareCA * 2.5f).rgb; for (int j = 0; j < iChapFlareCount; ++j) { float2 foffset = sample_vector * float(j); chaplens += GetDistortedTex(ReShade::BackBuffer, texcoord.xy + foffset, foffset, fChapFlareCA).rgb; } chaplens *= 1.0 / iChapFlareCount; lens.xyz += chaplens; } // Godrays if (bGodrayEnable) { const float2 ScreenLightPos = float2(0.5, 0.5); float2 texcoord2 = texcoord; float2 deltaTexCoord = (texcoord2 - ScreenLightPos); deltaTexCoord *= 1.0 / (float)iGodraySamples * fGodrayDensity; float illuminationDecay = 1.0; for (int g = 0; g < iGodraySamples; g++) { texcoord2 -= deltaTexCoord;; float4 sample2 = tex2Dlod(ReShade::BackBuffer, float4(texcoord2, 0, 0)); float sampledepth = tex2Dlod(ReShade::DepthBuffer, float4(texcoord2, 0, 0)).x; sample2.w = saturate(dot(sample2.xyz, 0.3333) - fGodrayThreshold); sample2.r *= 1.00; sample2.g *= 0.95; sample2.b *= 0.85; sample2 *= illuminationDecay * fGodrayWeight; #if GODRAY_DEPTH_CHECK == 1 if (sampledepth > 0.99999) lens.rgb += sample2.xyz * sample2.w; #else lens.rgb += sample2.xyz * sample2.w; #endif illuminationDecay *= fGodrayDecay; } } // Anamorphic flare if (bAnamFlareEnable) { float3 anamFlare = 0; const float gaussweight[5] = { 0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162 }; for (int z = -4; z < 5; z++) { anamFlare += GetAnamorphicSample(0, texcoord.xy + float2(0, z * BUFFER_RCP_HEIGHT * 2), fFlareBlur) * fFlareTint * gaussweight[abs(z)]; } lens.xyz += anamFlare * fFlareIntensity; } } void LensFlarePass1(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 lens : SV_Target) { lens = GaussBlur22(texcoord, SamplerLensFlare1, 2, 0, 1); } void LensFlarePass2(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 lens : SV_Target) { lens = GaussBlur22(texcoord, SamplerLensFlare2, 2, 0, 0); } void LightingCombine(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 color : SV_Target) { color = tex2D(ReShade::BackBuffer, texcoord); // Bloom float3 colorbloom = 0; colorbloom += tex2D(SamplerBloom3, texcoord).rgb * 1.0; colorbloom += tex2D(SamplerBloom5, texcoord).rgb * 9.0; colorbloom *= 0.1; colorbloom = saturate(colorbloom); float colorbloomgray = dot(colorbloom, 0.333); colorbloom = lerp(colorbloomgray, colorbloom, fBloomSaturation); colorbloom *= fBloomTint; if (iBloomMixmode == 0) color.rgb += colorbloom; else if (iBloomMixmode == 1) color.rgb = 1 - (1 - color.rgb) * (1 - colorbloom); else if (iBloomMixmode == 2) color.rgb = max(0.0f, max(color.rgb, lerp(color.rgb, (1 - (1 - saturate(colorbloom)) * (1 - saturate(colorbloom))), 1.0))); else if (iBloomMixmode == 3) color.rgb = max(color.rgb, colorbloom); // Anamorphic flare if (bAnamFlareEnable) { float3 anamflare = tex2D(SamplerBloom5, texcoord.xy).w * 2 * fAnamFlareColor; anamflare = max(anamflare, 0.0); color.rgb += pow(anamflare, 1.0 / fAnamFlareCurve); } // Lens dirt if (bLensdirtEnable) { float lensdirtmult = dot(tex2D(SamplerBloom5, texcoord).rgb, 0.333); float3 dirttex = tex2D(SamplerDirt, texcoord).rgb; float3 lensdirt = dirttex * lensdirtmult * fLensdirtIntensity; lensdirt = lerp(dot(lensdirt.xyz, 0.333), lensdirt.xyz, fLensdirtSaturation); if (iLensdirtMixmode == 0) color.rgb += lensdirt; else if (iLensdirtMixmode == 1) color.rgb = 1 - (1 - color.rgb) * (1 - lensdirt); else if (iLensdirtMixmode == 2) color.rgb = max(0.0f, max(color.rgb, lerp(color.rgb, (1 - (1 - saturate(lensdirt)) * (1 - saturate(lensdirt))), 1.0))); else if (iLensdirtMixmode == 3) color.rgb = max(color.rgb, lensdirt); } // Lens flares if (bAnamFlareEnable || bLenzEnable || bGodrayEnable || bChapFlareEnable) { float3 lensflareSample = tex2D(SamplerLensFlare1, texcoord.xy).rgb, lensflareMask; lensflareMask = tex2D(SamplerSprite, texcoord + float2( 0.5, 0.5) * BUFFER_PIXEL_SIZE).rgb; lensflareMask += tex2D(SamplerSprite, texcoord + float2(-0.5, 0.5) * BUFFER_PIXEL_SIZE).rgb; lensflareMask += tex2D(SamplerSprite, texcoord + float2( 0.5, -0.5) * BUFFER_PIXEL_SIZE).rgb; lensflareMask += tex2D(SamplerSprite, texcoord + float2(-0.5, -0.5) * BUFFER_PIXEL_SIZE).rgb; color.rgb += lensflareMask * 0.25 * lensflareSample; } } technique BloomAndLensFlares { pass BloomPass0 { VertexShader = PostProcessVS; PixelShader = BloomPass0; RenderTarget = texBloom1; } pass BloomPass1 { VertexShader = PostProcessVS; PixelShader = BloomPass1; RenderTarget = texBloom2; } pass BloomPass2 { VertexShader = PostProcessVS; PixelShader = BloomPass2; RenderTarget = texBloom3; } pass BloomPass3 { VertexShader = PostProcessVS; PixelShader = BloomPass3; RenderTarget = texBloom4; } pass BloomPass4 { VertexShader = PostProcessVS; PixelShader = BloomPass4; RenderTarget = texBloom5; } pass LensFlarePass0 { VertexShader = PostProcessVS; PixelShader = LensFlarePass0; RenderTarget = texLensFlare1; } pass LensFlarePass1 { VertexShader = PostProcessVS; PixelShader = LensFlarePass1; RenderTarget = texLensFlare2; } pass LensFlarePass2 { VertexShader = PostProcessVS; PixelShader = LensFlarePass2; RenderTarget = texLensFlare1; } pass LightingCombine { VertexShader = PostProcessVS; PixelShader = LightingCombine; } }