4.3 Sprites and Lighting

Is it possible to have a sprite respond to point lights with normal maps? I have a Sprite and a Mesh next to each other sharing the same textures and materials. The Mesh shows the new colors from the point lights but the Sprite does not.

The default sprite shader doesn’t use lighting. You’d need to use a different shader.

–Eric

I am currently using: Transparent/Cutout/Bumped Diffuse on both Mesh and Sprite. The Mesh is the only one that responds

I got the same problem. I also tried fiddling around with the shader, but without success. The shader works with a mesh though. Is the SpriteRenderer somehow skipping the lights?

So I am not crazy. :slight_smile:

Any official words?

Made a bug report this today: Case 575520

I made a similar bug report recently, and this is the response I got back:

:frowning:

1 Like

Well, that’s sad to know. Especially with the development of tools like SpriteLamp for painting normal maps. I haven’t had a chance to mess with 4.3 yet, but would there be any way to use the 2d animation tools without a SpriteRenderer? I mean, I highly doubt it (it wouldn’t really make much sense), but it would be good to confirm.

I don’t know their underlying implementation of SpriteRenderer, but it would be nice if in a future release they’d allow the enabling of dynamic lights.

I’ve found this video:

but I still don’t understand how it was made

Sprites are basically quads aligned to the XY plane. Use any material other than the default one and you can have even parallax mapping on them. It’s all in the shader you use!

I just wrote some details on how I did that in this Answers thread: Can Normal maps be used to create a 2D sprites lighting system? - Questions & Answers - Unity Discussions

I wrote an experimental shader, to get normal mapping to work for the SpriteRenderer. At first it seemed like it doesn’t work, but after a lot of hours searching for bugs and reading documentation for Shaderlab I couldn’t find anything wrong. So after a few days apart I did a small test by multiplying the normal value with 2 and seeing it actually works, but it’s A LOT more subtle, than when applied to a quad. Now what the exact reason is I couldn’t figure out, but I highly suspect it being correlated with the bug, where lighting disappears from the light sprite after the distance from nearest light is > 1 unit. There is probably a bug filed for that, I don’t know? But it’s easy to see, using the Sprite-Diffuse shader from the built-in package.

Along comes the code:

Shader "CustomSprite/Sprite-Normal"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _BumpMap ("Normalmap", 2D) = "bump" {}
        _Color ("Tint", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags
        { 
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
            //"CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Blend SrcAlpha OneMinusSrcAlpha

        CGPROGRAM
        #pragma surface surf Lambert vertex:vert

        sampler2D _MainTex;
        sampler2D _BumpMap;
        fixed4 _Color;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_BumpMap;
            fixed4 color;
        };
        
        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.color = _Color;
        }

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

Fallback "Transparent/VertexLit"
}

If you find anything wrong or a better way to do stuff, please share :slight_smile:

EDIT: SpriteAtlas I deactivated, to not get to a situation, where UV maps of the colormap and bumpmap don’t allign. I suspect this could lead to shit not working. Correct me if I’m wrong, didn’t test this!

I implemented a simple system for lighting with normal mapped sprites. Is this worth releasing to the asset store?


Depends if it’s just normal mapping I doubt it is worth it because it’s simple to implement, but if it includes proper depth mapping then maybe.

I’m going to add a lot of commonly needed features, anyone interested in getting an email update when it’s out can get on the list here:
http://eepurl.com/LfGNv

Also taking feature requests.

Thanks for sharing. I found by chance that changing the Z size of the sprite changes the bump height, so bumps are relative to this Z value. This gives a lot of control over bump height including realtime bump height changes just by scaling the Z size.

:smile:

Oh, you are right! I actually had my Sprite scaled along x&y and therefore had such a low contrast :rage: Playing around with the scale values I found something interesting.
1st: Scaling a Sprite along X/Y-axis, lowers the bump height - so don’t forget to adjust the z-scale, if you adjust the other two.
2nd: (and this is a weird one) - If I set scale to about 5, lighting disappears from Sprite, if distance of light to object > 1 unit. This doesn’t happen at all, if scale is left to one. How come?

2nd is actually a show stopper, since I need all my sprite scaled, after import.

Just for future searches: Set material on Sprite to Sprite/Diffuse for lighting sprites.

I managed to get lighting working with 2D sprites by changing it to sprites-diffuse instead of sprites-default. However when using sprites-diffuse it seems the color of the sprites can no longer be changed. I use the following to change the color of the sprites: GetComponent ().color = Color.red;

Anyone know how I can continue to use sprites-diffuse and allow the color to be changed?

EDIT:

I figured it out. I changed the code to renderer.material.color = Color.red; and that worked.

Changing the material that way will increase your draw calls and undercut the benefit of the sprites batching. The color property on the SpriteRenderer just modifies the vertex color so you can “fix” the Sprites-Diffuse shader by changing the line:
o.color = _Color;
to:
o.color = v.color * _Color;

Now when then sprites render you get the same batching as the “default” sprite shader, but individual sprites can change their color.