December 19, 2014  by  
Tags: , ,

When working on my 2D lighting system, I needed to create some shadows. Shadows for sprites can easily be created by skewing the sprite and drawing it in all black. How much you skew depends on the position in relation to the light source. I already had a lighting and shadow system working in XNA, and now I just needed to get it working in Unity.

My first thought was to perfrom a skew from within Unity, in C#, like I did in XNA. As it turns out, you can’t (you can skew GUI elements, but not actual game objects). If you want to skew game objects, you need to skew the mesh itself, which I did actually get to work. However, this solution was a little ugly, and I’m not sure about the performance ramifications when recalculating every frame. So, I set off to find a more elegant solution.

My next idea was to try to skew the sprite from within the vertex shader. I knew it had to be possible, but I wasn’t sure exactly how. To my great surprise (and frustration), I was absolutely unable to find a simple vertex shader skew demo or tutorial anywhere on the web. I searched for literally hours one day, but came up empty. I suppose I shouldn’t be too surprised, since vertex shaders are rarely used with pure 2D games.

With no options left, I had a go at it myself. After a bit of trial and error I was able to create a working solution. All in all, it actually took less time for me to implement it myself than I spent searching for a tutorial! Sigh. Live and learn.

I’ll share the shader here in hopes of saving someone the hassle of what I went through. For a great article on understanding skew matrices themselves, check out this Flash transformation matrix tutorial. Enjoy!

sprite_skew

 
  1. // Adapted from the built-in Sprites-Default.shader
  2. // You can download the source for the built-in shaders from:
  3. // http://unity3d.com/unity/download/archive
  4. Shader "Sector12/SpriteSkewShader"
  5. {
  6.     Properties
  7.     {
  8.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
  9.         _Color ("Tint", Color) = (1,1,1,1)
  10.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
  11.         
  12.         _HorizontalSkew ("Horizontal Skew", Float) = 0
  13.         _VerticalSkew ("Vertical Skew", Float) = 0
  14.     }
  15.     SubShader
  16.     {
  17.         Tags
  18.         {
  19.             "Queue"="Transparent"
  20.             "IgnoreProjector"="True"
  21.             "RenderType"="Transparent"
  22.             "PreviewType"="Plane"
  23.             "CanUseSpriteAtlas"="True"
  24.         }
  25.         Cull Off
  26.         Lighting Off
  27.         ZWrite Off
  28.         Fog { Mode Off }
  29.         Blend One OneMinusSrcAlpha
  30.         Pass
  31.         {
  32.         CGPROGRAM
  33.             #pragma vertex vert
  34.             #pragma fragment frag
  35.             #pragma multi_compile DUMMY PIXELSNAP_ON
  36.             #include "UnityCG.cginc"
  37.             
  38.             struct appdata_t
  39.             {
  40.                 float4 vertex : POSITION;
  41.                 float4 color : COLOR;
  42.                 float2 texcoord : TEXCOORD0;
  43.             };
  44.             struct v2f
  45.             {
  46.                 float4 vertex : SV_POSITION;
  47.                 fixed4 color : COLOR;
  48.                 half2 texcoord : TEXCOORD0;
  49.             };
  50.             
  51.             sampler2D _MainTex;
  52.             fixed4 _Color;
  53.             float _HorizontalSkew;
  54.             float _VerticalSkew;
  55.             v2f vert(appdata_t IN)
  56.             {
  57.                 v2f OUT;
  58.                 OUT.texcoord = IN.texcoord;
  59.                 OUT.color = IN.color * _Color;
  60.                 
  61.                 // Create a skew transformation matrix
  62.                 float h = _HorizontalSkew;
  63.                 float v = _VerticalSkew;
  64.                 float4x4 transformMatrix = float4x4(
  65.                     1,h,0,0,
  66.                     v,1,0,0,
  67.                     0,0,1,0,
  68.                     0,0,0,1);
  69.                 
  70.                 float4 skewedVertex = mul(transformMatrix, IN.vertex);
  71.                 OUT.vertex = mul(UNITY_MATRIX_MVP, skewedVertex);
  72.                 
  73.                 #ifdef PIXELSNAP_ON
  74.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
  75.                 #endif
  76.                 return OUT;
  77.             }
  78.             fixed4 frag(v2f IN) : SV_Target
  79.             {
  80.                 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
  81.                 c.rgb *= c.a;
  82.                 return c;
  83.             }
  84.         ENDCG
  85.         }
  86.     }
  87. }


Comments are closed here.