Best way to add a Normal Power Slider for Surface Shader?

Hey Guys,

I’m just wondering what the best/most accurate way is to create a Normal scale slider (similar to the Unity Standard shader one). Ideally one that can go from 0 - 3 or even more. I have tried a couple of different ways with mixed results. I have looked briefly at the way Unity does it in their shader but I didnt really understand how to replicate it.

Any help would be great!

Here are some examples on the methods I have tried.

sampler2D _MainTex;
        sampler2D _BumpMap;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _BumpScale;
        half _Metallic;
        fixed4 _Color;
        half3 _NormalDefault;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;

            //Method 1
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex) *_BumpScale);

            //Method 2
            //_NormalDefault = Half3(128, 128, 255) --found these values online
            o.Normal = lerp(_NormalDefault, UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex)), _BumpScale);


            //fallback method
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
            //o.Normal = _NormalDefault;
            o.Alpha = c.a;
        }

UnityStandardUtils.cginc has the one that the Standard shaders use.

half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
{
    #if defined(UNITY_NO_DXT5nm)
        return packednormal.xyz * 2 - 1;
    #else
        half3 normal;
        normal.xy = (packednormal.wy * 2 - 1);
        #if (SHADER_TARGET >= 30)
            // SM2.0: instruction count limitation
            // SM2.0: normal scaler is not supported
            normal.xy *= bumpScale;
        #endif
        normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
        return normal;
    #endif
}

The lerp method in your example can work as well, except your _NormalDefault value is for the values of an 8 bit normal map texture, not the actual tangent space normal direction which o.Normal expects and UnpackNormal() returns.

You could try:
o.Normal = lerp(half3(0.0, 0.0, 1.0), UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex), _BumpScale);

3 Likes

Great Thanks that works , I must have missed that!