Search code examples
unity-game-engineshadercg

Shader trouble. Object is illuminated only from the side of the normal


Problems with this shader

Shader "Diffuse " {
Properties {
_Color("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}

}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 150
Cull Off

CGPROGRAM
#pragma surface surf Lambert noforwardadd

sampler2D _MainTex;
fixed4 _Color;

struct Input {
float2 uv_MainTex;
};

void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb * _Color;
o.Alpha = c.a;
}
ENDCG
}

Fallback "Mobile/VertexLit"
}

If you use this shader on the object's material, then the object is illuminated only from the side of the normal, and the opposite side remains unlit, even if you direct the light directly at it. What code to add to the shader, to light displayed on the opposite normal side, too? It works perfectly with the Nature / Tree Soft Occlusion Leaves shader, but this shader is very heavy and dependency to another, and another dependency to the other one shader. And,leaves shader contains a lot of excess there. The shader above is very lightweight and I would like to add something minimal, just to light cover two sides - the normal and the opposite of the normal. Normal and opposite-normal side with directional light. Cyan spikes is direction of normals


Solution

  • What exactly is it that you want to use this for? Is it for foliage?

    There are two options here: Either you create a Vertex Fragment shader instead of a Surface shader, and code the lighting yourself (using abs(NdotL) instead of saturate(NdotL)), or you implement your own lighting function.

    If you want to stick with surface shaders, create a new function like this:

    #include "UnityCG.cginc"
    half4 LightingFoliage(SurfaceOutput s, half3 lightDir, half atten) {
        half NdotL = abs(dot(s.Normal, lightDir));
        half4 color;
        color.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
        color.a = s.Alpha;
    
        return color;
    }
    

    Then change this:

    #pragma surface surf Lambert noforwardadd
    

    To this:

    #pragma surface surf Foliage noforwardadd
    

    Now you have basic Lambertian lighting, you can build upon this function however you want. Note that using abs(NdotL) only looks right for flat things like leaves; you can make a more general purpose double-sided shader by using the VFACE semantic to find out if you are rendering a backface and just multiply the normal with the VFACE value (-1 if backfacing, 1 if front facing). You can read more about VFACE here: https://docs.unity3d.com/Manual/SL-ShaderSemantics.html