How do I make this shader accept the default unity lighting?

Hey everyone,
I’ve been using this shader by beeky on the forums, that allows me to change the hue and saturation of my diffuse textures (http://forum.unity3d.com/threads/89041-Problem-with-getting-hue-shift-shader-right.)

I did some modifications to make it work as opaque instead of transparent, but now I have the problem it’s showing up fullbright in my game. I’m not experienced at all in shader writing and have been going through a lot of documentation to find the answer, but it’s all a bit confusing right now :s.

If anyone can help me find a quick solution to this, that would be awesome!
This is the current shader code:

 Shader "HSB_HSV_Colorpicker" {
  Properties {
  	  _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
      _MainTex ("Texture", 2D) = "white" {}
      _HueShift("HueShift", Range(0,1) ) = 0
      _Sat("Saturation", Range(0, 1)) = 0
    }
    SubShader {
    
    	
      //Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType" = "Transparent" }
	  Tags { "RenderType" = "Opaque" }
      //ZWrite Off
      Blend SrcAlpha OneMinusSrcAlpha
      Cull Off
	  //Lighting On
      
    Pass
    {
      CGPROGRAM
	  #pragma vertex vert
      #pragma fragment surf Lambert
      #pragma target 3.0
      
      #include "UnityCG.cginc"
	  //Lighting On
         
	struct v2f {
		float4  pos : SV_POSITION;
		float2  uv : TEXCOORD;
	};

	float4 _MainTex_ST;
         
	v2f vert (appdata_base v)
	{
	    v2f o = (v2f)0;
	    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
	    o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
	    return o;
	}
	 
	float3 rgb_to_hsv_no_clip(float3 RGB)
	{
		float3 HSV = 0;
		
		float minChannel, maxChannel;
		
		maxChannel = max(RGB.x, RGB.y);
		minChannel = min(RGB.x, RGB.y);
		
		maxChannel = max(RGB.z, maxChannel);
		minChannel = min(RGB.z, minChannel);
		
		HSV.z = maxChannel;
		
		float delta = maxChannel - minChannel;    //Delta RGB value
		
		HSV.y = delta / HSV.z;
		float3 delRGB = (HSV.zzz - RGB + 3*delta) / (6*delta);
		if ( RGB.x == HSV.z ) HSV.x = delRGB.z - delRGB.y;
		if ( RGB.y == HSV.z ) HSV.x = ( 1.0 / 3.0 ) + delRGB.x - delRGB.z;
		if ( RGB.z == HSV.z ) HSV.x = ( 2.0 / 3.0 ) + delRGB.y - delRGB.x;
		
		return (HSV);
	}
	
	float3 hsv_to_rgb(float3 HSV)
	{
		float var_h = HSV.x * 6;
		
		float var_1 = HSV.z * ( 1.0 - HSV.y );
		float var_2 = HSV.z * ( 1.0 - HSV.y * (var_h-floor( var_h )));
		float var_3 = HSV.z * ( 1.0 - HSV.y * (1-(var_h-floor( var_h ))));
		
		float3 RGB = float3(HSV.z, var_1, var_2);
		
		if (var_h < 5) 	{ RGB = float3(var_3, var_1, HSV.z); }
		if (var_h < 4) 	{ RGB = float3(var_1, var_2, HSV.z); }
		if (var_h < 3) 	{ RGB = float3(var_1, HSV.z, var_3); }
		if (var_h < 2) 	{ RGB = float3(var_2, HSV.z, var_1); }
		if (var_h < 1) 	{ RGB = float3(HSV.z, var_3, var_1); }
	    
		return (RGB);
	}

	struct Input 
	{
	  float2 uv_MainTex : TEXCOORD;
	};
	
	sampler2D _MainTex;
	float _HueShift;
	float _Sat;
	
	half4 surf (Input IN) : COLOR
	{
	  half4 col = tex2D (_MainTex, IN.uv_MainTex);
	 
	  float3 hsv = rgb_to_hsv_no_clip(col.xyz);
	  hsv.x += _HueShift;
	  hsv.y *= _Sat;
	  
	  if ( hsv.x > 1.0 ) { hsv.x -= 1.0; }
	  return half4( half3(hsv_to_rgb(hsv) ), col.a);
	}
     
      ENDCG
    }
    }
    Fallback "Diffuse"
}

Try it out, it works really well, except it shows up fullbright. If anyone has any fix to make it accept the default lighting, it would be much appreciated! Thanks :).

