"Fading in" a Normal Map

Hello all!

I’m currently attempting to “fade in” lighting information via a normal map in a surface shader. We’re using forward rendering and gamma space lighting as well as static and dynamic batching. I won’t get into the specifics for our choices unless somehow they impact the solution to my problem. The shader interpolates between the colours of two textures and as the _LerpAmt approaches 1, the normal map should “fade in”. I’m using this to blend in some procedural detail as the camera comes closer while allowing me to blend the high detail colour/normal information with a lower resolution base texture (essentially a compositor). The approach I took is that I’m lerping the normal vector from “straight up” to the desired direction specified by the normal map using a shader constant with a range [0,1].

So here’s my issue: the shader which I’ve written seems to work as I expect in the preview window while the game isn’t running and an example of the desired effect is shown below.

alt text

Now, when running the game the amount at which the geometry is lit appears to start at gray and go to full white as _LerpAmt approaches 1. I’ve made sure that the material’s colour is set to full white (1, 1, 1, 1) when I instantiate the geometry. The light I’m using is a global directional light with a colour of (1, 1, 1, 1), an intensity of 0.5 and a strength of 1: I first thought that the intensity was an issue however, if I increase the intensity at all the colours become blown out when _LerpAmt approaches 1 (the higher the intensity, the sooner the colours become blown out, as expected).

Now, here’s the kicker. If I remove the LERP for the normal map information (and just use the unpacknormal for o.Normal) there is no change in the amount of light the surface receives. I’ve attached the shader as a code snippet below!

So anyone with some experience in these matters know what the problem may be? Thanks!


Shader "theshader"
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _DetailTex ("Detail (RGB)", 2D) = "white" {}
        _DetailNormal ("Detail Normal (RGB)", 2D) = "white" {}
        _TopLeft ("UVs into Base (Bottom, Left, Top, Right)", VECTOR) = (0, 0, 1, 1)
        _LerpAmt ("Interpolation between Base and Detail", Range (0, 1)) = 0
    }

    SubShader
    {
        Tags { "Queue"="Geometry" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        float4 _TopLeft;
        sampler2D _DetailTex;
        sampler2D _DetailNormal;
        float _LerpAmt;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_DetailTex;
            float2 uv_DetailNormal;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            //Find our UV offset into the base texture
            float2 uvs = lerp(_TopLeft.xy, _TopLeft.zw, IN.uv_MainTex);
            half4 c = tex2D(_MainTex, uvs);
            c = lerp(c, tex2D(_DetailTex, IN.uv_DetailTex), clamp(sqrt(_LerpAmt) + (1f - c.a), 0, 1));
            o.Albedo = c.rgb;
            o.Alpha = c.a;
            float3 norm1 = UnpackNormal(tex2D(_DetailNormal, IN.uv_DetailNormal));
            o.Normal = normalize(lerp(float3(0.5, 0.5, 1), norm1, sqrt(_LerpAmt)));
        }
        ENDCG
    }
    FallBack "Diffuse"
}

o.Normal = normalize(lerp(float3(0, 0, 1), norm1, sqrt(_LerpAmt)));

try this

why not

float3 norm1 = UnpackNormal(tex2D(_DetailNormal, IN.uv_DetailNormal));
float3 norm1Scaled = (norm1 - float3(0.5, 0.5, 1)) * _LerpAmt;
o.Normal = normalize(float3(0.5, 0.5, 1) + norm1Scaled);

I have not tested it, but sounds good for me. Of yourse you have to apply the easing curve to LerpAmt outside of the shader.