Need help with a 2D Sprite Shader (Shadows, etc)

I’m very new to shaders, and I’m having trouble implementing a 2D sprite shader. My game uses 2D graphics in 3D space, and I’ve messed around with the default shader and was able to implement z buffering as well as alpha-test to make the sprites properly display based on z distance rather than layers.

Now, I’m trying to add some more complex features to the shader, but I have no idea where to begin.
What I’m trying to implement to my shader:
-Casting and receiving shadows
-normal/depth maps and self shadows (I’m trying to use this shader, although it doesn’t have self shadows)
-And of course using z depth instead of layers

One more thing that I want to try, if it’s possible, is essentially have a “side shadow” for objects. When casting shadows off the sprites, the shadow would look fine as long as the light is behind or infront of the sprite. When the light is to the side of the sprite, however, it will only project a thin line. I was thinking of having each object have a “side sprite” that the shader will use to cast a shadow if the light is to the side of the object, instead of it’s current sprite. I’m worried if it’s possible or how well the shadow will line up, though.

Any advice or help would be much appreciated, as shaders are still very confusing for me

Well, I’m still trying it on my own, since no is responding here…
I’m having trouble getting it to work with directional lights. I’ve attempted editing the shader I linked to in my original post, and here is what I have so far:

// Shader for Unity integration with SpriteLamp
// Written by Steve Karolewics  Indreams Studios
Shader "Custom/shr_SpriteNormalShader"
{
    Properties
    {
        _MainTex ("Diffuse Texture", 2D) = "white" {}
        _Normal ("Normal", 2D) = "bump" {}
        _Depth ("Depth", 2D) = "gray" {}
        _SpecColor ("Specular Material Color", Color) = (1,1,1,1) 
        _Shininess ("Shininess", Float) = 10
        _AmplifyDepth ("Amplify Depth", Float) = 1
        _CelShadingLevels ("Cel Shading Levels", Float) = 0
    }

    SubShader
    {
    
        ZWrite On
		AlphaTest Greater 0.1
        Pass
        {    
            Tags { "LightMode" = "ForwardBase" }

            CGPROGRAM

            #pragma vertex vert  
            #pragma fragment frag 
            #include "UnityCG.cginc"

            // User-specified properties
            uniform sampler2D _MainTex;

            struct VertexInput
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float4 uv : TEXCOORD0;    
            };

            struct VertexOutput
            {
                float4 pos : POSITION;
                float4 color : COLOR;
                float2 uv : TEXCOORD0;
            };

            VertexOutput vert(VertexInput input) 
            {
                VertexOutput output;

                output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
                output.color = input.color;
                output.uv = float2(input.uv);
                return output;
            }

            float4 frag(VertexOutput input) : COLOR
            {
                float4 diffuseColor = tex2D(_MainTex, input.uv);

                float3 ambientLighting = float3(UNITY_LIGHTMODEL_AMBIENT) * float3(diffuseColor) *
                    float3(input.color);
                return float4(ambientLighting, diffuseColor.a);
            }

            ENDCG
        }

        Pass
        {    
            Tags { "LightMode" = "ForwardAdd" }
            Blend One One // additive blending 

            CGPROGRAM

            #pragma vertex vert  
            #pragma fragment frag
            #pragma target 3.0

            #include "UnityCG.cginc"

            // User-specified properties
            uniform sampler2D _MainTex;
            uniform sampler2D _Normal;
            uniform sampler2D _Depth;
            uniform float4 _SpecColor; 
            uniform float4 _LightColor0;
            uniform float _Shininess;
            uniform float _AmplifyDepth;
            uniform float _CelShadingLevels;

            struct VertexInput
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float4 uv : TEXCOORD0;
            };

            struct VertexOutput
            {
                float4 pos : POSITION;
                float4 color : COLOR;
                float2 uv : TEXCOORD0;
                float4 posWorld : TEXCOORD1;
            };

            VertexOutput vert(VertexInput input)
            {
                VertexOutput output;

                output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
                output.posWorld = mul(_Object2World, input.vertex);

                output.uv = float2(input.uv);
                output.color = input.color;
                return output;
            }

            float4 frag(VertexOutput input) : COLOR
            {
                float4 diffuseColor = tex2D(_MainTex, input.uv);

                // To compute the correct normal: 
                //   1) Get the pixel value from the normal map
                //   2) Subtract 0.5 and multiply by 2 to convert from the range 0...1 to -1...1
                //   3) Multiply by world to object matrix, to handle rotation, etc
                //   4) Negate Z so that lighting works as expected (sprites further away from the camera than
                //      a light are lit, etc.)
                //   5) Normalize
                float3 normalDirection = (tex2D(_Normal, input.uv).xyz - 0.5f) * 2.0f;
                normalDirection = float3(mul(float4(normalDirection, 1.0f), _World2Object));
                normalDirection.z *= -1;
                normalDirection = normalize(normalDirection);

                // To adjust depth:
                //   1) Get the depth value from the depth map
                //   2) Subtract 0.5 and multiply by 2 to convert from the range 0...1 to -1...1
                //   3) Multiply by the amplify depth value, and subtract from the fragment's z position
                float depthColor = (tex2D(_Depth, input.uv).x - 0.5f) * 2.0f;
                float3 posWorld = float3(input.posWorld);
                posWorld.z -= depthColor * _AmplifyDepth;
                
                float attenuation;
                float3 lightDirection;
                
				if (0.0 == _WorldSpaceLightPos0.w) // directional light?
            	{
            		attenuation = 1.0; // no attenuation
            		lightDirection = normalize(float3(_WorldSpaceLightPos0));
            	}
            	else{
            		//float3 vertexToLightSource = float3(_WorldSpaceLightPos0 - mul(modelMatrix, input.vertex));
					float3 vertexToLightSource = float3(_WorldSpaceLightPos0) - posWorld;
					float distance = length(vertexToLightSource);
					attenuation = 1.0 / distance; // linear attenuation 
					lightDirection = normalize(vertexToLightSource);
            	}
            	

                // Compute diffuse part of lighting
                float normalDotLight = dot(normalDirection, lightDirection);
                float diffuseLevel = attenuation * max(0.0f, normalDotLight);

                // Compute specular part of lighting
                float specularLevel;
                if (normalDotLight < 0.0f)
                {
                    // Light is on the wrong side, no specular reflection
                    specularLevel = 0.0f;
                }
                else
                {
                    // For orthographic cameras, the view direction is always known
                    float3 viewDirection = float3(0.0f, 0.0f, -1.0f);
                    specularLevel = attenuation * pow(max(0.0, dot(reflect(-lightDirection, normalDirection),
                        viewDirection)), _Shininess);
                }

                // Add cel-shading if enough levels were specified
                if (_CelShadingLevels >= 2)
                {
                    diffuseLevel = floor(diffuseLevel * _CelShadingLevels) / (_CelShadingLevels - 0.5f);
                    specularLevel = floor(specularLevel * _CelShadingLevels) / (_CelShadingLevels - 0.5f);
                }

                float3 diffuseReflection = float3(diffuseColor) * input.color *
                    float3(_LightColor0) * diffuseLevel;
                float3 specularReflection = float3(_LightColor0) * float3(_SpecColor) *
                    input.color * specularLevel;
                return float4(diffuseReflection + specularReflection, diffuseColor.a);
             }

             ENDCG
        }
    }
    // The definition of a fallback shader should be commented out 
    // during development:
    // Fallback "Transparent/Diffuse"
}

