Unity Shader + Script
PRE-RENDERED SPRITE OUTLINE
An Unity sprite outline solution that only render outline once.

Source code and demo files can be download from Github page.

introduction

Demo scene with Unity standard assets

Some 2D games may need the feature of sprites’ outline. (In detective game for example, may need highlight the object when the cursor hover it). The outlines may also need the flexibility to change color, width and sorting layer.

Currently there are several solutions in Unity.
First is relay on the artist to create outlines sprite using Photoshop, it will make the artist painful even it just means click a button in Photoshop considering the sprites’ amount and possible many iterations.

Fortunately, there’s a shader can help us do this. Ryan Nielson gives a clever pixel shader which compare the neighbor pixels to get a great outline for our sprites. But since it samples the texture 8 times per pixel per frame, in some graphic limited hardware, it seems a little bit cost.

Problems & Challenges:

1. Directly apply the outline shader to original sprite makes the gpu do repeat calculations each frame.

2. The outline is in the same layer with the sprite ( sometimes we may want it in top most). we can implement depth write in the shader, but it will affect the graphic pipeline’s early-z feature.

3. Dynamic change sprite’s shader will lead to extra cost.

Updates & New solution:

Issue settled.
I found out in sprite render when using property block to modify material’s _MainTex, it lead to only replace the source texture with the new one the sprite’s definition still pass from the renderer and it support Texture class which is the parent class of RenderTexture and Texture2D.

New Solution
:

1. Create a child gameObject and add a SpriteRenderer component. Set the sorting order.

2. Use Graphics.Blit only when meet sprite with new source texture, render the source sprite texture into outline texture using outline shader.

3. Copy the spriterenderer property block to the child gameObject’s, only modify the “_MainTex” to the rendered texture above.

void LateUpdate()
{
    Sprite sourceSprite = spriteRenderer.sprite;
    //check if the sprite already in the list 
    if (!SpriteStorage.textureDict.ContainsKey(sourceSprite.texture))
    {
        //do the generation of the new sprite 
        GenerateSprite(sourceSprite);
        textureCount++;
    }
    if (showOutline)
    {
        //check if the object is enabled
        if (!oSprite.activeInHierarchy)
        {
            //set the object active 
            oSprite.SetActive(true);
            //get and set the property 
            outlineRenderer.sortingOrder = outlineSortingOrder;
        }
        //using property block to change the outline texture
        outlineRenderer.sprite = sourceSprite;
        destTexture = SpriteStorage.textureDict[spriteRenderer.sprite.texture];
        spriteRenderer.GetPropertyBlock(outlineProperties);
        outlineProperties.SetTexture("_MainTex", destTexture);
        outlineRenderer.SetPropertyBlock(outlineProperties);
    }
    else
    {
        if (oSprite.activeInHierarchy)
        {
            oSprite.SetActive(false);
        }
    }
}

lateupdate function in the scripting