Search Unity

Normal mapped surfaces aren't working correctly. Light from wrong direction

Discussion in 'Shaders' started by SoftwareGeezers, Jul 28, 2014.

  1. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    902
    I'm trying to create a custom shader and found that what works with a stationary object fails when it starts to rotate in 3 dimensions. The normal map reflects light from the wrong direction, as if the light direction is following the object's rotation. I then tried the in-built Normal/Specular shader and found it has the same problem.

    My scene is lit with a single directional light from 'top right'. If the attached normal map is added to a Bumped Specular material and applied to a sphere, and the sphere rotated, the major crater can be lit on the wrong side opposite the light source. It's like the light is spinning twice as fast as the rock.

    Here's my shader code, although as I say, the default exhibits the same behaviour.

    Code (csharp):
    1.  
    2. Shader "SG/_rockShader" {
    3.    // Applies base colour, texture, and specular normals
    4.    Properties {
    5.      _BaseColour ("Base colour", Color) = (1,1,1,1)
    6.      _MainTex ("Base (RGB)", 2D) = "white" {}
    7.      _NormalTex ("Normal map", 2D) = "bump" {}
    8.      _SpecColour ("Specular colour", Color) = (1,1,1,1)
    9.      _SpecPower ("Specular power", Range (0.0,2.0)) = 0.5
    10.    }
    11.    SubShader {
    12.      Tags { "RenderType"="Opaque" }
    13.      LOD 200
    14.      
    15.      CGPROGRAM
    16.      #pragma surface surf BlinnPhongBaseIllumination
    17.    
    18.      fixed4 _BaseColour;
    19.      sampler2D _MainTex;
    20.      sampler2D _NormalTex;
    21.      fixed4 _SpecColour;
    22.      half _SpecPower;
    23.      
    24.      inline fixed4 LightingBlinnPhongBaseIllumination (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
    25.     half3 h = normalize (lightDir + viewDir);
    26.        fixed diff = max (0, dot (s.Normal, lightDir));
    27.     float nh = max (0, dot (s.Normal, h));
    28.        float spec = pow (nh, s.Specular*16.0);// * s.Gloss;
    29.        fixed4 c;
    30.        c.rgb = _BaseColour;
    31.        c.rgb += (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColour.rgb * spec) * (atten * 2);
    32.        c.a = 0;
    33.        return c;
    34.      }
    35.  
    36.      struct Input {
    37.        float2 uv_MainTex;
    38.      };
    39.  
    40.      void surf (Input IN, inout SurfaceOutput o) {
    41.        fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    42.        o.Albedo = c.rgb;
    43.        o.Alpha = 0;
    44.        o.Normal = UnpackNormal(tex2D (_NormalTex, IN.uv_MainTex));
    45.        o.Specular = _SpecPower;
    46.        o.Gloss = 1;
    47.      }
    48.      ENDCG
    49.    }
    50.    FallBack "Diffuse"
    51. }
     

    Attached Files:

  2. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    350
    Try to invert red channel of the texture.
     
  3. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Generally it's the green channel that gets inverted.
     
  4. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    902
    You're both right! The normal map was wrong (inverted light source) when I imported it, so I inverted both red and green. That caused the light to rotate twice speed, as it were. I have now flipped back the red to starting point and it works as it should. So mouurusai was right with the fix, and Farfarer was right with what one should do and what I should have done in the first place. Thanks!