I’ve gone through this page to see how directional lights were done there and to try to add it to this shader, but I honestly have no clue what I’m doing.
Would really like some help, please.

After reading through the article for the 5th time, I noticed that he mentioned that since we are using 2D, we always know the normaldirection and viewdirection. In my case, this is not true, since I’m doing everything in a 3D environment.
I’ve tried to adjust the shader to calculate the normaldirection and viewdirection, but I’m getting an error. Here is what I changed in the above shader:

float3 myNormal = (tex2D(_Normal, input.uv).xyz - 0.5f) * 2.0f;
myNormal.z *= -1;
				
float4x4 modelMatrix = _Object2World;
float4x4 modelMatrixInverse = _World2Object; 

float3 normalDirection = normalize(float3(mul(float4(myNormal, 0.0), modelMatrixInverse)));
float3 viewDirection = normalize(float3(float4(_WorldSpaceCameraPos, 1.0) - mul(modelMatrix, input.vertex)));

Everything seems to work fine except for the viewdirection line. It gets the following errors:
Shader error in ‘Custom/shr_SpriteNormalShader’: Shader program had errors at line 76
Shader error in ‘Custom/shr_SpriteNormalShader’: Program ‘frag’, expression left of .“vertex” is not a struct or array at line 143
Shader error in ‘Custom/shr_SpriteNormalShader’: Program ‘vert’, expression left of .“vertex” is not a struct or array at line 143

Any help at all?