I think you may be starting from the wrong direction. The shader you have is explicitly designed for doing an HSV color picker, and it is well tuned for that. But if what you want is a Diffuse shader that has controls for Hue and Saturation, you should start with the Unity Diffuse shader and make that small change.

You can download the Unity shaders here, then in Normal-Diffuse.shader where you see this:

fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;

you will after this add your modification to change c, which from the code you paste above would be:

float3 hsv = rgb_to_hsv_no_clip(c.xyz);
hsv.x += _HueShift;
hsv.y *= _Sat;

if ( hsv.x > 1.0 ) { hsv.x -= 1.0; }
c = float4( hsv_to_rgb(hsv), c.a);

Of course, keep the functions which this added code refers to.

Voila! You’ve edited a Unity shader. Now that you’ve done it for Diffuse, you also know how to do it for Specular and many of the other shaders.

Thanks a lot! I got it working now, and this helped me understand a lot better how a shader is built up :). The next thing I want to try is make it only hueshift parts that are masked in the alpha. I think I can figure that out by myself. Thanks again!

I wasn’t able to get this working with Unity 4.3. However, after an evening of hacking I did come up with a solution that support diffuse lighting, normal maps and adjustable brightness, saturation and contrast. It was a pain to find so I’m posting it here.

    Shader "SBCLit" {
        Properties {
            _Color ("Main Color", Color) = (1,1,1,1)
            _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
            _Shininess ("Shininess", Range (0.03, 1)) = 0.078125
            _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
            _BumpMap ("Normalmap", 2D) = "bump" {}
			_SaturationAmount ("Saturation Amount", Range(0.0, 2.0)) = 1.0
			_BrightnessAmount ("Brightness Amount", Range(0.0, 5.0)) = 1.0
			_ContrastAmount ("Contrast Amount", Range(0.0,2.0)) = 1.0              
        }
        SubShader {
            Tags {"Queue" = "Geometry" "RenderType" = "Opaque"}
     
            Pass {
                Tags {"LightMode" = "ForwardBase"}                      // This Pass tag is important or Unity may not give it the correct light information.
                CGPROGRAM
                    #pragma vertex vert
                    #pragma fragment frag
                    #pragma multi_compile_fwdbase                       // This line tells Unity to compile this pass for forward base.
                    #pragma fragmentoption ARB_fog_exp2
                    #pragma fragmentoption ARB_precision_hint_fastest
                    #pragma target 3.0
                   
                    #include "UnityCG.cginc"
                    #include "AutoLight.cginc"
                    
					uniform float _SaturationAmount;
					uniform float _BrightnessAmount;
					uniform float _ContrastAmount;                    
                   
			float3 ContrastSaturationBrightness( float3 color, float brt, float sat, float con)
			{
				//RGB Color Channels
				float AvgLumR = 0.5;
				float AvgLumG = 0.5;
				float AvgLumB = 0.5;
				
				//Luminace Coefficients for brightness of image
				float3 LuminaceCoeff = float3(0.2125,0.7154,0.0721);
				
				//Brigntess calculations
				float3 AvgLumin = float3(AvgLumR,AvgLumG,AvgLumB);
				float3 brtColor = color * brt;
				float intensityf = dot(brtColor, LuminaceCoeff);
				float3 intensity = float3(intensityf, intensityf, intensityf);
				
				//Saturation calculation
				float3 satColor = lerp(intensity, brtColor, sat);
				
				//Contrast calculations
				float3 conColor = lerp(AvgLumin, satColor, con);
				
				return conColor;
				
			}
                   
                   
                    struct v2f
                    {
                        float4  pos         : SV_POSITION;
                        float2  uv          : TEXCOORD0;
                        float3  viewDir     : TEXCOORD1;
                        float3  lightDir    : TEXCOORD2;
                        LIGHTING_COORDS(3,4)                            // Macro to send shadow & attenuation to the vertex shader.
                    };
     
                    v2f vert (appdata_tan v)
                    {
                        v2f o;
                       
                        o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
                        o.uv = v.texcoord.xy;
                        TANGENT_SPACE_ROTATION;                         // Macro for unity to build the Object>Tangent rotation matrix "rotation".
                        o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex));
                        o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
     
                        TRANSFER_VERTEX_TO_FRAGMENT(o);                 // Macro to send shadow & attenuation to the fragment shader.
                        return o;
                    }
     
                    sampler2D _MainTex;
                    sampler2D _BumpMap;
                    fixed4 _Color;
                    half _Shininess;
     
                    fixed4 _SpecColor;
                    fixed4 _LightColor0; // Colour of the light used in this pass.
                    
                    fixed4 frag(v2f i) : COLOR
                    {
                        i.viewDir = normalize(i.viewDir);
                        i.lightDir = normalize(i.lightDir);
                       
                        fixed atten = LIGHT_ATTENUATION(i); // Macro to get you the combined shadow & attenuation value.
     
                        fixed4 tex = tex2D(_MainTex, i.uv);
                        fixed gloss = tex.a;
                        tex *= _Color;
                        fixed3 normal = UnpackNormal(tex2D(_BumpMap, i.uv));
     
                        half3 h = normalize(i.lightDir + i.viewDir);
                       
                        fixed diff = saturate(dot(normal, i.lightDir));
                       
                        float nh = saturate(dot (normal, h));
                        float spec = pow(nh, _Shininess * 128.0) * gloss;
                       
                        fixed4 c;
                        c.rgb = UNITY_LIGHTMODEL_AMBIENT.rgb * 2 * tex.rgb;         // Ambient term. Only do this in Forward Base. It only needs calculating once.
                        c.rgb += (tex.rgb * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2); // Diffuse and specular.
				
						c.rgb += ContrastSaturationBrightness(c.rgb, _BrightnessAmount, _SaturationAmount, _ContrastAmount);                         
                        
                        c.a = tex.a + _LightColor0.a * _SpecColor.a * spec * atten;
                        return c;
                    }
                ENDCG
            }
     
            Pass {
                Tags {"LightMode" = "ForwardAdd"}                       // Again, this pass tag is important otherwise Unity may not give the correct light information.
                Blend One One                                           // Additively blend this pass with the previous one(s). This pass gets run once per pixel light.
                CGPROGRAM
                    #pragma vertex vert
                    #pragma fragment frag
                    #pragma multi_compile_fwdadd                        // This line tells Unity to compile this pass for forward add, giving attenuation information for the light.
                    //#pragma multi_compile_fwdadd_fullshadows                      // This line tells Unity to compile this pass for forward add and give shadow information as well as attenuation. Swap this line for the one above if you want forward add with shadows.
                    #pragma fragmentoption ARB_fog_exp2
                    #pragma fragmentoption ARB_precision_hint_fastest
                    #pragma target 3.0
                   
                    #include "UnityCG.cginc"
                    #include "AutoLight.cginc"
                   
                    struct v2f
                    {
                        float4  pos         : SV_POSITION;
                        float2  uv          : TEXCOORD0;
                        float3  viewDir     : TEXCOORD1;
                        float3  lightDir    : TEXCOORD2;
                        LIGHTING_COORDS(3,4)                            // Macro to send shadow & attenuation to the vertex shader.
                    };
     
                    v2f vert (appdata_tan v)
                    {
                        v2f o;
                       
                        o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
                        o.uv = v.texcoord.xy;
                        TANGENT_SPACE_ROTATION;                         // Macro for unity to build the Object>Tangent rotation matrix "rotation".
                        o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex));
                        o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
     
                        TRANSFER_VERTEX_TO_FRAGMENT(o);                 // Macro to send shadow & attenuation to the fragment shader.
                        return o;
                    }
     
                    sampler2D _MainTex;
                    sampler2D _BumpMap;
                    fixed4 _Color;
                    half _Shininess;
     
                    fixed4 _SpecColor;
                    fixed4 _LightColor0; // Colour of the light used in this pass.
     
                    fixed4 frag(v2f i) : COLOR
                    {
                        i.viewDir = normalize(i.viewDir);
                        i.lightDir = normalize(i.lightDir);
                       
                        fixed atten = LIGHT_ATTENUATION(i); // Macro to get you the combined shadow & attenuation value.
     
                        fixed4 tex = tex2D(_MainTex, i.uv);
                        fixed gloss = tex.a;
                        tex *= _Color;
                        fixed3 normal = UnpackNormal(tex2D(_BumpMap, i.uv));
     
                        half3 h = normalize(i.lightDir + i.viewDir);
                       
                        fixed diff = saturate(dot(normal, i.lightDir));
                       
                        float nh = saturate(dot (normal, h));
                        float spec = pow(nh, _Shininess * 128.0) * gloss;
                       
                        fixed4 c;
                        c.rgb = (tex.rgb * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2); // Diffuse and specular.
                        c.a = tex.a + _LightColor0.a * _SpecColor.a * spec * atten;
                        return c;
                    }
                ENDCG
            }
        }
        FallBack "VertexLit"    // Use VertexLit's shadow caster/receiver passes.
    }