Is it possible to set a saturation limit / threshold for colors ?

  • Posts: 2
2 months 1 day ago #1 by yamgo
Does a shader exist that allows you to set a saturation limit for colors? I'd like any color that is over that limit to be desaturated, without affecting any colors under the limit. Kind of equalize the colors to be on the same level. I've tried around with many shaders, but the only color adjustments I can find adjust the colors across the board and not only the oversaturated ones.

Please Log in or Create an account to join the conversation.

  • Posts: 3
1 month 4 weeks ago - 1 month 4 weeks ago #2 by onestalkyboi
quint lightroom shader

Please Log in or Create an account to join the conversation.

  • Posts: 42
1 month 3 weeks ago #3 by Marty
Or better, Prod80's shaders. They work far better than lightroom imo.

Please Log in or Create an account to join the conversation.

  • Posts: 122
1 month 3 weeks ago #4 by prod80

yamgo wrote: Does a shader exist that allows you to set a saturation limit for colors? I'd like any color that is over that limit to be desaturated, without affecting any colors under the limit. Kind of equalize the colors to be on the same level. I've tried around with many shaders, but the only color adjustments I can find adjust the colors across the board and not only the oversaturated ones.


There's no shader that only affects those colors that are over a certain "saturation" limit, only shaders that set a limit but will affects everything up to that point too (ie- normal saturation effect).

It can be done, what you want, using HSV color space instead of RGB. But would like to understand what you're trying to achieve.

Also you have to understand, such shader will basically reduce the bit depth of any color particularly at the set limit (ie gradients will turn flat - single color - at the limit), and you may/will get banding artifacts.

Please Log in or Create an account to join the conversation.

  • Posts: 122
1 month 3 weeks ago #5 by prod80
Here you go, this should do exactly what you want.
#include "ReShade.fxh"
#include "ReShadeUI.fxh"

namespace pd80_satlimit
{
    //// PREPROCESSOR DEFINITIONS ///////////////////////////////////////////////////

    //// UI ELEMENTS ////////////////////////////////////////////////////////////////
    uniform float saturation_limit <
        ui_type = "slider";
        ui_label = "Saturation Limit";
        ui_tooltip = "Saturation Limit";
        ui_min = 0.0;
        ui_max = 1.0;
        > = 1.0;
    //// TEXTURES ///////////////////////////////////////////////////////////////////
    
    //// SAMPLERS ///////////////////////////////////////////////////////////////////

    //// DEFINES ////////////////////////////////////////////////////////////////////

    //// FUNCTIONS //////////////////////////////////////////////////////////////////
    float3 HUEToRGB( in float H )
    {
        return saturate( float3( abs( H * 6.0f - 3.0f ) - 1.0f,
                                    2.0f - abs( H * 6.0f - 2.0f ),
                                    2.0f - abs( H * 6.0f - 4.0f )));
    }

    float3 RGBToHCV( in float3 RGB )
    {
        // Based on work by Sam Hocevar and Emil Persson
        float4 P         = ( RGB.g < RGB.b ) ? float4( RGB.bg, -1.0f, 2.0f/3.0f ) : float4( RGB.gb, 0.0f, -1.0f/3.0f );
        float4 Q1        = ( RGB.r < P.x ) ? float4( P.xyw, RGB.r ) : float4( RGB.r, P.yzx );
        float C          = Q1.x - min( Q1.w, Q1.y );
        float H          = abs(( Q1.w - Q1.y ) / ( 6.0f * C + 0.000001f ) + Q1.z );
        return float3( H, C, Q1.x );
    }

    float3 RGBToHSL( in float3 RGB )
    {
        RGB.xyz          = max( RGB.xyz, 0.000001f );
        float3 HCV       = RGBToHCV(RGB);
        float L          = HCV.z - HCV.y * 0.5f;
        float S          = HCV.y / ( 1.0f - abs( L * 2.0f - 1.0f ) + 0.000001f);
        return float3( HCV.x, S, L );
    }

    float3 HSLToRGB( in float3 HSL )
    {
        float3 RGB       = HUEToRGB(HSL.x);
        float C          = (1.0f - abs(2.0f * HSL.z - 1.0f)) * HSL.y;
        return ( RGB - 0.5f ) * C + HSL.z;
    }

    //// PIXEL SHADERS //////////////////////////////////////////////////////////////
    float4 PS_Satlimit(float4 pos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
    {
	float3 color = tex2D( ReShade::BackBuffer, texcoord ).xyz;
	color.xyz = RGBToHSL( color.xyz );
	color.y = min( color.y, saturation_limit );
        color.xyz = HSLToRGB( color.xyz );
        return float4( color.xyz, 1.0f );
    }

    //// TECHNIQUES /////////////////////////////////////////////////////////////////
    technique prod80_Saturation_Limiter
    {
        pass prod80_pass0
        {
            VertexShader   = PostProcessVS;
            PixelShader    = PS_Satlimit;
        }
    }
}
The following user(s) said Thank You: Faustus86

Please Log in or Create an account to join the conversation.

  • Posts: 2
1 month 2 weeks ago #6 by yamgo
This is fantastic, thank you!

Is the same thing possible with brightness? I'd like everything over a certain brightness limit to be darkened.

Please Log in or Create an account to join the conversation.

  • Posts: 122
1 month 2 weeks ago - 1 month 2 weeks ago #7 by prod80

yamgo wrote: This is fantastic, thank you!

Is the same thing possible with brightness? I'd like everything over a certain brightness limit to be darkened.


[snip]
Scrapped that stuff. Because lowering Luminance in HSL will cause Saturation to go up when transforming back to RGB.

Would just use a Levels shader after, and reduce whitepoint.

Please Log in or Create an account to join the conversation.