3
\$\begingroup\$

I have a sprite with Transparent/Cutout/Diffuse shader. Recieving shadows is turned on in SpriteRenderer. The light is a pointlight and I am using deffered rendering path.

However when I am above or right of the object, it is covered in shadow. When I am below or left of the object everything seem to work as it should.If I place the light in the center of the sprite, only a part of the sprite is lit up, the other part is covered in shadow.

Maybe it is something with normals? I need to get rid of the self shading effect.

enter image description hereenter image description here

Shader

Shader "Transparent/Cutout/Diffuse" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}

SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
LOD 200

CGPROGRAM
#pragma surface surf Lambert alphatest:_Cutoff

sampler2D _MainTex;
fixed4 _Color;

struct Input {
    float2 uv_MainTex;
};

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

Fallback "Transparent/Cutout/VertexLit"
}

I found out what unity uses for lambert lightning. Since I use deffered rendering so unity should use function with _PrePass prefix. But the implementation of the actual lighning is implemented somewhere else and is it used for all materials, that looks like dead end.

Custom Lightning

inline fixed4 LightingSLambert (SurfaceOutput s, fixed3 lightDir, fixed atten)
{
fixed diff = max (0, dot (s.Normal, lightDir));

fixed4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
c.a = s.Alpha;
return c;
}


inline fixed4 LightingSLambert_PrePass (SurfaceOutput s, half4 light)
{
fixed4 c;
c.rgb = s.Albedo * light.rgb;
c.a = s.Alpha;
return c;
}

inline half4 LightingSLambert_DirLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal)
{
UNITY_DIRBASIS
half3 scalePerBasisVector;  
half3 lm = DirLightmapDiffuse (unity_DirBasis, color, scale, s.Normal, surfFuncWritesNormal, scalePerBasisVector);  
return half4(lm, 0);
}
\$\endgroup\$
  • \$\begingroup\$ What's the light's Y coordinate relative to the sprites? in front of them, behind them or same depth? \$\endgroup\$ – zaratustra May 13 '14 at 13:56
  • \$\begingroup\$ Infront of them, closer to the camera. \$\endgroup\$ – jellyfication May 13 '14 at 14:41
  • \$\begingroup\$ Is the type of the light a point light or a directional light? \$\endgroup\$ – d3dave May 13 '14 at 18:14
  • \$\begingroup\$ It is a point light. \$\endgroup\$ – jellyfication May 13 '14 at 18:44
1
+100
\$\begingroup\$

Unity's SpriteRenderer does not use normals by default. From the SpriteRenderer Component page in docs.

http://docs.unity3d.com/Documentation/Components/class-SpriteRenderer.html

"SpriteRenderer uses a mesh combined of position, color and UV to render. Normal vector is not included. If normals are required, you can generate them in a vertex shader. See 'Custom data computed per-vertex' in Surface Shader Examples."

What you want is possible but is not what the SpriteRenderer is intended for. This code below adds normals to the surface shader which removes the immediate shading error by supplying a normal vector manually.

While this should work for your use case, it may be better to not use a sprite at all and use an actual MeshRenderer/Filter with a quad or plane.

(The example normals below work for having the light behind the sprite, assuming Y-up and Z-positive away from the camera)

Shader "Custom/SpriteLightWithNormals" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}

SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
LOD 200

CGPROGRAM

#pragma surface surf Lambert vertex:vert alphatest:_Cutoff 

sampler2D _MainTex;
fixed4 _Color;

struct Input 
{
    float2 uv_MainTex;
    float3 nrmls;
};

void vert(inout appdata_full v, out Input o)
{
    v.normal = float3(0,0,-1);
    v.tangent = float4 (1,0,0,-1);
    UNITY_INITIALIZE_OUTPUT(Input,o);
    o.nrmls = v.normal;
}

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

    ENDCG
}FallBack "Diffuse"}

Edit: I've updated the shader to support shadows.

Shader "Custom/SpriteLightWithNormals" 
{
Properties 
{
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}

SubShader 
{
    Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutOut" "CanUseSpriteAtlas"="True"}
    LOD 200

    CGPROGRAM

    #pragma surface surf Lambert alpha vertex:vert  alphatest:_Cutoff fullforwardshadows
    #pragma multi_compile DUMMY PIXELSNAP_ON 

    sampler2D _MainTex;
    fixed4 _Color;

    struct Input 
    {
        float2 uv_MainTex;
        float3 nrmls;
    };

    void vert(inout appdata_full v, out Input o)
    {
        v.normal = float3(0,0,-1);
        v.tangent = float4 (0,0,0,0);
        UNITY_INITIALIZE_OUTPUT(Input,o);
        o.nrmls = v.normal;
    }

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

    ENDCG
}   }
\$\endgroup\$
  • \$\begingroup\$ It looks like it's working, there are just couple of thing, the part that is in the shadow is not dark and crab is slightly to the blue, here take a look. \$\endgroup\$ – jellyfication May 17 '14 at 23:08
  • \$\begingroup\$ I'm not sure what could be causing the blue color you are seeing. perhaps the Color property of the material has/is being modified? \$\endgroup\$ – Will C May 19 '14 at 17:21
  • \$\begingroup\$ Ok, so that blue color was just a light that did not affect world only the sprites and few other things, totally forgot about it. Thank you :) \$\endgroup\$ – jellyfication May 19 '14 at 19:39
0
\$\begingroup\$

It seems like a fair assessment that it has got something to with normals, but it is hard to know exactly given only the posted code. It looks like the sprite's normal is pointing down left, rather than towards the screen.

Given that the sprites seem to be located in the same plane as the light fixing this to be physically correct would actually make the sprites black all of the time, so I guess you better make some non-physical light. It should be possible to write a lighting shader that simply ignore normals, I think that would work well for your sprites.

I haven't got the full grasp of your code, but the following line has what looks like a calculation of lighting with regards to surface normals:

fixed diff = max (0, dot (s.Normal, lightDir));

If you simply set diff to 1 for sprites I suppose that it will work.

\$\endgroup\$
  • \$\begingroup\$ Do you have an idea how to modify the shader ? I thought about modifing the Lamber implementation somehow. \$\endgroup\$ – jellyfication May 13 '14 at 17:53
  • \$\begingroup\$ I use deffered rendering and changes in LightingSLambert does not seem to take effect. \$\endgroup\$ – jellyfication May 13 '14 at 23:18
  • \$\begingroup\$ So, your code is a lot of copy-paste work, you don't really know yourself what parts are responsible for what? I'm afraid that I can't think of any simple way to help you with that. \$\endgroup\$ – aaaaaaaaaaaa May 14 '14 at 9:36
  • \$\begingroup\$ AFAIK LightingSLambert is only used when forward rendering is enabled and LightingSLambert_PrePass is only called with deffered rendering. I think that the part before PrePass is called is burried somewhere inside unity and is common for all materials. Well, thanks for your help anyway :) \$\endgroup\$ – jellyfication May 14 '14 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.