Shadow looks broken with custom lighting, but looks good with built-in standard shader

Hi guys,
I’m trying to make a simple skin shader for my game. Almost got it looking ok until I turned on the self-shadows.
As you can see from the attached file:
2971540--220726--1.png 2971540--220727--2.png
pic 1 pic 2
pic 1 is my own shader, pic 2 is the result with the standard shader.
My own shader results in broken shadow edges that looks really bad. And I don’t think it’s anything to do with the Quality Settings(I’ve tried). I believe there might be something wrong in my shader:
// the code here:
inline float4 LightingCustomLighting(SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
{
viewDir = normalize(viewDir);
lightDir = normalize(lightDir);
s.Normal = normalize(s.Normal);
float3 halfVec = normalize(lightDir + viewDir);
float NdotL = dot(s.Normal, lightDir);
float halfLambert = NdotL * 0.5 + 0.5;

// fresnel and rim
float fresnel = saturate(pow(1 - dot(viewDir, halfVec), 5.0));
fresnel += 0.2 * (1.0 - fresnel);
float rim = saturate(pow(1 - dot(viewDir, s.Normal), _RimPower)) * fresnel;

// specular
float specBase = max(0, dot(s.Normal, halfVec));
float spec = pow(specBase, s.Specular * 128) * s.Gloss * fresnel;

// ramp
float3 ramp = tex2D(_RampTex, float2(halfLambert, 0)).rgb;

float4 col;

fixed3 colWithoutShadow = s.Albedo * _LightColor0.rgb * ramp * 0.5;
col.rgb = colWithoutShadow * atten + colWithoutShadow + (spec) + (rim * _RimColor);
col.a = s.Alpha;

return col;
}

Please point out the reason for me if you knows why. Thanks!

This is why.

Think of a sphere and a directional light using a basic Lambert (clamped dot product) shading model. The parts of the mesh that are facing towards the light are lit, and those away aren’t. The areas that are self shadowing are also on the areas facing away from the light, but since they are already not lit from the lighting model they don’t show even though they’re there. If you change the shading, like if you remove the dot product and just use the light color over the entire object, that shadow gets exposed.

On the left is a basic Lambert, on the right is the shadow by itself.
2972013--220774--LambertVsUnlitShadow.png

Since half lambert, what you’re using, takes the dark “edge” from Lambert and removes it by making the entire sphere lit, that ugly shadow gets exposed.

1 Like

Thank you! That is indeed why!
I’m not sure how the light attenuation works, but seems I can only use the lambert which is max(0, NdotL) to multiply with the _LightColor0 and the atten… for the rest calculation, will be added to that result. It works fine now. Thanks a lot!