Search code examples
unity-game-engine3dshader

Simple double sided custom shader looks strange


I'm very new to Shaders programming, I was trying to create a shader which:

  • Allows to change 2 textures with 2 corresponding normal maps (fade in/fade out)
  • Doublesided (show mesh from both sides of the surface)

Here is what I end up with:

  Shader "Custom/TextureBlend" {
         Properties {
             _Color ("Color", Color) = (1,1,1,1)
             _Blend ("Texture Blend", Range(0,1)) = 0.0
             _MainTex ("Albedo (RGB)", 2D) = "white" {}
             _MainTex2 ("Albedo 2 (RGB)", 2D) = "white" {}
             _Glossiness ("Smoothness", Range(0,1)) = 0.5
             _Metallic ("Metallic", Range(0,1)) = 0.0
             _BumpMap ("Bumpmap", 2D) = "bump" {}
             _BumpMap2 ("Bumpmap", 2D) = "bump" {}
         }
         SubShader {
             Tags { "RenderType"="Opaque" }
             LOD 200
              Cull Off
              ZTest LEqual

             CGPROGRAM
             // Physically based Standard lighting model, and enable shadows on all light types
             #pragma surface surf Standard fullforwardshadows

             // Use shader model 3.0 target, to get nicer looking lighting
             #pragma target 3.0

             sampler2D _MainTex;
             sampler2D _MainTex2;
             sampler2D _BumpMap;
             sampler2D _BumpMap2;

             struct Input {
                 float2 uv_MainTex;
                 float2 uv_MainTex2;
                 float2 uv_BumpMap;
                 float2 uv_BumpMap2;
             };

             half _Blend;
             half _Glossiness;
             half _Metallic;
             fixed4 _Color;

             void surf (Input IN, inout SurfaceOutputStandard o) {
                 // Albedo comes from a texture tinted by color
                 fixed4 c = lerp (tex2D (_MainTex, IN.uv_MainTex), tex2D (_MainTex2, IN.uv_MainTex2), _Blend) * _Color;
                 o.Albedo = c.rgb;
                 // Metallic and smoothness come from slider variables
                 o.Metallic = _Metallic;
                 o.Smoothness = _Glossiness;
                 o.Alpha = c.a;
                 fixed4 n = lerp (tex2D (_BumpMap, IN.uv_BumpMap), tex2D (_BumpMap2, IN.uv_BumpMap2), _Blend) * _Color;
                 o.Normal = n.rgb;
             }
             ENDCG
         }
         FallBack "Diffuse"
     }

It works but for some reason the texture on the surface looks dim (on the other side of the mesh which usually invisible it's even darker), and normal map reflections barely visible.

Here, on the left you can see the plane with my shader, on the right - standard shader:

enter image description here

Also the reflection looks really strange, if I will move Metallic slider to the right you will see it:

enter image description here


Solution

  • Normal maps store vector information while regular textures are unsigned, so you need to use the UnpackNormal() helper method as shown in the samples. You also don't need to multiply by Color.

    final code would then be along the lines of:

    fixed4 n0 = tex2D(_BumpMap, IN.uv_BumpMap);
    fixed4 n1 = tex2D(_BumpMap2, IN.uv_BumpMap2);
    o.Normal = UnpackNormal(lerp(n0, n1, _Blend)).xyz;