HLSL: RGB to HSV controls (WORKING)

Hi fabulous people, I’m fairly new coding HLSL.

I’m trying to influence the HUE of an Albedo and I found this way to do:

I implemented it, succeed for the Saturation and Value, working Great ! But the HUE won’t work.

Afterward I noticed that the input should be in degrees. What range should I expose for the slider ? Have we to declare this variable as a float ? or other type ?

Thx :slight_smile:

{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}
        _ColorizeTex ("Colorize", 2D) = "white" {}

        H ("Hue", Range(0.0, 1.1)) = 0            //should be degrees !!!
        S ("Saturation", Range(0.0, 1.0)) = 1.0 //Working great
        V ("Value", Range(0.0, 1.0)) = 1.0        //Working great

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
        
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Color;
            float4 BaseColor;

            float H;
            float S;
            float V;
            float PI = float(3.14159265);
 
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
        
            fixed4 frag (v2f i) : SV_Target
            {
                float VSU = float(V*S*cos(H*PI/180));
                float VSW = float(V*S*sin(H*PI/180));

                float4 BaseColor = tex2D(_MainTex, i.uv) *_Color;
              
                float retr = float((0.299*V+0.701*VSU+0.168*VSW)*BaseColor.r + (0.587*V-0.587*VSU+0.330*VSW)*BaseColor.g + (0.114*V-0.114*VSU-0.497*VSW)*BaseColor.b);
                float retg = float((0.299*V-0.299*VSU-0.328*VSW)*BaseColor.r + (0.587*V+0.413*VSU+0.035*VSW)*BaseColor.g + (0.114*V-0.114*VSU+0.292*VSW)*BaseColor.b);
                float retb = float((0.299*V-0.3*VSU+1.25*VSW)*BaseColor.r + (0.587*V-.588*VSU-1.05*VSW)*BaseColor.g + (0.114*V+.886*VSU-0.203*VSW)*BaseColor.b);

                fixed4 col = fixed4 (retr, retg, retb, 1);

                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}
float3 hsv_to_rgb(float3 HSV)
        {
                float3 RGB = HSV.z;
        
                   float var_h = HSV.x * 6;
                   float var_i = floor(var_h);   // Or ... var_i = floor( var_h )
                   float var_1 = HSV.z * (1.0 - HSV.y);
                   float var_2 = HSV.z * (1.0 - HSV.y * (var_h-var_i));
                   float var_3 = HSV.z * (1.0 - HSV.y * (1-(var_h-var_i)));
                   if      (var_i == 0) { RGB = float3(HSV.z, var_3, var_1); }
                   else if (var_i == 1) { RGB = float3(var_2, HSV.z, var_1); }
                   else if (var_i == 2) { RGB = float3(var_1, HSV.z, var_3); }
                   else if (var_i == 3) { RGB = float3(var_1, var_2, HSV.z); }
                   else if (var_i == 4) { RGB = float3(var_3, var_1, HSV.z); }
                   else                 { RGB = float3(HSV.z, var_1, var_2); }
        
           return (RGB);
        }

try that in reverse to get the HSV, from how to get hsv(hsb) color in shader

or converting these:

1 Like

Thx a lot @MadeFromPolygons_1
I had hardtime trying to fit your code (surface albedo) to a frag unlit (experience I need, indeed).

But, I tried to troubleshoot which value in my first implementation was doing nothing.
Now it’s working :smile: Hourra!

* of course it will be properly clean, if I’m setting the range of the slider from 0 to 1.0 and doing this 6.28 scale in the SIN and COS (H*6.28).

Here’s what I changed, the full code working below:

  • The definition of VSU and VSW pass SIN and COS on the HUE value entered with PI, etc… I simply put the HUE input direct to the SIN and COS
    float VSU = float(VScos(H));
    float VSW = float(VSsin(H));
  • Than manually (screenshot comparisons), found that the range for the HUE is 0 to 6.28 [yes, I can hear mathematician saying “haaaa, these little artists, lol”. But, it’s working, in this colorspace, lol]
Shader "DaPrato/Colorize_Unlit_Hue"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}
        H ("Hue", Range(0.0, 6.28)) = 0
        S ("Saturation", Range(0.0, 1.0)) = 1.0
        V ("Value", Range(0.0, 1.0)) = 1.0

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
         
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Color;
            float4 BaseColor;

            float H;
            float S;
            float V;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
 
            fixed4 frag (v2f i) : SV_Target
            {
                //cos and sin was on (H*PI/180)
                float VSU = float(V*S*cos(H));
                float VSW = float(V*S*sin(H));

                float4 BaseColor = tex2D(_MainTex, i.uv) *_Color;
               
                float retr = float((0.299*V+0.701*VSU+0.168*VSW)*BaseColor.r + (0.587*V-0.587*VSU+0.330*VSW)*BaseColor.g + (0.114*V-0.114*VSU-0.497*VSW)*BaseColor.b);
                float retg = float((0.299*V-0.299*VSU-0.328*VSW)*BaseColor.r + (0.587*V+0.413*VSU+0.035*VSW)*BaseColor.g + (0.114*V-0.114*VSU+0.292*VSW)*BaseColor.b);
                float retb = float((0.299*V-0.3*VSU+1.25*VSW)*BaseColor.r + (0.587*V-.588*VSU-1.05*VSW)*BaseColor.g + (0.114*V+.886*VSU-0.203*VSW)*BaseColor.b);

                fixed4 col = fixed4 (retr, retg, retb, 1);

                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}
2 Likes

Excellent work! thank you very much for detailing your fix process too :slight_smile:

1 Like