Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Fancy Sprite Lighting (Normals and Specular)

Discussion in '2D' started by stendec365, Nov 15, 2013.

  1. stendec365

    stendec365

    Joined:
    Nov 15, 2013
    Posts:
    1
    EDIT: Turns out I need to learn more. To get lighting working as it should, you just need to add a tangent line to your vertex shader, giving you something like:

    Code (csharp):
    1.         void vert (inout appdata_full v, out Input o) {
    2.             #if defined(PIXELSNAP_ON)  !defined(SHADER_API_FLASH)
    3.             v.vertex = UnityPixelSnap (v.vertex);
    4.             #endif
    5.  
    6.             v.normal = float3(0, 0, -1);
    7.             v.tangent = float4(1, 0, 0, 1);
    8.         }
    Thanks to PurulentExudate on reddit for their comment about this. As such, please ignore the code below. It's bad and, well, bad.




    When you're working with shaders on sprites, the provided lightDir doesn't work so you have to calculate it yourself.

    $Image.jpg

    I've got a little unity web player with my test project at http://stendec.me/LightDir/LightDir.html and you can download the project from http://stendec.me/LightDir/LightDirBug.7z

    I might be doing something wrong (and if I am, please let me know), but lightDir is just flat for a sprite. My first attempt at normals and specular lighting was this:

    Code (csharp):
    1. half4 LightingSpriteNormal (SurfaceOutputCustom s, half3 lightDir, half3 viewDir, half atten) {
    2.     half3 h = normalize(lightDir + viewDir);
    3.     fixed diff = max(0, dot(s.Normal, lightDir));
    4.    
    5.     float nh = max(0, dot(s.Normal, h));
    6.     float spec = pow(nh, s.Specular * 128.0) * s.Gloss;
    7.    
    8.     fixed4 c;
    9.     c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);
    10.     c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
    11.     return c;
    12. }
    Some of you may notice that that's exactly the same as LightingBlinnPhong. It doesn't work, because it relies on lightDir to be correct, which it's not.

    In order to make normals and specular work, I had to call ObjSpaceLightDir with code that ended up looking like:

    Code (csharp):
    1. void vert (inout appdata_full v, out Input o) {
    2.     v.normal = float3(0, 0, 1);
    3.     UNITY_INITIALIZE_OUTPUT(Input, o);
    4.     o.lightDir = ObjSpaceLightDir(v.vertex);
    5. }
    6.  
    7. void surf (Input IN, inout SurfaceOutputCustom o) {
    8.     half4 c = tex2D (_MainTex, IN.uv_MainTex);
    9.     o.Albedo = c.rgb;
    10.     o.Alpha = c.a;
    11.     o.Normal = UnpackNormal(tex2D(_NormTex, IN.uv_NormTex));
    12.     o.lightDir = IN.lightDir;  
    13.     o.Gloss = 1;
    14.     o.Specular = _SpecPower;
    15. }
    16.        
    17. half4 LightingSpriteNormal (SurfaceOutputCustom s, half3 lightDir, half3 viewDir, half atten) {
    18.     half3 h = normalize(s.lightDir + viewDir);
    19.     fixed diff = max(0, dot(s.Normal, s.lightDir));
    20.    
    21.     float nh = max(0, dot(s.Normal, h));
    22.     float spec = pow(nh, s.Specular * 128.0) * s.Gloss;
    23.    
    24.     fixed4 c;
    25.     c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);
    26.     c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
    27.     return c;
    28. }
    I've attached the full shader file to this post.
     

    Attached Files:

    Last edited: Nov 17, 2013
  2. XGundam05

    XGundam05

    Joined:
    Mar 29, 2012
    Posts:
    473
    Yeah, UT has said that SpriteRenderer is not meant to be affected by dynamic lights -.- So thanks for putting your findings up here :)