[SHADER] Lerp a color into a grayscale range

Hi everyone,

I want to lerp a color into a gray scale range. The gray scale is a single texture channel.
2910585--214568--Untitled-1.jpg

The additional color should be fade in and out at some predefined values. In this case 0.2 - 0.5. But should be also anything else inside 0 and 1. Between in and out the transition should be linear simply.

Does anyone has an idear to solve this in a fast way in shader code?
Thanks a lot…

I honestly don’t understand quite what you’re asking for. As best I can understand you have a grayscale texture and you want to colorize a range of values of that texture?

fixed g = tex2D(_GreyTex, i.uv).g;

// rescale the range 0.2 … 0.5 to 0.0 … 1.0
fixed desaturation = saturate((g - 0.2) / (0.5 - 0.2));

// change 0.0 … 0.5 … 1.0 to 1.0 … 0.0 … 1.0
desaturation = abs(c * 2.0 - 1.0);

// lerp between grey and colorized grey
fixed3 col = lerp(g * _Color.rgb, fixed3(g, g, g), desaturation);

2 Likes

Yes :slight_smile: Unfortunately there is anything wrong in the code…
I think should it be ?
desaturation = abs(desaturation * 2.0 - 1.0);

And it doesn’t matter what values are uses as from/to the result stays nearly the same strange wise.
2910868--214610--Untitled-2.jpg

Here is the shader code and texture to test.

Shader "Custom/U5_NFSPlaza" {
    Properties{

    [NoScaleOffset] _MainTex("MainTex(RGB)", 2D) = "white" {}
    _Color("Colorize", Color) = (0.2, 0.2, 1, 1)

    }
        SubShader{
        Tags{ "RenderType" = "Opaque" }
        LOD 200
        CGPROGRAM

#pragma surface surf StandardSpecular vertex:vert //fullforwardshadows
#pragma target 3.0

    struct Input {
        half2 uv_MainTex;
        half3 worldPos;
        INTERNAL_DATA
    };

    sampler2D   _MainTex;
    half4 _Color;

    void vert(inout appdata_full v, out Input o) {
        UNITY_SETUP_INSTANCE_ID(v);
        UNITY_INITIALIZE_OUTPUT(Input,o);
    }

    void surf(Input IN, inout SurfaceOutputStandardSpecular o) {

        fixed3 main = tex2D(_MainTex, IN.worldPos.xz * 1.2);

        fixed lo = 0.0;
        fixed hi = 1.0;

        // rescale the range 0.2 .. 0.5 to 0.0 .. 1.0
        fixed desaturation = saturate((main.g - lo) / (hi - lo));

        // change 0.0 .. 0.5 .. 1.0 to 1.0 .. 0.0 .. 1.0
        desaturation = abs((desaturation * 2.0) - 1.0);

        // lerp between grey and colorized grey
        fixed3 col = lerp(main * _Color.rgb, fixed3(main.g, main.g, main.g), desaturation);
        o.Albedo = col;

        o.Specular = 0.001; //lowest possible
        o.Smoothness = 0;

    }
    ENDCG
    }
        FallBack "Diffuse"
}

2910828--214608--gradient.jpg

Okay… I’m working in linear mode. The gradient itself looks correct in the scene.
Center gray values are about 0.5 or 128 in the center texture.

low = 0 and high 1 values in the function moves the max color center to the lighter values.
I expected they should near the center position.

2910868--214610--Untitled-2.jpg

Hmm… didn’t understand exactly why this happen.

Edit:
I got a nearly perfect result with :
fixed desaturation = saturate(abs(((main - lo) / (hi - lo))));
fixed3 col = lerp(main * _Color.rgb, fixed3(main.g, main.g, main.g), desaturation);

Thanks a lot!

Ah … because “0.5” or 128/255 in the shader isn’t where you think it is when you’re using the linear color space. Where 128 / 255 appears in the texture (when checked in an image editor) will be ~0.72 in the shader because in linear rendering the texture is converted from sRGB to a linear color when the shader uses it.

You can set the texture to be linear (set it to texture type “Advanced” and click on “bypass sRGB”) then do this:

                fixed g = tex2D(_MainTex, i.uv).g;

                // rescale the range 0.2 .. 0.5 to 0.0 .. 1.0
                fixed desaturation = saturate((g - _A) / (_B - _A));

                // change 0.0 .. 0.5 .. 1.0 to 1.0 .. 0.0 .. 1.0
                desaturation = abs(desaturation * 2.0 - 1.0);

                // lerp between grey and colorized grey
                fixed3 col = lerp(g * _Color.rgb, fixed3(g, g, g), desaturation);
                if (!IsGammaSpace())
                    col = GammaToLinearSpace(col);

This will get identical results regardless of being in gamma or linear!

Alternatively you can keep the texture as is and do extra math in the shader, or do the same amount of math but have slightly different results from linear and gamma color space.

2 Likes

Unfortunately I got strange results >= 2019.2 If I use this shader in Linear with the old one:
Set the texture property to srgb texture = false gives better LO HI position results.

5465502--558717--Untitled-5.jpg

5465502--558720--Untitled-7.jpg