// Implementation based on the article "Efficient Gaussian blur with linear sampling" // http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ // Updated and Modified by Marot Satil for ReShade 4.0 and lightly optimized for the GShade project. /*-----------------------------------------------------------. / Gaussian Blur settings / '-----------------------------------------------------------*/ #include "ReShade.fxh" //BrightPass *also affects blur and unsharpmask* *Recommend off for blur* //Doesn't seem to be working right but it makes bloom look better. 1 = on, 0 = off. #ifndef gUSE_BP #define gUSE_BP 1 #endif //Bloom / Blur direction //The direction the pixels are being shifted during the gaussian passes. 1 = on, 0 = off. #ifndef gUSE_HorizontalGauss #define gUSE_HorizontalGauss 1 #endif #ifndef gUSE_VerticalGauss #define gUSE_VerticalGauss 1 #endif #ifndef gUSE_SlantGauss #define gUSE_SlantGauss 1 #endif //GaussQuality //0 = original, 1 = new. New is the same as original but has additional sample points in-between. //When using 1, setting gGaussQuantity to 9 can help smooth wider bloom settings. #ifndef gGaussQuality #define gGaussQuality 0 #endif //Use a separate uniform for each GaussQuality type to avoid out-of-range compile failures from user input. #if (gGaussQuality == 0) #define gGaussQuantity gN_PASSES #else #define gGaussQuantity gN_PASSES_NEW #endif uniform int gGaussEffect < ui_label = "Gauss Effect"; ui_type = "combo"; ui_items="Off\0Blur\0Unsharpmask (expensive)\0Bloom\0Sketchy\0Effects Image Only\0"; > = 1; uniform float gGaussStrength < ui_label = "Gauss Strength"; ui_tooltip = "Amount of effect blended into the final image."; ui_type = "slider"; ui_min = 0.0; ui_max = 1.0; ui_step = 0.001; > = 0.3; uniform bool gAddBloom < ui_label = "Add Bloom"; > = 0; //Bloom Strength //[0.00 to 1.00] Amount of gAddBloom added to the final image. #define BloomStrength 0.33 uniform float gBloomStrength < ui_label = "Bloom Strength"; ui_tooltip = "Amount of Bloom added to the final image."; ui_type = "slider"; ui_min = 0.0; ui_max = 1.0; ui_step = 0.001; > = 0.33; uniform float gBloomIntensity < ui_label = "Bloom Intensity"; ui_tooltip = "Makes bright spots brighter. Also affects Blur and Unsharpmask."; ui_type = "slider"; ui_min = 0.0; ui_max = 6.0; ui_step = 0.001; > = 3.0; uniform int gGaussBloomWarmth < ui_label = "Bloom Warmth"; ui_tooltip = "Choose a tonemapping algorithm fitting your personal taste."; ui_type = "combo"; ui_items="Neutral\0Warm\0Hazy/Foggy\0"; > = 0; //When gGaussQuality = 0, gGaussQuantity must be set to 3, 4, or 5. When using gGaussQuality = 1, gGaussQuantity must be set to 3,4,5,6,7,8, or 9. #if (gGaussQuality == 0) uniform int gN_PASSES < ui_label = "Number of Gaussian Passes"; ui_tooltip = "Still fine tuning this. Changing the number of passes can affect brightness."; ui_type = "slider"; ui_min = 3; ui_max = 5; ui_step = 1; > = 5; #else uniform int gN_PASSES_NEW < ui_label = "Number of Gaussian Passes"; ui_tooltip = "Still fine tuning this. Changing the number of passes can affect brightness."; ui_type = "slider"; ui_min = 3; ui_max = 9; ui_step = 1; > = 5; #endif uniform float gBloomHW < ui_label = "Horizontal Bloom Width"; ui_tooltip = "Higher numbers = wider bloom."; ui_type = "slider"; ui_min = 0.001; ui_max = 10.0; ui_step = 0.001; > = 1.0; uniform float gBloomVW < ui_label = "Vertical Bloom Width"; ui_tooltip = "Higher numbers = wider bloom."; ui_type = "slider"; ui_min = 0.001; ui_max = 10.0; ui_step = 0.001; > = 1.0; uniform float gBloomSW < ui_label = "Bloom Slant"; ui_tooltip = "Higher numbers = wider bloom."; ui_type = "slider"; ui_min = 0.001; ui_max = 10.0; ui_step = 0.001; > = 2.0; #define PIXEL_SIZE float2(BUFFER_RCP_WIDTH,BUFFER_RCP_HEIGHT) #define CoefLuma_G float3(0.2126, 0.7152, 0.0722) // BT.709 & sRBG luma coefficient (Monitors and HD Television) #define sharp_strength_luma_G (CoefLuma_G * gGaussStrength + 0.2) #define sharp_clampG 0.035 texture origframeTex2D { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = R8G8B8A8; }; sampler origframeSampler { Texture = origframeTex2D; AddressU = Clamp; AddressV = Clamp; MipFilter = None; MinFilter = Linear; MagFilter = Linear; SRGBTexture = false; }; float4 BrightPassFilterPS(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : COLOR { const float4 color = tex2D(ReShade::BackBuffer, texcoord); return float4(color.rgb * pow (abs (max (color.r, max (color.g, color.b))), 2.0), 2.0f)*gBloomIntensity; } float4 HGaussianBlurPS(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : COLOR { #if (gGaussQuality == 0) const float sampleOffsets[5] = { 0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130 }; const float sampleWeights[5] = { 0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196 }; #else const float sampleOffsets[9] = { 0.0, 1.43*.50, 1.43, 2, 3.35, 4, 5.26, 6, 7.17 }; const float sampleWeights[9] = { 0.168, 0.273, 0.273, 0.117, 0.117, 0.024, 0.024, 0.002, 0.002}; #endif float4 color = tex2D(ReShade::BackBuffer, texcoord) * sampleWeights[0]; for(int i = 1; i < gGaussQuantity; ++i) { color += tex2Dlod(ReShade::BackBuffer, float4(texcoord + float2(sampleOffsets[i]*gBloomHW * PIXEL_SIZE.x, 0.0), 0.0, 0.0)) * sampleWeights[i]; color += tex2Dlod(ReShade::BackBuffer, float4(texcoord - float2(sampleOffsets[i]*gBloomHW * PIXEL_SIZE.x, 0.0), 0.0, 0.0)) * sampleWeights[i]; } return color; } float4 VGaussianBlurPS(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : COLOR { #if (gGaussQuality == 0) const float sampleOffsets[5] = { 0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130 }; const float sampleWeights[5] = { 0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196 }; #else const float sampleOffsets[9] = { 0.0, 1.4347826*.50, 1.4347826, 2, 3.3478260, 4, 5.2608695, 6, 7.1739130 }; const float sampleWeights[9] = { 0.16818994, 0.27276957, 0.27276957, 0.11690125, 0.11690125, 0.024067905, 0.024067905, 0.0021112196 , 0.0021112196}; #endif float4 color = tex2D(ReShade::BackBuffer, texcoord) * sampleWeights[0]; for(int i = 1; i < gGaussQuantity; ++i) { color += tex2Dlod(ReShade::BackBuffer, float4(texcoord + float2(0.0, sampleOffsets[i]*gBloomVW * PIXEL_SIZE.y), 0.0, 0.0)) * sampleWeights[i]; color += tex2Dlod(ReShade::BackBuffer, float4(texcoord - float2(0.0, sampleOffsets[i]*gBloomVW * PIXEL_SIZE.y), 0.0, 0.0)) * sampleWeights[i]; } return color; } float4 SGaussianBlurPS(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : COLOR { #if (gGaussQuality == 0) const float sampleOffsets[5] = { 0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130 }; const float sampleWeights[5] = { 0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196 }; #else const float sampleOffsets[9] = { 0.0, 1.4347826*.50, 1.4347826, 2, 3.3478260, 4, 5.2608695, 6, 7.1739130 }; const float sampleWeights[9] = { 0.16818994, 0.27276957, 0.27276957, 0.11690125, 0.11690125, 0.024067905, 0.024067905, 0.0021112196 , 0.0021112196}; #endif float4 color = tex2D(ReShade::BackBuffer, texcoord) * sampleWeights[0]; for(int i = 1; i < gGaussQuantity; ++i) { color += tex2Dlod(ReShade::BackBuffer, float4(texcoord + float2(sampleOffsets[i]*gBloomSW * PIXEL_SIZE.x, sampleOffsets[i] * PIXEL_SIZE.y), 0.0, 0.0)) * sampleWeights[i]; color += tex2Dlod(ReShade::BackBuffer, float4(texcoord - float2(sampleOffsets[i]*gBloomSW * PIXEL_SIZE.x, sampleOffsets[i] * PIXEL_SIZE.y), 0.0, 0.0)) * sampleWeights[i]; color += tex2Dlod(ReShade::BackBuffer, float4(texcoord + float2(-sampleOffsets[i]*gBloomSW * PIXEL_SIZE.x, sampleOffsets[i] * PIXEL_SIZE.y), 0.0, 0.0)) * sampleWeights[i]; color += tex2Dlod(ReShade::BackBuffer, float4(texcoord + float2(sampleOffsets[i]*gBloomSW * PIXEL_SIZE.x, -sampleOffsets[i] * PIXEL_SIZE.y), 0.0, 0.0)) * sampleWeights[i]; } return color * 0.50; } float4 CombinePS(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : COLOR { // Unsharpmask ( Ref. http://www.bigano.com/index.php/en/consulting/40-davide-barranca/90-davide-barranca-notes-on-sharpening.html?start=1 ) // return tex2D(origframeTex2D, texcoord); // Unprocessed image // return tex2D(ReShade::BackBuffer, texcoord); // Blurred image float4 orig = tex2D(origframeSampler, texcoord); const float4 blur = tex2D(ReShade::BackBuffer, texcoord); float3 sharp; if (gGaussEffect == 0) orig = orig; else if (gGaussEffect == 1) { // Blur... orig = lerp(orig, blur, gGaussStrength); } else if (gGaussEffect == 2) { // Sharpening sharp = orig.rgb - blur.rgb; float sharp_luma = dot(sharp, sharp_strength_luma_G); sharp_luma = clamp(sharp_luma, -sharp_clampG, sharp_clampG); orig = orig + sharp_luma; } else if (gGaussEffect == 3) { // Bloom if (gGaussBloomWarmth == 0) orig = lerp(orig, blur *4, gGaussStrength); // Neutral else if (gGaussBloomWarmth == 1) orig = lerp(orig, max(orig *1.8 + (blur *5) - 1.0, 0.0), gGaussStrength); // Warm and cheap else orig = lerp(orig, (1.0 - ((1.0 - orig) * (1.0 - blur *1.0))), gGaussStrength); // Foggy bloom } else if (gGaussEffect == 4) { // Sketchy sharp = orig.rgb - blur.rgb; orig = float4(1.0, 1.0, 1.0, 0.0) - min(orig, dot(sharp, sharp_strength_luma_G)) *3; // orig = float4(1.0, 1.0, 1.0, 0.0) - min(blur, orig); // Negative } else orig = blur; if (gAddBloom == 1) { if (gGaussBloomWarmth == 0) { orig += lerp(orig, blur *4, gBloomStrength); orig = orig * 0.5; } else if (gGaussBloomWarmth == 1) { orig += lerp(orig, max(orig *1.8 + (blur *5) - 1.0, 0.0), gBloomStrength); orig = orig * 0.5; } else { orig += lerp(orig, (1.0 - ((1.0 - orig) * (1.0 - blur *1.0))), gBloomStrength); orig = orig * 0.5; } } else orig = orig; #if (USE_addBlur == 1) orig += lerp(orig, blur2, BlurStrength); //orig = blur2; #endif return orig; } float4 PassThrough(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD) : COLOR { return tex2D(ReShade::BackBuffer, texcoord); } technique GAUSSSIAN { pass { VertexShader = PostProcessVS; PixelShader = PassThrough; RenderTarget = origframeTex2D; } #if (gUSE_BP == 1) pass P0 { VertexShader = PostProcessVS; PixelShader = BrightPassFilterPS; } #endif #if (gUSE_HorizontalGauss == 1) pass P1 { VertexShader = PostProcessVS; PixelShader = HGaussianBlurPS; } #endif #if (gUSE_VerticalGauss == 1) pass P2 { VertexShader = PostProcessVS; PixelShader = VGaussianBlurPS; } #endif #if (gUSE_SlantGauss == 1) pass P3 { VertexShader = PostProcessVS; PixelShader = SGaussianBlurPS; } #endif pass P5 { VertexShader = PostProcessVS; PixelShader = CombinePS; } }