New Luma Sharpen
- Fu-Bama
- Topic Author
I would like to share with you new version of Luma Sharpen filter. It produces less aliasing artifacts with better performance.
Here's original filter sharpen layer:
And here's mine:
Some pics from Alien: Isolation
Before:
and After:
Before:
After:
Shader code:
Just paste the code into an empty ReShade.fx and save as FilmicSharpen.fx
/*
Copyright (c) 2018 Jacob Maximilian Fober
This work is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/4.0/.
*/
// Filmic Sharpen PS
////////////////////
/////// MENU ///////
////////////////////
uniform float Strength <
ui_label = "Sharpen strength";
ui_type = "drag";
ui_min = 0.0; ui_max = 3.0; ui_step = 0.005;
> = 1.0;
uniform bool Preview <
ui_label = "Preview sharpen layer";
> = false;
uniform int Coefficient <
ui_label = "Luma coefficient";
ui_tooltip = "Change if objects with relatively same brightness but different color get sharpened";
ui_type = "combo";
ui_items = "BT.709\0BT.601\0";
> = 0;
uniform float Clamp <
ui_label = "Sharpen clamping";
ui_type = "drag";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.001;
> = 1.0;
uniform int Offset <
ui_label = "High-pass offset";
ui_tooltip = "High-pass cross offset in pixels";
ui_type = "drag";
ui_min = 0; ui_max = 2;
> = 1;
//////////////////////
/////// SHADER ///////
//////////////////////
#include "ReShade.fxh"
// Overlay blending mode
float Overlay(float LayerA, float LayerB)
{
float MinA = min(LayerA, 0.5) * 2;
float MinB = min(LayerB, 0.5) * 2;
float MaxA = 1 - (max(LayerA, 0.5) * 2 - 1);
float MaxB = 1 - (max(LayerB, 0.5) * 2 - 1);
float Result = (MinA * MinB + 1 - MaxA * MaxB) * 0.5;
return Result;
}
// Convert RGB to YUV.luma
float Luma(float3 Source, float3 Coefficients)
{
float3 Result = Source * Coefficients;
return Result.r + Result.g + Result.b;
}
// Define screen texture with mirror tiles
texture TexColorBuffer : COLOR;
sampler SamplerColor
{
Texture = TexColorBuffer;
AddressU = MIRROR;
AddressV = MIRROR;
};
// Sharpen pass
float3 FilmicSharpenPS(float4 vois : SV_Position, float2 UvCoord : TexCoord) : SV_Target
{
float2 Pixel = ReShade::PixelSize;
Pixel *= Offset;
// Sample display image
float3 Source = tex2D(SamplerColor, UvCoord).rgb;
float2 North = float2(UvCoord.x, UvCoord.y + Pixel.y);
float2 South = float2(UvCoord.x, UvCoord.y - Pixel.y);
float2 West = float2(UvCoord.x + Pixel.x, UvCoord.y);
float2 East = float2(UvCoord.x - Pixel.x, UvCoord.y);
// Choose luma coefficient
float3 LumaCoefficient;
if (Coefficient == 0)
{
LumaCoefficient = float3( 0.2126, 0.7152, 0.0722); // BT.709 Luma
}
else
{
LumaCoefficient = float3( 0.299, 0.587, 0.114); // BT.601 Luma
}
// Luma high-pass
float HighPass;
HighPass = Luma(tex2D(SamplerColor, North).rgb, LumaCoefficient);
HighPass += Luma(tex2D(SamplerColor, South).rgb, LumaCoefficient);
HighPass += Luma(tex2D(SamplerColor, West).rgb, LumaCoefficient);
HighPass += Luma(tex2D(SamplerColor, East).rgb, LumaCoefficient);
HighPass *= 0.25;
HighPass = 1 - HighPass;
HighPass = (HighPass + Luma(Source, LumaCoefficient)) * 0.5;
// Sharpen strength
HighPass = lerp(0.5, HighPass, Strength);
// Clamping sharpen
HighPass = min(HighPass, Clamp);
HighPass = max(HighPass, 1 - Clamp);
float3 Sharpen;
Sharpen.r = Overlay(Source.r, HighPass);
Sharpen.g = Overlay(Source.g, HighPass);
Sharpen.b = Overlay(Source.b, HighPass);
if (Preview)
{
return HighPass;
}
else
{
return Sharpen;
}
}
technique FilmicSharpen
{
pass
{
VertexShader = PostProcessVS;
PixelShader = FilmicSharpenPS;
}
}
Please Log in or Create an account to join the conversation.
- SandyCheeks
I guess what i'm really asking is, would we get the same(ish) results by using a form of anti aliasing followed by the old version of lumasharpen as we would by just using your shader by itself?
Please Log in or Create an account to join the conversation.
- Martigen
Please Log in or Create an account to join the conversation.
- Marty McFly
SandyCheeks wrote: That second debug screenshot is beautiful. I'm curious, is your new luma shader also implementing a form of anti-aliasing and then sharpening? Or is the lack of aliasing in your version a result of some genius shader writing ?
I guess what i'm really asking is, would we get the same(ish) results by using a form of anti aliasing followed by the old version of lumasharpen as we would by just using your shader by itself?
He's using a different blur kernel than original luma sharpen.
Please Log in or Create an account to join the conversation.
- robgrab
Please Log in or Create an account to join the conversation.
Thank youSandyCheeks wrote: That second debug screenshot is beautiful. I'm curious, is your new luma shader also implementing a form of anti-aliasing and then sharpening? Or is the lack of aliasing in your version a result of some genius shader writing ?
I guess what i'm really asking is, would we get the same(ish) results by using a form of anti aliasing followed by the old version of lumasharpen as we would by just using your shader by itself?
There's no anti-aliasing implemented in this shader, just approach to high-pass filter, or blur as Marty McFly noted, is different.
You won't get the same result with the old version as it implements it's own aliasing even to anti-aliased source. As seen on debug example.
Please Log in or Create an account to join the conversation.
Thank you.robgrab wrote: I tried it last night and now it's my new default luma sharpen. Great work!
Maybe it should replace the default Luma Sharpen in Reshade-shaders?
What do you think? I can create pull request.
Please Log in or Create an account to join the conversation.
- bacondither
Have fun experimenting
Please Log in or Create an account to join the conversation.
- Sunesha
I used it with Fallout 4 with TAA(Blurry but a very calm picture in motion) and this settings was decent:
Sharpen: 2,400
BT709
Clamp: 0,600
Highpass:1
I gonna check out later how it looks with a game with SMAA which has a lot more creepy crawly pixels in another game. But this sharpener is very subtle and nice.
But I can see how I will use this instead of the LumaSharpen in most cases. Though I like to use LumaSharpen with a low offset bias setting and high sharpen setting. If there was depth-based sharpen tool I would love that. I use selective sharpening in photowork in similar way. And depth based control sharpen would be super awesome. But not sure how it would look in a game.
Thank you, it is a vert nice sharpener on its own. More alternatives is never a bad thing
Please Log in or Create an account to join the conversation.
- Kleio420
Please Log in or Create an account to join the conversation.
What do you mean by depth-driven sharpen? Should it leave smooth transitions between foreground-background objects edges, like Panavision lenses vimeo.com/167050590 and sharpen only foreground/background-planes content? Or sharpen foreground and leave background untouched?Kleio420 wrote: what about making two modes for it one just depth based and then a third mode using depth to compare to the original pass to help only sharpen what you want more specifically then just a broad range offered atm?
I can experiment with both. I just want to know what you imagine the depth-driven sharpening would do.
Please Log in or Create an account to join the conversation.
- Kleio420
similar to the edited version of luma sharpen that was made for enb usage was thinking you could use depth as a way to lower the radius of whats sharpened rather then what appears to be applied to the entire image?Fu-Bama wrote:
What do you mean by depth-driven sharpen? Should it leave smooth transitions between foreground-background objects edges, like Panavision lenses vimeo.com/167050590 and sharpen only foreground/background-planes content? Or sharpen foreground and leave background untouched?Kleio420 wrote: what about making two modes for it one just depth based and then a third mode using depth to compare to the original pass to help only sharpen what you want more specifically then just a broad range offered atm?
I can experiment with both. I just want to know what you imagine the depth-driven sharpening would do.
Please Log in or Create an account to join the conversation.
- Sunesha
Please Log in or Create an account to join the conversation.
- Kleio420
if a sharpen shader for reshade were to work more like that it would be greatSunesha wrote: My idea of a depth--based sharpener. I show instead of tell with help of photoshop and a video. A bit long (5min)
Please Log in or Create an account to join the conversation.
Sunesha wrote: My idea of a depth--based sharpener. I show instead of tell with help of photoshop and a video. A bit long (5min)
Ok, I added depth mask to the shader.
By default it's set to preview mode for the sharpening start and stop.
Shader Code:
/*
Copyright (c) 2018 Jacob Maximilian Fober
This work is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/4.0/.
*/
// Filmic Sharpen with Depth PS
////////////////////
/////// MENU ///////
////////////////////
uniform float Strength <
ui_label = "Sharpen strength";
ui_type = "drag";
ui_min = 0.0; ui_max = 3.0; ui_step = 0.005;
> = 1.0;
uniform bool Preview <
ui_label = "Preview sharpen layer";
> = false;
uniform int Coefficient <
ui_label = "Luma coefficient";
ui_tooltip = "Change if objects with relatively same brightness but different color get sharpened";
ui_type = "combo";
ui_items = "BT.709\0BT.601\0";
> = 0;
uniform float Clamp <
ui_label = "Sharpen clamping";
ui_type = "drag";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.001;
> = 1.0;
uniform int Offset <
ui_label = "High-pass offset";
ui_tooltip = "High-pass cross offset in pixels";
ui_type = "drag";
ui_min = 0; ui_max = 2;
> = 1;
uniform bool PreviewPlane <
ui_label = "Preview clip planes";
ui_tooltip = "See Green and Red; Far and Near sharpen clip plane";
> = true;
uniform float NearPlane <
ui_label = "Sharpen Start position";
ui_tooltip = "Adjust sharpen clamping start (Red)";
ui_type = "drag";
ui_min = 0.0; ui_max = 10.0; ui_step = 0.001;
> = 9.755;
uniform float FarPlane <
ui_label = "Sharpen Stop position";
ui_tooltip = "Adjust sharpen clamping stop (Green)";
ui_type = "drag";
ui_min = 0.0; ui_max = 10.0; ui_step = 0.001;
> = 9.95;
uniform float NearPlaneWidth <
ui_label = "Start blur";
ui_tooltip = "Adjust sharpen start smoothness (Red)";
ui_type = "drag";
ui_min = 0.0; ui_max = 0.5; ui_step = 0.001;
> = 0.05;
uniform float FarPlaneWidth <
ui_label = "Stop blur";
ui_tooltip = "Adjust sharpen stop smoothness (Green)";
ui_type = "drag";
ui_min = 0.0; ui_max = 0.5; ui_step = 0.001;
> = 0.006;
uniform float Gamma <
ui_label = "Depth gamma";
ui_tooltip = "Adjust Depth gamma value";
ui_type = "drag";
ui_min = 1.0; ui_max = 10.0; ui_step = 0.01;
> = 1.0;
//////////////////////
/////// SHADER ///////
//////////////////////
#include "ReShade.fxh"
// Overlay blending mode
float Overlay(float LayerA, float LayerB)
{
float MinA = min(LayerA, 0.5) * 2;
float MinB = min(LayerB, 0.5) * 2;
float MaxA = 1 - (max(LayerA, 0.5) * 2 - 1);
float MaxB = 1 - (max(LayerB, 0.5) * 2 - 1);
float Result = (MinA * MinB + 1 - MaxA * MaxB) * 0.5;
return Result;
}
// Convert RGB to YUV.luma
float Luma(float3 Source, float3 Coefficients)
{
float3 Result = Source * Coefficients;
return Result.r + Result.g + Result.b;
}
// Define screen texture with mirror tiles
texture TexColorBuffer : COLOR;
sampler SamplerColor
{
Texture = TexColorBuffer;
AddressU = MIRROR;
AddressV = MIRROR;
};
// Sharpen pass
float3 FilmicSharpenWithDepthPS(float4 vois : SV_Position, float2 UvCoord : TexCoord) : SV_Target
{
// Grab Depth Pass
float Depth = tex2D(ReShade::DepthBuffer, UvCoord).r;
Depth = pow(Depth, Gamma);
// Grab Pixel UV Size
float2 Pixel = ReShade::PixelSize;
Pixel *= Offset;
// Sample display image
float3 Source = tex2D(SamplerColor, UvCoord).rgb;
float2 North = float2(UvCoord.x, UvCoord.y + Pixel.y);
float2 South = float2(UvCoord.x, UvCoord.y - Pixel.y);
float2 West = float2(UvCoord.x + Pixel.x, UvCoord.y);
float2 East = float2(UvCoord.x - Pixel.x, UvCoord.y);
// Choose luma coefficient
float3 LumaCoefficient;
if (Coefficient == 0)
{
LumaCoefficient = float3( 0.2126, 0.7152, 0.0722); // BT.709 Luma
}
else
{
LumaCoefficient = float3( 0.299, 0.587, 0.114); // BT.601 Luma
}
// Luma high-pass
float HighPass;
HighPass = Luma(tex2D(SamplerColor, North).rgb, LumaCoefficient);
HighPass += Luma(tex2D(SamplerColor, South).rgb, LumaCoefficient);
HighPass += Luma(tex2D(SamplerColor, West).rgb, LumaCoefficient);
HighPass += Luma(tex2D(SamplerColor, East).rgb, LumaCoefficient);
HighPass *= 0.25;
HighPass = 1 - HighPass;
HighPass = (HighPass + Luma(Source, LumaCoefficient)) * 0.5;
//////////////////////
/// Depth clipping ///
//////////////////////
float3 Red = float3(1.0, 0.0, 0.0);
float3 Green = float3(0.0, 1.0, 0.0);
float2 DepthMask;
DepthMask.r = saturate(Depth - NearPlane * 0.1 + NearPlaneWidth * 0.05);
DepthMask.r = saturate(DepthMask.r / NearPlaneWidth / 0.1);
DepthMask.g = saturate(Depth - FarPlane * 0.1 + FarPlaneWidth * 0.05);
DepthMask.g = saturate(DepthMask.g / FarPlaneWidth / 0.1);
DepthMask = saturate(DepthMask);
DepthMask.r = 1.0 - DepthMask.r;
// Sharpen strength and mask
HighPass = lerp(0.5, HighPass, Strength * (1.0 - (DepthMask.r + DepthMask.g)));
DepthMask *= 0.85;
// Clamping sharpen
HighPass = min(HighPass, Clamp);
HighPass = max(HighPass, 1 - Clamp);
float3 Sharpen;
Sharpen.r = Overlay(Source.r, HighPass);
Sharpen.g = Overlay(Source.g, HighPass);
Sharpen.b = Overlay(Source.b, HighPass);
if (Preview)
{
return HighPass;
}
else if (PreviewPlane)
{
Sharpen = lerp(Sharpen, Red, DepthMask.r);
Sharpen = lerp(Sharpen, Green, DepthMask.g);
return Sharpen;
}
else
{
return Sharpen;
}
}
technique FilmicSharpenWithDepth
{
pass
{
VertexShader = PostProcessVS;
PixelShader = FilmicSharpenWithDepthPS;
}
}
Please Log in or Create an account to join the conversation.
It gives some interesting results
Images:
Shader Code:
/*
Copyright (c) 2018 Jacob Maximilian Fober
This work is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/4.0/.
*/
// Filmic Anamorph Sharpen PS
////////////////////
/////// MENU ///////
////////////////////
uniform float Strength <
ui_label = "Sharpen strength";
ui_type = "drag";
ui_min = 0.0; ui_max = 3.0; ui_step = 0.005;
> = 1.0;
uniform bool Preview <
ui_label = "Preview";
ui_tooltip = "Preview sharpen layer and mask for adjustment";
> = false;
uniform int Coefficient <
ui_label = "Luma coefficient";
ui_tooltip = "Change if objects with relatively same brightness but different color get sharpened";
ui_type = "combo";
ui_items = "BT.709\0BT.601\0";
> = 0;
uniform float Clamp <
ui_label = "Sharpen clamping";
ui_type = "drag";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.001;
> = 1.0;
uniform int Offset <
ui_label = "High-pass offset";
ui_tooltip = "High-pass cross offset in pixels";
ui_type = "drag";
ui_min = 0; ui_max = 2;
> = 1;
uniform int Contrast <
ui_label = "Edges mask";
ui_tooltip = "Depth high-pass mask amount";
ui_type = "drag";
ui_min = 0; ui_max = 2000; ui_step = 1;
> = 1618;
//////////////////////
/////// SHADER ///////
//////////////////////
#include "ReShade.fxh"
// Overlay blending mode
float Overlay(float LayerA, float LayerB)
{
float MinA = min(LayerA, 0.5) * 2;
float MinB = min(LayerB, 0.5) * 2;
float MaxA = 1 - (max(LayerA, 0.5) * 2 - 1);
float MaxB = 1 - (max(LayerB, 0.5) * 2 - 1);
float Result = (MinA * MinB + 1 - MaxA * MaxB) * 0.5;
return Result;
}
// Convert RGB to YUV.luma
float Luma(float3 Source, float3 Coefficients)
{
float3 Result = Source * Coefficients;
return Result.r + Result.g + Result.b;
}
// Define screen texture with mirror tiles
texture TexColorBuffer : COLOR;
sampler SamplerColor
{
Texture = TexColorBuffer;
AddressU = MIRROR;
AddressV = MIRROR;
};
// Define depth texture with mirror tiles
texture TexDepthBuffer : DEPTH;
sampler SamplerDepth
{
Texture = TexDepthBuffer;
AddressU = MIRROR;
AddressV = MIRROR;
};
// Sharpen pass
float3 FilmicAnamorphSharpenPS(float4 vois : SV_Position, float2 UvCoord : TexCoord) : SV_Target
{
float2 Pixel = ReShade::PixelSize;
float2 DepthPixel = Pixel * float(Offset + 1);
Pixel *= float(Offset);
// Sample display image
float3 Source = tex2D(SamplerColor, UvCoord).rgb;
// Sample display depth image
float SourceDepth = tex2D(SamplerDepth, UvCoord).r;
float2 North = float2(UvCoord.x, UvCoord.y + Pixel.y);
float2 South = float2(UvCoord.x, UvCoord.y - Pixel.y);
float2 West = float2(UvCoord.x + Pixel.x, UvCoord.y);
float2 East = float2(UvCoord.x - Pixel.x, UvCoord.y);
float2 DepthNorth = float2(UvCoord.x, UvCoord.y + DepthPixel.y);
float2 DepthSouth = float2(UvCoord.x, UvCoord.y - DepthPixel.y);
float2 DepthWest = float2(UvCoord.x + DepthPixel.x, UvCoord.y);
float2 DepthEast = float2(UvCoord.x - DepthPixel.x, UvCoord.y);
// Choose luma coefficient
float3 LumaCoefficient;
if (Coefficient == 0)
{
LumaCoefficient = float3( 0.2126, 0.7152, 0.0722); // BT.709 Luma
}
else
{
LumaCoefficient = float3( 0.299, 0.587, 0.114); // BT.601 Luma
}
// Luma high-pass color
float HighPassColor;
HighPassColor = Luma(tex2D(SamplerColor, North).rgb, LumaCoefficient);
HighPassColor += Luma(tex2D(SamplerColor, South).rgb, LumaCoefficient);
HighPassColor += Luma(tex2D(SamplerColor, West).rgb, LumaCoefficient);
HighPassColor += Luma(tex2D(SamplerColor, East).rgb, LumaCoefficient);
HighPassColor *= 0.25;
HighPassColor = 1 - HighPassColor;
HighPassColor = (HighPassColor + Luma(Source, LumaCoefficient)) * 0.5;
// Luma high-pass depth
float DepthMask;
DepthMask = tex2D(SamplerDepth, DepthNorth).r;
DepthMask += tex2D(SamplerDepth, DepthSouth).r;
DepthMask += tex2D(SamplerDepth, DepthWest).r;
DepthMask += tex2D(SamplerDepth, DepthEast).r;
DepthMask *= 0.25;
DepthMask = 1.0 - DepthMask;
DepthMask = (DepthMask + SourceDepth);
DepthMask = min(1.0, DepthMask) + 1.0 - max(1.0, DepthMask);
DepthMask = 1.0 - Contrast * (1.0 - DepthMask);
DepthMask = saturate(DepthMask);
// Sharpen strength
HighPassColor = lerp(0.5, HighPassColor, Strength * DepthMask);
// Clamping sharpen
HighPassColor = min(HighPassColor, Clamp);
HighPassColor = max(HighPassColor, 1 - Clamp);
float3 Sharpen;
Sharpen.r = Overlay(Source.r, HighPassColor);
Sharpen.g = Overlay(Source.g, HighPassColor);
Sharpen.b = Overlay(Source.b, HighPassColor);
if (Preview) // Preview mode ON
{
float PreviewChannel = lerp(HighPassColor, HighPassColor * DepthMask, 0.5);
return float3(
1.0 - DepthMask * (1.0 - HighPassColor),
PreviewChannel,
PreviewChannel
);
}
else
{
return Sharpen;
}
}
technique FilmicAnamorphSharpen
{
pass
{
VertexShader = PostProcessVS;
PixelShader = FilmicAnamorphSharpenPS;
}
}
Please Log in or Create an account to join the conversation.
- Chavolatra
Panavision one and one with depth mask are two different sharpen effects. But I would suggest to use the Panavison one, since it solves the problem that Sunesha mentioned in the video in a more automatic way.Chavolatra wrote: it is last version ?
Please Log in or Create an account to join the conversation.
- Zarathustra
When I used it for Civ 6, I noticed that it accentuates white edges more than the default LumaSharpen filter, which I prefer in that case.
The accentuated bright edges are maybe something to look out for and I guess it depends primarily on the use case and personal preference which filter to use.
Please Log in or Create an account to join the conversation.
- Scorpio82CO
Please Log in or Create an account to join the conversation.